diff options
Diffstat (limited to 'src/rule-list.zig')
| -rw-r--r-- | src/rule-list.zig | 91 |
1 files changed, 91 insertions, 0 deletions
diff --git a/src/rule-list.zig b/src/rule-list.zig new file mode 100644 index 0000000..a438750 --- /dev/null +++ b/src/rule-list.zig @@ -0,0 +1,91 @@ +const std = @import("std"); +const CharSet = @import("char-set.zig"); +const Character = @import("character.zig").Character; + +const Self = @This(); +const Rhs = []Character; + +name: u8, +rhs: std.ArrayList(Rhs), +first: CharSet, +follows: CharSet, + +pub fn init(name: u8, allocator: std.mem.Allocator) Self { + return Self { + .name = name, + .rhs = std.ArrayList(Rhs).init(allocator), + .first = CharSet {}, + .follows = CharSet {}, + }; +} + +pub fn deinit(self: *Self, allocator: std.mem.Allocator) void { + for (self.rhs.items) |item| { + allocator.free(item); + } + + self.rhs.deinit(); +} + +pub fn add_rule(self: *Self, rhs: Rhs) !void { + try self.rhs.append(rhs); +} + +pub fn parse_rule( + buffer: []const u8, + allocator: std.mem.Allocator +) !struct { u8, Rhs } { + + var rhs = std.ArrayList(Character).init(allocator); + errdefer rhs.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 rhs.append(Character.from_u8(token[0])); + } + + if (rhs.items.len == 0) { + return error.EmptyProduction; + } + + return .{ lhs[0], try rhs.toOwnedSlice() }; +} + +pub inline fn is_empty(self: *const Self) bool { + return self.rhs.items.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.rhs.items.len > 0) { + for (self.rhs.items[0]) |c| { + try writer.print("{}", .{c}); + } + + for (self.rhs.items[1..]) |r| { + try writer.print(" | ", .{}); + for (r) |c| { + try writer.print("{}", .{c}); + } + } + } + + try writer.writeByte(']'); +} |