Commit dccf1247b2
Changed files (3)
lib
lib/std/c/ast.zig
@@ -26,21 +26,43 @@ pub const Tree = struct {
};
pub const Error = union(enum) {
- InvalidToken: InvalidToken,
+ InvalidToken: SingleTokenError("Invalid token '{}'"),
+ ExpectedToken: ExpectedToken,
+ ExpectedExpr: SingleTokenError("Expected expression, found '{}'"),
+ ExpectedStmt: SingleTokenError("Expected statement, found '{}'"),
pub fn render(self: *const Error, tokens: *Tree.TokenList, stream: var) !void {
switch (self.*) {
.InvalidToken => |*x| return x.render(tokens, stream),
+ .ExpectedToken => |*x| return x.render(tokens, stream),
+ .ExpectedExpr => |*x| return x.render(tokens, stream),
+ .ExpectedStmt => |*x| return x.render(tokens, stream),
}
}
pub fn loc(self: *const Error) TokenIndex {
switch (self.*) {
.InvalidToken => |x| return x.token,
+ .ExpectedToken => |x| return x.token,
+ .ExpectedExpr => |x| return x.token,
+ .ExpectedStmt => |x| return x.token,
}
}
- pub const InvalidToken = SingleTokenError("Invalid token '{}'");
+ pub const ExpectedToken = struct {
+ token: TokenIndex,
+ expected_id: @TagType(Token.Id),
+
+ pub fn render(self: *const ExpectedToken, tokens: *Tree.TokenList, stream: var) !void {
+ const found_token = tokens.at(self.token);
+ if (found_token.id == .Invalid) {
+ return stream.print("expected '{}', found invalid bytes", .{self.expected_id.symbol()});
+ } else {
+ const token_name = found_token.id.symbol();
+ return stream.print("expected '{}', found '{}'", .{ self.expected_id.symbol(), token_name });
+ }
+ }
+ };
fn SingleTokenError(comptime msg: []const u8) type {
return struct {
@@ -62,6 +84,8 @@ pub const Node = struct {
JumpStmt,
ExprStmt,
Label,
+ CompoundStmt,
+ IfStmt,
};
pub const Root = struct {
@@ -73,7 +97,7 @@ pub const Node = struct {
};
pub const JumpStmt = struct {
- base: Node = Node{ .id = .JumpStmt},
+ base: Node = Node{ .id = .JumpStmt },
ltoken: TokenIndex,
kind: Kind,
semicolon: TokenIndex,
@@ -87,14 +111,33 @@ pub const Node = struct {
};
pub const ExprStmt = struct {
- base: Node = Node{ .id = .ExprStmt},
+ base: Node = Node{ .id = .ExprStmt },
expr: ?*Node,
semicolon: TokenIndex,
};
pub const Label = struct {
- base: Node = Node{ .id = .Label},
+ base: Node = Node{ .id = .Label },
identifier: TokenIndex,
colon: TokenIndex,
};
+
+ pub const CompoundStmt = struct {
+ base: Node = Node{ .id = .CompoundStmt },
+ lbrace: TokenIndex,
+ statements: StmtList,
+ rbrace: TokenIndex,
+
+ pub const StmtList = Root.DeclList;
+ };
+
+ pub const IfStmt = struct {
+ base: Node = Node{ .id = .IfStmt },
+ @"if": TokenIndex,
+ cond: *Node,
+ @"else": ?struct {
+ tok: TokenIndex,
+ stmt: *Node,
+ },
+ };
};
lib/std/c/parse.zig
@@ -284,7 +284,19 @@ const Parser = struct {
fn designator(parser: *Parser) !*Node {}
/// CompoundStmt <- LBRACE (Declaration / Stmt)* RBRACE
- fn compoundStmt(parser: *Parser) !?*Node {}
+ fn compoundStmt(parser: *Parser) !?*Node {
+ const lbrace = parser.eatToken(.LBrace) orelse return null;
+ const node = try parser.arena.create(Node.CompoundStmt);
+ node.* = .{
+ .lbrace = lbrace,
+ .statements = Node.JumpStmt.StmtList.init(parser.arena),
+ .rbrace = undefined,
+ };
+ while (parser.declaration() orelse parser.stmt()) |node|
+ try node.statements.push(node);
+ node.rbrace = try parser.expectToken(.RBrace);
+ return &node.base;
+ }
/// Stmt
/// <- CompoundStmt
@@ -303,7 +315,27 @@ const Parser = struct {
/// / ExprStmt
fn stmt(parser: *Parser) !?*Node {
if (parser.compoundStmt()) |node| return node;
- // if (parser.eatToken(.Keyword_if)) |tok| {}
+ if (parser.eatToken(.Keyword_if)) |tok| {
+ const node = try parser.arena.create(Node.IfStmt);
+ _ = try parser.expectToken(.LParen);
+ node.* = .{
+ .@"if" = tok,
+ .cond = try parser.expect(expr, .{
+ .ExpectedExpr = .{ .token = it.index },
+ }),
+ .@"else" = null,
+ };
+ _ = try parser.expectToken(.RParen);
+ if (parser.eatToken(.Keyword_else)) |else_tok| {
+ node.@"else" = .{
+ .tok = else_tok,
+ .stmt = try parser.stmt(expr, .{
+ .ExpectedStmt = .{ .token = it.index },
+ }),
+ };
+ }
+ return &node.base;
+ }
// if (parser.eatToken(.Keyword_switch)) |tok| {}
// if (parser.eatToken(.Keyword_while)) |tok| {}
// if (parser.eatToken(.Keyword_do)) |tok| {}
@@ -407,4 +439,15 @@ const Parser = struct {
return;
}
}
+
+ fn expect(
+ parser: *Parser,
+ parseFn: fn (*Parser) Error!?*Node,
+ err: ast.Error, // if parsing fails
+ ) Error!*Node {
+ return (try parseFn(arena, it, tree)) orelse {
+ try parser.tree.errors.push(err);
+ return error.ParseError;
+ };
+ }
};
lib/std/c/tokenizer.zig
@@ -6,7 +6,7 @@ pub const Source = struct {
file_name: []const u8,
tokens: TokenList,
- pub const TokenList = SegmentedList(Token, 64);
+ pub const TokenList = std.SegmentedList(Token, 64);
};
pub const Token = struct {
@@ -134,6 +134,121 @@ pub const Token = struct {
Keyword_ifndef,
Keyword_error,
Keyword_pragma,
+
+ pub fn symbol(tok: Token) []const u8 {
+ return switch (tok.id) {
+ .Invalid => "Invalid",
+ .Eof => "Eof",
+ .Nl => "NewLine",
+ .Identifier => "Identifier",
+ .MacroString => "MacroString",
+ .StringLiteral => "StringLiteral",
+ .CharLiteral => "CharLiteral",
+ .IntegerLiteral => "IntegerLiteral",
+ .FloatLiteral => "FloatLiteral",
+ .LineComment => "LineComment",
+ .MultiLineComment => "MultiLineComment",
+
+ .Bang => "!",
+ .BangEqual => "!=",
+ .Pipe => "|",
+ .PipePipe => "||",
+ .PipeEqual => "|=",
+ .Equal => "=",
+ .EqualEqual => "==",
+ .LParen => "(",
+ .RParen => ")",
+ .LBrace => "{",
+ .RBrace => "}",
+ .LBracket => "[",
+ .RBracket => "]",
+ .Period => ".",
+ .Ellipsis => "...",
+ .Caret => "^",
+ .CaretEqual => "^=",
+ .Plus => "+",
+ .PlusPlus => "++",
+ .PlusEqual => "+=",
+ .Minus => "-",
+ .MinusMinus => "--",
+ .MinusEqual => "-=",
+ .Asterisk => "*",
+ .AsteriskEqual => "*=",
+ .Percent => "%",
+ .PercentEqual => "%=",
+ .Arrow => "->",
+ .Colon => ":",
+ .Semicolon => ";",
+ .Slash => "/",
+ .SlashEqual => "/=",
+ .Comma => ",",
+ .Ampersand => "&",
+ .AmpersandAmpersand => "&&",
+ .AmpersandEqual => "&=",
+ .QuestionMark => "?",
+ .AngleBracketLeft => "<",
+ .AngleBracketLeftEqual => "<=",
+ .AngleBracketAngleBracketLeft => "<<",
+ .AngleBracketAngleBracketLeftEqual => "<<=",
+ .AngleBracketRight => ">",
+ .AngleBracketRightEqual => ">=",
+ .AngleBracketAngleBracketRight => ">>",
+ .AngleBracketAngleBracketRightEqual => ">>=",
+ .Tilde => "~",
+ .Hash => "#",
+ .HashHash => "##",
+ .Keyword_auto => "auto",
+ .Keyword_break => "break",
+ .Keyword_case => "case",
+ .Keyword_char => "char",
+ .Keyword_const => "const",
+ .Keyword_continue => "continue",
+ .Keyword_default => "default",
+ .Keyword_do => "do",
+ .Keyword_double => "double",
+ .Keyword_else => "else",
+ .Keyword_enum => "enum",
+ .Keyword_extern => "extern",
+ .Keyword_float => "float",
+ .Keyword_for => "for",
+ .Keyword_goto => "goto",
+ .Keyword_if => "if",
+ .Keyword_int => "int",
+ .Keyword_long => "long",
+ .Keyword_register => "register",
+ .Keyword_return => "return",
+ .Keyword_short => "short",
+ .Keyword_signed => "signed",
+ .Keyword_sizeof => "sizeof",
+ .Keyword_static => "static",
+ .Keyword_struct => "struct",
+ .Keyword_switch => "switch",
+ .Keyword_typedef => "typedef",
+ .Keyword_union => "union",
+ .Keyword_unsigned => "unsigned",
+ .Keyword_void => "void",
+ .Keyword_volatile => "volatile",
+ .Keyword_while => "while",
+ .Keyword_bool => "_Bool",
+ .Keyword_complex => "_Complex",
+ .Keyword_imaginary => "_Imaginary",
+ .Keyword_inline => "inline",
+ .Keyword_restrict => "restrict",
+ .Keyword_alignas => "_Alignas",
+ .Keyword_alignof => "_Alignof",
+ .Keyword_atomic => "_Atomic",
+ .Keyword_generic => "_Generic",
+ .Keyword_noreturn => "_Noreturn",
+ .Keyword_static_assert => "_Static_assert",
+ .Keyword_thread_local => "_Thread_local",
+ .Keyword_include => "include",
+ .Keyword_define => "define",
+ .Keyword_ifdef => "ifdef",
+ .Keyword_ifndef => "ifndef",
+ .Keyword_error => "error",
+ .Keyword_pragma => "pragma",
+ };
+ }
};
pub const Keyword = struct {
@@ -1121,8 +1236,7 @@ pub const Tokenizer = struct {
}
} else if (self.index == self.source.buffer.len) {
switch (state) {
- .AfterStringLiteral,
- .Start => {},
+ .AfterStringLiteral, .Start => {},
.u, .u8, .U, .L, .Identifier => {
result.id = Token.getKeyword(self.source.buffer[result.start..self.index], self.prev_tok_id == .Hash and !self.pp_directive) orelse .Identifier;
},
@@ -1416,6 +1530,7 @@ fn expectTokens(source: []const u8, expected_tokens: []const Token.Id) void {
.source = &Source{
.buffer = source,
.file_name = undefined,
+ .tokens = undefined,
},
};
for (expected_tokens) |expected_token_id| {