Skip to content

Commit

Permalink
(#72) Parser: custom parsing for a struct declaration item
Browse files Browse the repository at this point in the history
  • Loading branch information
ForNeVeR committed Feb 15, 2022
1 parent 59f3fac commit e1cc91d
Show file tree
Hide file tree
Showing 2 changed files with 208 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
{
"$type": "Cesium.Ast.TranslationUnit, Cesium.Ast",
"Declarations": [
{
"$type": "Cesium.Ast.SymbolDeclaration, Cesium.Ast",
"Declaration": {
"$type": "Cesium.Ast.Declaration, Cesium.Ast",
"Specifiers": [
{
"$type": "Cesium.Ast.StorageClassSpecifier, Cesium.Ast",
"Name": "typedef"
},
{
"$type": "Cesium.Ast.StructOrUnionSpecifier, Cesium.Ast",
"TypeKind": "Struct",
"Identifier": null,
"StructDeclarations": [
{
"$type": "Cesium.Ast.StructDeclaration, Cesium.Ast",
"SpecifiersQualifiers": [
{
"$type": "Cesium.Ast.SimpleTypeSpecifier, Cesium.Ast",
"TypeName": "int"
}
],
"Declarators": [
{
"$type": "Cesium.Ast.StructDeclarator, Cesium.Ast",
"Declarator": {
"$type": "Cesium.Ast.Declarator, Cesium.Ast",
"Pointer": null,
"DirectDeclarator": {
"$type": "Cesium.Ast.IdentifierDirectDeclarator, Cesium.Ast",
"Identifier": "x",
"Base": null
}
}
}
]
}
]
}
],
"InitDeclarators": [
{
"$type": "Cesium.Ast.InitDeclarator, Cesium.Ast",
"Declarator": {
"$type": "Cesium.Ast.Declarator, Cesium.Ast",
"Pointer": null,
"DirectDeclarator": {
"$type": "Cesium.Ast.IdentifierDirectDeclarator, Cesium.Ast",
"Identifier": "foo",
"Base": null
}
},
"Initializer": null
}
]
}
},
{
"$type": "Cesium.Ast.FunctionDefinition, Cesium.Ast",
"Specifiers": [
{
"$type": "Cesium.Ast.SimpleTypeSpecifier, Cesium.Ast",
"TypeName": "int"
}
],
"Declarator": {
"$type": "Cesium.Ast.Declarator, Cesium.Ast",
"Pointer": null,
"DirectDeclarator": {
"$type": "Cesium.Ast.ParameterListDirectDeclarator, Cesium.Ast",
"Base": {
"$type": "Cesium.Ast.IdentifierDirectDeclarator, Cesium.Ast",
"Identifier": "main",
"Base": null
},
"Parameters": {
"$type": "Cesium.Ast.ParameterTypeList, Cesium.Ast",
"Parameters": [
{
"$type": "Cesium.Ast.ParameterDeclaration, Cesium.Ast",
"Specifiers": [
{
"$type": "Cesium.Ast.SimpleTypeSpecifier, Cesium.Ast",
"TypeName": "void"
}
],
"Declarator": null,
"AbstractDeclarator": null
}
],
"HasEllipsis": false
}
}
},
"Declarations": null,
"Statement": {
"$type": "Cesium.Ast.CompoundStatement, Cesium.Ast",
"Block": [
{
"$type": "Cesium.Ast.Declaration, Cesium.Ast",
"Specifiers": [
{
"$type": "Cesium.Ast.NamedTypeSpecifier, Cesium.Ast",
"TypeDefName": "foo"
}
],
"InitDeclarators": [
{
"$type": "Cesium.Ast.InitDeclarator, Cesium.Ast",
"Declarator": {
"$type": "Cesium.Ast.Declarator, Cesium.Ast",
"Pointer": null,
"DirectDeclarator": {
"$type": "Cesium.Ast.IdentifierDirectDeclarator, Cesium.Ast",
"Identifier": "x",
"Base": null
}
},
"Initializer": null
}
]
},
{
"$type": "Cesium.Ast.ReturnStatement, Cesium.Ast",
"Expression": {
"$type": "Cesium.Ast.ConstantExpression, Cesium.Ast",
"Constant": {
"Kind": "IntLiteral",
"Text": "0"
}
}
}
]
}
}
]
}
75 changes: 68 additions & 7 deletions Cesium.Parser/CParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ private static StructOrUnionSpecifier MakeStructOrUnionSpecifier(
IToken? identifier,
IToken _,
StructDeclarationList structDeclarationList,
IToken __) => new StructOrUnionSpecifier(structOrUnion, identifier?.Text, structDeclarationList);
IToken __) => new(structOrUnion, identifier?.Text, structDeclarationList);

