diff options
Diffstat (limited to 'test/racc/assets/cast.y')
-rw-r--r-- | test/racc/assets/cast.y | 926 |
1 files changed, 926 insertions, 0 deletions
diff --git a/test/racc/assets/cast.y b/test/racc/assets/cast.y new file mode 100644 index 0000000000..d180c09e14 --- /dev/null +++ b/test/racc/assets/cast.y @@ -0,0 +1,926 @@ +# The MIT License +# +# Copyright (c) George Ogata +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +class C::Parser +# shift/reduce conflict on "if (c) if (c) ; else ; else ;" +expect 1 +rule + +# A.2.4 External definitions + +# Returns TranslationUnit +translation_unit + : external_declaration {result = TranslationUnit.new_at(val[0].pos, NodeChain[val[0]])} + | translation_unit external_declaration {result = val[0]; result.entities << val[1]} + +# Returns Declaration|FunctionDef +external_declaration + : function_definition {result = val[0]} + | declaration {result = val[0]} + +# Returns FunctionDef +function_definition + : declaration_specifiers declarator declaration_list compound_statement {result = make_function_def(val[0][0], val[0][1], val[1], val[2], val[3])} + | declaration_specifiers declarator compound_statement {result = make_function_def(val[0][0], val[0][1], val[1], nil , val[2])} + +# Returns [Declaration] +declaration_list + : declaration {result = [val[0]]} + | declaration_list declaration {result = val[0] << val[1]} + +# A.2.3 Statements + +# Returns Statement +statement + : labeled_statement {result = val[0]} + | compound_statement {result = val[0]} + | expression_statement {result = val[0]} + | selection_statement {result = val[0]} + | iteration_statement {result = val[0]} + | jump_statement {result = val[0]} + +# Returns Statement +labeled_statement + : identifier COLON statement {val[2].labels.unshift(PlainLabel.new_at(val[0].pos, val[0].val)); result = val[2]} + | CASE constant_expression COLON statement {val[3].labels.unshift(Case .new_at(val[0].pos, val[1] )); result = val[3]} + | DEFAULT COLON statement {val[2].labels.unshift(Default .new_at(val[0].pos )); result = val[2]} + # type names can also be used as labels + | typedef_name COLON statement {val[2].labels.unshift(PlainLabel.new_at(val[0].pos, val[0].name)); result = val[2]} + +# Returns Block +compound_statement + : LBRACE block_item_list RBRACE {result = Block.new_at(val[0].pos, val[1])} + | LBRACE RBRACE {result = Block.new_at(val[0].pos )} + +# Returns NodeChain[Declaration|Statement] +block_item_list + : block_item {result = NodeChain[val[0]]} + | block_item_list block_item {result = val[0] << val[1]} + +# Returns Declaration|Statement +block_item + : declaration {result = val[0]} + | statement {result = val[0]} + +# Returns ExpressionStatement +expression_statement + : expression SEMICOLON {result = ExpressionStatement.new_at(val[0].pos, val[0])} + | SEMICOLON {result = ExpressionStatement.new_at(val[0].pos )} + +# Returns Statement +selection_statement + : IF LPAREN expression RPAREN statement {result = If .new_at(val[0].pos, val[2], val[4] )} + | IF LPAREN expression RPAREN statement ELSE statement {result = If .new_at(val[0].pos, val[2], val[4], val[6])} + | SWITCH LPAREN expression RPAREN statement {result = Switch.new_at(val[0].pos, val[2], val[4] )} + +# Returns Statement +iteration_statement + : WHILE LPAREN expression RPAREN statement {result = While.new_at(val[0].pos, val[2], val[4] )} + | DO statement WHILE LPAREN expression RPAREN SEMICOLON {result = While.new_at(val[0].pos, val[4], val[1], :do => true )} + | FOR LPAREN expression SEMICOLON expression SEMICOLON expression RPAREN statement {result = For.new_at(val[0].pos, val[2], val[4], val[6], val[8])} + | FOR LPAREN expression SEMICOLON expression SEMICOLON RPAREN statement {result = For.new_at(val[0].pos, val[2], val[4], nil , val[7])} + | FOR LPAREN expression SEMICOLON SEMICOLON expression RPAREN statement {result = For.new_at(val[0].pos, val[2], nil , val[5], val[7])} + | FOR LPAREN expression SEMICOLON SEMICOLON RPAREN statement {result = For.new_at(val[0].pos, val[2], nil , nil , val[6])} + | FOR LPAREN SEMICOLON expression SEMICOLON expression RPAREN statement {result = For.new_at(val[0].pos, nil , val[3], val[5], val[7])} + | FOR LPAREN SEMICOLON expression SEMICOLON RPAREN statement {result = For.new_at(val[0].pos, nil , val[3], nil , val[6])} + | FOR LPAREN SEMICOLON SEMICOLON expression RPAREN statement {result = For.new_at(val[0].pos, nil , nil , val[4], val[6])} + | FOR LPAREN SEMICOLON SEMICOLON RPAREN statement {result = For.new_at(val[0].pos, nil , nil , nil , val[5])} + | FOR LPAREN declaration expression SEMICOLON expression RPAREN statement {result = For.new_at(val[0].pos, val[2], val[3], val[5], val[7])} + | FOR LPAREN declaration expression SEMICOLON RPAREN statement {result = For.new_at(val[0].pos, val[2], val[3], nil , val[6])} + | FOR LPAREN declaration SEMICOLON expression RPAREN statement {result = For.new_at(val[0].pos, val[2], nil , val[4], val[6])} + | FOR LPAREN declaration SEMICOLON RPAREN statement {result = For.new_at(val[0].pos, val[2], nil , nil , val[5])} + +# Returns Statement +jump_statement + : GOTO identifier SEMICOLON {result = Goto .new_at(val[0].pos, val[1].val)} + | CONTINUE SEMICOLON {result = Continue.new_at(val[0].pos )} + | BREAK SEMICOLON {result = Break .new_at(val[0].pos )} + | RETURN expression SEMICOLON {result = Return .new_at(val[0].pos, val[1] )} + | RETURN SEMICOLON {result = Return .new_at(val[0].pos )} + # type names can also be used as labels + | GOTO typedef_name SEMICOLON {result = Goto .new_at(val[0].pos, val[1].name)} + +# A.2.2 Declarations + +# Returns Declaration +declaration + : declaration_specifiers init_declarator_list SEMICOLON {result = make_declaration(val[0][0], val[0][1], val[1])} + | declaration_specifiers SEMICOLON {result = make_declaration(val[0][0], val[0][1], NodeArray[])} + +# Returns {Pos, [Symbol]} +declaration_specifiers + : storage_class_specifier declaration_specifiers {val[1][1] << val[0][1]; result = val[1]} + | storage_class_specifier {result = [val[0][0], [val[0][1]]]} + | type_specifier declaration_specifiers {val[1][1] << val[0][1]; result = val[1]} + | type_specifier {result = [val[0][0], [val[0][1]]]} + | type_qualifier declaration_specifiers {val[1][1] << val[0][1]; result = val[1]} + | type_qualifier {result = [val[0][0], [val[0][1]]]} + | function_specifier declaration_specifiers {val[1][1] << val[0][1]; result = val[1]} + | function_specifier {result = [val[0][0], [val[0][1]]]} + +# Returns NodeArray[Declarator] +init_declarator_list + : init_declarator {result = NodeArray[val[0]]} + | init_declarator_list COMMA init_declarator {result = val[0] << val[2]} + +# Returns Declarator +init_declarator + : declarator {result = val[0]} + | declarator EQ initializer {val[0].init = val[2]; result = val[0]} + +# Returns [Pos, Symbol] +storage_class_specifier + : TYPEDEF {result = [val[0].pos, :typedef ]} + | EXTERN {result = [val[0].pos, :extern ]} + | STATIC {result = [val[0].pos, :static ]} + | AUTO {result = [val[0].pos, :auto ]} + | REGISTER {result = [val[0].pos, :register]} + +# Returns [Pos, Type|Symbol] +type_specifier + : VOID {result = [val[0].pos, :void ]} + | CHAR {result = [val[0].pos, :char ]} + | SHORT {result = [val[0].pos, :short ]} + | INT {result = [val[0].pos, :int ]} + | LONG {result = [val[0].pos, :long ]} + | FLOAT {result = [val[0].pos, :float ]} + | DOUBLE {result = [val[0].pos, :double ]} + | SIGNED {result = [val[0].pos, :signed ]} + | UNSIGNED {result = [val[0].pos, :unsigned ]} + | BOOL {result = [val[0].pos, :_Bool ]} + | COMPLEX {result = [val[0].pos, :_Complex ]} + | IMAGINARY {result = [val[0].pos, :_Imaginary]} + | struct_or_union_specifier {result = [val[0].pos, val[0] ]} + | enum_specifier {result = [val[0].pos, val[0] ]} + | typedef_name {result = [val[0].pos, val[0] ]} + +# Returns Struct|Union +struct_or_union_specifier + : struct_or_union identifier LBRACE struct_declaration_list RBRACE {result = val[0][1].new_at(val[0][0], val[1].val, val[3])} + | struct_or_union LBRACE struct_declaration_list RBRACE {result = val[0][1].new_at(val[0][0], nil , val[2])} + | struct_or_union identifier {result = val[0][1].new_at(val[0][0], val[1].val, nil )} + # type names can also be used as struct identifiers + | struct_or_union typedef_name LBRACE struct_declaration_list RBRACE {result = val[0][1].new_at(val[0][0], val[1].name, val[3])} + | struct_or_union typedef_name {result = val[0][1].new_at(val[0][0], val[1].name, nil )} + +# Returns [Pos, Class] +struct_or_union + : STRUCT {result = [val[0].pos, Struct]} + | UNION {result = [val[0].pos, Union ]} + +# Returns NodeArray[Declaration] +struct_declaration_list + : struct_declaration {result = NodeArray[val[0]]} + | struct_declaration_list struct_declaration {val[0] << val[1]; result = val[0]} + +# Returns Declaration +struct_declaration + : specifier_qualifier_list struct_declarator_list SEMICOLON {result = make_declaration(val[0][0], val[0][1], val[1])} + +# Returns {Pos, [Symbol]} +specifier_qualifier_list + : type_specifier specifier_qualifier_list {val[1][1] << val[0][1]; result = val[1]} + | type_specifier {result = [val[0][0], [val[0][1]]]} + | type_qualifier specifier_qualifier_list {val[1][1] << val[0][1]; result = val[1]} + | type_qualifier {result = [val[0][0], [val[0][1]]]} + +# Returns NodeArray[Declarator] +struct_declarator_list + : struct_declarator {result = NodeArray[val[0]]} + | struct_declarator_list COMMA struct_declarator {result = val[0] << val[2]} + +# Returns Declarator +struct_declarator + : declarator {result = val[0]} + | declarator COLON constant_expression {result = val[0]; val[0].num_bits = val[2]} + | COLON constant_expression {result = Declarator.new_at(val[0].pos, :num_bits => val[1])} + +# Returns Enum +enum_specifier + : ENUM identifier LBRACE enumerator_list RBRACE {result = Enum.new_at(val[0].pos, val[1].val, val[3])} + | ENUM LBRACE enumerator_list RBRACE {result = Enum.new_at(val[0].pos, nil , val[2])} + | ENUM identifier LBRACE enumerator_list COMMA RBRACE {result = Enum.new_at(val[0].pos, val[1].val, val[3])} + | ENUM LBRACE enumerator_list COMMA RBRACE {result = Enum.new_at(val[0].pos, nil , val[2])} + | ENUM identifier {result = Enum.new_at(val[0].pos, val[1].val, nil )} + # type names can also be used as enum names + | ENUM typedef_name LBRACE enumerator_list RBRACE {result = Enum.new_at(val[0].pos, val[1].name, val[3])} + | ENUM typedef_name LBRACE enumerator_list COMMA RBRACE {result = Enum.new_at(val[0].pos, val[1].name, val[3])} + | ENUM typedef_name {result = Enum.new_at(val[0].pos, val[1].name, nil )} + +# Returns NodeArray[Enumerator] +enumerator_list + : enumerator {result = NodeArray[val[0]]} + | enumerator_list COMMA enumerator {result = val[0] << val[2]} + +# Returns Enumerator +enumerator + : enumeration_constant {result = Enumerator.new_at(val[0].pos, val[0].val, nil )} + | enumeration_constant EQ constant_expression {result = Enumerator.new_at(val[0].pos, val[0].val, val[2])} + +# Returns [Pos, Symbol] +type_qualifier + : CONST {result = [val[0].pos, :const ]} + | RESTRICT {result = [val[0].pos, :restrict]} + | VOLATILE {result = [val[0].pos, :volatile]} + +# Returns [Pos, Symbol] +function_specifier + : INLINE {result = [val[0].pos, :inline]} + +# Returns Declarator +declarator + : pointer direct_declarator {result = add_decl_type(val[1], val[0])} + | direct_declarator {result = val[0]} + +# Returns Declarator +direct_declarator + : identifier {result = Declarator.new_at(val[0].pos, nil, val[0].val)} + | LPAREN declarator RPAREN {result = val[1]} + | direct_declarator LBRACKET type_qualifier_list assignment_expression RBRACKET {result = add_decl_type(val[0], Array.new_at(val[0].pos ))} # TODO + | direct_declarator LBRACKET type_qualifier_list RBRACKET {result = add_decl_type(val[0], Array.new_at(val[0].pos ))} # TODO + | direct_declarator LBRACKET assignment_expression RBRACKET {result = add_decl_type(val[0], Array.new_at(val[0].pos, nil, val[2]))} + | direct_declarator LBRACKET RBRACKET {result = add_decl_type(val[0], Array.new_at(val[0].pos ))} + | direct_declarator LBRACKET STATIC type_qualifier_list assignment_expression RBRACKET {result = add_decl_type(val[0], Array.new_at(val[0].pos ))} # TODO + | direct_declarator LBRACKET STATIC assignment_expression RBRACKET {result = add_decl_type(val[0], Array.new_at(val[0].pos ))} # TODO + | direct_declarator LBRACKET type_qualifier_list STATIC assignment_expression RBRACKET {result = add_decl_type(val[0], Array.new_at(val[0].pos ))} # TODO + | direct_declarator LBRACKET type_qualifier_list MUL RBRACKET {result = add_decl_type(val[0], Array.new_at(val[0].pos ))} # TODO + | direct_declarator LBRACKET MUL RBRACKET {result = add_decl_type(val[0], Array.new_at(val[0].pos ))} # TODO + | direct_declarator LPAREN parameter_type_list RPAREN {result = add_decl_type(val[0], Function.new_at(val[0].pos, nil, param_list(*val[2]), :var_args => val[2][1]))} + | direct_declarator LPAREN identifier_list RPAREN {result = add_decl_type(val[0], Function.new_at(val[0].pos, nil, val[2]))} + | direct_declarator LPAREN RPAREN {result = add_decl_type(val[0], Function.new_at(val[0].pos ))} + +# Returns Pointer +pointer + : MUL type_qualifier_list {result = add_type_quals(Pointer.new_at(val[0].pos), val[1][1]) } + | MUL {result = Pointer.new_at(val[0].pos) } + | MUL type_qualifier_list pointer {p = add_type_quals(Pointer.new_at(val[0].pos), val[1][1]); val[2].direct_type = p; result = val[2]} + | MUL pointer {p = Pointer.new_at(val[0].pos) ; val[1].direct_type = p; result = val[1]} + +# Returns {Pos, [Symbol]} +type_qualifier_list + : type_qualifier {result = [val[0][0], [val[0][1]]]} + | type_qualifier_list type_qualifier {val[0][1] << val[1][1]; result = val[0]} + +# Returns [NodeArray[Parameter], var_args?] +parameter_type_list + : parameter_list {result = [val[0], false]} + | parameter_list COMMA ELLIPSIS {result = [val[0], true ]} + +# Returns NodeArray[Parameter] +parameter_list + : parameter_declaration {result = NodeArray[val[0]]} + | parameter_list COMMA parameter_declaration {result = val[0] << val[2]} + +# Returns Parameter +parameter_declaration + : declaration_specifiers declarator {ind_type = val[1].indirect_type and ind_type.detach + result = make_parameter(val[0][0], val[0][1], ind_type, val[1].name)} + | declaration_specifiers abstract_declarator {result = make_parameter(val[0][0], val[0][1], val[1] , nil )} + | declaration_specifiers {result = make_parameter(val[0][0], val[0][1], nil , nil )} + +# Returns NodeArray[Parameter] +identifier_list + : identifier {result = NodeArray[Parameter.new_at(val[0].pos, nil, val[0].val)]} + | identifier_list COMMA identifier {result = val[0] << Parameter.new_at(val[2].pos, nil, val[2].val)} + +# Returns Type +type_name + : specifier_qualifier_list abstract_declarator {val[1].direct_type = make_direct_type(val[0][0], val[0][1]); result = val[1]} + | specifier_qualifier_list {result = make_direct_type(val[0][0], val[0][1]) } + +# Returns Type +abstract_declarator + : pointer {result = val[0]} + | pointer direct_abstract_declarator {val[1].direct_type = val[0]; result = val[1]} + | direct_abstract_declarator {result = val[0]} + +# Returns Type +direct_abstract_declarator + : LPAREN abstract_declarator RPAREN {result = val[1]} + | direct_abstract_declarator LBRACKET assignment_expression RBRACKET {val[0].direct_type = Array.new_at(val[0].pos, nil, val[2]); result = val[0]} + | direct_abstract_declarator LBRACKET RBRACKET {val[0].direct_type = Array.new_at(val[0].pos, nil, nil ); result = val[0]} + | LBRACKET assignment_expression RBRACKET {result = Array.new_at(val[0].pos, nil, val[1])} + | LBRACKET RBRACKET {result = Array.new_at(val[0].pos )} + | direct_abstract_declarator LBRACKET MUL RBRACKET {val[0].direct_type = Array.new_at(val[0].pos); result = val[0]} # TODO + | LBRACKET MUL RBRACKET {result = Array.new_at(val[0].pos)} # TODO + | direct_abstract_declarator LPAREN parameter_type_list RPAREN {val[0].direct_type = Function.new_at(val[0].pos, nil, param_list(*val[2]), val[2][1]); result = val[0]} + | direct_abstract_declarator LPAREN RPAREN {val[0].direct_type = Function.new_at(val[0].pos ); result = val[0]} + | LPAREN parameter_type_list RPAREN {result = Function.new_at(val[0].pos, nil, param_list(*val[1]), val[1][1])} + | LPAREN RPAREN {result = Function.new_at(val[0].pos )} + +# Returns CustomType +typedef_name + #: identifier -- insufficient since we must distinguish between type + # names and var names (otherwise we have a conflict) + : TYPENAME {result = CustomType.new_at(val[0].pos, val[0].val)} + +# Returns Expression +initializer + : assignment_expression {result = val[0]} + | LBRACE initializer_list RBRACE {result = CompoundLiteral.new_at(val[0].pos, nil, val[1])} + | LBRACE initializer_list COMMA RBRACE {result = CompoundLiteral.new_at(val[0].pos, nil, val[1])} + +# Returns NodeArray[MemberInit] +initializer_list + : designation initializer {result = NodeArray[MemberInit.new_at(val[0][0] , val[0][1], val[1])]} + | initializer {result = NodeArray[MemberInit.new_at(val[0].pos, nil , val[0])]} + | initializer_list COMMA designation initializer {result = val[0] << MemberInit.new_at(val[2][0] , val[2][1], val[3])} + | initializer_list COMMA initializer {result = val[0] << MemberInit.new_at(val[2].pos, nil , val[2])} + +# Returns {Pos, NodeArray[Expression|Token]} +designation + : designator_list EQ {result = val[0]} + +# Returns {Pos, NodeArray[Expression|Token]} +designator_list + : designator {result = val[0]; val[0][1] = NodeArray[val[0][1]]} + | designator_list designator {result = val[0]; val[0][1] << val[1][1]} + +# Returns {Pos, Expression|Member} +designator + : LBRACKET constant_expression RBRACKET {result = [val[1].pos, val[1] ]} + | DOT identifier {result = [val[1].pos, Member.new_at(val[1].pos, val[1].val)]} + +# A.2.1 Expressions + +# Returns Expression +primary_expression + : identifier {result = Variable.new_at(val[0].pos, val[0].val)} + | constant {result = val[0]} + | string_literal {result = val[0]} + # GCC EXTENSION: allow a compound statement in parentheses as an expression + | LPAREN expression RPAREN {result = val[1]} + | LPAREN compound_statement RPAREN {block_expressions_enabled? or parse_error val[0].pos, "compound statement found where expression expected" + result = BlockExpression.new(val[1]); result.pos = val[0].pos} + +# Returns Expression +postfix_expression + : primary_expression {result = val[0]} + | postfix_expression LBRACKET expression RBRACKET {result = Index .new_at(val[0].pos, val[0], val[2])} + | postfix_expression LPAREN argument_expression_list RPAREN {result = Call .new_at(val[0].pos, val[0], val[2] )} + | postfix_expression LPAREN RPAREN {result = Call .new_at(val[0].pos, val[0], NodeArray[])} + | postfix_expression DOT identifier {result = Dot .new_at(val[0].pos, val[0], Member.new(val[2].val))} + | postfix_expression ARROW identifier {result = Arrow .new_at(val[0].pos, val[0], Member.new(val[2].val))} + | postfix_expression INC {result = PostInc .new_at(val[0].pos, val[0] )} + | postfix_expression DEC {result = PostDec .new_at(val[0].pos, val[0] )} + | LPAREN type_name RPAREN LBRACE initializer_list RBRACE {result = CompoundLiteral.new_at(val[0].pos, val[1], val[4])} + | LPAREN type_name RPAREN LBRACE initializer_list COMMA RBRACE {result = CompoundLiteral.new_at(val[0].pos, val[1], val[4])} + +# Returns [Expression|Type] +argument_expression_list + : argument_expression {result = NodeArray[val[0]]} + | argument_expression_list COMMA argument_expression {result = val[0] << val[2]} + +# Returns Expression|Type -- EXTENSION: allow type names here too, to support some standard library macros (e.g., va_arg [7.15.1.1]) +argument_expression + : assignment_expression {result = val[0]} + | type_name {result = val[0]} + +# Returns Expression +unary_expression + : postfix_expression {result = val[0]} + | INC unary_expression {result = PreInc.new_at(val[0].pos, val[1])} + | DEC unary_expression {result = PreDec.new_at(val[0].pos, val[1])} + | unary_operator cast_expression {result = val[0][0].new_at(val[0][1], val[1])} + | SIZEOF unary_expression {result = Sizeof.new_at(val[0].pos, val[1])} + | SIZEOF LPAREN type_name RPAREN {result = Sizeof.new_at(val[0].pos, val[2])} + +# Returns [Class, Pos] +unary_operator + : AND {result = [Address , val[0].pos]} + | MUL {result = [Dereference, val[0].pos]} + | ADD {result = [Positive , val[0].pos]} + | SUB {result = [Negative , val[0].pos]} + | NOT {result = [BitNot , val[0].pos]} + | BANG {result = [Not , val[0].pos]} + +# Returns Expression +cast_expression + : unary_expression {result = val[0]} + | LPAREN type_name RPAREN cast_expression {result = Cast.new_at(val[0].pos, val[1], val[3])} + +# Returns Expression +multiplicative_expression + : cast_expression {result = val[0]} + | multiplicative_expression MUL cast_expression {result = Multiply.new_at(val[0].pos, val[0], val[2])} + | multiplicative_expression DIV cast_expression {result = Divide .new_at(val[0].pos, val[0], val[2])} + | multiplicative_expression MOD cast_expression {result = Mod .new_at(val[0].pos, val[0], val[2])} + +# Returns Expression +additive_expression + : multiplicative_expression {result = val[0]} + | additive_expression ADD multiplicative_expression {result = Add .new_at(val[0].pos, val[0], val[2])} + | additive_expression SUB multiplicative_expression {result = Subtract.new_at(val[0].pos, val[0], val[2])} + +# Returns Expression +shift_expression + : additive_expression {result = val[0]} + | shift_expression LSHIFT additive_expression {result = ShiftLeft .new_at(val[0].pos, val[0], val[2])} + | shift_expression RSHIFT additive_expression {result = ShiftRight.new_at(val[0].pos, val[0], val[2])} + +# Returns Expression +relational_expression + : shift_expression {result = val[0]} + | relational_expression LT shift_expression {result = Less.new_at(val[0].pos, val[0], val[2])} + | relational_expression GT shift_expression {result = More.new_at(val[0].pos, val[0], val[2])} + | relational_expression LEQ shift_expression {result = LessOrEqual.new_at(val[0].pos, val[0], val[2])} + | relational_expression GEQ shift_expression {result = MoreOrEqual.new_at(val[0].pos, val[0], val[2])} + +# Returns Expression +equality_expression + : relational_expression {result = val[0]} + | equality_expression EQEQ relational_expression {result = Equal .new_at(val[0].pos, val[0], val[2])} + | equality_expression NEQ relational_expression {result = NotEqual.new_at(val[0].pos, val[0], val[2])} + +# Returns Expression +and_expression + : equality_expression {result = val[0]} + | and_expression AND equality_expression {result = BitAnd.new_at(val[0].pos, val[0], val[2])} + +# Returns Expression +exclusive_or_expression + : and_expression {result = val[0]} + | exclusive_or_expression XOR and_expression {result = BitXor.new_at(val[0].pos, val[0], val[2])} + +# Returns Expression +inclusive_or_expression + : exclusive_or_expression {result = val[0]} + | inclusive_or_expression OR exclusive_or_expression {result = BitOr.new_at(val[0].pos, val[0], val[2])} + +# Returns Expression +logical_and_expression + : inclusive_or_expression {result = val[0]} + | logical_and_expression ANDAND inclusive_or_expression {result = And.new_at(val[0].pos, val[0], val[2])} + +# Returns Expression +logical_or_expression + : logical_and_expression {result = val[0]} + | logical_or_expression OROR logical_and_expression {result = Or.new_at(val[0].pos, val[0], val[2])} + +# Returns Expression +conditional_expression + : logical_or_expression {result = val[0]} + | logical_or_expression QUESTION expression COLON conditional_expression {result = Conditional.new_at(val[0].pos, val[0], val[2], val[4])} + +# Returns Expression +assignment_expression + : conditional_expression {result = val[0]} + | unary_expression assignment_operator assignment_expression {result = val[1].new_at(val[0].pos, val[0], val[2])} + +# Returns Class +assignment_operator + : EQ {result = Assign} + | MULEQ {result = MultiplyAssign} + | DIVEQ {result = DivideAssign} + | MODEQ {result = ModAssign} + | ADDEQ {result = AddAssign} + | SUBEQ {result = SubtractAssign} + | LSHIFTEQ {result = ShiftLeftAssign} + | RSHIFTEQ {result = ShiftRightAssign} + | ANDEQ {result = BitAndAssign} + | XOREQ {result = BitXorAssign} + | OREQ {result = BitOrAssign} + +# Returns Expression +expression + : assignment_expression {result = val[0]} + | expression COMMA assignment_expression { + if val[0].is_a? Comma + if val[2].is_a? Comma + val[0].exprs.push(*val[2].exprs) + else + val[0].exprs << val[2] + end + result = val[0] + else + if val[2].is_a? Comma + val[2].exprs.unshift(val[0]) + val[2].pos = val[0].pos + result = val[2] + else + result = Comma.new_at(val[0].pos, NodeArray[val[0], val[2]]) + end + end + } + +# Returns Expression +constant_expression + : conditional_expression {result = val[0]} + +# A.1.1 -- Lexical elements +# +# token +# : keyword (raw string) +# | identifier expanded below +# | constant expanded below +# | string_literal expanded below +# | punctuator (raw string) +# +# preprocessing-token (skip) + +# Returns Token +identifier + : ID {result = val[0]} + +# Returns Literal +constant + : ICON {result = val[0].val; result.pos = val[0].pos} + | FCON {result = val[0].val; result.pos = val[0].pos} + #| enumeration_constant -- these are parsed as identifiers at all + # places the `constant' nonterminal appears + | CCON {result = val[0].val; result.pos = val[0].pos} + +# Returns Token +enumeration_constant + : ID {result = val[0]} + +# Returns StringLiteral +# Also handles string literal concatenation (6.4.5.4) +string_literal + : string_literal SCON {val[0].val << val[1].val.val; result = val[0]} + | SCON { result = val[0].val; result.pos = val[0].pos } + +---- inner + # A.1.9 -- Preprocessing numbers -- skip + # A.1.8 -- Header names -- skip + + # A.1.7 -- Puncuators -- we don't bother with {##,#,%:,%:%:} since + # we don't do preprocessing + @@punctuators = %r'\+\+|-[->]|&&|\|\||\.\.\.|(?:<<|>>|[<>=!*/%+\-&^|])=?|[\[\](){}.~?:;,]' + @@digraphs = %r'<[:%]|[:%]>' + + # A.1.6 -- String Literals -- simple for us because we don't decode + # the string (and indeed accept some illegal strings) + @@string_literal = %r'L?"(?:[^\\]|\\.)*?"'m + + # A.1.5 -- Constants + @@decimal_floating_constant = %r'(?:(?:\d*\.\d+|\d+\.)(?:e[-+]?\d+)?|\d+e[-+]?\d+)[fl]?'i + @@hexadecimal_floating_constant = %r'0x(?:(?:[0-9a-f]*\.[0-9a-f]+|[0-9a-f]+\.)|[0-9a-f]+)p[-+]?\d+[fl]?'i + + @@integer_constant = %r'(?:[1-9][0-9]*|0x[0-9a-f]+|0[0-7]*)(?:ul?l?|ll?u?)?'i + @@floating_constant = %r'#{@@decimal_floating_constant}|#{@@hexadecimal_floating_constant}' + @@enumeration_constant = %r'[a-zA-Z_\\][a-zA-Z_\\0-9]*' + @@character_constant = %r"L?'(?:[^\\]|\\.)+?'" + # (note that as with string-literals, we accept some illegal + # character-constants) + + # A.1.4 -- Universal character names -- skip + + # A.1.3 -- Identifiers -- skip, since an identifier is lexically + # identical to an enumeration constant + + # A.1.2 Keywords + keywords = %w'auto break case char const continue default do +double else enum extern float for goto if inline int long register +restrict return short signed sizeof static struct switch typedef union + unsigned void volatile while _Bool _Complex _Imaginary' + @@keywords = %r"#{keywords.join('|')}" + + def initialize + @type_names = ::Set.new + + @warning_proc = lambda{} + @pos = C::Node::Pos.new(nil, 1, 0) + end + def initialize_copy(x) + @pos = x.pos.dup + @type_names = x.type_names.dup + end + attr_accessor :pos, :type_names + + def parse(str) + if str.respond_to? :read + str = str.read + end + @str = str + begin + prepare_lexer(str) + return do_parse + rescue ParseError => e + e.set_backtrace(caller) + raise + end + end + + # + # Error handler, as used by racc. + # + def on_error(error_token_id, error_value, value_stack) + if error_value == '$' + parse_error @pos, "unexpected EOF" + else + parse_error(error_value.pos, + "parse error on #{token_to_str(error_token_id)} (#{error_value.val})") + end + end + + def self.feature(name) + attr_writer "#{name}_enabled" + class_eval <<-EOS + def enable_#{name} + @#{name}_enabled = true + end + def #{name}_enabled? + @#{name}_enabled + end + EOS + end + private_class_method :feature + + # + # Allow blocks in parentheses as expressions, as per the gcc + # extension. [http://rubyurl.com/iB7] + # + feature :block_expressions + + private # --------------------------------------------------------- + + class Token + attr_accessor :pos, :val + def initialize(pos, val) + @pos = pos + @val = val + end + end + def eat(str) + lines = str.split(/\r\n|[\r\n]/, -1) + if lines.length == 1 + @pos.col_num += lines[0].length + else + @pos.line_num += lines.length - 1 + @pos.col_num = lines[-1].length + end + end + + # + # Make a Declaration from the given specs and declarators. + # + def make_declaration(pos, specs, declarators) + specs.all?{|x| x.is_a?(Symbol) || x.is_a?(Type)} or raise specs.map{|x| x.class}.inspect + decl = Declaration.new_at(pos, nil, declarators) + + # set storage class + storage_classes = specs.find_all do |x| + [:typedef, :extern, :static, :auto, :register].include? x + end + # 6.7.1p2: at most, one storage-class specifier may be given in + # the declaration specifiers in a declaration + storage_classes.length <= 1 or + begin + if declarators.length == 0 + for_name = '' + else + for_name = "for `#{declarators[0].name}'" + end + parse_error pos, "multiple or duplicate storage classes given #{for_name}'" + end + decl.storage = storage_classes[0] + + # set type (specifiers, qualifiers) + decl.type = make_direct_type(pos, specs) + + # set function specifiers + decl.inline = specs.include?(:inline) + + # look for new type names + if decl.typedef? + decl.declarators.each do |d| + if d.name + @type_names << d.name + end + end + end + + return decl + end + + def make_function_def(pos, specs, func_declarator, decl_list, defn) + add_decl_type(func_declarator, make_direct_type(pos, specs)) + + # get types from decl_list if necessary + function = func_declarator.indirect_type + function.is_a? Function or + parse_error pos, "non function type for function `#{func_declarator.name}'" + params = function.params + if decl_list + params.all?{|p| p.type.nil?} or + parse_error pos, "both prototype and declaration list given for `#{func_declarator.name}'" + decl_list.each do |declaration| + declaration.declarators.each do |declarator| + param = params.find{|p| p.name == declarator.name} or + parse_error pos, "no parameter named #{declarator.name}" + if declarator.indirect_type + param.type = declarator.indirect_type + param.type.direct_type = declaration.type.dup + else + param.type = declaration.type.dup + end + end + end + params.all?{|p| p.type} or + begin + s = params.find_all{|p| p.type.nil?}.map{|p| "`#{p.name}'"}.join(' and ') + parse_error pos, "types missing for parameters #{s}" + end + end + + fd = FunctionDef.new_at(pos, + function.detach, + func_declarator.name, + defn, + :no_prototype => !decl_list.nil?) + + # set storage class + # 6.9.1p4: only extern or static allowed + specs.each do |s| + [:typedef, :auto, :register].include?(s) and + "`#{s}' illegal for function" + end + storage_classes = specs.find_all do |s| + s == :extern || s == :static + end + # 6.7.1p2: at most, one storage-class specifier may be given in + # the declaration specifiers in a declaration + storage_classes.length <= 1 or + "multiple or duplicate storage classes given for `#{func_declarator.name}'" + fd.storage = storage_classes[0] if storage_classes[0] + + # set function specifiers + # 6.7.4p5 'inline' can be repeated + fd.inline = specs.include?(:inline) + + return fd + end + + # + # Make a direct type from the list of type specifiers and type + # qualifiers. + # + def make_direct_type(pos, specs) + specs_order = [:signed, :unsigned, :short, :long, :double, :void, + :char, :int, :float, :_Bool, :_Complex, :_Imaginary] + + type_specs = specs.find_all do |x| + specs_order.include?(x) || !x.is_a?(Symbol) + end + type_specs.sort! do |a, b| + (specs_order.index(a)||100) <=> (specs_order.index(b)||100) + end + + # set type specifiers + # 6.7.2p2: the specifier list should be one of these + type = + case type_specs + when [:void] + Void.new + when [:char] + Char.new + when [:signed, :char] + Char.new :signed => true + when [:unsigned, :char] + Char.new :signed => false + when [:short], [:signed, :short], [:short, :int], + [:signed, :short, :int] + Int.new :longness => -1 + when [:unsigned, :short], [:unsigned, :short, :int] + Int.new :unsigned => true, :longness => -1 + when [:int], [:signed], [:signed, :int] + Int.new + when [:unsigned], [:unsigned, :int] + Int.new :unsigned => true + when [:long], [:signed, :long], [:long, :int], + [:signed, :long, :int] + Int.new :longness => 1 + when [:unsigned, :long], [:unsigned, :long, :int] + Int.new :longness => 1, :unsigned => true + when [:long, :long], [:signed, :long, :long], + [:long, :long, :int], [:signed, :long, :long, :int] + Int.new :longness => 2 + when [:unsigned, :long, :long], [:unsigned, :long, :long, :int] + Int.new :longness => 2, :unsigned => true + when [:float] + Float.new + when [:double] + Float.new :longness => 1 + when [:long, :double] + Float.new :longness => 2 + when [:_Bool] + Bool.new + when [:float, :_Complex] + Complex.new + when [:double, :_Complex] + Complex.new :longness => 1 + when [:long, :double, :_Complex] + Complex.new :longness => 2 + when [:float, :_Imaginary] + Imaginary.new + when [:double, :_Imaginary] + Imaginary.new :longness => 1 + when [:long, :double, :_Imaginary] + Imaginary.new :longness => 2 + else + if type_specs.length == 1 && + [CustomType, Struct, Union, Enum].any?{|c| type_specs[0].is_a? c} + type_specs[0] + else + if type_specs == [] + parse_error pos, "no type specifiers given" + else + parse_error pos, "invalid type specifier combination: #{type_specs.join(' ')}" + end + end + end + type.pos ||= pos + + # set type qualifiers + # 6.7.3p4: type qualifiers can be repeated + type.const = specs.any?{|x| x.equal? :const } + type.restrict = specs.any?{|x| x.equal? :restrict} + type.volatile = specs.any?{|x| x.equal? :volatile} + + return type + end + + def make_parameter(pos, specs, indirect_type, name) + type = indirect_type + if type + type.direct_type = make_direct_type(pos, specs) + else + type = make_direct_type(pos, specs) + end + [:typedef, :extern, :static, :auto, :inline].each do |sym| + specs.include? sym and + parse_error pos, "parameter `#{declarator.name}' declared `#{sym}'" + end + return Parameter.new_at(pos, type, name, + :register => specs.include?(:register)) + end + + def add_type_quals(type, quals) + type.const = quals.include?(:const ) + type.restrict = quals.include?(:restrict) + type.volatile = quals.include?(:volatile) + return type + end + + # + # Add te given type as the "most direct" type to the given + # declarator. Return the declarator. + # + def add_decl_type(declarator, type) + if declarator.indirect_type + declarator.indirect_type.direct_type = type + else + declarator.indirect_type = type + end + return declarator + end + + def param_list(params, var_args) + if params.length == 1 && + params[0].type.is_a?(Void) && + params[0].name.nil? + return NodeArray[] + elsif params.empty? + return nil + else + return params + end + end + + def parse_error(pos, str) + raise ParseError, "#{pos}: #{str}" + end + +---- header + +require 'set' + +# Error classes +module C + class ParseError < StandardError; end +end + +# Local variables: +# mode: ruby +# end: |