aboutsummaryrefslogtreecommitdiffstats
path: root/test/racc/assets/cast.y
diff options
context:
space:
mode:
Diffstat (limited to 'test/racc/assets/cast.y')
-rw-r--r--test/racc/assets/cast.y926
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: