std-c parse switch

This commit is contained in:
Vexu 2020-01-11 21:46:36 +02:00
parent e21ea5bd95
commit 4c0776b2a5
No known key found for this signature in database
GPG Key ID: 59AEB8936E16A6AC
2 changed files with 94 additions and 54 deletions

View File

@ -48,7 +48,6 @@ pub const Error = union(enum) {
InvalidToken: SingleTokenError("invalid token '{}'"),
ExpectedToken: ExpectedToken,
ExpectedExpr: SingleTokenError("expected expression, found '{}'"),
ExpectedStmt: SingleTokenError("expected statement, found '{}'"),
ExpectedTypeName: SingleTokenError("expected type name, found '{}'"),
ExpectedFnBody: SingleTokenError("expected function body, found '{}'"),
ExpectedDeclarator: SingleTokenError("expected declarator, found '{}'"),
@ -70,7 +69,6 @@ pub const Error = union(enum) {
.InvalidToken => |*x| return x.render(tree, stream),
.ExpectedToken => |*x| return x.render(tree, stream),
.ExpectedExpr => |*x| return x.render(tree, stream),
.ExpectedStmt => |*x| return x.render(tree, stream),
.ExpectedTypeName => |*x| return x.render(tree, stream),
.ExpectedDeclarator => |*x| return x.render(tree, stream),
.ExpectedFnBody => |*x| return x.render(tree, stream),
@ -94,7 +92,6 @@ pub const Error = union(enum) {
.InvalidToken => |x| return x.token,
.ExpectedToken => |x| return x.token,
.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,
@ -226,9 +223,10 @@ pub const Node = struct {
RecordField,
JumpStmt,
ExprStmt,
Label,
LabeledStmt,
CompoundStmt,
IfStmt,
SwitchStmt,
WhileStmt,
DoStmt,
ForStmt,
@ -454,26 +452,29 @@ pub const Node = struct {
pub const JumpStmt = struct {
base: Node = Node{ .id = .JumpStmt },
ltoken: TokenIndex,
kind: Kind,
semicolon: TokenIndex,
pub const Kind = union(enum) {
kind: union(enum) {
Break,
Continue,
Return: ?*Node,
Goto: TokenIndex,
};
},
semicolon: TokenIndex,
};
pub const ExprStmt = struct {
base: Node = Node{ .id = .ExprStmt },
expr: ?*Node,
expr: ?*Expr,
semicolon: TokenIndex,
};
pub const Label = struct {
base: Node = Node{ .id = .Label },
identifier: TokenIndex,
pub const LabeledStmt = struct {
base: Node = Node{ .id = .LabeledStmt },
kind: union(enum) {
Label: TokenIndex,
Case: TokenIndex,
Default: TokenIndex,
},
stmt: *Node,
};
pub const CompoundStmt = struct {
@ -496,6 +497,14 @@ pub const Node = struct {
},
};
pub const SwitchStmt = struct {
base: Node = Node{ .id = .SwitchStmt },
@"switch": TokenIndex,
expr: *Expr,
rparen: TokenIndex,
stmt: *Node,
};
pub const WhileStmt = struct {
base: Node = Node{ .id = .WhileStmt },
@"while": TokenIndex,

View File

@ -104,7 +104,14 @@ const Parser = struct {
ty: *Type,
};
fn pushScope(parser: *Parser) usize {
const ScopeKind = enum {
Block,
Loop,
Root,
Switch,
};
fn pushScope(parser: *Parser, kind: ScopeKind) usize {
return parser.symbols.len;
}
@ -130,6 +137,8 @@ const Parser = struct {
/// Root <- ExternalDeclaration* eof
fn root(parser: *Parser) Allocator.Error!*Node.Root {
const scope = parser.pushScope(.Root);
defer parser.popScope(scope);
const node = try parser.arena.create(Node.Root);
node.* = .{
.decls = Node.Root.DeclList.init(parser.arena),
@ -779,7 +788,7 @@ const Parser = struct {
.ty = ty,
});
if (parser.eatToken(.LBrace)) |lbrace| {
const scope = parser.pushScope();
const scope = parser.pushScope(.Block);
defer parser.popScope(scope);
var fields = Node.RecordType.FieldList.init(parser.arena);
while (true) {
@ -1079,18 +1088,22 @@ const Parser = struct {
/// CompoundStmt <- LBRACE (Declaration / Stmt)* RBRACE
fn compoundStmt(parser: *Parser) Error!?*Node {
const scope = parser.pushScope();
defer parser.popScope(scope);
const lbrace = parser.eatToken(.LBrace) orelse return null;
const scope = parser.pushScope(.Block);
defer parser.popScope(scope);
const body_node = try parser.arena.create(Node.CompoundStmt);
body_node.* = .{
.lbrace = lbrace,
.statements = Node.CompoundStmt.StmtList.init(parser.arena),
.rbrace = undefined,
};
while ((try parser.declaration()) orelse (try parser.stmt())) |node|
try body_node.statements.push(node);
body_node.rbrace = try parser.expectToken(.RBrace);
while (true) {
if (parser.eatToken(.RBRACE)) |rbrace| {
body_node.rbrace = rbrace;
break;
}
try body_node.statements.push((try parser.declaration()) orelse (try parser.stmt()));
}
return &body_node.base;
}
@ -1109,7 +1122,7 @@ const Parser = struct {
/// / Keyword_return Expr? SEMICOLON
/// / IDENTIFIER COLON Stmt
/// / ExprStmt
fn stmt(parser: *Parser) Error!?*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);
@ -1123,22 +1136,18 @@ const Parser = struct {
.@"else" = null,
};
_ = try parser.expectToken(.RParen);
node.body = (try parser.stmt()) orelse return parser.err(.{
.ExpectedStmt = .{ .token = parser.it.index },
});
node.body = try parser.stmt();
if (parser.eatToken(.Keyword_else)) |else_tok| {
node.@"else" = .{
.tok = else_tok,
.body = (try parser.stmt()) orelse return parser.err(.{
.ExpectedStmt = .{ .token = parser.it.index },
}),
.body = try parser.stmt(),
};
}
return &node.base;
}
// TODO loop scope
if (parser.eatToken(.Keyword_while)) |tok| {
const scope = parser.pushScope(.Loop);
defer parser.popScope(scope);
_ = try parser.expectToken(.LParen);
const cond = (try parser.expr()) orelse return parser.err(.{
.ExpectedExpr = .{ .token = parser.it.index },
@ -1149,18 +1158,15 @@ const Parser = struct {
.@"while" = tok,
.cond = cond,
.rparen = rparen,
.body = (try parser.stmt()) orelse return parser.err(.{
.ExpectedStmt = .{ .token = parser.it.index },
}),
.body = try parser.stmt(),
.semicolon = try parser.expectToken(.Semicolon),
};
return &node.base;
}
if (parser.eatToken(.Keyword_do)) |tok| {
const body = (try parser.stmt()) orelse return parser.err(.{
.ExpectedStmt = .{ .token = parser.it.index },
});
const @"while" = try parser.expectToken(.Keyword_while);
const scope = parser.pushScope(.Loop);
defer parser.popScope(scope);
const body = try parser.stmt();
_ = try parser.expectToken(.LParen);
const cond = (try parser.expr()) orelse return parser.err(.{
.ExpectedExpr = .{ .token = parser.it.index },
@ -1177,6 +1183,8 @@ const Parser = struct {
return &node.base;
}
if (parser.eatToken(.Keyword_for)) |tok| {
const scope = parser.pushScope(.Loop);
defer parser.popScope(scope);
_ = try parser.expectToken(.LParen);
const init = if (try parser.declaration()) |decl| blk:{
// TODO disallow storage class other than auto and register
@ -1194,15 +1202,43 @@ const Parser = struct {
.semicolon = semicolon,
.incr = incr,
.rparen = rparen,
.body = (try parser.stmt()) orelse return parser.err(.{
.ExpectedStmt = .{ .token = parser.it.index },
}),
.body = try parser.stmt(),
};
return &node.base;
}
if (parser.eatToken(.Keyword_switch)) |tok| {
const scope = parser.pushScope(.Switch);
defer parser.popScope(scope);
_ = try parser.expectToken(.LParen);
const switch_expr = try parser.exprStmt();
const rparen = try parser.expectToken(.RParen);
const node = try parser.arena.create(Node.SwitchStmt);
node.* = .{
.@"switch" = tok,
.expr = switch_expr,
.rparen = rparen,
.body = try parser.stmt(),
};
return &node.base;
}
if (parser.eatToken(.Keyword_default)) |tok| {
_ = try parser.expectToken(.Colon);
const node = try parser.arena.create(Node.LabeledStmt);
node.* = .{
.kind = .{.Default = tok },
.stmt = try parser.stmt(),
};
return &node.base;
}
if (parser.eatToken(.Keyword_case)) |tok| {
_ = try parser.expectToken(.Colon);
const node = try parser.arena.create(Node.LabeledStmt);
node.* = .{
.kind = .{.Case = tok },
.stmt = try parser.stmt(),
};
return &node.base;
}
// if (parser.eatToken(.Keyword_switch)) |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.* = .{
@ -1241,29 +1277,24 @@ const Parser = struct {
}
if (parser.eatToken(.Identifier)) |tok| {
if (parser.eatToken(.Colon)) |_| {
const node = try parser.arena.create(Node.Label);
const node = try parser.arena.create(Node.LabeledStmt);
node.* = .{
.identifier = tok,
.kind = .{.Label = tok },
.stmt = try parser.stmt(),
};
return &node.base;
}
parser.putBackToken(tok);
}
if (try parser.exprStmt()) |node| return node;
return null;
return parser.exprStmt();
}
/// 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 = expr_node,
.semicolon = semicolon,
.expr = try parser.expr(),
.semicolon = try parser.expectToken(.Semicolon),
};
return &node.base;
}