std-c parser and ast organization

master
Vexu 2020-01-04 21:26:43 +02:00
parent 73a53fa263
commit a20c0b31de
No known key found for this signature in database
GPG Key ID: 59AEB8936E16A6AC
2 changed files with 345 additions and 197 deletions

View File

@ -54,13 +54,47 @@ pub const Error = union(enum) {
} }
}; };
pub const Root = struct { pub const Node = struct {
decls: DeclList, id: Id,
eof_token: TokenIndex,
pub const DeclList = SegmentedList(*Decl, 4); pub const Id = enum {
Root,
JumpStmt,
ExprStmt,
Label,
};
pub const Root = struct {
base: Node,
decls: DeclList,
eof: TokenIndex,
pub const DeclList = SegmentedList(*Node, 4);
};
pub const JumpStmt = struct {
base: Node = Node{ .id = .JumpStmt},
ltoken: TokenIndex,
kind: Kind,
semicolon: TokenIndex,
pub const Kind = union(enum) {
Break,
Continue,
Return: ?*Node,
Goto: TokenIndex,
};
};
pub const ExprStmt = struct {
base: Node = Node{ .id = .ExprStmt},
expr: ?*Node,
semicolon: TokenIndex,
};
pub const Label = struct {
base: Node = Node{ .id = .Label},
identifier: TokenIndex,
colon: TokenIndex,
};
}; };
pub const Decl = struct {
};

View File

@ -55,242 +55,356 @@ pub fn parse(allocator: *Allocator, source: []const u8) !*Tree {
} }
} }
tree.root_node = try parseRoot(arena, &it, tree); var parser = Parser{
.arena = arena,
.it = &it,
.tree = tree,
};
tree.root_node = try parser.root();
return tree; return tree;
} }
/// Root <- ExternalDeclaration* eof const Parser = struct {
fn parseRoot(arena: *Allocator, it: *TokenIterator, tree: *Tree) Allocator.Error!*Node { arena: *Allocator,
const node = try arena.create(ast.Root); it: *TokenIterator,
node.* = .{ tree: *Tree,
.decls = ast.Node.DeclList.init(arena),
.eof_token = undefined, /// Root <- ExternalDeclaration* eof
}; fn root(parser: *Parser) Allocator.Error!*Node {
while (parseExternalDeclarations(arena, it, tree) catch |err| switch (err) { const node = try arena.create(ast.Root);
error.OutOfMemory => return error.OutOfMemory, node.* = .{
error.ParseError => return node, .decls = ast.Node.DeclList.init(arena),
}) |decl| { .eof = undefined,
try node.decls.push(decl); };
} while (parser.externalDeclarations() catch |err| switch (err) {
node.eof_token = eatToken(it, .Eof) orelse { error.OutOfMemory => return error.OutOfMemory,
try tree.errors.push(.{ error.ParseError => return node,
.ExpectedDecl = .{ .token = it.index }, }) |decl| {
}); try node.decls.push(decl);
}
node.eof = eatToken(it, .Eof) orelse {
try tree.errors.push(.{
.ExpectedDecl = .{ .token = it.index },
});
return node;
};
return node; return node;
}; }
return node;
}
/// ExternalDeclaration /// ExternalDeclaration
/// <- Declaration /// <- Declaration
/// / DeclarationSpecifiers Declarator Declaration* CompoundStmt /// / DeclarationSpecifiers Declarator Declaration* CompoundStmt
fn parseExternalDeclarations(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { fn externalDeclarations(parser: *Parser) !?*Node {
if (try parseDeclaration(arena, it, tree)) |decl| {} if (try Declaration(parser)) |decl| {}
return null; return null;
} }
/// Declaration /// Declaration
/// <- DeclarationSpecifiers (Declarator (EQUAL Initializer)?)* SEMICOLON /// <- DeclarationSpecifiers (Declarator (EQUAL Initializer)?)* SEMICOLON
/// \ StaticAssertDeclaration /// \ StaticAssertDeclaration
fn parseDeclaration(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {} fn declaration(parser: *Parser) !?*Node {}
/// StaticAssertDeclaration <- Keyword_static_assert LPAREN ConstExpr COMMA STRINGLITERAL RPAREN SEMICOLON /// StaticAssertDeclaration <- Keyword_static_assert LPAREN ConstExpr COMMA STRINGLITERAL RPAREN SEMICOLON
fn parseStaticAssertDeclaration(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {} fn staticAssertDeclaration(parser: *Parser) !?*Node {}
/// DeclarationSpecifiers /// DeclarationSpecifiers
/// <- StorageClassSpecifier DeclarationSpecifiers? /// <- StorageClassSpecifier DeclarationSpecifiers?
/// / TypeSpecifier DeclarationSpecifiers? /// / TypeSpecifier DeclarationSpecifiers?
/// / TypeQualifier DeclarationSpecifiers? /// / TypeQualifier DeclarationSpecifiers?
/// / FunctionSpecifier DeclarationSpecifiers? /// / FunctionSpecifier DeclarationSpecifiers?
/// / AlignmentSpecifier DeclarationSpecifiers? /// / AlignmentSpecifier DeclarationSpecifiers?
fn parseDeclarationSpecifiers(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {} fn declarationSpecifiers(parser: *Parser) !*Node {}
/// StorageClassSpecifier /// StorageClassSpecifier
/// <- Keyword_typedef / Keyword_extern / Keyword_static / Keyword_thread_local / Keyword_auto / Keyword_register /// <- Keyword_typedef / Keyword_extern / Keyword_static / Keyword_thread_local / Keyword_auto / Keyword_register
fn parseStorageClassSpecifier(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {} fn storageClassSpecifier(parser: *Parser) !*Node {}
/// TypeSpecifier /// TypeSpecifier
/// <- Keyword_void / Keyword_char / Keyword_short / Keyword_int / Keyword_long / Keyword_float / Keyword_double /// <- Keyword_void / Keyword_char / Keyword_short / Keyword_int / Keyword_long / Keyword_float / Keyword_double
/// / Keyword_signed / Keyword_unsigned / Keyword_bool / Keyword_complex / Keyword_imaginary / /// / Keyword_signed / Keyword_unsigned / Keyword_bool / Keyword_complex / Keyword_imaginary /
/// / Keyword_atomic LPAREN TypeName RPAREN /// / Keyword_atomic LPAREN TypeName RPAREN
/// / EnumSpecifier /// / EnumSpecifier
/// / RecordSpecifier /// / RecordSpecifier
/// / IDENTIFIER // typedef name /// / IDENTIFIER // typedef name
fn parseTypeSpecifier(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {} fn typeSpecifier(parser: *Parser) !*Node {}
/// TypeQualifier <- Keyword_const / Keyword_restrict / Keyword_volatile / Keyword_atomic /// TypeQualifier <- Keyword_const / Keyword_restrict / Keyword_volatile / Keyword_atomic
fn parseTypeQualifier(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {} fn typeQualifier(parser: *Parser) !*Node {}
/// FunctionSpecifier <- Keyword_inline / Keyword_noreturn /// FunctionSpecifier <- Keyword_inline / Keyword_noreturn
fn parseFunctionSpecifier(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {} fn functionSpecifier(parser: *Parser) !*Node {}
/// AlignmentSpecifier <- Keyword_alignas LPAREN (TypeName / ConstExpr) RPAREN /// AlignmentSpecifier <- Keyword_alignas LPAREN (TypeName / ConstExpr) RPAREN
fn parseAlignmentSpecifier(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {} fn alignmentSpecifier(parser: *Parser) !*Node {}
/// EnumSpecifier <- Keyword_enum IDENTIFIER? (LBRACE EnumField RBRACE)? /// EnumSpecifier <- Keyword_enum IDENTIFIER? (LBRACE EnumField RBRACE)?
fn parseEnumSpecifier(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {} fn enumSpecifier(parser: *Parser) !*Node {}
/// EnumField <- IDENTIFIER (EQUAL ConstExpr)? (COMMA EnumField) COMMA? /// EnumField <- IDENTIFIER (EQUAL ConstExpr)? (COMMA EnumField) COMMA?
fn parseEnumField(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {} fn enumField(parser: *Parser) !*Node {}
/// RecordSpecifier <- (Keyword_struct / Keyword_union) IDENTIFIER? (LBRACE RecordField+ RBRACE)? /// RecordSpecifier <- (Keyword_struct / Keyword_union) IDENTIFIER? (LBRACE RecordField+ RBRACE)?
fn parseRecordSpecifier(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {} fn recordSpecifier(parser: *Parser) !*Node {}
/// RecordField /// RecordField
/// <- SpecifierQualifer (RecordDeclarator (COMMA RecordDeclarator))? SEMICOLON /// <- SpecifierQualifer (RecordDeclarator (COMMA RecordDeclarator))? SEMICOLON
/// \ StaticAssertDeclaration /// \ StaticAssertDeclaration
fn parseRecordField(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {} fn recordField(parser: *Parser) !*Node {}
/// TypeName /// TypeName
/// <- SpecifierQualifer AbstractDeclarator? /// <- SpecifierQualifer AbstractDeclarator?
fn parseTypeName(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {} fn typeName(parser: *Parser) !*Node {}
/// SpecifierQualifer /// SpecifierQualifer
/// <- TypeSpecifier SpecifierQualifer? /// <- TypeSpecifier SpecifierQualifer?
/// / TypeQualifier SpecifierQualifer? /// / TypeQualifier SpecifierQualifer?
fn parseSpecifierQualifer(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {} fn specifierQualifer(parser: *Parser) !*Node {}
/// RecordDeclarator <- Declarator? (COLON ConstExpr)? /// RecordDeclarator <- Declarator? (COLON ConstExpr)?
fn parseRecordDeclarator(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {} fn recordDeclarator(parser: *Parser) !*Node {}
/// Declarator <- Pointer? DirectDeclarator /// Declarator <- Pointer? DirectDeclarator
fn parseDeclarator(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {} fn declarator(parser: *Parser) !*Node {}
/// Pointer <- ASTERISK TypeQualifier* Pointer? /// Pointer <- ASTERISK TypeQualifier* Pointer?
fn parsePointer(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {} fn pointer(parser: *Parser) !*Node {}
/// DirectDeclarator /// DirectDeclarator
/// <- IDENTIFIER /// <- IDENTIFIER
/// / LPAREN Declarator RPAREN /// / LPAREN Declarator RPAREN
/// / DirectDeclarator LBRACKET (ASTERISK / BracketDeclarator)? RBRACKET /// / DirectDeclarator LBRACKET (ASTERISK / BracketDeclarator)? RBRACKET
/// / DirectDeclarator LPAREN (ParamDecl (COMMA ParamDecl)* (COMMA ELLIPSIS)?)? RPAREN /// / DirectDeclarator LPAREN (ParamDecl (COMMA ParamDecl)* (COMMA ELLIPSIS)?)? RPAREN
fn parseDirectDeclarator(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {} fn directDeclarator(parser: *Parser) !*Node {}
/// BracketDeclarator /// BracketDeclarator
/// <- Keyword_static TypeQualifier* AssignmentExpr /// <- Keyword_static TypeQualifier* AssignmentExpr
/// / TypeQualifier+ (ASTERISK / Keyword_static AssignmentExpr) /// / TypeQualifier+ (ASTERISK / Keyword_static AssignmentExpr)
/// / TypeQualifier+ AssignmentExpr? /// / TypeQualifier+ AssignmentExpr?
/// / AssignmentExpr /// / AssignmentExpr
fn parseBracketDeclarator(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {} fn bracketDeclarator(parser: *Parser) !*Node {}
/// ParamDecl <- DeclarationSpecifiers (Declarator / AbstractDeclarator) /// ParamDecl <- DeclarationSpecifiers (Declarator / AbstractDeclarator)
fn parseParamDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {} fn paramDecl(parser: *Parser) !*Node {}
/// AbstractDeclarator <- Pointer? DirectAbstractDeclarator? /// AbstractDeclarator <- Pointer? DirectAbstractDeclarator?
fn parseAbstractDeclarator(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {} fn abstractDeclarator(parser: *Parser) !*Node {}
/// DirectAbstractDeclarator /// DirectAbstractDeclarator
/// <- IDENTIFIER /// <- IDENTIFIER
/// / LPAREN DirectAbstractDeclarator RPAREN /// / LPAREN DirectAbstractDeclarator RPAREN
/// / DirectAbstractDeclarator? LBRACKET (ASTERISK / BracketDeclarator)? RBRACKET /// / DirectAbstractDeclarator? LBRACKET (ASTERISK / BracketDeclarator)? RBRACKET
/// / DirectAbstractDeclarator? LPAREN (ParamDecl (COMMA ParamDecl)* (COMMA ELLIPSIS)?)? RPAREN /// / DirectAbstractDeclarator? LPAREN (ParamDecl (COMMA ParamDecl)* (COMMA ELLIPSIS)?)? RPAREN
fn parseDirectAbstractDeclarator(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {} fn directAbstractDeclarator(parser: *Parser) !*Node {}
/// Expr <- AssignmentExpr (COMMA Expr)* /// Expr <- AssignmentExpr (COMMA Expr)*
fn parseExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {} fn expr(parser: *Parser) !*Node {}
/// AssignmentExpr /// AssignmentExpr
/// <- ConditionalExpr /// <- ConditionalExpr // TODO recursive?
/// / UnaryExpr (EQUAL / ASTERISKEQUAL / SLASHEQUAL / PERCENTEQUAL / PLUSEQUAL / MINUSEQUA / /// / UnaryExpr (EQUAL / ASTERISKEQUAL / SLASHEQUAL / PERCENTEQUAL / PLUSEQUAL / MINUSEQUA /
/// / ANGLEBRACKETANGLEBRACKETLEFTEQUAL / ANGLEBRACKETANGLEBRACKETRIGHTEQUAL / /// / ANGLEBRACKETANGLEBRACKETLEFTEQUAL / ANGLEBRACKETANGLEBRACKETRIGHTEQUAL /
/// / AMPERSANDEQUAL / CARETEQUAL / PIPEEQUAL) AssignmentExpr /// / AMPERSANDEQUAL / CARETEQUAL / PIPEEQUAL) AssignmentExpr
fn parseAssignmentExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {} fn assignmentExpr(parser: *Parser) !*Node {}
/// ConstExpr <- ConditionalExpr /// ConstExpr <- ConditionalExpr
/// ConditionalExpr <- LogicalOrExpr (QUESTIONMARK Expr COLON ConditionalExpr)? /// ConditionalExpr <- LogicalOrExpr (QUESTIONMARK Expr COLON ConditionalExpr)?
fn parseConditionalExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {} fn conditionalExpr(parser: *Parser) !*Node {}
/// LogicalOrExpr <- LogicalAndExpr (PIPEPIPE LogicalOrExpr)* /// LogicalOrExpr <- LogicalAndExpr (PIPEPIPE LogicalOrExpr)*
fn parseLogicalOrExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {} fn logicalOrExpr(parser: *Parser) !*Node {}
/// LogicalAndExpr <- BinOrExpr (AMPERSANDAMPERSAND LogicalAndExpr)* /// LogicalAndExpr <- BinOrExpr (AMPERSANDAMPERSAND LogicalAndExpr)*
fn parseLogicalAndExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {} fn logicalAndExpr(parser: *Parser) !*Node {}
/// BinOrExpr <- BinXorExpr (PIPE BinOrExpr)* /// BinOrExpr <- BinXorExpr (PIPE BinOrExpr)*
fn parseBinOrExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {} fn binOrExpr(parser: *Parser) !*Node {}
/// BinXorExpr <- BinAndExpr (CARET BinXorExpr)* /// BinXorExpr <- BinAndExpr (CARET BinXorExpr)*
fn parseBinXorExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {} fn binXorExpr(parser: *Parser) !*Node {}
/// BinAndExpr <- EqualityExpr (AMPERSAND BinAndExpr)* /// BinAndExpr <- EqualityExpr (AMPERSAND BinAndExpr)*
fn parseBinAndExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {} fn binAndExpr(parser: *Parser) !*Node {}
/// EqualityExpr <- ComparisionExpr ((EQUALEQUAL / BANGEQUAL) EqualityExpr)* /// EqualityExpr <- ComparisionExpr ((EQUALEQUAL / BANGEQUAL) EqualityExpr)*
fn parseEqualityExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {} fn equalityExpr(parser: *Parser) !*Node {}
/// ComparisionExpr <- ShiftExpr (ANGLEBRACKETLEFT / ANGLEBRACKETLEFTEQUAL /ANGLEBRACKETRIGHT / ANGLEBRACKETRIGHTEQUAL) ComparisionExpr)* /// ComparisionExpr <- ShiftExpr (ANGLEBRACKETLEFT / ANGLEBRACKETLEFTEQUAL /ANGLEBRACKETRIGHT / ANGLEBRACKETRIGHTEQUAL) ComparisionExpr)*
fn parseComparisionExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {} fn comparisionExpr(parser: *Parser) !*Node {}
/// ShiftExpr <- AdditiveExpr (ANGLEBRACKETANGLEBRACKETLEFT / ANGLEBRACKETANGLEBRACKETRIGHT) ShiftExpr)* /// ShiftExpr <- AdditiveExpr (ANGLEBRACKETANGLEBRACKETLEFT / ANGLEBRACKETANGLEBRACKETRIGHT) ShiftExpr)*
fn parseShiftExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {} fn shiftExpr(parser: *Parser) !*Node {}
/// AdditiveExpr <- MultiplicativeExpr (PLUS / MINUS) AdditiveExpr)* /// AdditiveExpr <- MultiplicativeExpr (PLUS / MINUS) AdditiveExpr)*
fn parseAdditiveExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {} fn additiveExpr(parser: *Parser) !*Node {}
/// MultiplicativeExpr <- UnaryExpr (ASTERISK / SLASH / PERCENT) MultiplicativeExpr)* /// MultiplicativeExpr <- UnaryExpr (ASTERISK / SLASH / PERCENT) MultiplicativeExpr)*
fn parseMultiplicativeExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {} fn multiplicativeExpr(parser: *Parser) !*Node {}
/// UnaryExpr /// UnaryExpr
/// <- LPAREN TypeName RPAREN UnaryExpr /// <- LPAREN TypeName RPAREN UnaryExpr
/// / Keyword_sizeof LAPERN TypeName RPAREN /// / Keyword_sizeof LAPERN TypeName RPAREN
/// / Keyword_sizeof UnaryExpr /// / Keyword_sizeof UnaryExpr
/// / Keyword_alignof LAPERN TypeName RPAREN /// / Keyword_alignof LAPERN TypeName RPAREN
/// / (AMPERSAND / ASTERISK / PLUS / PLUSPLUS / MINUS / MINUSMINUS / TILDE / BANG) UnaryExpr /// / (AMPERSAND / ASTERISK / PLUS / PLUSPLUS / MINUS / MINUSMINUS / TILDE / BANG) UnaryExpr
/// / PrimaryExpr PostFixExpr* /// / PrimaryExpr PostFixExpr*
fn parseUnaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {} fn unaryExpr(parser: *Parser) !*Node {}
/// PrimaryExpr /// PrimaryExpr
/// <- IDENTIFIER /// <- IDENTIFIER
/// / INTEGERLITERAL / FLITERAL / STRINGLITERAL / CHARLITERAL /// / INTEGERLITERAL / FLITERAL / STRINGLITERAL / CHARLITERAL
/// / LPAREN Expr RPAREN /// / LPAREN Expr RPAREN
/// / Keyword_generic LPAREN AssignmentExpr (COMMA Generic)+ RPAREN /// / Keyword_generic LPAREN AssignmentExpr (COMMA Generic)+ RPAREN
fn parsePrimaryExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {} fn primaryExpr(parser: *Parser) !*Node {}
/// Generic /// Generic
/// <- TypeName COLON AssignmentExpr /// <- TypeName COLON AssignmentExpr
/// / Keyword_default COLON AssignmentExpr /// / Keyword_default COLON AssignmentExpr
fn parseGeneric(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {} fn generic(parser: *Parser) !*Node {}
/// PostFixExpr /// PostFixExpr
/// <- LPAREN TypeName RPAREN LBRACE Initializers RBRACE /// <- LPAREN TypeName RPAREN LBRACE Initializers RBRACE
/// / LBRACKET Expr RBRACKET /// / LBRACKET Expr RBRACKET
/// / LPAREN (AssignmentExpr (COMMA AssignmentExpr)*)? RPAREN /// / LPAREN (AssignmentExpr (COMMA AssignmentExpr)*)? RPAREN
/// / (PERIOD / ARROW) IDENTIFIER /// / (PERIOD / ARROW) IDENTIFIER
/// / (PLUSPLUS / MINUSMINUS) /// / (PLUSPLUS / MINUSMINUS)
fn parsePostFixExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {} fn postFixExpr(parser: *Parser) !*Node {}
/// Initializers <- ((Designator+ EQUAL)? Initializer COMMA)* (Designator+ EQUAL)? Initializer COMMA? /// Initializers <- ((Designator+ EQUAL)? Initializer COMMA)* (Designator+ EQUAL)? Initializer COMMA?
fn parseInitializers(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {} fn initializers(parser: *Parser) !*Node {}
/// Initializer /// Initializer
/// <- LBRACE Initializers RBRACE /// <- LBRACE Initializers RBRACE
/// / AssignmentExpr /// / AssignmentExpr
fn parseInitializer(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {} fn initializer(parser: *Parser) !*Node {}
/// Designator /// Designator
/// <- LBRACKET Initializers RBRACKET /// <- LBRACKET Initializers RBRACKET
/// / PERIOD IDENTIFIER /// / PERIOD IDENTIFIER
fn parseDesignator(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {} fn designator(parser: *Parser) !*Node {}
/// CompoundStmt <- LBRACE (Declaration / Stmt)* RBRACE /// CompoundStmt <- LBRACE (Declaration / Stmt)* RBRACE
fn parseCompoundStmt(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {} fn compoundStmt(parser: *Parser) !?*Node {}
/// Stmt /// Stmt
/// <- CompoundStmt /// <- CompoundStmt
/// / Keyword_if LPAREN Expr RPAREN Stmt (Keyword_ELSE Stmt)? /// / Keyword_if LPAREN Expr RPAREN Stmt (Keyword_ELSE Stmt)?
/// / Keyword_switch LPAREN Expr RPAREN Stmt /// / Keyword_switch LPAREN Expr RPAREN Stmt
/// / Keyword_while LPAREN Expr RPAREN Stmt /// / Keyword_while LPAREN Expr RPAREN Stmt
/// / Keyword_do statement Keyword_while LPAREN Expr RPAREN SEMICOLON /// / Keyword_do statement Keyword_while LPAREN Expr RPAREN SEMICOLON
/// / Keyword_for LPAREN (Declaration / ExprStmt) ExprStmt Expr? RPAREN Stmt /// / Keyword_for LPAREN (Declaration / ExprStmt) ExprStmt Expr? RPAREN Stmt
/// / Keyword_default COLON Stmt /// / Keyword_default COLON Stmt
/// / Keyword_case ConstExpr COLON Stmt /// / Keyword_case ConstExpr COLON Stmt
/// / Keyword_goto IDENTIFIER SEMICOLON /// / Keyword_goto IDENTIFIER SEMICOLON
/// / Keyword_continue SEMICOLON /// / Keyword_continue SEMICOLON
/// / Keyword_break SEMICOLON /// / Keyword_break SEMICOLON
/// / Keyword_return Expr? SEMICOLON /// / Keyword_return Expr? SEMICOLON
/// / IDENTIFIER COLON Stmt /// / IDENTIFIER COLON Stmt
/// / ExprStmt /// / ExprStmt
fn parseStmt(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {} fn stmt(parser: *Parser) !?*Node {
if (parser.compoundStmt()) |node| return node;
// if (parser.eatToken(.Keyword_if)) |tok| {}
// if (parser.eatToken(.Keyword_switch)) |tok| {}
// if (parser.eatToken(.Keyword_while)) |tok| {}
// if (parser.eatToken(.Keyword_do)) |tok| {}
// if (parser.eatToken(.Keyword_for)) |tok| {}
// if (parser.eatToken(.Keyword_default)) |tok| {}
// if (parser.eatToken(.Keyword_case)) |tok| {}
if (parser.eatToken(.Keyword_goto)) |tok| {
const node = try parser.arena.create(Node.JumpStmt);
node.* = .{
.ltoken = tok,
.kind = .Goto,
.semicolon = parser.expectToken(.Semicolon),
};
return &node.base;
}
if (parser.eatToken(.Keyword_continue)) |tok| {
const node = try parser.arena.create(Node.JumpStmt);
node.* = .{
.ltoken = tok,
.kind = .Continue,
.semicolon = parser.expectToken(.Semicolon),
};
return &node.base;
}
if (parser.eatToken(.Keyword_break)) |tok| {
const node = try parser.arena.create(Node.JumpStmt);
node.* = .{
.ltoken = tok,
.kind = .Break,
.semicolon = parser.expectToken(.Semicolon),
};
return &node.base;
}
if (parser.eatToken(.Keyword_return)) |tok| {
const node = try parser.arena.create(Node.JumpStmt);
node.* = .{
.ltoken = tok,
.kind = .{ .Return = try parser.expr() },
.semicolon = parser.expectToken(.Semicolon),
};
return &node.base;
}
if (parser.eatToken(.Identifier)) |tok| {
if (parser.eatToken(.Colon)) |col| {
const node = try parser.arena.create(Node.Label);
node.* = .{
.identifier = tok,
.semicolon = parser.expectToken(.Colon),
};
return &node.base;
}
putBackToken(tok);
}
if (parser.exprStmt()) |node| return node;
return null;
}
/// ExprStmt <- Expr? SEMICOLON /// ExprStmt <- Expr? SEMICOLON
fn parseExprStmt(arena: *Allocator, it: *TokenIterator, tree: *Tree) !*Node {} fn exprStmt(parser: *Parser) !*Node {
const node = try parser.arena.create(Node.ExprStmt);
node.* = .{
.expr = try parser.expr(),
.semicolon = parser.expectToken(.Semicolon),
};
return &node.base;
}
fn eatToken(parser: *Parser, id: Token.Id) ?TokenIndex {
while (true) {
const next_tok = parser.it.next() orelse return null;
if (next_tok.id != .LineComment and next_tok.id != .MultiLineComment) {
if (next_tok.id == id) {
return parser.it.index;
}
parser.it.prev();
return null;
}
}
}
fn expectToken(parser: *Parser, id: Token.Id) Error!TokenIndex {
while (true) {
const next_tok = parser.it.next() orelse return error.ParseError;
if (next_tok.id != .LineComment and next_tok.id != .MultiLineComment) {
if (next_tok.id != id) {
try tree.errors.push(.{
.ExpectedToken = .{ .token = parser.it.index, .expected_id = id },
});
return error.ParseError;
}
return parser.it.index;
}
}
}
fn putBackToken(it: *TokenIterator, putting_back: TokenIndex) void {
while (true) {
const prev_tok = it.prev() orelse return;
if (next_tok.id == .LineComment or next_tok.id == .MultiLineComment) continue;
assert(it.list.at(putting_back) == prev_tok);
return;
}
}
};