/* C front-end Copyright (c) 2001 David Monniaux See the BSD.LICENSE for licensing issues. */ /* The grammar mostly follows ISO/IEC 9899:1999 (C99) appendix A. */ %{ open C_syntax open Parsing_helper (* All nonterminals have types of the form 'a * extent *) let arith (op, x, y) = C_binary((C_arithmetic(op)), x, y) let comparison (op, x, y) = C_binary((C_comparison(op)), x, y) let logical (op, x, y) = C_binary((C_logical(op)), x, y) %} %type <(C_syntax.clex_string*Parsing_helper.extent) list> token_list_eof %type expression_eof %type statement_eof %type translation_unit_eof %type <('a->C_syntax.c_external_declaration->'a)->'a->'a> translation_unit2_eof %start token_list_eof expression_eof statement_eof translation_unit_eof translation_unit2_eof /* Elements of the form CLEX_xxx are terminals. Terminals are then recoded to nonterminals so that they fit also in the 'a * extent type format. */ %token CLEX_integer_constant %token CLEX_floating_constant %token CLEX_character_constant %token CLEX_string_constant %token CLEX_lbracket %token CLEX_rbracket %token CLEX_lparen %token CLEX_rparen %token CLEX_lbrace %token CLEX_rbrace %token CLEX_period %token CLEX_arrow %token CLEX_plus_plus %token CLEX_minus_minus %token CLEX_ampersand %token CLEX_star %token CLEX_plus %token CLEX_minus %token CLEX_tilde %token CLEX_exclamation %token CLEX_slash %token CLEX_percent %token CLEX_less_less %token CLEX_greater_greater %token CLEX_less %token CLEX_greater %token CLEX_less_equal %token CLEX_greater_equal %token CLEX_equal_equal %token CLEX_exclamation_equal %token CLEX_caret %token CLEX_pipe %token CLEX_ampersand_ampersand %token CLEX_pipe_pipe %token CLEX_interrogation %token CLEX_colon %token CLEX_semicolon %token CLEX_ellipsis %token CLEX_equal %token CLEX_star_equal %token CLEX_slash_equal %token CLEX_percent_equal %token CLEX_plus_equal %token CLEX_minus_equal %token CLEX_less_less_equal %token CLEX_greater_greater_equal %token CLEX_ampersand_equal %token CLEX_caret_equal %token CLEX_pipe_equal %token CLEX_comma %token CLEX_hash %token CLEX_hash_hash %token CLEX_less_colon %token CLEX_colon_greater %token CLEX_less_percent %token CLEX_percent_greater %token CLEX_percent_colon %token CLEX_percent_colon_percent_colon %token CLEX_eof %token CLEX_auto %token CLEX_break %token CLEX_case %token CLEX_char %token CLEX_const %token CLEX_continue %token CLEX_default %token CLEX_do %token CLEX_double %token CLEX_else %token CLEX_enum %token CLEX_extern %token CLEX_float %token CLEX_for %token CLEX_goto %token CLEX_if /* New tokens */ %token CLEX_known_fact %token CLEX_assert %token CLEX_analysis_log %token CLEX_wait_for_clock %token CLEX_partition_begin %token CLEX_partition_merge %token CLEX_partition_controle %token CLEX_inline %token CLEX_int %token CLEX_long %token CLEX_register %token CLEX_restrict %token CLEX_return %token CLEX_short %token CLEX_signed %token CLEX_sizeof %token CLEX_static %token CLEX_struct %token CLEX_switch %token CLEX_typedef %token CLEX_union %token CLEX_unsigned %token CLEX_void %token CLEX_volatile %token CLEX_while %token CLEX__Bool %token CLEX__Complex %token CLEX__Imaginary %token CLEX_identifier %token CLEX_typedef_identifier %% /** Lexical structure */ integer_constant: CLEX_integer_constant { $1 } floating_constant: CLEX_floating_constant { $1 } character_constant: CLEX_character_constant { $1 } string_literal: CLEX_string_constant { $1 } /* shift-reduce conflict */ string_literal_list: string_literal { [fst $1], (snd $1) } | string_literal string_literal_list { ((fst $1)::(fst $2)), (fromto $1 $2) } string_constant: string_literal_list { (String.concat "" (fst $1)), (snd $1) } /* We convert terminals so that they use the common nonterminal type: semantic_value * extent, the semantic_value depending on the nonterminal */ lbracket: CLEX_lbracket { ((), $1) } rbracket: CLEX_rbracket { ((), $1) } lparen: CLEX_lparen { ((), $1) } rparen: CLEX_rparen { ((), $1) } lbrace: CLEX_lbrace { ((), $1) } rbrace: CLEX_rbrace { ((), $1) } period: CLEX_period { ((), $1) } arrow: CLEX_arrow { ((), $1) } plus_plus: CLEX_plus_plus { ((), $1) } minus_minus: CLEX_minus_minus { ((), $1) } ampersand: CLEX_ampersand { ((), $1) } star: CLEX_star { ((), $1) } plus: CLEX_plus { ((), $1) } minus: CLEX_minus { ((), $1) } tilde: CLEX_tilde { ((), $1) } exclamation: CLEX_exclamation { ((), $1) } slash: CLEX_slash { ((), $1) } percent: CLEX_percent { ((), $1) } less_less: CLEX_less_less { ((), $1) } greater_greater: CLEX_greater_greater { ((), $1) } less: CLEX_less { ((), $1) } greater: CLEX_greater { ((), $1) } less_equal: CLEX_less_equal { ((), $1) } greater_equal: CLEX_greater_equal { ((), $1) } equal_equal: CLEX_equal_equal { ((), $1) } exclamation_equal: CLEX_exclamation_equal { ((), $1) } caret: CLEX_caret { ((), $1) } pipe: CLEX_pipe { ((), $1) } ampersand_ampersand: CLEX_ampersand_ampersand { ((), $1) } pipe_pipe: CLEX_pipe_pipe { ((), $1) } interrogation: CLEX_interrogation { ((), $1) } colon: CLEX_colon { ((), $1) } semicolon: CLEX_semicolon { ((), $1) } ellipsis: CLEX_ellipsis { ((), $1) } equal: CLEX_equal { ((), $1) } star_equal: CLEX_star_equal { ((), $1) } slash_equal: CLEX_slash_equal { ((), $1) } percent_equal: CLEX_percent_equal { ((), $1) } plus_equal: CLEX_plus_equal { ((), $1) } minus_equal: CLEX_minus_equal { ((), $1) } less_less_equal: CLEX_less_less_equal { ((), $1) } greater_greater_equal: CLEX_greater_greater_equal { ((), $1) } ampersand_equal: CLEX_ampersand_equal { ((), $1) } caret_equal: CLEX_caret_equal { ((), $1) } pipe_equal: CLEX_pipe_equal { ((), $1) } comma: CLEX_comma { ((), $1) } hash: CLEX_hash { ((), $1) } hash_hash: CLEX_hash_hash { ((), $1) } less_colon: CLEX_less_colon { ((), $1) } colon_greater: CLEX_colon_greater { ((), $1) } less_percent: CLEX_less_percent { ((), $1) } percent_greater: CLEX_percent_greater { ((), $1) } percent_colon: CLEX_percent_colon { ((), $1) } percent_colon_percent_colon: CLEX_percent_colon_percent_colon { ((), $1) } eof: CLEX_eof { ((), $1) } /* All keywords are represented by kw_xxxx where xxxx is the keyword (literally, including upper/lowercase). */ kw_auto: CLEX_auto { ((), $1) } kw_break: CLEX_break { ((), $1) } kw_case: CLEX_case { ((), $1) } kw_char: CLEX_char { ((), $1) } kw_const: CLEX_const { ((), $1) } kw_continue: CLEX_continue { ((), $1) } kw_default: CLEX_default { ((), $1) } kw_do: CLEX_do { ((), $1) } kw_double: CLEX_double { ((), $1) } kw_else: CLEX_else { ((), $1) } kw_enum: CLEX_enum { ((), $1) } kw_extern: CLEX_extern { ((), $1) } kw_float: CLEX_float { ((), $1) } kw_for: CLEX_for { ((), $1) } kw_goto: CLEX_goto { ((), $1) } kw_if: CLEX_if { ((), $1) } kw_inline: CLEX_inline { ((), $1) } kw_int: CLEX_int { ((), $1) } kw_known_fact: CLEX_known_fact { ((), $1) } kw_assert: CLEX_assert { ((), $1) } kw_analysis_log: CLEX_analysis_log { ((), $1) } kw_wait_for_clock: CLEX_wait_for_clock { ((), $1) } kw_partition_begin: CLEX_partition_begin { ((), $1) } kw_partition_merge: CLEX_partition_merge { ((), $1) } kw_partition_controle: CLEX_partition_controle { ((), $1) } kw_long: CLEX_long { ((), $1) } kw_register: CLEX_register { ((), $1) } kw_restrict: CLEX_restrict { ((), $1) } kw_return: CLEX_return { ((), $1) } kw_short: CLEX_short { ((), $1) } kw_signed: CLEX_signed { ((), $1) } kw_sizeof: CLEX_sizeof { ((), $1) } kw_static: CLEX_static { ((), $1) } kw_struct: CLEX_struct { ((), $1) } kw_switch: CLEX_switch { ((), $1) } kw_typedef: CLEX_typedef { ((), $1) } kw_union: CLEX_union { ((), $1) } kw_unsigned: CLEX_unsigned { ((), $1) } kw_void: CLEX_void { ((), $1) } kw_volatile: CLEX_volatile { ((), $1) } kw_while: CLEX_while { ((), $1) } kw__Bool: CLEX__Bool { ((), $1) } kw__Complex: CLEX__Complex { ((), $1) } kw__Imaginary: CLEX__Imaginary { ((), $1) } identifier: CLEX_identifier { $1 } typedef_identifier: CLEX_typedef_identifier { $1 } any_identifier: identifier { $1 } | typedef_identifier { $1 } token: integer_constant { let (v, e)=$1 in (("integer: " ^v), e)} | floating_constant { let (v, e)=$1 in (("float: " ^v), e) } | character_constant { let (v, e)=$1 in (("char: " ^v), e) } | string_constant { let (v, e)=$1 in (("string: " ^v), e) } | lbracket { ("lbracket", (snd $1)) } | rbracket { ("rbracket", (snd $1)) } | lparen { ("lparen", (snd $1)) } | rparen { ("rparen", (snd $1)) } | lbrace { ("lbrace", (snd $1)) } | rbrace { ("rbrace", (snd $1)) } | period { ("period", (snd $1)) } | arrow { ("arrow", (snd $1)) } | plus_plus { ("plus_plus", (snd $1)) } | minus_minus { ("minus_minus", (snd $1)) } | ampersand { ("ampersand", (snd $1)) } | star { ("star", (snd $1)) } | plus { ("plus", (snd $1)) } | minus { ("minus", (snd $1)) } | tilde { ("tilde", (snd $1)) } | exclamation { ("exclamation", (snd $1)) } | slash { ("slash", (snd $1)) } | percent { ("percent", (snd $1)) } | less_less { ("less_less", (snd $1)) } | greater_greater { ("greater_greater", (snd $1)) } | less { ("less", (snd $1)) } | greater { ("greater", (snd $1)) } | less_equal { ("less_equal", (snd $1)) } | greater_equal { ("greater_equal", (snd $1)) } | equal_equal { ("equal_equal", (snd $1)) } | exclamation_equal { ("exclamation_equal", (snd $1)) } | caret { ("caret", (snd $1)) } | pipe { ("pipe", (snd $1)) } | ampersand_ampersand { ("ampersand_ampersand", (snd $1)) } | pipe_pipe { ("pipe_pipe", (snd $1)) } | interrogation { ("interrogation", (snd $1)) } | colon { ("colon", (snd $1)) } | semicolon { ("semicolon", (snd $1)) } | ellipsis { ("ellipsis", (snd $1)) } | equal { ("equal", (snd $1)) } | star_equal { ("star_equal", (snd $1)) } | slash_equal { ("slash_equal", (snd $1)) } | percent_equal { ("percent_equal", (snd $1)) } | plus_equal { ("plus_equal", (snd $1)) } | minus_equal { ("minus_equal", (snd $1)) } | less_less_equal { ("less_less_equal", (snd $1)) } | greater_greater_equal { ("greater_greater_equal", (snd $1)) } | ampersand_equal { ("ampersand_equal", (snd $1)) } | caret_equal { ("caret_equal", (snd $1)) } | pipe_equal { ("pipe_equal", (snd $1)) } | comma { ("comma", (snd $1)) } | hash { ("hash", (snd $1)) } | hash_hash { ("hash_hash", (snd $1)) } | less_colon { ("less_colon", (snd $1)) } | colon_greater { ("colon_greater", (snd $1)) } | less_percent { ("less_percent", (snd $1)) } | percent_greater { ("percent_greater", (snd $1)) } | percent_colon { ("percent_colon", (snd $1)) } | percent_colon_percent_colon { ("percent_colon_percent_colon", (snd $1)) } | kw_auto { ("auto", (snd $1)) } | kw_break { ("break", (snd $1)) } | kw_case { ("case", (snd $1)) } | kw_char { ("char", (snd $1)) } | kw_const { ("const", (snd $1)) } | kw_continue { ("continue", (snd $1)) } | kw_default { ("default", (snd $1)) } | kw_do { ("do", (snd $1)) } | kw_double { ("double", (snd $1)) } | kw_else { ("else", (snd $1)) } | kw_enum { ("enum", (snd $1)) } | kw_extern { ("extern", (snd $1)) } | kw_float { ("float", (snd $1)) } | kw_for { ("for", (snd $1)) } | kw_goto { ("goto", (snd $1)) } | kw_if { ("if", (snd $1)) } | kw_inline { ("inline", (snd $1)) } | kw_int { ("int", (snd $1)) } | kw_long { ("long", (snd $1)) } | kw_register { ("register", (snd $1)) } | kw_restrict { ("restrict", (snd $1)) } | kw_return { ("return", (snd $1)) } | kw_short { ("short", (snd $1)) } | kw_signed { ("signed", (snd $1)) } | kw_sizeof { ("sizeof", (snd $1)) } | kw_static { ("static", (snd $1)) } | kw_struct { ("struct", (snd $1)) } | kw_switch { ("switch", (snd $1)) } | kw_typedef { ("typedef", (snd $1)) } | kw_union { ("union", (snd $1)) } | kw_unsigned { ("unsigned", (snd $1)) } | kw_void { ("void", (snd $1)) } | kw_volatile { ("volatile", (snd $1)) } | kw_while { ("while", (snd $1)) } | kw__Bool { ("_Bool", (snd $1)) } | kw__Complex { ("_Complex", (snd $1)) } | kw__Imaginary { ("_Imaginary", (snd $1)) } | identifier { let (s,e) = $1 in (("identifier: "^s), e) } | typedef_identifier { let (s,e) = $1 in (("typedef: "^s), e) } token_list: /* */ { [] } | token token_list { $1::$2 } token_list_eof: token_list eof { $1 } /** Syntax */ /*** Expressions */ primary_expression: identifier { (C_identifier($1)), (snd $1) } | integer_constant { (C_integer_constant(fst $1)), (snd $1) } | floating_constant { (C_floating_constant(fst $1)), (snd $1) } | string_constant { (C_string_literal(fst $1), (snd $1)) } | character_constant { (C_character_constant(fst $1), (snd $1)) } | lparen expression rparen { (fst $2), (fromto $1 $3) } postfix_expression: primary_expression { $1 } | postfix_expression lbracket expression rbracket { (C_binary(C_ARRAY_LOOKUP, $1, $3)), (fromto $1 $4) } | postfix_expression lparen argument_expression_list_opt rparen { (C_function_call($1, $3)), (fromto $1 $4) } | postfix_expression period any_identifier { (C_unary((C_struct_member $3), $1)), (fromto $1 $3) } | postfix_expression arrow any_identifier { (C_unary((C_indirect_member $3), $1)), (fromto $1 $3) } | postfix_expression plus_plus { (C_unary_assign(C_POST_INCR, $1), (fromto $1 $2)) } | postfix_expression minus_minus { (C_unary_assign(C_POST_DECR, $1), (fromto $1 $2)) } /* missing end of list*/ argument_expression_list: assignment_expression { [$1] } | assignment_expression comma argument_expression_list {$1::$3} argument_expression_list_opt: /* */ { [] } | argument_expression_list { $1 } unary_expression: postfix_expression { $1 } | plus_plus unary_expression { (C_unary_assign(C_PRE_INCR, $2)), (fromto $1 $2) } | minus_minus unary_expression { (C_unary_assign(C_PRE_DECR, $2)), (fromto $1 $2) } | unary_operator cast_expression { (C_unary((fst $1), $2)), (fromto $1 $2) } | kw_sizeof lparen type_name rparen { (C_special_op(C_sizeof_type($3))), (fromto $1 $4) } | kw_sizeof unary_expression { (C_special_op(C_sizeof_expr($2))), (fromto $1 $2) } unary_operator: ampersand { C_ADDRESS_OF, (snd $1) } | star { C_DEREFERENCE, (snd $1) } | plus { C_UNARY_PLUS, (snd $1) } | minus { C_UNARY_MINUS, (snd $1) } | tilde { C_COMPLEMENT, (snd $1) } | exclamation { C_NOT, (snd $1) } cast_expression: unary_expression { $1 } | lparen type_name rparen cast_expression { (C_unary((C_cast $2), $4)), (fromto $1 $4) } multiplicative_expression: cast_expression { $1 } | multiplicative_expression star cast_expression { (arith(C_MULTIPLY, $1, $3)), (fromto $1 $3) } | multiplicative_expression slash cast_expression { (arith(C_DIVIDE, $1, $3)), (fromto $1 $3) } | multiplicative_expression percent cast_expression { (arith(C_MODULO, $1, $3)), (fromto $1 $3) } additive_expression: multiplicative_expression { $1 } | additive_expression plus multiplicative_expression { (arith(C_ADD, $1, $3)), (fromto $1 $3) } | additive_expression minus multiplicative_expression { (arith(C_SUBTRACT, $1, $3)), (fromto $1 $3) } shift_expression: additive_expression { $1 } | shift_expression less_less additive_expression { (arith(C_SHIFT_LEFT, $1, $3)), (fromto $1 $3) } | shift_expression greater_greater additive_expression { (arith(C_SHIFT_RIGHT, $1, $3)), (fromto $1 $3) } relational_expression: shift_expression { $1 } | relational_expression less shift_expression { (comparison(C_LESS, $1, $3)), (fromto $1 $3) } | relational_expression greater shift_expression { (comparison(C_GREATER, $1, $3)), (fromto $1 $3) } | relational_expression less_equal shift_expression { (comparison(C_LESS_EQUAL, $1, $3)), (fromto $1 $3) } | relational_expression greater_equal shift_expression { (comparison(C_GREATER_EQUAL, $1, $3)), (fromto $1 $3) } equality_expression: relational_expression { $1 } | equality_expression equal_equal relational_expression { (comparison(C_EQUAL, $1, $3)), (fromto $1 $3) } | equality_expression exclamation_equal relational_expression { (comparison(C_UNEQUAL, $1, $3)), (fromto $1 $3) } and_expression: equality_expression { $1 } | and_expression ampersand equality_expression { (arith(C_BITWISE_AND, $1, $3)), (fromto $1 $3) } exclusive_or_expression: and_expression { $1 } | exclusive_or_expression caret and_expression { (arith(C_BITWISE_XOR, $1, $3)), (fromto $1 $3) } inclusive_or_expression: exclusive_or_expression { $1 } | inclusive_or_expression pipe exclusive_or_expression { (arith(C_BITWISE_OR, $1, $3)), (fromto $1 $3) } logical_and_expression: inclusive_or_expression { $1 } | logical_and_expression ampersand_ampersand inclusive_or_expression { (logical(C_LOGICAL_AND, $1, $3)), (fromto $1 $3) } logical_or_expression: logical_and_expression { $1 } | logical_or_expression pipe_pipe logical_and_expression { (logical(C_LOGICAL_OR, $1, $3)), (fromto $1 $3) } conditional_expression: logical_or_expression { $1 } | logical_or_expression interrogation expression colon conditional_expression { (C_conditional($1, $3, $5)), (fromto $1 $5) } assignment_expression: conditional_expression { $1 } | unary_expression assignment_operator assignment_expression { (C_assignment((fst $2), $1, $3)), (fromto $1 $3) } assignment_operator: equal { None, (snd $1) } | star_equal { (Some C_MULTIPLY), (snd $1) } | slash_equal { (Some C_DIVIDE), (snd $1) } | percent_equal { (Some C_MODULO), (snd $1) } | plus_equal { (Some C_ADD), (snd $1) } | minus_equal { (Some C_SUBTRACT), (snd $1) } | less_less_equal { (Some C_SHIFT_LEFT), (snd $1) } | greater_greater_equal { (Some C_SHIFT_RIGHT), (snd $1) } | pipe_equal { (Some C_BITWISE_OR), (snd $1) } | ampersand_equal { (Some C_BITWISE_AND), (snd $1) } | caret_equal { (Some C_BITWISE_XOR), (snd $1) } expression: assignment_expression { $1 } | expression comma assignment_expression { (C_comma($1, $3)), (fromto $1 $3) } constant_expression: conditional_expression { $1 } expression_eof: expression eof { $1 } /*** Declarations */ /* Declarations are the most complex elements parsed. Let us consider the following declaration: static const double *x, *y; are the declaration specifiers. C allows mixing three kinds of elements in there: - storage class specifiers (i.e. static) - type qualifiers (const, volatile, restrict) - type specifiers (short, int, double..., struct, enum, union...) Storage class specifiers are relative to the element being declared, type specifiers and qualifiers to the "left-type". <*x> and <*y> are declarators. For each variable, the declarator is combined with the left-type to form the full type. This declaration declares two static variables, both of which are pointers to constant doubles. */ declaration: declaration_specifiers init_declarator_list_opt semicolon { (if (decl_specifiers_has_typedef (fst $1)) then List.iter (fun ((declarator, initializer_opt), _) -> Parsing_helper.add_typedef (fst (extract_id_from_declarator declarator))) $2); { c_decl_specifiers = fst $1; c_decl_list = $2 }, (fromto $1 $3) } declaration_specifiers: declaration_specifier { [$1], (snd $1) } | declaration_specifier declaration_specifiers { ($1::(fst $2)), (fromto $1 $2) } declaration_specifier: type_specifier { (C_type_specifier($1)), (snd $1) } | storage_class_specifier { (C_storage_specifier($1)), (snd $1) } | type_qualifier { (C_type_qualifier($1)), (snd $1) } | function_specifier { (C_function_specifier($1)), (snd $1) } init_declarator_list_opt: /* */ { [] } | init_declarator_list { $1 } init_declarator_list: init_declarator { [$1] } | init_declarator comma init_declarator_list { $1::$3 } init_declarator: declarator { ($1, None), (snd $1) } | declarator equal c_initializer { ($1, (Some $3)), (snd $1) } storage_class_specifier: kw_typedef { C_TYPEDEF, (snd $1) } | kw_extern { C_EXTERN, (snd $1) } | kw_static { C_STATIC, (snd $1) } | kw_auto { C_AUTO, (snd $1) } | kw_register { C_REGISTER, (snd $1) } type_specifier: predefined_type { (C_predefined_type(fst $1)), (snd $1) } | typedef_identifier { (C_typedef_use($1)), (snd $1) } | struct_or_union_specifier { (C_struct_or_union($1)), (snd $1) } | enum_specifier { (C_enum($1)), (snd $1) } predefined_type: kw_void { C_void, (snd $1) } | kw_char { C_char, (snd $1) } | kw_short { C_short, (snd $1) } | kw_int { C_int, (snd $1) } | kw_long { C_long, (snd $1) } | kw_float { C_float, (snd $1) } | kw_double { C_double, (snd $1) } | kw_signed { C_signed, (snd $1) } | kw_unsigned { C_unsigned, (snd $1) } | kw__Bool { C__Bool, (snd $1) } | kw__Complex { C__Complex, (snd $1) } | kw__Imaginary { C__Imaginary, (snd $1) } struct_or_union_specifier: struct_or_union lbrace struct_declaration_list rbrace { { c_stru_kind = (fst $1); c_stru_identifier = None; c_stru_decl_list = (Some $3) }, (fromto $1 $4) } | struct_or_union any_identifier lbrace struct_declaration_list rbrace { { c_stru_kind = (fst $1); c_stru_identifier = (Some $2); c_stru_decl_list = (Some $4) }, (fromto $1 $5) } | struct_or_union any_identifier { { c_stru_kind = (fst $1); c_stru_identifier = (Some $2); c_stru_decl_list = None }, (fromto $1 $2) } struct_or_union: kw_struct { C_STRUCT, (snd $1) } | kw_union { C_UNION, (snd $1) } struct_declaration_list: struct_declaration { [$1] } | struct_declaration struct_declaration_list { $1::$2 } struct_declaration: specifier_qualifier_list struct_declarator_list semicolon { { c_strdecl_specifiers_qualifiers = (fst $1); c_strdecl_declarators = $2 }, (fromto $1 $3) } specifier_qualifier_list: type_specifier { [C_type_name_specifier($1)], (snd $1) } | type_specifier specifier_qualifier_list { (C_type_name_specifier($1))::(fst $2), (fromto $1 $2) } | type_qualifier { [C_type_name_qualifier($1)], (snd $1) } | type_qualifier specifier_qualifier_list { (C_type_name_qualifier($1))::(fst $2), (fromto $1 $2) } struct_declarator: declarator { { c_strdecl_field_declarator = (Some $1); c_strdecl_field_length = None }, (snd $1) } | declarator colon constant_expression { { c_strdecl_field_declarator = (Some $1); c_strdecl_field_length = (Some $3) }, (fromto $1 $3) } | colon constant_expression { { c_strdecl_field_declarator = None; c_strdecl_field_length = (Some $2) }, (fromto $1 $2) } struct_declarator_list: struct_declarator comma struct_declarator_list { $1::$3 } | struct_declarator { [$1] } enum_specifier: kw_enum any_identifier_opt lbrace enumerator_list rbrace { { c_enum_identifier = $2; c_enum_tags = Some $4 }, (fromto $1 $5) } | kw_enum any_identifier { { c_enum_identifier = Some $2; c_enum_tags = None }, (fromto $1 $2) } any_identifier_opt: any_identifier { Some $1} | /* */ { None } enumerator_list: enumerator comma enumerator_list { $1::$3 } | enumerator { [$1] } | enumerator comma { [$1] } enumerator: any_identifier { { c_enumerator_identifier = $1; c_enumerator_value = None }, (snd $1) } | any_identifier equal constant_expression { { c_enumerator_identifier = $1; c_enumerator_value = Some $3 }, (fromto $1 $3) } declarator: direct_declarator { $1 } | pointer direct_declarator { (C_pointer($1, $2)), (fromto $1 $2) } direct_declarator: identifier { (C_declarator_identifier $1), (snd $1) } | lparen declarator rparen { $2 } | direct_declarator lparen parameter_type_list rparen { (C_declarator_function($1, (fst $3), (snd $3))), (fromto $1 $4) } | direct_declarator lparen identifier_list_opt rparen { (C_declarator_old_function($1, $3)), (fromto $1 $4) } | direct_declarator lbracket type_qualifier_list_opt assignment_expression rbracket { (C_declarator_array($1, $3, (C_array_size_expr $4))), (fromto $1 $5) } | direct_declarator lbracket type_qualifier_list_opt rbracket { (C_declarator_array($1, $3, C_ARRAY_SIZE_NONE)), (fromto $1 $4) } | direct_declarator lbracket kw_static type_qualifier_list_opt assignment_expression rbracket { (C_declarator_array($1, $4, (C_array_size_static_expr $5))), (fromto $1 $6) } | direct_declarator lbracket type_qualifier_list kw_static assignment_expression rbracket { (C_declarator_array($1, (fst $3), (C_array_size_static_expr $5))), (fromto $1 $6) } | direct_declarator lbracket type_qualifier_list_opt star rbracket { (C_declarator_array($1, $3, C_ARRAY_SIZE_STAR)), (fromto $1 $5) } pointer: star type_qualifier_list { (C_pointer_one(fst $2)), (fromto $1 $2) } | star type_qualifier_list pointer { (C_pointer_recur((fst $2), $3)), (fromto $1 $3) } | star { (C_pointer_one([])), (snd $1) } | star pointer { (C_pointer_recur([], $2)), (fromto $1 $2) } type_qualifier: kw_const { C_CONST, (snd $1) } | kw_volatile { C_VOLATILE, (snd $1) } | kw_restrict { C_RESTRICT, (snd $1) } type_qualifier_list: type_qualifier { [$1], (snd $1) } | type_qualifier type_qualifier_list { ($1::(fst $2)), (fromto $1 $2) } type_qualifier_list_opt: /* */ { [] } | type_qualifier type_qualifier_list_opt { $1::$2 } function_specifier: kw_inline { C_INLINE, (snd $1) } parameter_type_list: parameter_declaration { [$1], false } | parameter_declaration comma ellipsis { [$1], true } | parameter_declaration comma parameter_type_list { ($1::(fst $3)), (snd $3) } /* | error { syntax_error "parameter type list"; [], false } */ parameter_type_list_opt: /* */ { [], false } | parameter_type_list { $1 } /* unneeded parameter_list: parameter_declaration { [$1] } | parameter_declaration comma parameter_list { $1::$3 } */ parameter_declaration: declaration_specifiers declarator { (C_parameter_decl((fst $1), $2)), (fromto $1 $2) } | declaration_specifiers abstract_declarator { (C_parameter_abstract_decl((fst $1), $2)), (fromto $1 $2) } | declaration_specifiers { (C_parameter_no_decl(fst $1)), (snd $1) } identifier_list_opt: /* */ { [] } | identifier_list { $1 } identifier_list: identifier { [$1] } | identifier comma identifier_list { $1::$3 } type_name: specifier_qualifier_list { { c_type_name_specifier_qualifiers = $1; c_type_name_declarator = None }, (snd $1) } | specifier_qualifier_list abstract_declarator { { c_type_name_specifier_qualifiers = $1; c_type_name_declarator = Some $2 }, (fromto $1 $2) } abstract_declarator: direct_abstract_declarator { $1 } | pointer direct_abstract_declarator { (C_abstract_pointer($1, (Some $2))), (fromto $1 $2) } | pointer { (C_abstract_pointer($1, None)), (snd $1) } direct_abstract_declarator: lparen abstract_declarator rparen { $2 } | direct_abstract_declarator lbracket assignment_expression rbracket { (C_abstract_declarator_array((Some $1), (C_array_size_expr $3))), (fromto $1 $4) } | direct_abstract_declarator lbracket rbracket { (C_abstract_declarator_array((Some $1), C_ARRAY_SIZE_NONE)), (fromto $1 $3) } | direct_abstract_declarator lbracket star rbracket { (C_abstract_declarator_array((Some $1), C_ARRAY_SIZE_STAR)), (fromto $1 $4) } | direct_abstract_declarator lparen parameter_type_list_opt rparen { (C_abstract_declarator_function((Some $1), (fst $3), (snd $3))), (fromto $1 $4) } | lbracket assignment_expression rbracket { (C_abstract_declarator_array(None, (C_array_size_expr $2))), (fromto $1 $3) } | lbracket rbracket { (C_abstract_declarator_array(None, C_ARRAY_SIZE_NONE)), (fromto $1 $2) } | lbracket star rbracket { (C_abstract_declarator_array(None, C_ARRAY_SIZE_STAR)), (fromto $1 $3) } | lparen parameter_type_list_opt rparen { (C_abstract_declarator_function(None, (fst $2), (snd $2))), (fromto $1 $3) } c_initializer: assignment_expression { (C_initializer_expression $1), (snd $1) } | lbrace initializer_list rbrace { (C_initializer_compound $2), (fromto $1 $3) } initializer_list: sub_initializer { [$1] } | sub_initializer comma { [$1] } | sub_initializer comma initializer_list { $1::$3 } sub_initializer: designator_list equal c_initializer { {c_initializer_designation = Some $1; c_initializer_sub = $3 }, (fromto $1 $3) } | c_initializer { {c_initializer_designation = None; c_initializer_sub = $1 }, (snd $1) } designator_list: designator { [$1], (snd $1) } | designator designator_list { ($1::(fst $2)), (fromto $1 $2) } designator: lbracket constant_expression rbracket { (C_designator_index $2), (fromto $1 $3) } | period any_identifier { (C_designator_member $2), (fromto $1 $2) } /*** Statements */ statement: labeled_statement { $1 } | compound_statement { $1 } | expression_statement { $1 } | selection_statement { $1 } | iteration_statement { $1 } | jump_statement { $1 } | partition_controle_statement { $1 } partition_controle_statement: partition_controle iteration_statement { (C_partition_controle (fst $1,$2), fromto $1 $2) } | partition_controle selection_statement { (C_partition_controle (fst $1,$2), fromto $1 $2) } partition_controle: kw_partition_controle { ("0", snd $1) } | kw_partition_controle lbracket integer_constant rbracket { (fst $3, fromto $1 $4) } labeled_statement: label_kind statement { (C_labeled_statement($1, $2)), (fromto $1 $2) } label_kind: kw_default colon { C_default, (fromto $1 $2) } | any_identifier colon { (C_label $1), (fromto $1 $2) } | kw_case constant_expression colon { (C_case $2), (fromto $1 $3) } /* SHIFT/REDUCE conflict: nested if/else (ok) */ selection_statement: kw_if lparen expression rparen statement kw_else statement { (C_ifthenelse($3, $5, (Some $7))), (fromto $1 $7) } | kw_if lparen expression rparen statement { (C_ifthenelse($3, $5, None)), (fromto $1 $5) } | kw_switch lparen expression rparen statement { (C_switch($3, $5)), (fromto $1 $5) } | kw_known_fact lparen expression rparen semicolon { (C_known_fact($3)), (fromto $1 $4) } | kw_assert lparen expression rparen semicolon { (C_assert($3)), (fromto $1 $4) } iteration_statement: kw_while lparen expression rparen statement { (C_while_loop($3, $5)), (fromto $1 $5) } | kw_do statement kw_while lparen expression rparen semicolon { (C_do_while_loop($2, $5)), (fromto $1 $7) } | kw_for lparen expression_opt semicolon expression_opt semicolon expression_opt rparen statement { (C_for_loop($3, $5, $7, $9)), (fromto $1 $9) } | kw_for lparen declaration expression_opt semicolon expression_opt rparen statement { (C_for_loop_decl($3, $4, $6, $8)), (fromto $1 $8) } compound_statement: lbrace block_item_list_opt rbrace { (C_compound_statement $2), (fromto $1 $3) } block_item_list_opt: /* */ { [] } | block_item block_item_list_opt { $1::$2 } block_item: statement { C_statement($1) } | declaration { C_declaration($1) } expression_statement: expression semicolon { (C_expression_statement(Some $1)), (fromto $1 $2) } | kw_analysis_log lparen rparen semicolon { C_analysis_log_statement, (fromto $1 $2) } | kw_wait_for_clock lparen rparen semicolon { C_wait_for_clock_statement, (fromto $1 $2) } | kw_partition_begin lparen identifier rparen semicolon { C_partition_begin_statement $3, (fromto $1 $4) } | kw_partition_merge lparen rparen semicolon { C_partition_merge_statement, (fromto $1 $2) } | semicolon { (C_expression_statement None), (snd $1) } jump_statement: kw_goto any_identifier semicolon { (C_jump_statement (C_goto $2)), (fromto $1 $2) } | kw_continue semicolon { (C_jump_statement C_continue), (snd $1) } | kw_break semicolon { (C_jump_statement C_break), (snd $1) } | kw_return expression semicolon { (C_jump_statement (C_return (Some $2))), (fromto $1 $3) } | kw_return semicolon { (C_jump_statement (C_return None)), (fromto $1 $2) } expression_opt: expression { Some $1 } | /* */ { None } statement_eof: statement eof { $1 } /*** External definitions */ translation_unit: /* */ { [] } | external_declaration translation_unit { $1::$2 } translation_unit_eof: translation_unit eof { $1 } external_declaration2: external_declaration { fun handler env -> handler env $1 } translation_unit2: /* */ { fun handler env -> env } | external_declaration2 translation_unit2 { fun handler env -> $2 handler ($1 handler env) } translation_unit2_eof: translation_unit2 eof { $1 } external_declaration: function_definition { C_toplevel_function($1) } | declaration { C_toplevel_declaration($1) } /* | error rbrace { syntax_error "toplevel declaration"; C_toplevel_error } */ declaration_list_opt: declaration declaration_list_opt { $1::$2 } | /* */ { [] } function_definition: declaration_specifiers declarator declaration_list_opt lbrace block_item_list_opt rbrace { { c_fun_def_specifiers = fst $1; c_fun_def_declarator = $2; c_fun_def_old_declarations = $3; c_fun_def_body = $5, (fromto $4 $6) }, (fromto $1 $6) } | declarator declaration_list_opt lbrace block_item_list_opt rbrace { { c_fun_def_specifiers = []; c_fun_def_declarator = $1; c_fun_def_old_declarations = $2; c_fun_def_body = $4, (fromto $3 $5) }, (fromto $1 $5) }