Commit f934f9b419
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);
+ };
};
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;
}