// TODO: struct-or-union-specifier: struct-or-union identifier

Expand All @@ -327,19 +327,80 @@ private static StructDeclarationList MakeStructDeclarationList(
StructDeclarationList prev,
StructDeclaration structDeclaration) => prev.Add(structDeclaration);

[Rule("struct_declaration: specifier_qualifier_list struct_declarator_list? ';'")]
// HACK: custom parsing is required here due to the reasons outlined in
// https://github.com/LanguageDev/Yoakke/issues/138
//
// struct_declaration: specifier_qualifier_list struct_declarator_list? ';'
[CustomParser("struct_declaration")]
private ParseResult<StructDeclaration> customParseStructDeclaration(int offset)
{
// HACK: Usually, this would be a call to parseSpecifierQualifierList(offset). But here, we have to parse them
// one by one and remember the offset of every one, to be able to backtrack if necessary.
var firstListItem = parseSpecifierQualifierListItem(offset);
if (firstListItem.IsError) return firstListItem.Error;
offset = firstListItem.Ok.Offset;

var specifiersQualifiers = new List<(ISpecifierQualifierListItem Item, int Offset)>
{ (firstListItem.Ok.Value, offset) };
while (true)
{
var listItem = parseSpecifierQualifierListItem(offset);
if (listItem.IsError) break;
offset = listItem.Ok.Offset;

specifiersQualifiers.Add((listItem.Ok.Value, offset));
}

var structDeclaratorList = parseStructDeclaratorList(offset);
if (structDeclaratorList.IsError && specifiersQualifiers.Count > 1)
{
// Try backtracking: drop the last declaration specifier and parse again:
var preLastSpecifierQualifier = specifiersQualifiers[^2];
structDeclaratorList = parseStructDeclaratorList(preLastSpecifierQualifier.Offset);
if (structDeclaratorList.IsOk)
specifiersQualifiers.RemoveAt(specifiersQualifiers.Count - 1);
}

if (structDeclaratorList.IsOk)
offset = structDeclaratorList.Ok.Offset;

if (TokenStream.TryLookAhead(offset, out var t) && t.Text == ";")
{
++offset;
return ParseResult.Ok(
MakeStructDeclaration(
MakeSpecifierQualifierList(specifiersQualifiers.Select(pair => pair.Item)),
structDeclaratorList.IsOk ? structDeclaratorList.Ok.Value : null,
t
),
offset,
structDeclaratorList.FurthestError);
}

return ParseResult.Error(";", t, t!.Range.Start, ";");
}

private static StructDeclaration MakeStructDeclaration(
SpecifierQualifierList specifiersQualifiers,
StructDeclaratorList? structDeclarators,
IToken _) => new(specifiersQualifiers, structDeclarators);

// TODO: struct-declaration: static_assert-declaration

[Rule("specifier_qualifier_list: type_specifier specifier_qualifier_list?")]
[Rule("specifier_qualifier_list: type_qualifier specifier_qualifier_list?")]
private SpecifierQualifierList MakeSpecifierQualifierList(
ISpecifierQualifierListItem item,
SpecifierQualifierList? rest) => rest?.Insert(0, item) ?? ImmutableArray.Create(item);
// HACK: This is a synthetic set of rules which is absent from the C standard, but required for simplification of
// the implementation of https://github.com/LanguageDev/Yoakke/issues/138
//
// Actual rules are:
// specifier_qualifier_list: type_specifier specifier_qualifier_list?
// specifier_qualifier_list: type_qualifier specifier_qualifier_list?
[Rule("specifier_qualifier_list: specifier_qualifier_list_item+")]
private static SpecifierQualifierList MakeSpecifierQualifierList(
IEnumerable<ISpecifierQualifierListItem> specifiersQualifiers) =>
specifiersQualifiers.ToImmutableArray();

[Rule("specifier_qualifier_list_item: type_specifier")]
[Rule("specifier_qualifier_list_item: type_qualifier")]
private static ISpecifierQualifierListItem MakeSpecifierQualifierListItem(ISpecifierQualifierListItem item) => item;

// TODO: specifier-qualifier-list: alignment-specifier specifier-qualifier-list?

Expand Down

0 comments on commit e1cc91d

Please sign in to comment.