std-c declaration parsing
parent
4184d4c66a
commit
dbc0457068
|
@ -51,9 +51,14 @@ pub const Error = union(enum) {
|
|||
ExpectedEnumField: SingleTokenError("expected enum field, found '{}'"),
|
||||
ExpectedType: SingleTokenError("expected enum field, found '{}'"),
|
||||
InvalidTypeSpecifier: InvalidTypeSpecifier,
|
||||
InvalidStorageClass: SingleTokenError("invalid storage class, found '{}'"),
|
||||
InvalidDeclarator: SimpleError("invalid declarator"),
|
||||
DuplicateQualifier: SingleTokenError("duplicate type qualifier '{}'"),
|
||||
DuplicateSpecifier: SingleTokenError("duplicate declaration specifier '{}'"),
|
||||
MustUseKwToRefer: MustUseKwToRefer,
|
||||
FnSpecOnNonFn: SingleTokenError("function specifier '{}' on non function"),
|
||||
NothingDeclared: SimpleError("declaration doesn't declare anything"),
|
||||
QualifierIgnored: SingleTokenError("qualifier '{}' ignored"),
|
||||
|
||||
pub fn render(self: *const Error, tree: *Tree, stream: var) !void {
|
||||
switch (self.*) {
|
||||
|
@ -68,9 +73,14 @@ pub const Error = union(enum) {
|
|||
.ExpectedEnumField => |*x| return x.render(tree, stream),
|
||||
.ExpectedType => |*x| return x.render(tree, stream),
|
||||
.InvalidTypeSpecifier => |*x| return x.render(tree, stream),
|
||||
.InvalidStorageClass => |*x| return x.render(tree, stream),
|
||||
.InvalidDeclarator => |*x| return x.render(tree, stream),
|
||||
.DuplicateQualifier => |*x| return x.render(tree, stream),
|
||||
.DuplicateSpecifier => |*x| return x.render(tree, stream),
|
||||
.MustUseKwToRefer => |*x| return x.render(tree, stream),
|
||||
.FnSpecOnNonFn => |*x| return x.render(tree, stream),
|
||||
.NothingDeclared => |*x| return x.render(tree, stream),
|
||||
.QualifierIgnored => |*x| return x.render(tree, stream),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -87,9 +97,14 @@ pub const Error = union(enum) {
|
|||
.ExpectedEnumField => |x| return x.token,
|
||||
.ExpectedType => |*x| return x.token,
|
||||
.InvalidTypeSpecifier => |x| return x.token,
|
||||
.InvalidStorageClass => |x| return x.token,
|
||||
.InvalidDeclarator => |x| return x.token,
|
||||
.DuplicateQualifier => |x| return x.token,
|
||||
.DuplicateSpecifier => |x| return x.token,
|
||||
.MustUseKwToRefer => |*x| return x.name,
|
||||
.FnSpecOnNonFn => |*x| return x.name,
|
||||
.NothingDeclared => |*x| return x.name,
|
||||
.QualifierIgnored => |*x| return x.name,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -125,7 +140,7 @@ pub const Error = union(enum) {
|
|||
name: TokenIndex,
|
||||
|
||||
pub fn render(self: *const ExpectedToken, tree: *Tree, stream: var) !void {
|
||||
return stream.print("must use '{}' tag to refer to type '{}'", .{tree.slice(kw), tree.slice(name)});
|
||||
return stream.print("must use '{}' tag to refer to type '{}'", .{ tree.slice(kw), tree.slice(name) });
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -139,6 +154,18 @@ pub const Error = union(enum) {
|
|||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn SimpleError(comptime msg: []const u8) type {
|
||||
return struct {
|
||||
const ThisError = @This();
|
||||
|
||||
token: TokenIndex,
|
||||
|
||||
pub fn render(self: *const ThisError, tokens: *Tree.TokenList, stream: var) !void {
|
||||
return stream.write(msg);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub const Type = struct {
|
||||
|
@ -194,9 +221,11 @@ pub const Node = struct {
|
|||
CompoundStmt,
|
||||
IfStmt,
|
||||
StaticAssert,
|
||||
Fn,
|
||||
Declarator,
|
||||
Pointer,
|
||||
FnDecl,
|
||||
Typedef,
|
||||
Var,
|
||||
VarDecl,
|
||||
};
|
||||
|
||||
pub const Root = struct {
|
||||
|
@ -457,7 +486,7 @@ pub const Node = struct {
|
|||
|
||||
pub const Declarator = struct {
|
||||
base: Node = Node{ .id = .Declarator },
|
||||
pointer: *Pointer,
|
||||
pointer: ?*Pointer,
|
||||
prefix: union(enum) {
|
||||
None,
|
||||
Identifer: TokenIndex,
|
||||
|
@ -482,7 +511,7 @@ pub const Node = struct {
|
|||
};
|
||||
|
||||
pub const Array = struct {
|
||||
rbracket: TokenIndex,
|
||||
lbracket: TokenIndex,
|
||||
inner: union(enum) {
|
||||
Inferred,
|
||||
Unspecified: TokenIndex,
|
||||
|
@ -490,7 +519,7 @@ pub const Node = struct {
|
|||
asterisk: ?TokenIndex,
|
||||
static: ?TokenIndex,
|
||||
qual: TypeQual,
|
||||
expr: *Expr,
|
||||
// expr: *Expr,
|
||||
},
|
||||
},
|
||||
rbracket: TokenIndex,
|
||||
|
@ -514,10 +543,10 @@ pub const Node = struct {
|
|||
},
|
||||
};
|
||||
|
||||
pub const Fn = struct {
|
||||
base: Node = Node{ .id = .Fn },
|
||||
pub const FnDecl = struct {
|
||||
base: Node = Node{ .id = .FnDecl },
|
||||
decl_spec: DeclSpec,
|
||||
declarator: *Node,
|
||||
declarator: *Declarator,
|
||||
old_decls: OldDeclList,
|
||||
body: ?*CompoundStmt,
|
||||
|
||||
|
@ -528,20 +557,23 @@ pub const Node = struct {
|
|||
base: Node = Node{ .id = .Typedef },
|
||||
decl_spec: DeclSpec,
|
||||
declarators: DeclaratorList,
|
||||
semicolon: TokenIndex,
|
||||
|
||||
pub const DeclaratorList = Root.DeclList;
|
||||
};
|
||||
|
||||
pub const Var = struct {
|
||||
base: Node = Node{ .id = .Var },
|
||||
pub const VarDecl = struct {
|
||||
base: Node = Node{ .id = .VarDecl },
|
||||
decl_spec: DeclSpec,
|
||||
initializers: Initializers,
|
||||
semicolon: TokenIndex,
|
||||
|
||||
pub const Initializers = std.SegmentedList(*Initialized, 2);
|
||||
pub const Initializers = Root.DeclList;
|
||||
};
|
||||
|
||||
pub const Initialized = struct {
|
||||
declarator: *Node,
|
||||
base: Node = Node{ .id = Initialized },
|
||||
declarator: *Declarator,
|
||||
eq: TokenIndex,
|
||||
init: Initializer,
|
||||
};
|
||||
|
|
|
@ -105,6 +105,10 @@ const Parser = struct {
|
|||
return null;
|
||||
}
|
||||
|
||||
fn declareSymbol(parser: *Parser, decl_spec: *Node.DeclSpec, dr: *Node.Declarator) Error!void {
|
||||
return; // TODO
|
||||
}
|
||||
|
||||
/// Root <- ExternalDeclaration* eof
|
||||
fn root(parser: *Parser) Allocator.Error!*Node.Root {
|
||||
const node = try parser.arena.create(Node.Root);
|
||||
|
@ -140,75 +144,125 @@ const Parser = struct {
|
|||
|
||||
fn declarationExtra(parser: *Parser, local: bool) !?*Node {
|
||||
if (try parser.staticAssert()) |decl| return decl;
|
||||
const begin = parser.it.index + 1;
|
||||
var ds = Node.DeclSpec{};
|
||||
const got_ds = try parser.declSpec(&ds);
|
||||
if (local and !got_ds) {
|
||||
// not a declaration
|
||||
return null;
|
||||
}
|
||||
var dr = try parser.declarator();
|
||||
// TODO disallow auto and register
|
||||
const next_tok = parser.it.peek().?;
|
||||
if (next_tok.id == .Eof and !got_ds and dr == null) {
|
||||
return null;
|
||||
}
|
||||
switch (next_tok.id) {
|
||||
.Semicolon,
|
||||
.Equal,
|
||||
.Comma,
|
||||
.Eof,
|
||||
=> {
|
||||
while (dr != null) {
|
||||
if (parser.eatToken(.Equal)) |tok| {
|
||||
// TODO typedef
|
||||
// dr.?.init = try parser.expect(initializer, .{
|
||||
// .ExpectedInitializer = .{ .token = parser.it.index },
|
||||
// });
|
||||
}
|
||||
if (parser.eatToken(.Comma) != null) break;
|
||||
dr = (try parser.declarator()) orelse return parser.err(.{
|
||||
.ExpectedDeclarator = .{ .token = parser.it.index },
|
||||
});
|
||||
// .push(dr);
|
||||
}
|
||||
const semicolon = try parser.expectToken(.Semicolon);
|
||||
|
||||
// TODO VarDecl, TypeDecl, TypeDef
|
||||
return null;
|
||||
},
|
||||
else => {
|
||||
if (dr == null)
|
||||
return parser.err(.{
|
||||
.ExpectedDeclarator = .{ .token = parser.it.index },
|
||||
});
|
||||
var old_decls = Node.FnDef.OldDeclList.init(parser.arena);
|
||||
while (true) {
|
||||
var old_ds = Node.DeclSpec{};
|
||||
if (!(try parser.declSpec(&old_ds))) {
|
||||
// not old decl
|
||||
break;
|
||||
}
|
||||
var old_dr = (try parser.declarator());
|
||||
// if (old_dr == null)
|
||||
// try parser.err(.{
|
||||
// .NoParamName = .{ .token = parser.it.index },
|
||||
// });
|
||||
// try old_decls.push(decl);
|
||||
}
|
||||
const body = (try parser.compoundStmt()) orelse return parser.err(.{
|
||||
.ExpectedFnBody = .{ .token = parser.it.index },
|
||||
});
|
||||
|
||||
const node = try parser.arena.create(Node.FnDef);
|
||||
switch (ds.storage_class) {
|
||||
.Auto, .Register => |tok| return parser.err(.{
|
||||
.InvalidStorageClass = .{ .token = tok },
|
||||
}),
|
||||
.Typedef => {
|
||||
const node = try parser.arena.create(Node.Typedef);
|
||||
node.* = .{
|
||||
.decl_spec = ds,
|
||||
.declarator = dr orelse return null,
|
||||
.old_decls = old_decls,
|
||||
.body = @fieldParentPtr(Node.CompoundStmt, "base", body),
|
||||
.declarators = Node.Typedef.DeclaratorList.init(parser.arena),
|
||||
.semicolon = undefined,
|
||||
};
|
||||
while (true) {
|
||||
const dr = @fieldParentPtr(Node.Declarator, "base", (try parser.declarator(.Must)) orelse return parser.err(.{
|
||||
.ExpectedDeclarator = .{ .token = parser.it.index },
|
||||
}));
|
||||
try parser.declareSymbol(&ds, dr);
|
||||
try node.declarators.push(&dr.base);
|
||||
if (parser.eatToken(.Comma)) |_| {} else break;
|
||||
}
|
||||
return &node.base;
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
var first_dr = try parser.declarator(.Must);
|
||||
if (first_dr != null and declaratorIsFunction(first_dr.?)) {
|
||||
const dr = @fieldParentPtr(Node.Declarator, "base", first_dr.?);
|
||||
try parser.declareSymbol(&ds, dr);
|
||||
var old_decls = Node.FnDecl.OldDeclList.init(parser.arena);
|
||||
const body = if (parser.eatToken(.Semicolon)) |_|
|
||||
null
|
||||
else blk: {
|
||||
// TODO first_dr.is_old
|
||||
// while (true) {
|
||||
// var old_ds = Node.DeclSpec{};
|
||||
// if (!(try parser.declSpec(&old_ds))) {
|
||||
// // not old decl
|
||||
// break;
|
||||
// }
|
||||
// var old_dr = (try parser.declarator(.Must));
|
||||
// // if (old_dr == null)
|
||||
// // try parser.err(.{
|
||||
// // .NoParamName = .{ .token = parser.it.index },
|
||||
// // });
|
||||
// // try old_decls.push(decl);
|
||||
// }
|
||||
const body_node = (try parser.compoundStmt()) orelse return parser.err(.{
|
||||
.ExpectedFnBody = .{ .token = parser.it.index },
|
||||
});
|
||||
break :blk @fieldParentPtr(Node.CompoundStmt, "base", body_node);
|
||||
};
|
||||
|
||||
const node = try parser.arena.create(Node.FnDecl);
|
||||
node.* = .{
|
||||
.decl_spec = ds,
|
||||
.declarator = dr,
|
||||
.old_decls = old_decls,
|
||||
.body = body,
|
||||
};
|
||||
return &node.base;
|
||||
} else {
|
||||
switch (ds.fn_spec) {
|
||||
.Inline, .Noreturn => |tok| return parser.err(.{
|
||||
.FnSpecOnNonFn = .{ .token = tok },
|
||||
}),
|
||||
else => {},
|
||||
}
|
||||
// TODO threadlocal without static or extern on local variable
|
||||
const node = try parser.arena.create(Node.VarDecl);
|
||||
node.* = .{
|
||||
.decl_spec = ds,
|
||||
.initializers = Node.VarDecl.Initializers.init(parser.arena),
|
||||
.semicolon = undefined,
|
||||
};
|
||||
if (first_dr == null) {
|
||||
node.semicolon = try parser.expectToken(.Semicolon);
|
||||
const ok = switch (ds.type_spec.spec) {
|
||||
.Enum => |e| e.name != null,
|
||||
.Record => |r| r.name != null,
|
||||
else => false,
|
||||
};
|
||||
const q = ds.type_spec.qual;
|
||||
if (!ok)
|
||||
try parser.warn(.{
|
||||
.NothingDeclared = .{ .token = begin },
|
||||
})
|
||||
else if (q.@"const" orelse q.atomic orelse q.@"volatile" orelse q.restrict) |tok|
|
||||
try parser.warn(.{
|
||||
.QualifierIgnored = .{ .token = tok },
|
||||
});
|
||||
return &node.base;
|
||||
}
|
||||
var dr = @fieldParentPtr(Node.Declarator, "base", first_dr.?);
|
||||
while (true) {
|
||||
try parser.declareSymbol(&ds, dr);
|
||||
if (parser.eatToken(.Equal)) |tok| {
|
||||
try node.initializers.push((try parser.initializer(dr)) orelse return parser.err(.{
|
||||
.ExpectedInitializer = .{ .token = parser.it.index },
|
||||
}));
|
||||
} else
|
||||
try node.initializers.push(&dr.base);
|
||||
if (parser.eatToken(.Comma) != null) break;
|
||||
dr = @fieldParentPtr(Node.Declarator, "base", (try parser.declarator(.Must)) orelse return parser.err(.{
|
||||
.ExpectedDeclarator = .{ .token = parser.it.index },
|
||||
}));
|
||||
}
|
||||
node.semicolon = try parser.expectToken(.Semicolon);
|
||||
return &node.base;
|
||||
}
|
||||
}
|
||||
|
||||
fn declaratorIsFunction(dr: *Node) bool {
|
||||
return false; // TODO
|
||||
}
|
||||
|
||||
/// StaticAssert <- Keyword_static_assert LPAREN ConstExpr COMMA STRINGLITERAL RPAREN SEMICOLON
|
||||
|
@ -733,7 +787,7 @@ const Parser = struct {
|
|||
fn recordDeclarator(parser: *Parser) !*Node {}
|
||||
|
||||
/// Pointer <- ASTERISK TypeQual* Pointer?
|
||||
fn pointer(parser: *Parser) Error!?*Node {
|
||||
fn pointer(parser: *Parser) Error!?*Node.Pointer {
|
||||
const asterisk = parser.eatToken(.Asterisk) orelse return null;
|
||||
const node = try parser.arena.create(Node.Pointer);
|
||||
node.* = .{
|
||||
|
@ -743,7 +797,7 @@ const Parser = struct {
|
|||
};
|
||||
while (try parser.typeQual(&node.qual)) {}
|
||||
node.pointer = try parser.pointer();
|
||||
return &node.base;
|
||||
return node;
|
||||
}
|
||||
|
||||
const Named = enum {
|
||||
|
@ -772,7 +826,7 @@ const Parser = struct {
|
|||
node.* = .{
|
||||
.pointer = ptr,
|
||||
.prefix = .{
|
||||
.Comples = .{
|
||||
.Complex = .{
|
||||
.lparen = lparen,
|
||||
.inner = inner,
|
||||
.rparen = try parser.expectToken(.RParen),
|
||||
|
@ -785,7 +839,7 @@ const Parser = struct {
|
|||
node = try parser.arena.create(Node.Declarator);
|
||||
node.* = .{
|
||||
.pointer = ptr,
|
||||
.prefix = .{ .Simple = tok },
|
||||
.prefix = .{ .Identifer = tok },
|
||||
.suffix = .None,
|
||||
};
|
||||
} else if (named == .Must) {
|
||||
|
@ -793,7 +847,9 @@ const Parser = struct {
|
|||
.ExpectedToken = .{ .token = parser.it.index, .expected_id = .Identifier },
|
||||
});
|
||||
} else {
|
||||
return ptr;
|
||||
if (ptr) |some|
|
||||
return &some.base;
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
node = try parser.arena.create(Node.Declarator);
|
||||
|
@ -808,16 +864,16 @@ const Parser = struct {
|
|||
node.suffix = .{
|
||||
.Fn = .{
|
||||
.lparen = lparen,
|
||||
.params = .Node.Declarator.Params.init(parser.arena),
|
||||
.params = Node.Declarator.Params.init(parser.arena),
|
||||
.rparen = undefined,
|
||||
},
|
||||
};
|
||||
try parser.ParamDecl(node);
|
||||
try parser.paramDecl(node);
|
||||
node.suffix.Fn.rparen = try parser.expectToken(.RParen);
|
||||
} else {
|
||||
while (parser.arrayDeclarator()) |arr| {
|
||||
while (try parser.arrayDeclarator()) |arr| {
|
||||
if (node.suffix == .None)
|
||||
node.suffix = .{ .Array = .Node.Declarator.Arrays.init(parser.arena) };
|
||||
node.suffix = .{ .Array = Node.Declarator.Arrays.init(parser.arena) };
|
||||
try node.suffix.Array.push(arr);
|
||||
}
|
||||
}
|
||||
|
@ -825,7 +881,7 @@ const Parser = struct {
|
|||
return parser.err(.{
|
||||
.InvalidDeclarator = .{ .token = tok },
|
||||
});
|
||||
return node;
|
||||
return &node.base;
|
||||
}
|
||||
|
||||
/// ArrayDeclarator
|
||||
|
@ -834,11 +890,11 @@ const Parser = struct {
|
|||
/// / TypeQual+ (ASTERISK / Keyword_static AssignmentExpr)
|
||||
/// / TypeQual+ AssignmentExpr?
|
||||
/// / AssignmentExpr
|
||||
fn arrayDeclarator(parser: *Parser, dr: *Node.Declarator) !?*Node.Array {
|
||||
fn arrayDeclarator(parser: *Parser) !?*Node.Array {
|
||||
const lbracket = parser.eatToken(.LBracket) orelse return null;
|
||||
const arr = try parser.arena.create(Node.Array);
|
||||
arr.* = .{
|
||||
.lbracket = lbarcket,
|
||||
.lbracket = lbracket,
|
||||
.inner = .Inferred,
|
||||
.rbracket = undefined,
|
||||
};
|
||||
|
@ -856,12 +912,12 @@ const Parser = struct {
|
|||
fn paramDecl(parser: *Parser, dr: *Node.Declarator) !void {
|
||||
var old_style = false;
|
||||
while (true) {
|
||||
var ds = Node.DeclSpec;
|
||||
var ds = Node.DeclSpec{};
|
||||
if (try parser.declSpec(&ds)) {
|
||||
//TODO
|
||||
} else if (parser.eatToken(.Identifier)) {
|
||||
} else if (parser.eatToken(.Identifier)) |tok| {
|
||||
old_style = true;
|
||||
} else if (parser.eatToken(.Ellipsis)) {
|
||||
} else if (parser.eatToken(.Ellipsis)) |tok| {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue