aboutsummaryrefslogtreecommitdiff
path: root/src/non-terminal.zig
diff options
context:
space:
mode:
authorNathan Reiner <nathan@nathanreiner.xyz>2025-04-24 20:06:50 +0200
committerNathan Reiner <nathan@nathanreiner.xyz>2025-04-24 20:06:50 +0200
commitf593da7580f423b1405f4705081368acef0b3c21 (patch)
tree875e25e99da4f531e44e7537c7d8006da9ee0aa5 /src/non-terminal.zig
parent839271627d0cfd2240ec30a603ff60a0165fe6a2 (diff)
fix naming
the struct RuleList is now named NonTerminal and its member rhs is now called Rule.
Diffstat (limited to 'src/non-terminal.zig')
-rw-r--r--src/non-terminal.zig95
1 files changed, 95 insertions, 0 deletions
diff --git a/src/non-terminal.zig b/src/non-terminal.zig
new file mode 100644
index 0000000..097c603
--- /dev/null
+++ b/src/non-terminal.zig
@@ -0,0 +1,95 @@
+const std = @import("std");
+const CharSet = @import("char-set.zig");
+const Character = @import("character.zig").Character;
+
+const Self = @This();
+pub const Rule = []Character;
+
+name: u8,
+rule_list: std.ArrayList(Rule),
+first: CharSet,
+follows: CharSet,
+
+pub fn init(name: u8, allocator: std.mem.Allocator) Self {
+ return Self {
+ .name = name,
+ .rule_list = std.ArrayList(Rule).init(allocator),
+ .first = CharSet {},
+ .follows = CharSet {},
+ };
+}
+
+pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
+ for (self.rules()) |rule| {
+ allocator.free(rule);
+ }
+
+ self.rule_list.deinit();
+}
+
+pub inline fn rules(self: *Self) []Rule {
+ return self.rule_list.items;
+}
+
+pub fn add_rule(self: *Self, rule: Rule) !void {
+ try self.rule_list.append(rule);
+}
+
+pub fn parse_rule(
+ buffer: []const u8,
+ allocator: std.mem.Allocator
+) !struct { u8, Rule } {
+
+ var rule = std.ArrayList(Character).init(allocator);
+ errdefer rule.deinit();
+
+ var tokens = std.mem.tokenizeAny(u8, buffer, &std.ascii.whitespace);
+
+ const lhs = tokens.next() orelse return error.MissingLhs;
+ if (lhs.len > 1) return error.InvalidLhs;
+
+ const arrow = tokens.next() orelse return error.MissingArrow;
+ if (!std.mem.eql(u8, arrow, "->")) return error.InvalidArrow;
+
+ while (tokens.next()) |token| {
+ if (token.len > 1) return error.InvalidCharacter;
+ try rule.append(Character.from_u8(token[0]));
+ }
+
+ if (rule.items.len == 0) {
+ return error.EmptyProduction;
+ }
+
+ return .{ lhs[0], try rule.toOwnedSlice() };
+}
+
+pub inline fn is_empty(self: *const Self) bool {
+ return self.rules().len == 0;
+}
+
+pub fn format(
+ self: *const Self,
+ comptime fmt: []const u8,
+ options: std.fmt.FormatOptions,
+ writer: anytype,
+) !void {
+ _ = fmt;
+ _ = options;
+
+ try writer.print("[{c} -> ", .{ self.name });
+
+ if (self.rules().len > 0) {
+ for (self.rules()[0]) |c| {
+ try writer.print("{}", .{c});
+ }
+
+ for (self.rules()[1..]) |r| {
+ try writer.print(" | ", .{});
+ for (r) |c| {
+ try writer.print("{}", .{c});
+ }
+ }
+ }
+
+ try writer.writeByte(']');
+}