From f934f9b41938ee6208d7cdd8a26687bffbe171cf Mon Sep 17 00:00:00 2001 From: Vexu Date: Sun, 5 Jan 2020 15:15:55 +0200 Subject: [PATCH] std-c parser fndef and static assert --- lib/std/c/ast.zig | 30 ++++++++- lib/std/c/parse.zig | 148 +++++++++++++++++++++++++++++++------------- 2 files changed, 132 insertions(+), 46 deletions(-) diff --git a/lib/std/c/ast.zig b/lib/std/c/ast.zig index ea6abfad9d..0a600eb7f3 100644 --- a/lib/std/c/ast.zig +++ b/lib/std/c/ast.zig @@ -32,6 +32,8 @@ pub const Error = union(enum) { ExpectedExpr: SingleTokenError("expected expression, found '{}'"), ExpectedStmt: SingleTokenError("expected statement, found '{}'"), ExpectedTypeName: SingleTokenError("expected type name, found '{}'"), + ExpectedFnBody: SingleTokenError("expected function body, found '{}'"), + ExpectedInitializer: SingleTokenError("expected initializer, found '{}'"), InvalidTypeSpecifier: InvalidTypeSpecifier, DuplicateQualifier: SingleTokenError("duplicate type qualifier '{}'"), DuplicateSpecifier: SingleTokenError("duplicate declaration specifier '{}'"), @@ -43,6 +45,8 @@ pub const Error = union(enum) { .ExpectedExpr => |*x| return x.render(tokens, stream), .ExpectedStmt => |*x| return x.render(tokens, stream), .ExpectedTypeName => |*x| return x.render(tokens, stream), + .ExpectedDeclarator => |*x| return x.render(tokens, stream), + .ExpectedFnBody => |*x| return x.render(tokens, stream), .InvalidTypeSpecifier => |*x| return x.render(tokens, stream), .DuplicateQualifier => |*x| return x.render(tokens, stream), .DuplicateSpecifier => |*x| return x.render(tokens, stream), @@ -56,6 +60,8 @@ pub const Error = union(enum) { .ExpectedExpr => |x| return x.token, .ExpectedStmt => |x| return x.token, .ExpectedTypeName => |x| return x.token, + .ExpectedDeclarator => |x| return x.token, + .ExpectedFnBody => |x| return x.token, .InvalidTypeSpecifier => |x| return x.token, .DuplicateQualifier => |x| return x.token, .DuplicateSpecifier => |x| return x.token, @@ -85,7 +91,7 @@ pub const Error = union(enum) { try stream.write("invalid type specifier '"); try type_spec.spec.print(tokens, stream); const token_name = tokens.at(self.token).id.symbol(); - return stream.print("{}'", .{ token_name }); + return stream.print("{}'", .{token_name}); } }; @@ -111,10 +117,12 @@ pub const Node = struct { Label, CompoundStmt, IfStmt, + StaticAssert, + FnDef, }; pub const Root = struct { - base: Node, + base: Node = Node{ .id = .Root }, decls: DeclList, eof: TokenIndex, @@ -230,7 +238,6 @@ pub const Node = struct { pub const Label = struct { base: Node = Node{ .id = .Label }, identifier: TokenIndex, - colon: TokenIndex, }; pub const CompoundStmt = struct { @@ -251,4 +258,21 @@ pub const Node = struct { stmt: *Node, }, }; + + pub const StaticAssert = struct { + base: Node = Node{ .id = .StaticAssert }, + assert: TokenIndex, + expr: *Node, + semicolon: TokenIndex, + }; + + pub const FnDef = struct { + base: Node = Node{ .id = .FnDef }, + decl_spec: *DeclSpec, + declarator: *Node, + old_decls: OldDeclList, + body: *CompoundStmt, + + pub const OldDeclList = SegmentedList(*Node, 0); + }; }; diff --git a/lib/std/c/parse.zig b/lib/std/c/parse.zig index 9cb8e327fd..79790fd0ff 100644 --- a/lib/std/c/parse.zig +++ b/lib/std/c/parse.zig @@ -78,10 +78,10 @@ const Parser = struct { } /// Root <- ExternalDeclaration* eof - fn root(parser: *Parser) Allocator.Error!*Node { - const node = try arena.create(ast.Root); + fn root(parser: *Parser) Allocator.Error!*Node.Root { + const node = try parser.arena.create(Node.Root); node.* = .{ - .decls = ast.Node.DeclList.init(arena), + .decls = Node.Root.DeclList.init(parser.arena), .eof = undefined, }; while (parser.externalDeclarations() catch |err| switch (err) { @@ -90,31 +90,87 @@ const Parser = struct { }) |decl| { try node.decls.push(decl); } - node.eof = eatToken(it, .Eof) orelse { - try tree.errors.push(.{ - .ExpectedDecl = .{ .token = it.index }, - }); - return node; - }; + node.eof = parser.eatToken(.Eof) orelse return node; return node; } /// ExternalDeclaration /// <- DeclSpec Declarator Declaration* CompoundStmt - /// / DeclSpec (Declarator (EQUAL Initializer)?)* SEMICOLON - /// / StaticAssert + /// / Declaration fn externalDeclarations(parser: *Parser) !?*Node { - if (try Declaration(parser)) |decl| {} - return null; + if (try parser.staticAssert()) |decl| return decl; + const ds = try parser.declSpec(); + const dr = (try parser.declarator()); + if (dr == null) + try parser.warning(.{ + .ExpectedDeclarator = .{ .token = parser.it.index }, + }); + // TODO disallow auto and register + const next_tok = parser.it.peek().?; + switch (next_tok.id) { + .Semicolon, + .Equal, + .Comma, + .Eof, + => return parser.declarationExtra(ds, dr, false), + else => {}, + } + var old_decls = Node.FnDef.OldDeclList.init(parser.arena); + while (try parser.declaration()) |decl| { + // validate declaration + try old_decls.push(decl); + } + const body = try parser.expect(compoundStmt, .{ + .ExpectedFnBody = .{ .token = parser.it.index }, + }); + + const node = try parser.arena.create(Node.FnDef); + node.* = .{ + .decl_spec = ds, + .declarator = dr orelse return null, + .old_decls = old_decls, + .body = @fieldParentPtr(Node.CompoundStmt, "base", body), + }; + return &node.base; } /// Declaration - /// <- DeclSpec (Declarator (EQUAL Initializer)?)* SEMICOLON + /// <- DeclSpec (Declarator (EQUAL Initializer)? COMMA)* SEMICOLON /// / StaticAssert - fn declaration(parser: *Parser) !?*Node {} + fn declaration(parser: *Parser) !?*Node { + if (try parser.staticAssert()) |decl| return decl; + const ds = try parser.declSpec(); + const dr = (try parser.declarator()); + if (dr == null) + try parser.warning(.{ + .ExpectedDeclarator = .{ .token = parser.it.index }, + }); + // TODO disallow threadlocal without static or extern + return parser.declarationExtra(ds, dr, true); + } + + fn declarationExtra(parser: *Parser, ds: *Node.DeclSpec, dr: ?*Node, local: bool) !?*Node { + } /// StaticAssert <- Keyword_static_assert LPAREN ConstExpr COMMA STRINGLITERAL RPAREN SEMICOLON - fn StaticAssert(parser: *Parser) !?*Node {} + fn staticAssert(parser: *Parser) !?*Node { + const tok = parser.eatToken(.Keyword_static_assert) orelse return null; + _ = try parser.expectToken(.LParen); + const const_expr = try parser.expect(constExpr, .{ + .ExpectedExpr = .{ .token = parser.it.index }, + }); + _ = try parser.expectToken(.Comma); + const str = try parser.expectToken(.StringLiteral); + _ = try parser.expectToken(.RParen); + const semicolon = try parser.expectToken(.Semicolon); + const node = try parser.arena.create(Node.StaticAssert); + node.* = .{ + .assert = tok, + .expr = const_expr, + .semicolon = semicolon, + }; + return &node.base; + } /// DeclSpec <- (StorageClassSpec / TypeSpec / FnSpec / AlignSpec)* fn declSpec(parser: *Parser) !*Node.DeclSpec { @@ -455,7 +511,7 @@ const Parser = struct { fn alignSpec(parser: *Parser, ds: *Node.DeclSpec) !bool { if (parser.eatToken(.Keyword_alignas)) |tok| { _ = try parser.expectToken(.LParen); - const node = (try parser.typeName()) orelse (try parser.expect(conditionalExpr, .{ + const node = (try parser.typeName()) orelse (try parser.expect(constExpr, .{ .ExpectedExpr = .{ .token = parser.it.index }, })); if (ds.align_spec != null) { @@ -538,6 +594,8 @@ const Parser = struct { fn assignmentExpr(parser: *Parser) !*Node {} /// ConstExpr <- ConditionalExpr + const constExpr = conditionalExpr; + /// ConditionalExpr <- LogicalOrExpr (QUESTIONMARK Expr COLON ConditionalExpr)? fn conditionalExpr(parser: *Parser) !*Node {} @@ -613,19 +671,19 @@ const Parser = struct { /// / PERIOD IDENTIFIER fn designator(parser: *Parser) !*Node {} - /// CompoundStmt <- LBRACE (Declaration / Stmt)* RBRACE - fn compoundStmt(parser: *Parser) !?*Node { + /// CompoundStmt <- LBRACE (Stmt / Declaration)* RBRACE + fn compoundStmt(parser: *Parser) Error!?*Node { const lbrace = parser.eatToken(.LBrace) orelse return null; - const node = try parser.arena.create(Node.CompoundStmt); - node.* = .{ + const body_node = try parser.arena.create(Node.CompoundStmt); + body_node.* = .{ .lbrace = lbrace, - .statements = Node.JumpStmt.StmtList.init(parser.arena), + .statements = Node.CompoundStmt.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; + while ((try parser.stmt()) orelse (try parser.declaration())) |node| + try body_node.statements.push(node); + body_node.rbrace = try parser.expectToken(.RBrace); + return &body_node.base; } /// Stmt @@ -643,15 +701,15 @@ const Parser = struct { /// / Keyword_return Expr? SEMICOLON /// / IDENTIFIER COLON Stmt /// / ExprStmt - fn stmt(parser: *Parser) !?*Node { - if (parser.compoundStmt()) |node| return node; + fn stmt(parser: *Parser) Error!?*Node { + if (try parser.compoundStmt()) |node| return node; 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 }, + .ExpectedExpr = .{ .token = parser.it.index }, }), .@"else" = null, }; @@ -659,8 +717,8 @@ const Parser = struct { if (parser.eatToken(.Keyword_else)) |else_tok| { node.@"else" = .{ .tok = else_tok, - .stmt = try parser.stmt(expr, .{ - .ExpectedStmt = .{ .token = it.index }, + .stmt = try parser.expect(stmt, .{ + .ExpectedStmt = .{ .token = parser.it.index }, }), }; } @@ -676,8 +734,8 @@ const Parser = struct { const node = try parser.arena.create(Node.JumpStmt); node.* = .{ .ltoken = tok, - .kind = .Goto, - .semicolon = parser.expectToken(.Semicolon), + .kind = .{ .Goto = tok }, + .semicolon = try parser.expectToken(.Semicolon), }; return &node.base; } @@ -686,7 +744,7 @@ const Parser = struct { node.* = .{ .ltoken = tok, .kind = .Continue, - .semicolon = parser.expectToken(.Semicolon), + .semicolon = try parser.expectToken(.Semicolon), }; return &node.base; } @@ -695,7 +753,7 @@ const Parser = struct { node.* = .{ .ltoken = tok, .kind = .Break, - .semicolon = parser.expectToken(.Semicolon), + .semicolon = try parser.expectToken(.Semicolon), }; return &node.base; } @@ -704,31 +762,35 @@ const Parser = struct { node.* = .{ .ltoken = tok, .kind = .{ .Return = try parser.expr() }, - .semicolon = parser.expectToken(.Semicolon), + .semicolon = try parser.expectToken(.Semicolon), }; return &node.base; } if (parser.eatToken(.Identifier)) |tok| { - if (parser.eatToken(.Colon)) |col| { + if (parser.eatToken(.Colon)) |_| { const node = try parser.arena.create(Node.Label); node.* = .{ .identifier = tok, - .semicolon = parser.expectToken(.Colon), }; return &node.base; } - putBackToken(tok); + parser.putBackToken(tok); } - if (parser.exprStmt()) |node| return node; + if (try parser.exprStmt()) |node| return node; return null; } /// ExprStmt <- Expr? SEMICOLON - fn exprStmt(parser: *Parser) !*Node { + fn exprStmt(parser: *Parser) !?*Node { const node = try parser.arena.create(Node.ExprStmt); + const expr_node = try parser.expr(); + const semicolon = if (expr_node != null) + try parser.expectToken(.Semicolon) + else + parser.eatToken(.Semicolon) orelse return null; node.* = .{ - .expr = try parser.expr(), - .semicolon = parser.expectToken(.Semicolon), + .expr = expr_node, + .semicolon = semicolon, }; return &node.base; }