using System; using System.Collections.Immutable; using System.Linq; using AST; using static Parsing.ParserCombinator; namespace Parsing { public partial class CParsers { /// /// declaration /// : declaration-specifiers [Init-declarator-list]? ';' /// public static NamedParser Declaration { get; } = new NamedParser("declaration"); /// /// declaration-specifiers /// : [ storage-class-specifier | Type-specifier | Type-qualifier ]+ /// /// /// 1. You can only have **one** storage class specifier. /// 2. You can have duplicate Type qualifiers, since it doesn't cause ambiguity. /// public static NamedParser DeclarationSpecifiers { get; } = new NamedParser("declaration-specifiers"); /// /// Init-declarator-list /// : Init-declarator [ ',' Init-declarator ]* /// /// /// a non-empty list of init_declarators separated by ',' /// public static NamedParser> InitDeclaratorList { get; } = new NamedParser>("Init-declarator-list"); /// /// Init-declarator /// : declarator [ '=' initializer ]? /// public static NamedParser InitDeclarator { get; } = new NamedParser("Init-declarator"); /// /// storage-class-specifier /// : auto | register | static | extern | typedef /// /// /// There can only be *one* storage class specifier in one declaration. /// public static NamedParser StorageClassSpecifier { get; } = new NamedParser("storage-class-specifier"); /// /// Type-specifier /// : void /// | char /// | short /// | int /// | long /// | float /// | double /// | signed /// | unsigned /// | struct-or-union-specifier /// | enum-specifier /// | typedef-name /// /// /// 1. void, char, short, int, long, float, double, signed, unsigned are called "basic Type specifiers". /// 2. struct-or-union_specifier and enum-specifier need more complicated parsing. /// 3. Parsing typedef-name actually requires the environment to participate. For example, consider this statement: /// T *v; /// Is T a Type or an object? If T is a Type, then this statement is a declaration: v is a pointer; if T is a object, then this statement is an expression. /// So, we need to keep track of the typedefs in the environment even in the parsing stage! /// public static NamedParser TypeSpecifier { get; } = new NamedParser("Type-specifier"); /// /// Type-qualifier /// : const /// | volatile /// /// /// Note that there can be multiple Type qualifiers in one declarations. /// public static NamedParser TypeQualifier { get; } = new NamedParser("Type-qualifier"); /// /// declarator /// : [pointer]? direct-declarator /// /// /// A declarator gives a name to the object and also modifies the Type. /// public static NamedParser Declarator { get; } = new NamedParser("declarator"); /// /// pointer /// : [ '*' [Type-qualifier-list]? ]+ /// public static NamedParser> Pointer { get; } = new NamedParser>("pointer"); /// /// parameter-Type-list /// : parameter-list [ ',' '...' ]? /// /// /// A parameter list and an optional vararg signature. /// Used in function declarations. /// public static NamedParser ParameterTypeList { get; } = new NamedParser("parameter-Type-list"); /// /// parameter-list /// : parameter-declaration [ ',' parameter-declaration ]* /// /// /// A non-empty list of parameters separated by ','. /// Used in a function signature. /// public static NamedParser> ParameterList { get; } = new NamedParser>("parameter-list"); /// /// Type-qualifier-list /// : [Type-qualifier]+ /// /// /// A non-empty list of Type qualifiers. /// public static NamedParser> TypeQualifierList { get; } = new NamedParser>("Type-qualifier-list"); /// /// direct-declarator /// : [ /// identifier | '(' declarator ')' /// ] [ /// '[' [constant-expression]? ']' /// | '(' [parameter-Type-list]? ')' /// ]* /// /// /// There is an old style of function definition: /// +-------------------------------+ /// | int foo(param1, param2) | /// | int param1; | /// | char param2; | /// | { | /// | .... | /// | } | /// +-------------------------------+ /// /// I'm not gonna support this style, and function definitions should always be like this: /// +------------------------------------------+ /// | int foo(int param1, char param2) { | /// | .... | /// | } | /// +------------------------------------------+ /// public static NamedParser DirectDeclarator { get; } = new NamedParser("direct-declarator"); /// /// enum-specifier /// : enum [identifier]? '{' enumerator-list '}' /// | enum identifier /// public static NamedParser EnumSpecifier { get; } = new NamedParser("enum-specifier"); /// /// enumerator-list /// : enumerator [ ',' enumerator ]* /// public static NamedParser> EnumeratorList { get; } = new NamedParser>("enumerator-list"); /// /// enumerator /// : enumeration-constant [ '=' constant-expression ]? /// public static NamedParser Enumerator { get; } = new NamedParser("enumerator"); /// /// enumeration-constant /// : identifier /// public static NamedParser EnumerationConstant { get; } = new NamedParser("enumeration-constant"); /// /// struct-or-union-specifier /// : struct-or-union [identifier]? { struct-declaration-list } /// | struct-or-union identifier /// /// /// Note: if no struct-declaration-list given, the Type is considered incomplete. /// public static NamedParser StructOrUnionSpecifier { get; } = new NamedParser("struct-or-union-specifier"); /// /// struct-or-union /// : struct | union /// public static NamedParser StructOrUnion { get; } = new NamedParser("struct-or-union"); /// /// struct-declaration-list /// : [struct-declaration]+ /// public static NamedParser> StructDeclarationList { get; } = new NamedParser>("struct-declaration-list"); /// /// struct-declaration /// : specifier-qualifier-list struct-declarator-list ';' /// /// /// Note that a struct declaration does not need a storage class specifier. /// public static NamedParser StructDeclaration { get; } = new NamedParser("struct-declaration"); /// /// specifier-qualifier-list /// : [ Type-specifier | Type-qualifier ]+ /// public static NamedParser SpecifierQualifierList { get; } = new NamedParser("specifier-qualifier-list"); /// /// struct-declarator-list /// : struct-declarator [ ',' struct-declarator ]* /// public static NamedParser> StructDeclaratorList { get; } = new NamedParser>("struct-declarator-list"); /// /// struct-declarator /// : [declarator]? ':' constant-expression /// | declarator /// /// /// Note that the second one represents a 'bit-field', which I'm not going to support. /// public static NamedParser StructDeclarator { get; } = new NamedParser("struct-declarator"); /// /// parameter-declaration /// : declaration-specifiers [ declarator | abstract-declarator ]? /// /// /// int foo(int arg1, int arg2); /// ~~~~~~~~ /// /// int foo(int, int); /// ~~~ /// /// The declarator can be completely omitted. /// public static NamedParser ParameterDeclaration { get; } = new NamedParser("parameter-declaration"); // identifier_list // : /* old style, i'm deleting this */ /// /// abstract-declarator /// : [pointer]? direct-abstract-declarator /// | pointer /// /// /// An abstract declarator is a non-empty list of (pointer, function, or array) Type modifiers /// public static NamedParser AbstractDeclarator { get; } = new NamedParser("abstract-declarator"); /// /// direct-abstract-declarator /// : [ /// '(' abstract-declarator ')' /// | '[' [constant-expression]? ']' // array modifier /// | '(' [parameter-type_list]? ')' // function modifier /// ] [ /// '[' [constant-expression]? ']' // array modifier /// | '(' [parameter-Type-list]? ')' // function modifier /// ]* /// public static NamedParser DirectAbstractDeclarator { get; } = new NamedParser("direct-abstract-declarator"); /// /// initializer /// : assignment-expression /// | '{' initializer-list '}' /// | '{' initializer-list ',' '}' /// public static NamedParser Initializer { get; } = new NamedParser("initializer"); /// /// initializer-list /// : initializer [ ',' initializer ]* /// /// A non-empty list of initializers. /// public static NamedParser InitializerList { get; } = new NamedParser("initializer-list"); /// /// Type-name /// : specifier-qualifier-list [abstract-declarator]? /// public static NamedParser TypeName { get; } = new NamedParser("Type-name"); /// /// typedef-name /// : identifier /// /// /// It must be something already defined. /// We need to look it up in the parser environment. /// public static NamedParser TypeDefName { get; } = new NamedParser("typedef-name"); /// /// attribute-list /// : parameter-declaration [ ',' parameter-declaration ]* /// /// /// A non-empty list of parameters separated by ','. /// Used in a function signature. /// public static NamedParser AttributeDecl { get; } = new NamedParser("attribute-decl"); /// /// interface-type-specifier /// : __interface("guid") /// public static NamedParser InterfaceTypeSpecifier { get; } = new NamedParser("interface-type-specifier"); public static void SetDeclarationRules() { // declaration // : declaration-specifiers [Init-declarator-list]? ';' Declaration.Is( (DeclarationSpecifiers) .Then(InitDeclaratorList.Optional(ImmutableList.Empty)) .Then(Semicolon) .Then(Decln.Create) .TransformResult( _ => { var result = _.Result; var env = _.Environment; env = result.InitDeclrs.Aggregate(env, (currentEnv, initDeclr) => currentEnv.AddSymbol( initDeclr.Declr.Name, result.DeclnSpecs.StorageClsSpecs.DefaultIfEmpty(StorageClsSpec.AUTO).First() ) ); return ParserSucceeded.Create(result, env, _.Source); } ) ); // declaration-specifiers // : [ storage-class-specifier | Type-specifier | Type-qualifier ]+ DeclarationSpecifiers.Is( Parser.Seed(DeclnSpecs.Empty) .Then( Either( Given() .Then(StorageClassSpecifier) .Then(DeclnSpecs.Add) ).Or( Given() .Then(TypeSpecifier) .Then(DeclnSpecs.Add) ).Or( Given() .Then(TypeQualifier) .Then(DeclnSpecs.Add) ).Or( Given() .Then(AttributeDecl) .Then(DeclnSpecs.Add) ).OneOrMore() ) ); // Init-declarator-list // : Init-declarator [ ',' Init-declarator ]* InitDeclaratorList.Is( InitDeclarator.OneOrMore(Comma) ); // Init-declarator // : declarator [ '=' initializer ]? InitDeclarator.Is( (Declarator) .Then( (Assign).Then(Initializer).Optional() ).Then(InitDeclr.Create) ); // storage-class-specifier // : auto | register | static | extern | typedef StorageClassSpecifier.Is( Either(Auto) .Or(Register) .Or(Static) .Or(Extern) .Or(Typedef) ); // Type-specifier // : void // | char // | short // | int // | long // | float // | double // | signed // | unsigned // | struct-or-union-specifier // | enum-specifier // | typedef-name TypeSpecifier.Is( Either( Either(Void) .Or(Char) .Or(Short) .Or(Int) .Or(Long) .Or(Int64) .Or(Float) .Or(Double) .Or(Signed) .Or(Unsigned) .Or(String) .Or(Variant) .Then(kind => new BasicTypeSpec(kind) as TypeSpec) ) .Or(InterfaceTypeSpecifier) .Or(StructOrUnionSpecifier) .Or(EnumSpecifier) .Or(TypeDefName.Then(TypedefName.Create)) ); // type_qualifier // : const // | volatile TypeQualifier.Is( Either(Const).Or(Volatile) ); // declarator // : [pointer]? direct-declarator Declarator.Is( (Pointer.Optional()) .Then(DirectDeclarator) .Then(Declr.Create) ); // pointer // : [ '*' [Type-qualifier-list]? ]+ Pointer.Is( ( Mult. Then(TypeQualifierList.Optional(ImmutableList.Empty)) .Then(PointerModifier.Create) ).OneOrMore() .Then(pointerModifiers => pointerModifiers.Reverse()) ); // parameter-Type-list // : parameter-list [ ',' '...' ]? ParameterTypeList.Is( ParameterList .Then( (Comma) .Then(Period).Then(Period).Then(Period) .Optional() ).Then(ParamTypeList.Create) ); // parameter-list // : parameter-declaration [ ',' parameter-declaration ]* ParameterList.Is( ParameterDeclaration.OneOrMore(Comma) ); // Type-qualifier-list // : [Type-qualifier]+ TypeQualifierList.Is( TypeQualifier.OneOrMore() ); // direct-declarator // : [ // identifier | '(' declarator ')' // ] [ // '[' [constant-expression]? ']' // | '(' [parameter-Type-list]? ')' // ]* DirectDeclarator.Is( ( Either( (Identifier).Then(Declr.Create) ).Or( (LeftParen).Then(Declarator).Then(RightParen) ) ).Then( Either( Given() .Then(LeftBracket) .Then( ConstantExpression.Optional().Then(ArrayModifier.Create) ).Then(RightBracket) .Then(Declr.Add) ).Or( Given() .Then(LeftParen) .Then( ParameterTypeList .Optional() .Then(FunctionModifier.Create) ).Then(RightParen) .Then(Declr.Add) ) .ZeroOrMore() ) ); // enum-specifier // : enum [identifier]? '{' enumerator-list '}' // | enum identifier EnumSpecifier.Is( (Enum) .Then( Either( Identifier.Optional() .Then(LeftCurlyBrace) .Then(EnumeratorList) .Then(RightCurlyBrace) .Then(EnumSpec.Create) ).Or( (Identifier) .Then(EnumSpec.Create) ) ) ); // enumerator-list // : enumerator [ ',' enumerator ]* EnumeratorList.Is( Enumerator.OneOrMore(Comma) ); // enumerator // : enumeration-constant [ '=' constant-expression ]? Enumerator.Is( EnumerationConstant .Then( (Assign) .Then(ConstantExpression) .Optional() ).Then(Enumr.Create) ); // enumeration-constant // : identifier EnumerationConstant.Is( Identifier ); // struct-or-union-specifier // : struct-or-union [identifier]? { struct-declaration-list } // | struct-or-union identifier StructOrUnionSpecifier.Is( (StructOrUnion) .Then( Either( Given() .Then(Identifier.Optional()) .Then(LeftCurlyBrace) .Then(StructDeclarationList) .Then(RightCurlyBrace) .Then(StructOrUnionSpec.Create) ).Or( Given() .Then(Identifier) .Then(StructOrUnionSpec.Create) ) ) ); // struct-or-union // : struct | union StructOrUnion.Is( Either(Struct).Or(Union) ); // struct-declaration-list // : [struct-declaration]+ StructDeclarationList.Is( StructDeclaration.OneOrMore() ); // struct-declaration // : specifier-qualifier-list struct-declarator-list ';' StructDeclaration.Is( (SpecifierQualifierList) .Then(StructDeclaratorList) .Then(Semicolon) .Then(StructDecln.Create) ); // specifier-qualifier-list // : [ Type-specifier | Type-qualifier ]+ SpecifierQualifierList.Is( Parser.Seed(SpecQualList.Empty) .Then( Either( Given() .Then(TypeSpecifier) .Then(SpecQualList.Add) ).Or( Given() .Then(TypeQualifier) .Then(SpecQualList.Add) ) .OneOrMore() ) ); // struct-declarator-list // : struct-declarator [ ',' struct-declarator ]* StructDeclaratorList.Is( StructDeclarator.OneOrMore(Comma) ); // struct-declarator // : [declarator]? ':' constant-expression // | declarator StructDeclarator.Is( Either( (Declarator.Optional()) .Then(Colon) .Then(ConstantExpression) .Then(StructDeclr.Create) ).Or( (Declarator) .Then(StructDeclr.Create) ) ); // parameter-declaration // : declaration-specifiers [ declarator | abstract-declarator ]? ParameterDeclaration.Is( (DeclarationSpecifiers) .Then( Either( (Declarator).Then(ParamDeclr.Create) ).Or( (AbstractDeclarator).Then(ParamDeclr.Create) ).Optional() ).Then(ParamDecln.Create) ); // abstract-declarator // : [pointer]? direct-abstract-declarator // | pointer AbstractDeclarator.Is( Either( (Pointer.Optional(ImmutableList.Empty)) .Then(DirectAbstractDeclarator) .Then(AbstractDeclr.Add) ).Or( (Pointer) .Then(AbstractDeclr.Create) ) ); // direct-abstract-declarator // : [ // '(' abstract-declarator ')' // | '[' [constant-expression]? ']' // array modifier // | '(' [parameter-type_list]? ')' // function modifier // ] [ // '[' [constant-expression]? ']' // array modifier // | '(' [parameter-Type-list]? ')' // function modifier // ]* DirectAbstractDeclarator.Is( ( Either( (LeftParen) .Then(AbstractDeclarator) .Then(RightParen) ).Or( (LeftBracket) .Then(ConstantExpression.Optional()) .Then(RightBracket) .Then(ArrayModifier.Create) .Then>(ImmutableList.Create) .Then(AbstractDeclr.Create) ).Or( (LeftParen) .Then(ParameterTypeList.Optional()) .Then(RightParen) .Then(FunctionModifier.Create) .Then>(ImmutableList.Create) .Then(AbstractDeclr.Create) ) ).Then( Either( Given() .Then( LeftBracket .Then(ConstantExpression.Optional()) .Then(RightBracket) .Then(ArrayModifier.Create) ).Then( AbstractDeclr.Add ) ).Or( Given() .Then( (LeftParen) .Then(ParameterTypeList.Optional()) .Then(RightParen) .Then(FunctionModifier.Create) ).Then( AbstractDeclr.Add ) ) .ZeroOrMore() ) ); // initializer // : assignment-expression // | '{' initializer-list '}' // | '{' initializer-list ',' '}' Initializer.Is( Either( (AssignmentExpression) .Then(InitExpr.Create) ).Or( (LeftCurlyBrace) .Then(InitializerList) .Then(RightCurlyBrace) ).Or( (LeftCurlyBrace) .Then(InitializerList) .Then(Comma) .Then(RightCurlyBrace) ) ); // initializer-list // : initializer [ ',' initializer ]* InitializerList.Is( Initializer.OneOrMore(Comma).Optional() .Then(InitList.Create) ); // Type-name // : specifier-qualifier-list [abstract-declarator]? TypeName.Is( (SpecifierQualifierList) .Then(AbstractDeclarator.Optional()) .Then(AST.TypeName.Create) ); // typedef-name // : identifier TypeDefName.Is( (Identifier) .Check( result => result.Environment.IsTypedefName(result.Result) ) ); AttributeDecl.Is( (AttributeKey) .Then(LeftParen) .Then(Variable) .Then( Either( Given() .Then(RightParen) .Then(TypeAttrib.Create) ).Or( Given() .Then(LeftParen) .Then(ArgumentExpressionList.Optional(ImmutableList.Empty)) .Then(RightParen) .Then(RightParen) .Then(TypeAttrib.Create) ) ) ); InterfaceTypeSpecifier.Is( (InterfaceTypeKey) .Then(LeftParen) .Then(PrimaryExpression) .Then( Given() .Then(RightParen) .Then(InterfaceTypeSpec.Create) ) ); } } }