std-c parser record and enum specifiers

master
Vexu 2020-01-07 19:05:46 +02:00
parent df12c1328e
commit 4184d4c66a
No known key found for this signature in database
GPG Key ID: 59AEB8936E16A6AC
2 changed files with 151 additions and 31 deletions

View File

@ -48,9 +48,12 @@ pub const Error = union(enum) {
ExpectedFnBody: SingleTokenError("expected function body, found '{}'"), ExpectedFnBody: SingleTokenError("expected function body, found '{}'"),
ExpectedDeclarator: SingleTokenError("expected declarator, found '{}'"), ExpectedDeclarator: SingleTokenError("expected declarator, found '{}'"),
ExpectedInitializer: SingleTokenError("expected initializer, found '{}'"), ExpectedInitializer: SingleTokenError("expected initializer, found '{}'"),
ExpectedEnumField: SingleTokenError("expected enum field, found '{}'"),
ExpectedType: SingleTokenError("expected enum field, found '{}'"),
InvalidTypeSpecifier: InvalidTypeSpecifier, InvalidTypeSpecifier: InvalidTypeSpecifier,
DuplicateQualifier: SingleTokenError("duplicate type qualifier '{}'"), DuplicateQualifier: SingleTokenError("duplicate type qualifier '{}'"),
DuplicateSpecifier: SingleTokenError("duplicate declaration specifier '{}'"), DuplicateSpecifier: SingleTokenError("duplicate declaration specifier '{}'"),
MustUseKwToRefer: MustUseKwToRefer,
pub fn render(self: *const Error, tree: *Tree, stream: var) !void { pub fn render(self: *const Error, tree: *Tree, stream: var) !void {
switch (self.*) { switch (self.*) {
@ -62,9 +65,12 @@ pub const Error = union(enum) {
.ExpectedDeclarator => |*x| return x.render(tree, stream), .ExpectedDeclarator => |*x| return x.render(tree, stream),
.ExpectedFnBody => |*x| return x.render(tree, stream), .ExpectedFnBody => |*x| return x.render(tree, stream),
.ExpectedInitializer => |*x| return x.render(tree, stream), .ExpectedInitializer => |*x| return x.render(tree, stream),
.ExpectedEnumField => |*x| return x.render(tree, stream),
.ExpectedType => |*x| return x.render(tree, stream),
.InvalidTypeSpecifier => |*x| return x.render(tree, stream), .InvalidTypeSpecifier => |*x| return x.render(tree, stream),
.DuplicateQualifier => |*x| return x.render(tree, stream), .DuplicateQualifier => |*x| return x.render(tree, stream),
.DuplicateSpecifier => |*x| return x.render(tree, stream), .DuplicateSpecifier => |*x| return x.render(tree, stream),
.MustUseKwToRefer => |*x| return x.render(tree, stream),
} }
} }
@ -78,9 +84,12 @@ pub const Error = union(enum) {
.ExpectedDeclarator => |x| return x.token, .ExpectedDeclarator => |x| return x.token,
.ExpectedFnBody => |x| return x.token, .ExpectedFnBody => |x| return x.token,
.ExpectedInitializer => |x| return x.token, .ExpectedInitializer => |x| return x.token,
.ExpectedEnumField => |x| return x.token,
.ExpectedType => |*x| return x.token,
.InvalidTypeSpecifier => |x| return x.token, .InvalidTypeSpecifier => |x| return x.token,
.DuplicateQualifier => |x| return x.token, .DuplicateQualifier => |x| return x.token,
.DuplicateSpecifier => |x| return x.token, .DuplicateSpecifier => |x| return x.token,
.MustUseKwToRefer => |*x| return x.name,
} }
} }
@ -111,6 +120,15 @@ pub const Error = union(enum) {
} }
}; };
pub const MustUseKwToRefer = struct {
kw: TokenIndex,
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)});
}
};
fn SingleTokenError(comptime msg: []const u8) type { fn SingleTokenError(comptime msg: []const u8) type {
return struct { return struct {
token: TokenIndex, token: TokenIndex,
@ -125,14 +143,13 @@ pub const Error = union(enum) {
pub const Type = struct { pub const Type = struct {
pub const TypeList = std.SegmentedList(*Type, 4); pub const TypeList = std.SegmentedList(*Type, 4);
@"const": bool, @"const": bool = false,
atomic: bool, atomic: bool = false,
@"volatile": bool, @"volatile": bool = false,
restrict: bool, restrict: bool = false,
id: union(enum) { id: union(enum) {
Int: struct { Int: struct {
quals: Qualifiers,
id: Id, id: Id,
is_signed: bool, is_signed: bool,
@ -145,7 +162,6 @@ pub const Type = struct {
}; };
}, },
Float: struct { Float: struct {
quals: Qualifiers,
id: Id, id: Id,
pub const Id = enum { pub const Id = enum {
@ -154,10 +170,7 @@ pub const Type = struct {
LongDouble, LongDouble,
}; };
}, },
Pointer: struct { Pointer: *Type,
quals: Qualifiers,
child_type: *Type,
},
Function: struct { Function: struct {
return_type: *Type, return_type: *Type,
param_types: TypeList, param_types: TypeList,
@ -173,6 +186,8 @@ pub const Node = struct {
pub const Id = enum { pub const Id = enum {
Root, Root,
EnumField,
RecordField,
JumpStmt, JumpStmt,
ExprStmt, ExprStmt,
Label, Label,
@ -350,15 +365,16 @@ pub const Node = struct {
}; };
pub const EnumField = struct { pub const EnumField = struct {
base: Node = Node{ .id = EnumField }, base: Node = Node{ .id = .EnumField },
name: TokenIndex, name: TokenIndex,
value: ?*Node, value: ?*Node,
}; };
pub const RecordType = struct { pub const RecordType = struct {
kind: union(enum) { tok: TokenIndex,
Struct: TokenIndex, kind: enum {
Union: TokenIndex, Struct,
Union,
}, },
name: ?TokenIndex, name: ?TokenIndex,
body: ?struct { body: ?struct {
@ -373,8 +389,12 @@ pub const Node = struct {
}; };
pub const RecordField = struct { pub const RecordField = struct {
base: Node = Node{ .id = RecordField }, base: Node = Node{ .id = .RecordField },
// TODO type_spec: TypeSpec,
declarators: DeclaratorList,
semicolon: TokenIndex,
pub const DeclaratorList = Root.DeclList;
}; };
pub const TypeQual = struct { pub const TypeQual = struct {

View File

@ -94,12 +94,11 @@ const Parser = struct {
} }
fn getSymbol(parser: *Parser, tok: TokenIndex) ?*Type { fn getSymbol(parser: *Parser, tok: TokenIndex) ?*Type {
const token = parser.it.list.at(tok); const name = parser.tree.slice(tok);
const name = parser.tree.slice(token);
const syms = parser.symbols.toSliceConst(); const syms = parser.symbols.toSliceConst();
var i = syms.len; var i = syms.len;
while (i > 0) : (i -= 1) { while (i > 0) : (i -= 1) {
if (mem.eql(u8, name, syms[i].name)) { if (std.mem.eql(u8, name, syms[i].name)) {
return syms[i].ty; return syms[i].ty;
} }
} }
@ -492,31 +491,29 @@ const Parser = struct {
} else if (parser.eatToken(.Keyword_enum)) |tok| { } else if (parser.eatToken(.Keyword_enum)) |tok| {
if (type_spec.spec != .None) if (type_spec.spec != .None)
break :blk; break :blk;
type_spec.Enum = try parser.enumSpec(tok); type_spec.spec.Enum = try parser.enumSpec(tok);
return true; return true;
} else if (parser.eatToken(.Keyword_union) orelse parser.eatToken(.Keyword_struct)) |tok| { } else if (parser.eatToken(.Keyword_union) orelse parser.eatToken(.Keyword_struct)) |tok| {
if (type_spec.spec != .None) if (type_spec.spec != .None)
break :blk; break :blk;
type_spec.Record = try parser.recordSpec(); type_spec.spec.Record = try parser.recordSpec(tok);
return true; return true;
} else if (parser.eatToken(.Identifier)) |tok| { } else if (parser.eatToken(.Identifier)) |tok| {
const ty = parser.getSymbol(tok) orelse { const ty = parser.getSymbol(tok) orelse {
parser.putBackToken(tok); parser.putBackToken(tok);
return false; return false;
}; };
switch (ty) { switch (ty.id) {
.Enum => |e| { .Enum => |e| {
return parser.err(.{ return parser.err(.{
.MustUseKwToRefer = .{ .kw = e.identifier, .sym = tok }, .MustUseKwToRefer = .{ .kw = e.tok, .name = tok },
}); });
}, },
.Record => |r| { .Record => |r| {
return parser.err(.{ return parser.err(.{
.MustUseKwToRefer = .{ .MustUseKwToRefer = .{
.kw = switch (r.kind) { .kw = r.tok,
.Struct, .Union => |kw| kw, .name = tok,
},
.sym = tok,
}, },
}); });
}, },
@ -613,18 +610,121 @@ const Parser = struct {
} }
/// EnumSpec <- Keyword_enum IDENTIFIER? (LBRACE EnumField RBRACE)? /// EnumSpec <- Keyword_enum IDENTIFIER? (LBRACE EnumField RBRACE)?
fn enumSpecifier(parser: *Parser) !*Node {} fn enumSpec(parser: *Parser, tok: TokenIndex) !*Node.EnumType {
const node = try parser.arena.create(Node.EnumType);
const name = parser.eatToken(.Identifier);
node.* = .{
.tok = tok,
.name = name,
.body = null,
};
const ty = try parser.arena.create(Type);
ty.* = .{
.id = .{
.Enum = node,
},
};
if (name) |some|
try parser.symbols.append(.{
.name = parser.tree.slice(some),
.ty = ty,
});
if (parser.eatToken(.LBrace)) |lbrace| {
var fields = Node.EnumType.FieldList.init(parser.arena);
try fields.push((try parser.enumField()) orelse return parser.err(.{
.ExpectedEnumField = .{ .token = parser.it.index },
}));
while (parser.eatToken(.Comma)) |_| {
try fields.push((try parser.enumField()) orelse break);
}
node.body = .{
.lbrace = lbrace,
.fields = fields,
.rbrace = try parser.expectToken(.RBrace),
};
}
return node;
}
/// EnumField <- IDENTIFIER (EQUAL ConstExpr)? (COMMA EnumField) COMMA? /// EnumField <- IDENTIFIER (EQUAL ConstExpr)? (COMMA EnumField) COMMA?
fn enumField(parser: *Parser) !*Node {} fn enumField(parser: *Parser) !?*Node {
const name = parser.eatToken(.Identifier) orelse return null;
const node = try parser.arena.create(Node.EnumField);
node.* = .{
.name = name,
.value = null,
};
if (parser.eatToken(.Equal)) |eq| {
node.value = try parser.constExpr();
}
return &node.base;
}
/// RecordSpec <- (Keyword_struct / Keyword_union) IDENTIFIER? (LBRACE RecordField+ RBRACE)? /// RecordSpec <- (Keyword_struct / Keyword_union) IDENTIFIER? (LBRACE RecordField+ RBRACE)?
fn recordSpecifier(parser: *Parser) !*Node {} fn recordSpec(parser: *Parser, tok: TokenIndex) !*Node.RecordType {
const node = try parser.arena.create(Node.RecordType);
const name = parser.eatToken(.Identifier);
const is_struct = parser.tree.slice(tok)[0] == 's';
node.* = .{
.tok = tok,
.kind = if (is_struct) .Struct else .Union,
.name = name,
.body = null,
};
const ty = try parser.arena.create(Type);
ty.* = .{
.id = .{
.Record = node,
},
};
if (name) |some|
try parser.symbols.append(.{
.name = parser.tree.slice(some),
.ty = ty,
});
if (parser.eatToken(.LBrace)) |lbrace| {
var fields = Node.RecordType.FieldList.init(parser.arena);
while (true) {
if (parser.eatToken(.RBrace)) |rbrace| {
node.body = .{
.lbrace = lbrace,
.fields = fields,
.rbrace = rbrace,
};
break;
}
try fields.push(try parser.recordField());
}
}
return node;
}
/// RecordField /// RecordField
/// <- TypeSpec* (RecordDeclarator (COMMA RecordDeclarator))? SEMICOLON /// <- TypeSpec* (RecordDeclarator (COMMA RecordDeclarator))? SEMICOLON
/// \ StaticAssert /// \ StaticAssert
fn recordField(parser: *Parser) !*Node {} fn recordField(parser: *Parser) Error!*Node {
if (try parser.staticAssert()) |decl| return decl;
var got = false;
var type_spec = Node.TypeSpec{};
while (try parser.typeSpec(&type_spec)) got = true;
if (!got)
return parser.err(.{
.ExpectedType = .{ .token = parser.it.index },
});
const node = try parser.arena.create(Node.RecordField);
node.* = .{
.type_spec = type_spec,
.declarators = Node.RecordField.DeclaratorList.init(parser.arena),
.semicolon = undefined,
};
while (true) {
try node.declarators.push(try parser.recordDeclarator());
if (parser.eatToken(.Comma)) |_| {} else break;
}
node.semicolon = try parser.expectToken(.Semicolon);
return &node.base;
}
/// TypeName <- TypeSpec* AbstractDeclarator? /// TypeName <- TypeSpec* AbstractDeclarator?
fn typeName(parser: *Parser) !*Node { fn typeName(parser: *Parser) !*Node {