diff --git a/lib/std/c/ast.zig b/lib/std/c/ast.zig index 5d34d26fe..b248ce2fb 100644 --- a/lib/std/c/ast.zig +++ b/lib/std/c/ast.zig @@ -41,6 +41,7 @@ pub const Error = union(enum) { ExpectedStmt: SingleTokenError("expected statement, found '{}'"), ExpectedTypeName: SingleTokenError("expected type name, found '{}'"), ExpectedFnBody: SingleTokenError("expected function body, found '{}'"), + ExpectedDeclarator: SingleTokenError("expected declarator, found '{}'"), ExpectedInitializer: SingleTokenError("expected initializer, found '{}'"), InvalidTypeSpecifier: InvalidTypeSpecifier, DuplicateQualifier: SingleTokenError("duplicate type qualifier '{}'"), @@ -55,6 +56,7 @@ pub const Error = union(enum) { .ExpectedTypeName => |*x| return x.render(tokens, stream), .ExpectedDeclarator => |*x| return x.render(tokens, stream), .ExpectedFnBody => |*x| return x.render(tokens, stream), + .ExpectedInitializer => |*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), @@ -70,6 +72,7 @@ pub const Error = union(enum) { .ExpectedTypeName => |x| return x.token, .ExpectedDeclarator => |x| return x.token, .ExpectedFnBody => |x| return x.token, + .ExpectedInitializer => |x| return x.token, .InvalidTypeSpecifier => |x| return x.token, .DuplicateQualifier => |x| return x.token, .DuplicateSpecifier => |x| return x.token, @@ -277,30 +280,48 @@ pub const Node = struct { }; pub const Declarator = struct { + base: Node = Node{ .id = .Declarator }, pointer: *Pointer, - identifier: ?TokenIndex, - kind: union(enum) { - Simple, + prefix: union(enum) { + None, + Identifer: TokenIndex, Complex: struct { lparen: TokenIndex, - inner: *Declarator, + inner: *Node, rparen: TokenIndex, }, - Fn: ParamList, - Array: ArrayList, + }, + suffix: union(enum) { + None, + Fn: struct { + lparen: TokenIndex, + params: Params, + rparen: TokenIndex, + }, + Array: Arrays, }, - pub const ArrayList = std.SegmentedList(*Array, 2); - pub const ParamList = std.SegmentedList(*Param, 4); + pub const Arrays = std.SegmentedList(*Array, 2); + pub const Params = std.SegmentedList(*Param, 4); }; - pub const Array = union(enum) { - Unspecified, - Variable: TokenIndex, - Known: *Expr, + pub const Array = struct { + rbracket: TokenIndex, + inner: union(enum) { + Inferred, + Unspecified: TokenIndex, + Variable: struct { + asterisk: ?TokenIndex, + static: ?TokenIndex, + qual: TypeQual, + expr: *Expr, + }, + }, + rbracket: TokenIndex, }; pub const Pointer = struct { + base: Node = Node{ .id = .Pointer }, asterisk: TokenIndex, qual: TypeQual, pointer: ?*Pointer, @@ -312,7 +333,7 @@ pub const Node = struct { Old: TokenIndex, Normal: struct { decl_spec: *DeclSpec, - declarator: *Declarator, + declarator: *Node, }, }, }; @@ -320,7 +341,7 @@ pub const Node = struct { pub const Fn = struct { base: Node = Node{ .id = .Fn }, decl_spec: DeclSpec, - declarator: *Declarator, + declarator: *Node, old_decls: OldDeclList, body: ?*CompoundStmt, @@ -332,7 +353,7 @@ pub const Node = struct { decl_spec: DeclSpec, declarators: DeclaratorList, - pub const DeclaratorList = std.SegmentedList(*Declarator, 2); + pub const DeclaratorList = Root.DeclList; }; pub const Var = struct { @@ -344,7 +365,7 @@ pub const Node = struct { }; pub const Initialized = struct { - declarator: *Declarator, + declarator: *Node, eq: TokenIndex, init: Initializer, }; diff --git a/lib/std/c/parse.zig b/lib/std/c/parse.zig index 0925d65d8..016de8826 100644 --- a/lib/std/c/parse.zig +++ b/lib/std/c/parse.zig @@ -589,7 +589,7 @@ const Parser = struct { fn recordDeclarator(parser: *Parser) !*Node {} /// Pointer <- ASTERISK TypeQual* Pointer? - fn pointer(parser: *Parser) !?*Node.Pointer { + fn pointer(parser: *Parser) Error!?*Node { const asterisk = parser.eatToken(.Asterisk) orelse return null; const node = try parser.arena.create(Node.Pointer); node.* = .{ @@ -599,34 +599,129 @@ const Parser = struct { }; while (try parser.typeQual(&node.qual)) {} node.pointer = try parser.pointer(); + return &node.base; + } + + const Named = enum { + Must, + Allowed, + Forbidden, + }; + + /// Declarator <- Pointer? DeclaratorSuffix + /// DeclaratorPrefix + /// <- IDENTIFIER // if named != .Forbidden + /// / LPAREN Declarator RPAREN + /// / (none) // if named != .Must + /// DeclaratorSuffix + /// <. DeclaratorPrefix (LBRACKET ArrayDeclarator? RBRACKET)* + /// / DeclaratorPrefix LPAREN (ParamDecl (COMMA ParamDecl)* (COMMA ELLIPSIS)?)? RPAREN + fn declarator(parser: *Parser, named: Named) Error!?*Node { + const ptr = try parser.pointer(); + var node: *Node.Declarator = undefined; + // prefix + if (parser.eatToken(.LParen)) |lparen| { + const inner = (try parser.declarator(named)) orelse return parser.err(.{ + .ExpectedDeclarator = .{ .token = lparen + 1 }, + }); + node = try parser.arena.create(Node.Declarator); + node.* = .{ + .pointer = ptr, + .prefix = .{ + .Comples = .{ + .lparen = lparen, + .inner = inner, + .rparen = try parser.expectToken(.RParen), + }, + }, + .suffix = .None, + }; + } else if (named != .Forbidden) { + if (parser.eatToken(.Identifier)) |tok| { + node = try parser.arena.create(Node.Declarator); + node.* = .{ + .pointer = ptr, + .prefix = .{ .Simple = tok }, + .suffix = .None, + }; + } else if (named == .Must) { + return parser.err(.{ + .ExpectedToken = .{ .token = parser.it.index, .expected_id = .Identifier }, + }); + } else { + return ptr; + } + } else { + node = try parser.arena.create(Node.Declarator); + node.* = .{ + .pointer = ptr, + .prefix = .None, + .suffix = .None, + }; + } + // suffix + if (parser.eatToken(.LParen)) |lparen| { + node.suffix = .{ + .Fn = .{ + .lparen = lparen, + .params = .Node.Declarator.Params.init(parser.arena), + .rparen = undefined, + }, + }; + try parser.ParamDecl(node); + node.suffix.Fn.rparen = try parser.expectToken(.RParen); + } else { + while (parser.arrayDeclarator()) |arr| { + if (node.suffix == .None) + node.suffix = .{ .Array = .Node.Declarator.Arrays.init(parser.arena) }; + try node.suffix.Array.push(arr); + } + } + if (parser.eatToken(.LParen) orelse parser.eatToken(.LBracket)) |tok| + return parser.err(.{ + .InvalidDeclarator = .{ .token = tok }, + }); return node; } - /// DirectDeclarator - /// <- IDENTIFIER - /// / LPAREN Declarator RPAREN - /// / DirectDeclarator LBRACKET (ASTERISK / BracketDeclarator)? RBRACKET - /// / DirectDeclarator LPAREN (ParamDecl (COMMA ParamDecl)* (COMMA ELLIPSIS)?)? RPAREN - fn directDeclarator(parser: *Parser) !*Node {} - /// BracketDeclarator - /// <- Keyword_static TypeQual* AssignmentExpr + /// ArrayDeclarator + /// <- ASTERISK + /// / Keyword_static TypeQual* AssignmentExpr /// / TypeQual+ (ASTERISK / Keyword_static AssignmentExpr) /// / TypeQual+ AssignmentExpr? /// / AssignmentExpr - fn bracketDeclarator(parser: *Parser) !*Node {} + fn arrayDeclarator(parser: *Parser, dr: *Node.Declarator) !?*Node.Array { + const lbracket = parser.eatToken(.LBracket) orelse return null; + const arr = try parser.arena.create(Node.Array); + arr.* = .{ + .lbracket = lbarcket, + .inner = .Inferred, + .rbracket = undefined, + }; + if (parser.eatToken(.Asterisk)) |tok| { + arr.inner = .{ .Unspecified = tok }; + } else { + // TODO + } + arr.rbracket = try parser.expectToken(.RBracket); + return arr; + } + /// Params <- ParamDecl (COMMA ParamDecl)* (COMMA ELLIPSIS)? /// ParamDecl <- DeclSpec (Declarator / AbstractDeclarator) - fn paramDecl(parser: *Parser) !*Node {} - - /// AbstractDeclarator <- Pointer? DirectAbstractDeclarator? - fn abstractDeclarator(parser: *Parser) !*Node {} - - /// DirectAbstractDeclarator - /// <- IDENTIFIER - /// / LPAREN DirectAbstractDeclarator RPAREN - /// / DirectAbstractDeclarator? LBRACKET (ASTERISK / BracketDeclarator)? RBRACKET - /// / DirectAbstractDeclarator? LPAREN (ParamDecl (COMMA ParamDecl)* (COMMA ELLIPSIS)?)? RPAREN - fn directAbstractDeclarator(parser: *Parser) !*Node {} + fn paramDecl(parser: *Parser, dr: *Node.Declarator) !void { + var old_style = false; + while (true) { + var ds = Node.DeclSpec; + if (try parser.declSpec(&ds)) { + //TODO + } else if (parser.eatToken(.Identifier)) { + old_style = true; + } else if (parser.eatToken(.Ellipsis)) { + // TODO + } + } + } /// Expr <- AssignmentExpr (COMMA Expr)* fn expr(parser: *Parser) !*Node {}