std-c parser record and enum specifiers
parent
df12c1328e
commit
4184d4c66a
|
@ -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 {
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Reference in New Issue