/// <summary> /// The following are rules for C expressions. /// </summary> 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( (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 <Expr>() .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 ) ); // 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 <Expr>() .Then(LeftBracket) .Then(Expression) .Then(RightBracket) .Then((array, index) => Dereference.Create(AST.Add.Create(array, index))) ).Or( Given <Expr>() .Then(LeftParen) .Then(ArgumentExpressionList.Optional(ImmutableList <Expr> .Empty)) .Then(RightParen) .Then(FuncCall.Create) ).Or( Given <Expr>() .Then(Period) .Then(Identifier) .Then(Attribute.Create) ).Or( Given <Expr>() .Then(RightArrow) .Then(Identifier) .Then((expr, member) => Attribute.Create(Dereference.Create(expr), member)) ).Or( Given <Expr>() .Then(Increment) .Then(PostIncrement.Create) ).Or( Given <Expr>() .Then(Decrement) .Then(PostDecrement.Create) ).ZeroOrMore() ) ); // argument-expression-list // : assignment-expression [ ',' assignment-expression ]* ArgumentExpressionList.Is( AssignmentExpression.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) ) ); }