using System.Collections.Immutable; using AST; using static Parsing.ParserCombinator; namespace Parsing { public partial class CParsers { public static NamedParser Expression { get; } = Parser.Create("expression"); public static NamedParser PrimaryExpression { get; } = Parser.Create("primary-expression"); public static NamedParser Variable { get; } = Parser.Create("variable"); public static NamedParser Constant { get; } = Parser.Create("constant"); public static NamedParser ConstantExpression { get; } = Parser.Create("constant-expression"); public static NamedParser ConditionalExpression { get; } = Parser.Create("conditional-expression"); public static NamedParser AssignmentExpression { get; } = Parser.Create("assignment-expression"); public static NamedParser ArgumentExpression { get; } = Parser.Create("argument-expression"); public static NamedParser PostfixExpression { get; } = Parser.Create("postfix-expression"); public static NamedParser> ArgumentExpressionList { get; } = Parser.Create>("argument-expression-list"); public static NamedParser UnaryExpression { get; } = Parser.Create("unary-expression"); public static NamedParser CastExpression { get; } = Parser.Create("cast-expression"); public static NamedParser MultiplicativeExpression { get; } = Parser.Create("multiplicative-expression"); public static NamedParser AdditiveExpression { get; } = Parser.Create("additive-expression"); public static NamedParser ShiftExpression { get; } = Parser.Create("shift-expression"); public static NamedParser RelationalExpression { get; } = Parser.Create("relational-expression"); public static NamedParser EqualityExpression { get; } = Parser.Create("equality-expression"); public static NamedParser AndExpression { get; } = Parser.Create("and-expression"); public static NamedParser ExclusiveOrExpression { get; } = Parser.Create("exclusive-or-expression"); public static NamedParser InclusiveOrExpression { get; } = Parser.Create("inclusive-or-expression"); public static NamedParser LogicalAndExpression { get; } = Parser.Create("logical-and-expression"); public static NamedParser LogicalOrExpression { get; } = Parser.Create("logical-or-expression"); /// /// The following are rules for C expressions. /// public static void SetExpressionRules() { // expression // : assignment-expression [ ',' assignment-expression ]* Expression.Is( AssignmentExpression .OneOrMore(Comma) .Then(exprs => { if (exprs.Count == 1) { return exprs[0]; } return AssignmentList.Create(exprs); }) ); // primary-expression // : identifier # Cannot be a typedef name. // | constant // | string-literal // | '(' expression ')' PrimaryExpression.Is( Either(Variable) .Or(Constant) .Or(StringLiteral) .Or(UnicodeStringLiteral) .Or( (LeftParen).Then(Expression).Then(RightParen) ) ); // An identifier for a variable must not be defined as a typedef name. Variable.Is( Identifier.Check(result => !result.Environment.IsTypedefName(result.Result)).Then(AST.Variable.Create) ); // constant // : const-char // : const-int // : const-float Constant.Is( Either(ConstChar) .Or(ConstInt) .Or(ConstFloat) ); // constant-expression // : conditional-expression // // Note: // The size of an array should be a constant. // Note that the check is actually performed in semantic analysis. ConstantExpression.Is( ConditionalExpression ); // conditional-expression // : logical-or-expression [ '?' expression ':' conditional-expression ]? ConditionalExpression.Is( (LogicalOrExpression) .Then( Given() .Then(Question) .Then(Expression) .Then(Colon) .Then(ConditionalExpression) .Then(AST.ConditionalExpression.Create) .Optional() ) ); // assignment-expression // : unary-expression assignment-operator assignment-expression # first-set = first-set(unary-expression) // | conditional-expression # first-set = first-set(cast-expression) = first-set(unary-expression) ++ { '(' } // // Note: // Assignment operators are: // '=', '*=', '/=', '%=', '+=', '-=', '<<=', '>>=', '&=', '^=', '|=' AssignmentExpression.Is( Either( AssignmentOperator( UnaryExpression, AssignmentExpression, BinaryOperatorBuilder.Create(Assign, Assignment.Create), BinaryOperatorBuilder.Create(MultAssign, AST.MultAssign.Create), BinaryOperatorBuilder.Create(DivAssign, AST.DivAssign.Create), BinaryOperatorBuilder.Create(ModAssign, AST.ModAssign.Create), BinaryOperatorBuilder.Create(AddAssign, AST.AddAssign.Create), BinaryOperatorBuilder.Create(SubAssign, AST.SubAssign.Create), BinaryOperatorBuilder.Create(LeftShiftAssign, LShiftAssign.Create), BinaryOperatorBuilder.Create(RightShiftAssign, RShiftAssign.Create), BinaryOperatorBuilder.Create(BitwiseAndAssign, AST.BitwiseAndAssign.Create), BinaryOperatorBuilder.Create(XorAssign, AST.XorAssign.Create), BinaryOperatorBuilder.Create(BitwiseOrAssign, AST.BitwiseOrAssign.Create) ) ).Or( ConditionalExpression ) ); ArgumentExpression.Is( Either( AssignmentExpression ).Or( (LeftCurlyBrace) .Then(InitializerList) .Then(RightCurlyBrace) .Then((x) => ExprInitList.Create(x as InitList)) ).Or( (LeftCurlyBrace) .Then(InitializerList) .Then(Comma) .Then(RightCurlyBrace) .Then((x) => ExprInitList.Create(x as InitList)) ) ); // postfix-expression // : primary-expression [ // '[' expression ']' # Get element from array // | '(' [argument-expression-list]? ')' # Function call // | '.' identifier # Get member from struct/union // | '->' identifier # Get member from struct/union // | '++' # Increment // | '--' # Decrement // ]* PostfixExpression.Is( PrimaryExpression .Then( Either( Given() .Then(LeftBracket) .Then(Expression) .Then(RightBracket) .Then((array, index) => Dereference.Create(AST.Add.Create(array, index))) ).Or( Given() .Then(LeftParen) .Then(ArgumentExpressionList.Optional(ImmutableList.Empty)) .Then(RightParen) .Then(FuncCall.Create) ).Or( Given() .Then(Period) .Then(Identifier) .Then(Attribute.Create) ).Or( Given() .Then(RightArrow) .Then(Identifier) .Then((expr, member) => Attribute.Create(Dereference.Create(expr), member)) ).Or( Given() .Then(Increment) .Then(PostIncrement.Create) ).Or( Given() .Then(Decrement) .Then(PostDecrement.Create) ).ZeroOrMore() ) ); // argument-expression-list // : assignment-expression [ ',' assignment-expression ]* ArgumentExpressionList.Is( ArgumentExpression.OneOrMore(Comma) ); // unary-expression // : postfix-expression # first-set = { id, const, string } // | '++' unary-expression # first-set = { '++' } // | '--' unary-expression # first-set = { '--' } // | unary-operator cast-expression # first-set = { '&', '*', '+', '-', '~', '!' } // | 'sizeof' unary-expression # first-set = { 'sizeof' } // | 'sizeof' '(' Type-name ')' # first-set = { 'sizeof' } // // Notes: // 1. unary-operator can be '&', '*', '+', '-', '~', '!'. // 2. The last two rules are ambiguous: you can't figure out whether the x in sizeof(x) is a typedef of a variable. // I have a parser hack for this: add a parser environment to track all the typedefs. // 3. first_set = first_set(postfix-expression) + { '++', '--', '&', '*', '+', '-', '~', '!', 'sizeof' } // = first_set(primary-expression) + { '++', '--', '&', '*', '+', '-', '~', '!', 'sizeof' } // = { id, const, string, '++', '--', '&', '*', '+', '-', '~', '!', 'sizeof' } UnaryExpression.Is( Either( PostfixExpression ).Or( (Increment).Then(UnaryExpression).Then(PreIncrement.Create) ).Or( (Decrement).Then(UnaryExpression).Then(PreDecrement.Create) ).Or( (BitwiseAnd).Then(CastExpression).Then(Reference.Create) ).Or( (Mult).Then(CastExpression).Then(Dereference.Create) ).Or( (Add).Then(CastExpression).Then(Positive.Create) ).Or( (Sub).Then(CastExpression).Then(Negative.Create) ).Or( (BitwiseNot).Then(CastExpression).Then(AST.BitwiseNot.Create) ).Or( (LogicalNot).Then(CastExpression).Then(AST.LogicalNot.Create) ).Or( (SizeOf).Then(UnaryExpression).Then(SizeofExpr.Create) ).Or( (SizeOf).Then(LeftParen).Then(TypeName).Then(RightParen).Then(SizeofType.Create) ) ); // cast-expression // : unary-expression # first-set = { id, const, string, '++', '--', '&', '*', '+', '-', '~', '!', 'sizeof' } // | '(' type_name ')' cast-expression # first-set = '(' CastExpression.Is( Either( UnaryExpression ).Or( (LeftParen).Then(TypeName).Then(RightParen).Then(CastExpression) .Then(TypeCast.Create) ) ); // multiplicative-expression // : cast-expression [ [ '*' | '/' | '%' ] cast-expression ]* MultiplicativeExpression.Is( BinaryOperator( CastExpression, BinaryOperatorBuilder.Create(Mult, Multiply.Create), BinaryOperatorBuilder.Create(Div, Divide.Create), BinaryOperatorBuilder.Create(Mod, Modulo.Create) ) ); // additive-expression // : multiplicative-expression [ [ '+' | '-' ] multiplicative-expression ]* AdditiveExpression.Is( BinaryOperator( MultiplicativeExpression, BinaryOperatorBuilder.Create(Add, AST.Add.Create), BinaryOperatorBuilder.Create(Sub, AST.Sub.Create) ) ); // shift-expression // : additive-expression [ [ '<<' | '>>' ] additive-expression ]* ShiftExpression.Is( BinaryOperator( AdditiveExpression, BinaryOperatorBuilder.Create(LeftShift, LShift.Create), BinaryOperatorBuilder.Create(RightShift, RShift.Create) ) ); // relational-expression // : shift-expression [ [ '<' | '>' | '<=' | '>=' ] shift-expression ]* RelationalExpression.Is( BinaryOperator( ShiftExpression, BinaryOperatorBuilder.Create(Less, AST.Less.Create), BinaryOperatorBuilder.Create(Greater, AST.Greater.Create), BinaryOperatorBuilder.Create(LessEqual, LEqual.Create), BinaryOperatorBuilder.Create(GreaterEqual, GEqual.Create) ) ); // equality-expression // : relational-expression [ [ '==' | '!=' ] relational-expression ]* EqualityExpression.Is( BinaryOperator( RelationalExpression, BinaryOperatorBuilder.Create(Equal, AST.Equal.Create), BinaryOperatorBuilder.Create(NotEqual, AST.NotEqual.Create) ) ); // and-expression // : equality-expression [ '&' equality-expression ]* AndExpression.Is( BinaryOperator( EqualityExpression, BinaryOperatorBuilder.Create(BitwiseAnd, AST.BitwiseAnd.Create) ) ); // exclusive-or-expression // : and-expression [ '^' and-expression ]* ExclusiveOrExpression.Is( BinaryOperator( AndExpression, BinaryOperatorBuilder.Create(Xor, AST.Xor.Create) ) ); // inclusive-or-expression // : exclusive-or-expression [ '|' exclusive-or-expression ]* InclusiveOrExpression.Is( BinaryOperator( ExclusiveOrExpression, BinaryOperatorBuilder.Create(BitwiseOr, AST.BitwiseOr.Create) ) ); // logical-and-expression // : inclusive-or-expression [ '&&' inclusive-or-expression ]* LogicalAndExpression.Is( BinaryOperator( InclusiveOrExpression, BinaryOperatorBuilder.Create(LogicalAnd, AST.LogicalAnd.Create) ) ); // logical-or-expression // :logical-and-expression [ '||' logical-and-expression ]* LogicalOrExpression.Is( BinaryOperator( LogicalAndExpression, BinaryOperatorBuilder.Create(LogicalOr, AST.LogicalOr.Create) ) ); } } }