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)
)
);
}
}
}