diff options
| author | Nathan Reiner <nathan@nathanreiner.xyz> | 2025-04-24 20:06:50 +0200 |
|---|---|---|
| committer | Nathan Reiner <nathan@nathanreiner.xyz> | 2025-04-24 20:06:50 +0200 |
| commit | f593da7580f423b1405f4705081368acef0b3c21 (patch) | |
| tree | 875e25e99da4f531e44e7537c7d8006da9ee0aa5 /src/non-terminal.zig | |
| parent | 839271627d0cfd2240ec30a603ff60a0165fe6a2 (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.zig | 95 |
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(']'); +} |