Commit e21ea5bd95
lib/std/c/ast.zig
@@ -229,6 +229,9 @@ pub const Node = struct {
Label,
CompoundStmt,
IfStmt,
+ WhileStmt,
+ DoStmt,
+ ForStmt,
StaticAssert,
Declarator,
Pointer,
@@ -438,7 +441,7 @@ pub const Node = struct {
pub const RecordDeclarator = struct {
base: Node = Node{ .id = .RecordField },
declarator: *Declarator,
- // bit_field_expr: ?*Expr,
+ bit_field_expr: ?*Expr,
};
pub const TypeQual = struct {
@@ -486,12 +489,41 @@ pub const Node = struct {
base: Node = Node{ .id = .IfStmt },
@"if": TokenIndex,
cond: *Node,
+ body: *Node,
@"else": ?struct {
tok: TokenIndex,
- stmt: *Node,
+ body: *Node,
},
};
+ pub const WhileStmt = struct {
+ base: Node = Node{ .id = .WhileStmt },
+ @"while": TokenIndex,
+ cond: *Expr,
+ rparen: TokenIndex,
+ body: *Node,
+ };
+
+ pub const DoStmt = struct {
+ base: Node = Node{ .id = .DoStmt },
+ do: TokenIndex,
+ body: *Node,
+ @"while": TokenIndex,
+ cond: *Expr,
+ semicolon: TokenIndex,
+ };
+
+ pub const ForStmt = struct {
+ base: Node = Node{ .id = .ForStmt },
+ @"for": TokenIndex,
+ init: ?*Node,
+ cond: ?*Expr,
+ semicolon: TokenIndex,
+ incr: ?*Expr,
+ rparen: TokenIndex,
+ body: *Node,
+ };
+
pub const StaticAssert = struct {
base: Node = Node{ .id = .StaticAssert },
assert: TokenIndex,
lib/std/c/parse.zig
@@ -1119,23 +1119,88 @@ const Parser = struct {
.cond = (try parser.expr()) orelse return parser.err(.{
.ExpectedExpr = .{ .token = parser.it.index },
}),
+ .body = undefined,
.@"else" = null,
};
_ = try parser.expectToken(.RParen);
+ node.body = (try parser.stmt()) orelse return parser.err(.{
+ .ExpectedStmt = .{ .token = parser.it.index },
+ });
if (parser.eatToken(.Keyword_else)) |else_tok| {
node.@"else" = .{
.tok = else_tok,
- .stmt = (try parser.stmt()) orelse return parser.err(.{
+ .body = (try parser.stmt()) orelse return parser.err(.{
.ExpectedStmt = .{ .token = parser.it.index },
}),
};
}
return &node.base;
}
+
+ // TODO loop scope
+ if (parser.eatToken(.Keyword_while)) |tok| {
+ _ = try parser.expectToken(.LParen);
+ const cond = (try parser.expr()) orelse return parser.err(.{
+ .ExpectedExpr = .{ .token = parser.it.index },
+ });
+ const rparen = try parser.expectToken(.RParen);
+ const node = try parser.arena.create(Node.WhileStmt);
+ node.* = .{
+ .@"while" = tok,
+ .cond = cond,
+ .rparen = rparen,
+ .body = (try parser.stmt()) orelse return parser.err(.{
+ .ExpectedStmt = .{ .token = parser.it.index },
+ }),
+ .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);
+ _ = try parser.expectToken(.LParen);
+ const cond = (try parser.expr()) orelse return parser.err(.{
+ .ExpectedExpr = .{ .token = parser.it.index },
+ });
+ _ = try parser.expectToken(.RParen);
+ const node = try parser.arena.create(Node.DoStmt);
+ node.* = .{
+ .do = tok,
+ .body = body,
+ .cond = cond,
+ .@"while" = @"while",
+ .semicolon = try parser.expectToken(.Semicolon),
+ };
+ return &node.base;
+ }
+ if (parser.eatToken(.Keyword_for)) |tok| {
+ _ = try parser.expectToken(.LParen);
+ const init = if (try parser.declaration()) |decl| blk:{
+ // TODO disallow storage class other than auto and register
+ break :blk decl;
+ } else try parser.exprStmt();
+ const cond = try parser.expr();
+ const semicolon = try parser.expectToken(.Semicolon);
+ const incr = try parser.expr();
+ const rparen = try parser.expectToken(.RParen);
+ const node = try parser.arena.create(Node.ForStmt);
+ node.* = .{
+ .@"for" = tok,
+ .init = init,
+ .cond = cond,
+ .semicolon = semicolon,
+ .incr = incr,
+ .rparen = rparen,
+ .body = (try parser.stmt()) orelse return parser.err(.{
+ .ExpectedStmt = .{ .token = parser.it.index },
+ }),
+ };
+ return &node.base;
+ }
// if (parser.eatToken(.Keyword_switch)) |tok| {}
- // if (parser.eatToken(.Keyword_while)) |tok| {}
- // if (parser.eatToken(.Keyword_do)) |tok| {}
- // if (parser.eatToken(.Keyword_for)) |tok| {}
// if (parser.eatToken(.Keyword_default)) |tok| {}
// if (parser.eatToken(.Keyword_case)) |tok| {}
if (parser.eatToken(.Keyword_goto)) |tok| {