std-c parser fndef and static assert

master
Vexu 2020-01-05 15:15:55 +02:00
parent 46f292982d
commit f934f9b419
No known key found for this signature in database
GPG Key ID: 59AEB8936E16A6AC
2 changed files with 132 additions and 46 deletions

View File

@ -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);
};
};

View File

@ -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;
}