IFPSTools.NET/LibIFPSCC/Parser/Declaration.cs
zc e16c00799d ifpscc: initial commit
libifpscc: initial commit
readme: document ifpscc/libifpscc
license: add credits for ifpscc/libifpscc (derived from code also MIT licensed)
libifps: make additional fields/types public for libifpscc
libifps: fix field documentation for some opcodes
libifps: fix loading functions that are not exported
libifps: allow saving a nonexistant primitive type if the same primitive type was added already
libifps: fix parsing Extended constants
libifps: fix ushort/short being mapped to the wrong types in one table
csproj: set Prefer32Bit=false for release builds
2023-03-28 17:24:19 +01:00

839 lines
30 KiB
C#

using System;
using System.Collections.Immutable;
using System.Linq;
using AST;
using static Parsing.ParserCombinator;
namespace Parsing {
public partial class CParsers {
/// <summary>
/// declaration
/// : declaration-specifiers [Init-declarator-list]? ';'
/// </summary>
public static NamedParser<Decln>
Declaration { get; } = new NamedParser<Decln>("declaration");
/// <summary>
/// declaration-specifiers
/// : [ storage-class-specifier | Type-specifier | Type-qualifier ]+
/// </summary>
/// <remarks>
/// 1. You can only have **one** storage class specifier.
/// 2. You can have duplicate Type qualifiers, since it doesn't cause ambiguity.
/// </remarks>
public static NamedParser<DeclnSpecs>
DeclarationSpecifiers { get; } = new NamedParser<DeclnSpecs>("declaration-specifiers");
/// <summary>
/// Init-declarator-list
/// : Init-declarator [ ',' Init-declarator ]*
/// </summary>
/// <remarks>
/// a non-empty list of init_declarators separated by ','
/// </remarks>
public static NamedParser<ImmutableList<InitDeclr>>
InitDeclaratorList { get; } = new NamedParser<ImmutableList<InitDeclr>>("Init-declarator-list");
/// <summary>
/// Init-declarator
/// : declarator [ '=' initializer ]?
/// </summary>
public static NamedParser<InitDeclr>
InitDeclarator { get; } = new NamedParser<InitDeclr>("Init-declarator");
/// <summary>
/// storage-class-specifier
/// : auto | register | static | extern | typedef
/// </summary>
/// <remarks>
/// There can only be *one* storage class specifier in one declaration.
/// </remarks>
public static NamedParser<StorageClsSpec>
StorageClassSpecifier { get; } = new NamedParser<StorageClsSpec>("storage-class-specifier");
/// <summary>
/// Type-specifier
/// : void
/// | char
/// | short
/// | int
/// | long
/// | float
/// | double
/// | signed
/// | unsigned
/// | struct-or-union-specifier
/// | enum-specifier
/// | typedef-name
/// </summary>
/// <remarks>
/// 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!
/// </remarks>
public static NamedParser<TypeSpec>
TypeSpecifier { get; } = new NamedParser<TypeSpec>("Type-specifier");
/// <summary>
/// Type-qualifier
/// : const
/// | volatile
/// </summary>
/// <remarks>
/// Note that there can be multiple Type qualifiers in one declarations.
/// </remarks>
public static NamedParser<TypeQual>
TypeQualifier { get; } = new NamedParser<TypeQual>("Type-qualifier");
/// <summary>
/// declarator
/// : [pointer]? direct-declarator
/// </summary>
/// <remarks>
/// A declarator gives a name to the object and also modifies the Type.
/// </remarks>
public static NamedParser<Declr>
Declarator { get; } = new NamedParser<Declr>("declarator");
/// <summary>
/// pointer
/// : [ '*' [Type-qualifier-list]? ]+
/// </summary>
public static NamedParser<ImmutableList<PointerModifier>>
Pointer { get; } = new NamedParser<ImmutableList<PointerModifier>>("pointer");
/// <summary>
/// parameter-Type-list
/// : parameter-list [ ',' '...' ]?
/// </summary>
/// <remarks>
/// A parameter list and an optional vararg signature.
/// Used in function declarations.
/// </remarks>
public static NamedParser<ParamTypeList>
ParameterTypeList { get; } = new NamedParser<ParamTypeList>("parameter-Type-list");
/// <summary>
/// parameter-list
/// : parameter-declaration [ ',' parameter-declaration ]*
/// </summary>
/// <remarks>
/// A non-empty list of parameters separated by ','.
/// Used in a function signature.
/// </remarks>
public static NamedParser<ImmutableList<ParamDecln>>
ParameterList { get; } = new NamedParser<ImmutableList<ParamDecln>>("parameter-list");
/// <summary>
/// Type-qualifier-list
/// : [Type-qualifier]+
/// </summary>
/// <remarks>
/// A non-empty list of Type qualifiers.
/// </remarks>
public static NamedParser<ImmutableList<TypeQual>>
TypeQualifierList { get; } = new NamedParser<ImmutableList<TypeQual>>("Type-qualifier-list");
/// <summary>
/// direct-declarator
/// : [
/// identifier | '(' declarator ')'
/// ] [
/// '[' [constant-expression]? ']'
/// | '(' [parameter-Type-list]? ')'
/// ]*
/// </summary>
/// <remarks>
/// 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) { |
/// | .... |
/// | } |
/// +------------------------------------------+
/// </remarks>
public static NamedParser<Declr>
DirectDeclarator { get; } = new NamedParser<Declr>("direct-declarator");
/// <summary>
/// enum-specifier
/// : enum [identifier]? '{' enumerator-list '}'
/// | enum identifier
/// </summary>
public static NamedParser<EnumSpec>
EnumSpecifier { get; } = new NamedParser<EnumSpec>("enum-specifier");
/// <summary>
/// enumerator-list
/// : enumerator [ ',' enumerator ]*
/// </summary>
public static NamedParser<ImmutableList<Enumr>>
EnumeratorList { get; } = new NamedParser<ImmutableList<Enumr>>("enumerator-list");
/// <summary>
/// enumerator
/// : enumeration-constant [ '=' constant-expression ]?
/// </summary>
public static NamedParser<Enumr>
Enumerator { get; } = new NamedParser<Enumr>("enumerator");
/// <summary>
/// enumeration-constant
/// : identifier
/// </summary>
public static NamedParser<String>
EnumerationConstant { get; } = new NamedParser<string>("enumeration-constant");
/// <summary>
/// struct-or-union-specifier
/// : struct-or-union [identifier]? { struct-declaration-list }
/// | struct-or-union identifier
/// </summary>
/// <remarks>
/// Note: if no struct-declaration-list given, the Type is considered incomplete.
/// </remarks>
public static NamedParser<StructOrUnionSpec>
StructOrUnionSpecifier { get; } = new NamedParser<StructOrUnionSpec>("struct-or-union-specifier");
/// <summary>
/// struct-or-union
/// : struct | union
/// </summary>
public static NamedParser<StructOrUnion>
StructOrUnion { get; } = new NamedParser<StructOrUnion>("struct-or-union");
/// <summary>
/// struct-declaration-list
/// : [struct-declaration]+
/// </summary>
public static NamedParser<ImmutableList<StructDecln>>
StructDeclarationList { get; } = new NamedParser<ImmutableList<StructDecln>>("struct-declaration-list");
/// <summary>
/// struct-declaration
/// : specifier-qualifier-list struct-declarator-list ';'
/// </summary>
/// <remarks>
/// Note that a struct declaration does not need a storage class specifier.
/// </remarks>
public static NamedParser<StructDecln>
StructDeclaration { get; } = new NamedParser<StructDecln>("struct-declaration");
/// <summary>
/// specifier-qualifier-list
/// : [ Type-specifier | Type-qualifier ]+
/// </summary>
public static NamedParser<SpecQualList>
SpecifierQualifierList { get; } = new NamedParser<SpecQualList>("specifier-qualifier-list");
/// <summary>
/// struct-declarator-list
/// : struct-declarator [ ',' struct-declarator ]*
/// </summary>
public static NamedParser<ImmutableList<StructDeclr>>
StructDeclaratorList { get; } = new NamedParser<ImmutableList<StructDeclr>>("struct-declarator-list");
/// <summary>
/// struct-declarator
/// : [declarator]? ':' constant-expression
/// | declarator
/// </summary>
/// <remarks>
/// Note that the second one represents a 'bit-field', which I'm not going to support.
/// </remarks>
public static NamedParser<StructDeclr>
StructDeclarator { get; } = new NamedParser<StructDeclr>("struct-declarator");
/// <summary>
/// parameter-declaration
/// : declaration-specifiers [ declarator | abstract-declarator ]?
/// </summary>
/// <remarks>
/// int foo(int arg1, int arg2);
/// ~~~~~~~~
///
/// int foo(int, int);
/// ~~~
///
/// The declarator can be completely omitted.
/// </remarks>
public static NamedParser<ParamDecln>
ParameterDeclaration { get; } = new NamedParser<ParamDecln>("parameter-declaration");
// identifier_list
// : /* old style, i'm deleting this */
/// <summary>
/// abstract-declarator
/// : [pointer]? direct-abstract-declarator
/// | pointer
/// </summary>
/// <remarks>
/// An abstract declarator is a non-empty list of (pointer, function, or array) Type modifiers
/// </remarks>
public static NamedParser<AbstractDeclr>
AbstractDeclarator { get; } = new NamedParser<AbstractDeclr>("abstract-declarator");
/// <summary>
/// direct-abstract-declarator
/// : [
/// '(' abstract-declarator ')'
/// | '[' [constant-expression]? ']' // array modifier
/// | '(' [parameter-type_list]? ')' // function modifier
/// ] [
/// '[' [constant-expression]? ']' // array modifier
/// | '(' [parameter-Type-list]? ')' // function modifier
/// ]*
/// </summary>
public static NamedParser<AbstractDeclr>
DirectAbstractDeclarator { get; } = new NamedParser<AbstractDeclr>("direct-abstract-declarator");
/// <summary>
/// initializer
/// : assignment-expression
/// | '{' initializer-list '}'
/// | '{' initializer-list ',' '}'
/// </summary>
public static NamedParser<Initr>
Initializer { get; } = new NamedParser<Initr>("initializer");
/// <summary>
/// initializer-list
/// : initializer [ ',' initializer ]*
///
/// A non-empty list of initializers.
/// </summary>
public static NamedParser<Initr>
InitializerList { get; } = new NamedParser<Initr>("initializer-list");
/// <summary>
/// Type-name
/// : specifier-qualifier-list [abstract-declarator]?
/// </summary>
public static NamedParser<TypeName>
TypeName { get; } = new NamedParser<TypeName>("Type-name");
/// <summary>
/// typedef-name
/// : identifier
/// </summary>
/// <remarks>
/// It must be something already defined.
/// We need to look it up in the parser environment.
/// </remarks>
public static NamedParser<String>
TypeDefName { get; } = new NamedParser<String>("typedef-name");
/// <summary>
/// attribute-list
/// : parameter-declaration [ ',' parameter-declaration ]*
/// </summary>
/// <remarks>
/// A non-empty list of parameters separated by ','.
/// Used in a function signature.
/// </remarks>
public static NamedParser<TypeAttrib>
AttributeDecl
{ get; } = new NamedParser<TypeAttrib>("attribute-decl");
/// <summary>
/// interface-type-specifier
/// : __interface("guid")
/// </summary>
public static NamedParser<InterfaceTypeSpec>
InterfaceTypeSpecifier
{ get; } = new NamedParser<InterfaceTypeSpec>("interface-type-specifier");
public static void SetDeclarationRules() {
// declaration
// : declaration-specifiers [Init-declarator-list]? ';'
Declaration.Is(
(DeclarationSpecifiers)
.Then(InitDeclaratorList.Optional(ImmutableList<InitDeclr>.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<DeclnSpecs>()
.Then(StorageClassSpecifier)
.Then(DeclnSpecs.Add)
).Or(
Given<DeclnSpecs>()
.Then(TypeSpecifier)
.Then(DeclnSpecs.Add)
).Or(
Given<DeclnSpecs>()
.Then(TypeQualifier)
.Then(DeclnSpecs.Add)
).Or(
Given<DeclnSpecs>()
.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<TypeQual>.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<Declr>()
.Then(LeftBracket)
.Then(
ConstantExpression.Optional().Then(ArrayModifier.Create)
).Then(RightBracket)
.Then(Declr.Add)
).Or(
Given<Declr>()
.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<StructOrUnion>()
.Then(Identifier.Optional())
.Then(LeftCurlyBrace)
.Then(StructDeclarationList)
.Then(RightCurlyBrace)
.Then(StructOrUnionSpec.Create)
).Or(
Given<StructOrUnion>()
.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<SpecQualList>()
.Then(TypeSpecifier)
.Then(SpecQualList.Add)
).Or(
Given<SpecQualList>()
.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<PointerModifier>.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<ArrayModifier, ImmutableList<ArrayModifier>>(ImmutableList.Create)
.Then(AbstractDeclr.Create)
).Or(
(LeftParen)
.Then(ParameterTypeList.Optional())
.Then(RightParen)
.Then(FunctionModifier.Create)
.Then<FunctionModifier, ImmutableList<FunctionModifier>>(ImmutableList.Create)
.Then(AbstractDeclr.Create)
)
).Then(
Either(
Given<AbstractDeclr>()
.Then(
LeftBracket
.Then(ConstantExpression.Optional())
.Then(RightBracket)
.Then(ArrayModifier.Create)
).Then(
AbstractDeclr.Add
)
).Or(
Given<AbstractDeclr>()
.Then(
(LeftParen)
.Then(ParameterTypeList.Optional())
.Then(RightParen)
.Then(FunctionModifier.Create)
).Then(
AbstractDeclr.Add
)
)
.ZeroOrMore()
)
);
// initializer
// : assignment-expression
// | '{' initializer-list '}'
// | '{' initializer-list ',' '}'
Initializer.Is(
Either<Initr>(
(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<Expr>()
.Then(RightParen)
.Then(TypeAttrib.Create)
).Or(
Given<Expr>()
.Then(LeftParen)
.Then(ArgumentExpressionList.Optional(ImmutableList<Expr>.Empty))
.Then(RightParen)
.Then(RightParen)
.Then(TypeAttrib.Create)
)
)
);
InterfaceTypeSpecifier.Is(
(InterfaceTypeKey)
.Then(LeftParen)
.Then(PrimaryExpression)
.Then(
Given<Expr>()
.Then(RightParen)
.Then(InterfaceTypeSpec.Create)
)
);
}
}
}