1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
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.rule_list.items.len > 0) {
for (self.rule_list.items[0]) |c| {
try writer.print("{}", .{c});
}
for (self.rule_list.items[1..]) |r| {
try writer.print(" | ", .{});
for (r) |c| {
try writer.print("{}", .{c});
}
}
}
try writer.writeByte(']');
}
|