std-c parser fndef and static assert
parent
46f292982d
commit
f934f9b419
|
@ -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);
|
||||
};
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue