/* * Copyright (c) 2002, The Tendra Project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice unmodified, this list of conditions, and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * * Crown Copyright (c) 1997 * * This TenDRA(r) Computer Program is subject to Copyright * owned by the United Kingdom Secretary of State for Defence * acting through the Defence Evaluation and Research Agency * (DERA). It is made available to Recipients with a * royalty-free licence for its use, reproduction, transfer * to other parties and amendment for any purpose not excluding * product development provided that any such use et cetera * shall be deemed to be acceptance of the following conditions:- * * (1) Its Recipients shall ensure that this Notice is * reproduced upon any copies or amended versions of it; * * (2) Any amended version of it shall be clearly marked to * show both the nature of and the organisation responsible * for the relevant amendment or amendments; * * (3) Its onward transfer from a recipient to another * party shall be deemed to be that party's acceptance of * these conditions; * * (4) DERA gives no warranty or assurance as to its * quality or suitability for any purpose and DERA accepts * no liability whatsoever in relation to any use to which * it may be put. * * $TenDRA: tendra/src/producers/c/syntax/syntax.act,v 1.13 2005/10/14 09:52:18 stefanf Exp $ */ %prefixes% /* * TERMINAL PREFIX * * This prefix is used to identify lexical token numbers in syntax.h * (see also symbols.h). */ terminal = lex_; %maps% /* * PARSER ENTRY POINTS * * There are a number of entry points into the parser. The main ones * are translation-unit which is used to parse an entire translation * unit and hash-if-expression which is used to parse expressions in * #if preprocessing directives. */ translation-unit -> parse_file; expression-entry -> parse_exp; id-entry -> parse_id; operator-id -> parse_operator; declaration-entry -> parse_decl; function-definition-entry -> parse_func; type-id-entry -> parse_type; token-type-id -> parse_tok_type; member-type-id -> parse_mem_type; parameter-entry -> parse_param; statement-entry -> parse_stmt; initialiser-entry -> parse_init; hash-if-expression -> parse_nat; template-type-param -> parse_type_param; constant-offset -> parse_offset; /* * BASIC TYPES * * The type BOOL is used to hold the predicate values, true and false. * The type COUNT is used to hold the various counters maintained (see * predict.c). The type LEX is used to hold a lexical token number * (i.e. one of the values defined in syntax.h). The other types used * in the parser map in a simple fashion to the main program types. * Note that it is necessary to use aliases for compound types because * of the restrictions imposed by sid. */ BOOL -> int; BTYPE -> BASE_TYPE; CONDITION -> unsigned; COUNT -> int; CV -> CV_SPEC; DECL -> IDENTIFIER; DSPEC -> DECL_SPEC; EXP -> EXP; IDENTIFIER -> IDENTIFIER; KEY -> BASE_TYPE; LEX -> int; LIST-EXP -> SID_LIST_EXP; NAMESPACE -> NAMESPACE; NUMBER -> int; OFFSET -> OFFSET; TYPE -> TYPE; /* * FILE HEADERS * * These headers are prepended to the parser definition and declaration * output files. Because of the simple file splitting algorithm applied * to the output this should contain only declarations and not definitions. */ %header% @{ /* * Crown Copyright (c) 1997, 1998 * * This TenDRA(r) Computer Program is subject to Copyright * owned by the United Kingdom Secretary of State for Defence * acting through the Defence Evaluation and Research Agency * (DERA). It is made available to Recipients with a * royalty-free licence for its use, reproduction, transfer * to other parties and amendment for any purpose not excluding * product development provided that any such use et cetera * shall be deemed to be acceptance of the following conditions:- * * (1) Its Recipients shall ensure that this Notice is * reproduced upon any copies or amended versions of it; * * (2) Any amended version of it shall be clearly marked to * show both the nature of and the organisation responsible * for the relevant amendment or amendments; * * (3) Its onward transfer from a recipient to another * party shall be deemed to be that party's acceptance of * these conditions; * * (4) DERA gives no warranty or assurance as to its * quality or suitability for any purpose and DERA accepts * no liability whatsoever in relation to any use to which * it may be put. */ #include "config.h" #include "producer.h" #include "c_types.h" #include "exp_ops.h" #include "hashid_ops.h" #include "id_ops.h" #include "type_ops.h" #include "error.h" #include "catalog.h" #include "option.h" #include "access.h" #include "allocate.h" #include "assign.h" #include "basetype.h" #include "cast.h" #include "chktype.h" #include "class.h" #include "constant.h" #include "construct.h" #include "convert.h" #include "declare.h" #include "derive.h" #include "dump.h" #include "exception.h" #include "expression.h" #include "function.h" #include "hash.h" #include "identifier.h" #include "initialise.h" #include "inttype.h" #include "label.h" #include "lex.h" #include "literal.h" #include "member.h" #include "namespace.h" #include "parse.h" #include "pragma.h" #include "predict.h" #include "preproc.h" #include "redeclare.h" #include "rewrite.h" #include "statement.h" #include "symbols.h" #include "template.h" #include "tokdef.h" #include "token.h" #include "typeid.h" #include "variable.h" /* * COMPOUND TYPE ALIASES * * These are the aliases for the compound types used in the parser. */ typedef LIST (EXP) SID_LIST_EXP; /* * FUNCTION DECLARATIONS * * The function declarations are included at this point so that the * type definitions are in scope. */ #include "syntax.h" /* * COMPILATION MODE * * The output of sid is automatically generated. Hence it is not * necessarily appropriate to apply the same level of checking to this * as to the rest of the program. These pragmas describe the relaxations * allowed for the sid output. */ #if FS_TENDRA #pragma TenDRA begin #pragma TenDRA const conditional allow #pragma TenDRA unreachable code allow #pragma TenDRA variable analysis off #endif @}, @{ /* * Crown Copyright (c) 1997, 1998 * * This TenDRA(r) Computer Program is subject to Copyright * owned by the United Kingdom Secretary of State for Defence * acting through the Defence Evaluation and Research Agency * (DERA). It is made available to Recipients with a * royalty-free licence for its use, reproduction, transfer * to other parties and amendment for any purpose not excluding * product development provided that any such use et cetera * shall be deemed to be acceptance of the following conditions:- * * (1) Its Recipients shall ensure that this Notice is * reproduced upon any copies or amended versions of it; * * (2) Any amended version of it shall be clearly marked to * show both the nature of and the organisation responsible * for the relevant amendment or amendments; * * (3) Its onward transfer from a recipient to another * party shall be deemed to be that party's acceptance of * these conditions; * * (4) DERA gives no warranty or assurance as to its * quality or suitability for any purpose and DERA accepts * no liability whatsoever in relation to any use to which * it may be put. */ #ifndef SYNTAX_INCLUDED #define SYNTAX_INCLUDED @}; %terminals% /* * IDENTIFIER TERMINALS * * Identifiers and related terminals (type names, namespace names and * destructor names) are identified by means of an identifier stored in * crt_token by expand_token. */ identifier: () -> (id) = @{ @id = crt_token->pp_data.id.use; @}; type-name: () -> (id) = @{ @id = crt_token->pp_data.id.use; @}; namespace-name: () -> (id) = @{ @id = crt_token->pp_data.id.use; @}; statement-name: () -> (id) = @{ @id = crt_token->pp_data.id.use; @}; destructor-name: () -> (id) = @{ @id = crt_token->pp_data.id.use; @}; template-id: () -> (id) = @{ IDENTIFIER id = crt_token->pp_data.tok.id; PPTOKEN *args = crt_token->pp_data.tok.args; @id = parse_id_template (id, args, 0); RESCAN_LEXER; @}; template-type: () -> (id) = @{ IDENTIFIER id = crt_token->pp_data.tok.id; PPTOKEN *args = crt_token->pp_data.tok.args; @id = parse_type_template (id, args, 0); RESCAN_LEXER; @}; /* * NAMESPACE SPECIFIER TERMINALS * * Namespace specifiers (i.e. sequences of namespace or class names * separated using '::') are identified by expand_token. The full nested * names are those which begin with the global namespace. */ nested-name: () -> (ns) = @{ @ns = crt_token->pp_data.ns; @}; full-name: () -> (ns) = @{ @ns = crt_token->pp_data.ns; @}; /* * POINTER TO MEMBER TERMINALS * * Pointer to member specifiers (such as 'C::*') are identified by * expand_token. The identifier corresponding to the given class is * stored in crt_token. */ nested-name-star: () -> (id) = @{ @id = crt_token->pp_data.id.use; @}; full-name-star: () -> (id) = @{ @id = crt_token->pp_data.id.use; @}; /* * INTEGER AND FLOATING-POINT LITERAL TERMINALS * * Integer and floating-point literal tokens have already been transformed * into their corresponding expressions by expand_token, which stores this * information in crt_token. */ integer-exp: () -> (e) = @{ @e = crt_token->pp_data.exp; @}; floating-exp: () -> (e) = @{ @e = crt_token->pp_data.exp; @}; /* * STRING AND CHARACTER LITERAL TERMINALS * * String and character literal tokens have already been transformed * into their corresponding expressions by expand_token, which stores this * information in crt_token. */ char-exp: () -> (e) = @{ @e = crt_token->pp_data.exp; @}; wchar-exp: () -> (e) = @{ @e = crt_token->pp_data.exp; @}; string-exp: () -> (e) = @{ @e = crt_token->pp_data.exp; @}; wstring-exp: () -> (e) = @{ @e = crt_token->pp_data.exp; @}; /* * CONDITIONAL COMPILATION TERMINALS * * Any target dependent conditional compilation expressions are stored * in crt_token by the preprocessing routines. */ hash-if: () -> (e) = @{ @e = crt_token->pp_data.exp; @}; hash-elif: () -> (e) = @{ @e = crt_token->pp_data.exp; @}; /* * COMPLEX EXPRESSION AND TYPE TERMINALS * * These terminals are used to handle complex expressions and types * such as token applications. */ complex-exp: () -> (e) = @{ IDENTIFIER id = crt_token->pp_data.tok.id; PPTOKEN *args = crt_token->pp_data.tok.args; @e = parse_exp_token (id, args); RESCAN_LEXER; @}; complex-stmt: () -> (e) = @{ IDENTIFIER id = crt_token->pp_data.tok.id; PPTOKEN *args = crt_token->pp_data.tok.args; @e = parse_exp_token (id, args); RESCAN_LEXER; @}; complex-type: () -> (t) = @{ IDENTIFIER id = crt_token->pp_data.tok.id; PPTOKEN *args = crt_token->pp_data.tok.args; @t = parse_type_token (id, args); have_type_declaration = TYPE_DECL_NONE; have_type_specifier = 1; RESCAN_LEXER; @}; %actions% /* * LEXICAL TOKENS * * These actions give the basic values for the type LEX. They are used * primarily in overloaded operator function names, but they are also used * to distinguish closely related groups of expressions, such as relational * expressions. Note that the primary form of the token has been given * whenever there is a choice, otherwise the actions are very dull. */ : () -> (t) = @{ @t = crt_lex_token; @}; : () -> (t) = @{ @t = lex_open_Hround; @}; : () -> (t) = @{ @t = lex_semicolon; @}; : () -> (t) = @{ @t = lex_alignof; @}; : () -> (t) = @{ @t = lex_sizeof; @}; /* * SPECIAL FUNCTION IDENTIFIERS * * These actions are used to construct the identifiers corresponding to * the operator-function-ids and conversion-function-ids. In addition, * id_none gives the null identifier and id_anon generates a unique * anonymous identifier. */ : () -> (id) = @{ @id = NULL_id; @}; : () -> (id) = @{ HASHID nm = lookup_anon (); @id = DEREF_id (hashid_id (nm)); @}; /* * NAMESPACES AND IDENTIFIER LOOK-UP * * These actions are used to identify namespaces and identifiers within * those namespaces. */ : (ns, id) -> (n) = @{ HASHID nm = DEREF_hashid (id_name (@id)); @n = find_qual_id (@ns, nm, 1, 0); @}; /* * LISTS OF EXPRESSIONS * * These actions give the basic constructs for building up lists of * expressions. They map directly to the calculus list operations. */ : () -> (p) = @{ @p = NULL_list (EXP); @}; : (e, q) -> (p) = @{ CONS_exp (@e, @q, @p); @}; /* * EXPRESSION CONSTRUCTORS * * These actions describe how to build up expressions from more primitive * expressions. The null expression, exp_none, is used to indicate that * an optional expression is absent. Most of the actions are very * straightforward, either directly calling a calculus EXP constructor * or the appropriate expression construction function. */ : () -> (e) = @{ @e = NULL_exp; @}; : (p) -> (e) = @{ /* The expression type is a dummy */ MAKE_exp_aggregate (type_void, @p, NULL_list (OFFSET), @e); @}; : (a, b) -> (e) = @{ @e = make_and_exp (@a, @b); @}; : (a) -> (e, t, ns) = @{ @e = begin_field_exp (lex_arrow, @a, &@t, &@ns); @}; : (a, t, ns, id) -> (e) = @{ @e = end_field_exp (lex_arrow, @a, @t, @ns, @id, 0); @}; : (a, b) -> (e) = @{ @e = make_assign_exp (@a, @b, 1); @}; : (op, a, b) -> (e) = @{ /* op will be in its primary form */ @e = make_become_exp (@op, @a, @b); @}; : (t, a, n) -> (e) = @{ /* n is the number of type definitions in t */ @e = make_cast_exp (@t, @a, @n); @}; : (p) -> (e) = @{ @e = make_comma_exp (@p); @}; : (a, b, c) -> (e) = @{ @e = make_cond_exp (@a, @b, @c); @}; : (a, b) -> (e) = @{ @e = make_mult_exp (lex_div, @a, @b); @}; : (a) -> (e, t, ns) = @{ @e = begin_field_exp (lex_dot, @a, &@t, &@ns); @}; : (a, t, ns, id) -> (e) = @{ @e = end_field_exp (lex_dot, @a, @t, @ns, @id, 0); @}; : () -> (e) = @{ @e = make_ellipsis_exp (); @}; : (op, a, b) -> (e) = @{ /* op will be in its primary form */ @e = make_equality_exp (@op, @a, @b); @}; : (a) -> (e) = @{ @e = convert_reference (@a, REF_NORMAL); @e = convert_lvalue (@e); @}; : (a, p) -> (e) = @{ @e = make_func_exp (@a, @p, 0); @}; : (id) -> (e) = @{ @e = make_id_exp (@id); @}; : (a) -> (e) = @{ @e = make_cast_exp (type_void, @a, 0); @}; : (a, b) -> (e) = @{ @e = make_index_exp (@a, @b); @}; : (a) -> (e) = @{ @e = make_indir_exp (@a); @}; : (a) -> (e) = @{ MAKE_exp_location (type_void, crt_loc, @a, @e); @}; : (a, b) -> (e) = @{ @e = make_log_and_exp (@a, @b); @}; : (a, b) -> (e) = @{ @e = make_log_or_exp (@a, @b); @}; : (a, b) -> (e) = @{ @e = make_shift_exp (lex_lshift, @a, @b); @}; : (op, a, b) -> (e) = @{ @e = make_mult_exp (@op, @a, @b); @}; : (a, b) -> (e) = @{ @e = make_minus_exp (@a, @b); @}; : (a, b) -> (e) = @{ @e = make_mult_exp (lex_star, @a, @b); @}; : (a) -> (e) = @{ @e = make_not_exp (@a); @}; : (a, b) -> (e) = @{ @e = make_or_exp (@a, @b); @}; : () -> () = @{ IGNORE incr_value (OPT_VAL_paren_depth); @}; : (a) -> (e) = @{ @e = make_paren_exp (@a); decr_value (OPT_VAL_paren_depth); @}; : (a, b) -> (e) = @{ @e = make_plus_exp (@a, @b); @}; : (a) -> (e) = @{ @e = make_postfix_exp (lex_minus_Hminus, @a); @}; : (a) -> (e) = @{ @e = make_postfix_exp (lex_plus_Hplus, @a); @}; : (a) -> (e) = @{ @e = make_prefix_exp (lex_minus_Hminus, @a); @}; : (a) -> (e) = @{ @e = make_prefix_exp (lex_plus_Hplus, @a); @}; : (a) -> (e) = @{ @e = make_ref_exp (@a, 0); @}; : (op, a, b) -> (e) = @{ /* op will be in its primary form */ @e = make_relation_exp (@op, @a, @b); @}; : (a, b) -> (e) = @{ @e = make_rem_exp (@a, @b); @}; : (a, b) -> (e) = @{ @e = make_shift_exp (lex_rshift, @a, @b); @}; : (a) -> (e) = @{ @e = make_set_exp (@a); @}; : (op, t, a, n) -> (e) = @{ @e = make_sizeof_exp (@t, @a, @n, @op); @}; : (op, a) -> (e) = @{ @e = make_uminus_exp (@op, @a); @}; : (a) -> (e) = @{ @e = make_unused_exp (@a); @}; : (a, b) -> (e) = @{ @e = make_xor_exp (@a, @b); @}; /* * STATEMENT CONSTRUCTORS * * These actions describe how to build up statements from expressions, * declarations, and more primitive statements. The empty statement is * represented by the null expression, stmt_none. The other statement * constructors map directly onto constructor functions. */ : () -> (e) = @{ @e = NULL_exp; @}; : () -> (e) = @{ @e = make_break_stmt (); @}; : (a) -> (e) = @{ @e = begin_case_stmt (@a, 0); @}; : (a, b) -> (e) = @{ @e = end_case_stmt (@a, @b); @}; : () -> (e) = @{ @e = begin_compound_stmt (1); @}; : (a) -> () = @{ mark_compound_stmt (@a); @}; : (a) -> (b) = @{ COPY_int (exp_sequence_block (@a), 2); @b = 1; @}; : (a, b) -> (e) = @{ @e = add_compound_stmt (@a, @b); @}; : (a) -> (e) = @{ @e = end_compound_stmt (@a); @}; : () -> (e) = @{ @e = make_continue_stmt (); @}; : () -> (e) = @{ in_declaration--; @e = NULL_exp; @}; : () -> (e) = @{ @e = begin_default_stmt (0); @}; : (a, b) -> (e) = @{ @e = end_default_stmt (@a, @b); @}; : () -> (e) = @{ @e = begin_do_stmt (); @}; : (a, b, c) -> (e) = @{ @e = end_do_stmt (@a, @b, @c); @}; : (a) -> (e) = @{ @e = make_exp_stmt (@a); @}; : () -> (e) = @{ in_for_decl++; @e = begin_for_stmt (); @}; : () -> () = @{ report (crt_loc, ERR_stmt_for_decl ()); @}; : (a, b) -> (e) = @{ @e = init_for_stmt (@a, &@b); in_for_decl--; @}; : (a, b, c) -> (e) = @{ @e = cond_for_stmt (@a, @b, @c); @}; : (a, b) -> (e) = @{ @e = end_for_stmt (@a, @b); @}; : (id) -> (e) = @{ @e = make_goto_stmt (@id); @}; : (a) -> (e) = @{ report (crt_loc, ERR_stmt_goto_case (lex_case)); @e = begin_case_stmt (@a, 1); @}; : () -> (e) = @{ report (crt_loc, ERR_stmt_goto_case (lex_default)); @e = begin_default_stmt (1); @}; : (a) -> (e) = @{ @e = begin_if_stmt (@a); @}; : (a, b) -> (e) = @{ @e = cont_if_stmt (@a, @b); @}; : (a, b) -> (e) = @{ @e = end_if_stmt (@a, @b); @}; : () -> () = @{ check_empty_stmt (lex_else); @}; : () -> (e) = @{ report (crt_loc, ERR_stmt_if_no_else ()); @e = NULL_exp; @}; : (id) -> (e) = @{ @e = begin_label_stmt (@id, lex_identifier); @}; : (a, b) -> (e) = @{ @e = end_label_stmt (@a, @b); @}; : () -> () = @{ unreached_fall = 0; @}; : () -> () = @{ unreached_fall = 1; @}; : () -> () = @{ if (unreached_code) unreached_fall = 0; @}; : (a) -> (e) = @{ @e = make_return_stmt (@a, lex_return); @}; : () -> (e) = @{ @e = fall_return_stmt (); @}; : (a) -> (e) = @{ @e = begin_switch_stmt (@a); @}; : (a, b, ex) -> (e) = @{ @e = end_switch_stmt (@a, @b, @ex); @}; : (a) -> (e) = @{ @e = begin_while_stmt (@a); @}; : (a, b) -> (e) = @{ @e = end_while_stmt (@a, @b); @}; : (a, b) -> (e) = @{ @e = begin_hash_if_stmt (@a, @b); @}; : (a, b, c) -> (e) = @{ @e = cont_hash_if_stmt (@a, @b, @c); @}; : (a, b) -> (e) = @{ @e = end_hash_if_stmt (@a, @b); @}; : (a) -> (e) = @{ @e = make_reach_stmt (@a, 1); @}; : (a) -> (e) = @{ @e = make_reach_stmt (@a, 0); @}; : (a) -> (e) = @{ @e = bind_temporary (@a); @}; /* * FLOW ANALYSIS * * These actions are concerned with flow and variable analysis. */ : () -> (r) = @{ @r = unreached_code; if (@r) { if (!unreached_last) { report (crt_loc, ERR_stmt_stmt_unreach ()); unreached_last = 1; } } else { unreached_last = 0; } @}; : (r) -> () = @{ unreached_prev = @r; @}; : () -> () = @{ unreached_code = 0; @}; : () -> () = @{ unreached_code = 1; @}; : () -> (c) = @{ @c = crt_condition; @}; : (c) -> () = @{ crt_condition = @c; @}; /* * FUNCTION DEFINITIONS CONSTRUCTORS * * These actions are called at the start and the end of a function * definition. Most of the work is done by construction functions, but * the flags have_type_declaration and in_function_defn are handled * locally. */ : (d) -> (b) = @{ @b = in_class_defn; in_class_defn = 0; in_function_defn++; really_in_function_defn++; begin_function (@d); @}; : (d, a, b) -> () = @{ IGNORE end_function (@d, @a); in_class_defn = @b; in_function_defn--; really_in_function_defn--; @}; : (id) -> () = @{ func_type_defn (0); begin_param (@id); have_type_declaration = TYPE_DECL_NONE; have_func_declarator = 0; @}; : () -> () = @{ end_param (); have_type_declaration = TYPE_DECL_NONE; have_func_declarator = 1; @}; : () -> () = @{ if (option (OPT_func_id) == OPTION_ALLOW) { declare_func_id (); } @}; /* * CONST-VOLATILE QUALIFIERS * * These actions describe how to construct and combine the const and * volatile type qualifiers. The main action is cv_join which combines * two CV bitmasks by bitwise or'ing them. It also checks for * duplicate qualifiers. */ : () -> (cv) = @{ @cv = cv_none; @}; : () -> (cv) = @{ @cv = cv_const; @}; : () -> (cv) = @{ @cv = cv_restrict; @}; : () -> (cv) = @{ @cv = cv_volatile; @}; : (a, b) -> (cv) = @{ CV_SPEC c = (@a & @b); if (c) report (crt_loc, ERR_dcl_type_cv_dup (c)); @cv = (@a | @b); @}; /* * BASIC TYPES * * These actions describe the basic type specifiers, char, short, int, * and so on. This is a simple map onto the calculus type BTYPE. */ : () -> (bt) = @{ @bt = btype_char; @}; : () -> (bt) = @{ @bt = btype_short; @}; : () -> (bt) = @{ @bt = btype_int; @}; : () -> (bt) = @{ @bt = btype_long; @}; : () -> (bt) = @{ @bt = btype_signed; @}; : () -> (bt) = @{ @bt = btype_unsigned; @}; : () -> (bt) = @{ @bt = btype_float; @}; : () -> (bt) = @{ @bt = btype_double; @}; : () -> (bt) = @{ @bt = btype_bool; @}; : () -> (bt) = @{ @bt = btype_wchar_t; @}; : () -> (bt) = @{ @bt = btype_size_t; @}; : () -> (bt) = @{ @bt = btype_ptrdiff_t; @}; : () -> (bt) = @{ @bt = btype_void; @}; : () -> (bt) = @{ @bt = btype_bottom; @}; : () -> (bt) = @{ @bt = btype_none; @}; : (b1, b2) -> (bt) = @{ if (@b1 & @b2) { @bt = join_pre_types (@b1, @b2); } else { @bt = (@b1 | @b2); } @}; /* * BASIC TYPE CONSTRUCTORS * * These actions describe how to combine the basic types into real type * descriptors. The null type, type_none, is used to indicate the absence * of an optional type. A base type specifier can be transformed into a * partial type by type_pre, and a type name by type_name. Two partial * types may be combined using type_join. A partial type may be turned * into a real type by type_complete, which also checks that the resultant * type is not an inferred type (also see dspec_complete). */ : () -> (t) = @{ @t = NULL_type; @}; : () -> (t) = @{ @t = NULL_type; have_type_specifier = 1; @}; : (id) -> (t) = @{ MAKE_type_pre (cv_none, btype_alias, qual_none, @t); COPY_id (type_name (@t), @id); have_type_specifier = 1; @}; : (id, k) -> (t) = @{ MAKE_type_pre (cv_none, @k, qual_none, @t); COPY_id (type_name (@t), @id); if (have_type_declaration == TYPE_DECL_NONE) { have_type_declaration = TYPE_DECL_ELABORATE; } have_type_specifier = 1; @}; : (a, b) -> (t) = @{ /* Join two partial types */ if (IS_NULL_type (@a)) { @t = @b; } else if (IS_NULL_type (@b)) { @t = @a; } else { report (crt_loc, ERR_dcl_type_simple_many (@a, @b)); @t = @b; } @}; : (bt, t, cv) -> (c) = @{ @c = complete_pre_type (@bt, @t, @cv, 1); have_type_specifier = 0; @}; : (op, e, n) -> (t) = @{ @t = typeof_exp (&@e, @n, @op); @}; : (t) -> () = @{ object_type (@t, null_tag); @}; /* * COMPOSITE TYPE CONSTRUCTORS * * These actions describe how to build up composite types from simpler * types. Except in bitfield types, the type formed is, for example, * pointer to null type, the type being pointed to only being filled in * later by type_inject. Note that type_new_array differs from type_array * in that the bound expression does not need to be constant. */ : (cv) -> (p) = @{ MAKE_type_ptr (@cv, NULL_type, @p); @}; : (e) -> (f) = @{ @f = make_func_type (NULL_type, @e, cv_c, empty_type_set); @}; : (e) -> (f) = @{ @f = make_func_type (NULL_type, (@e | FUNC_WEAK), cv_c, empty_type_set); @}; : () -> (f) = @{ @f = make_func_type (NULL_type, FUNC_PARAMS, cv_c, empty_type_set); @}; : () -> (f) = @{ @f = make_func_type (NULL_type, FUNC_NO_PARAMS, cv_c, empty_type_set); @}; : (e) -> (a) = @{ NAT n = make_array_dim (@e); MAKE_type_array (cv_none, NULL_type, n, @a); @}; : (p, q, e) -> (a) = @{ @a = make_bitfield_type (@p, @q, @e, 0); @}; : (p, q, e, id) -> (a) = @{ /* Check for anonymous bitfields */ HASHID nm = DEREF_hashid (id_name (@id)); int z = IS_hashid_anon (nm); @a = make_bitfield_type (@p, @q, @e, z); @}; : (p, t) -> (c) = @{ @c = (IS_NULL_type (@p) ? @t: inject_pre_type (@p, @t, 1)); @}; : (p, t) -> (c) = @{ @c = (IS_NULL_type (@p) ? @t: inject_pre_type (@p, @t, 0)); @}; /* * CLASS KEYS * * These actions describe the class key qualifiers, class, struct, union * and enum. These are representing by the corresponding lexical token * numbers. */ : () -> (key) = @{ @key = btype_struct; @}; : () -> (key) = @{ @key = btype_union; @}; : () -> (key) = @{ @key = btype_enum; @}; /* * CLASS AND ENUMERATION TYPE CONSTRUCTORS * * These actions describe how to build up class and enumeration types. * They also include the elaborated type specifiers. Note that the value * of have_type_declaration is set according to the declaration processed. */ : (id, k) -> (t, b) = @{ @t = begin_class_defn (@id, @k, cinfo_none, NULL_type); @b = in_function_defn; in_function_defn = 0; in_class_defn++; really_in_class_defn++; no_type_defns++; end_base_class (crt_class, 1); @}; : (p, b) -> (t) = @{ @t = end_class_defn (@p); in_function_defn = @b; in_class_defn--; really_in_class_defn--; @}; : (id) -> (t) = @{ @t = begin_enum_defn (@id, NULL_type); no_type_defns++; @}; : (p) -> (t) = @{ @t = end_enum_defn (@p); @}; /* * DECLARATION SPECIFIERS * * These actions describe how to construct and combine declaration * specifiers. These include the storage class specifiers, the function * specifiers, friend and typedef. The action dspec_join combines two * declaration specifiers by bitwise or'ing them and checking for * duplications. The action dspec_complete is analogous to tspec_complete * but also checks any associated declaration specifiers. It also does * not check for inferred types. */ : () -> (ds) = @{ @ds = dspec_none; @}; : () -> (ds) = @{ @ds = dspec_auto; @}; : () -> (ds) = @{ @ds = dspec_register; @}; : () -> (ds) = @{ @ds = dspec_static; @}; : () -> (ds) = @{ @ds = dspec_extern; @}; : () -> (ds) = @{ @ds = dspec_typedef; @}; : () -> (ds) = @{ @ds = dspec_inline; @}; : (a, b) -> (ds) = @{ /* Combine two declaration specifiers */ DECL_SPEC d = ((@a & @b) & dspec_duplicate); /* Duplicate inline is allowed */ if (d & ~dspec_inline) report (crt_loc, ERR_dcl_spec_dup (d)); @ds = (@a | @b); @}; : (ds) -> () = @{ if (have_type_specifier) report (crt_loc, ERR_dcl_spec_order (@ds)); @}; : (bt, t, cv, ds) -> (c, d) = @{ /* Complete a declaration specifier and a type */ @d = complete_dspec (@ds, @bt, @t, @cv); @c = complete_pre_type (@bt, @t, @cv, 0); have_type_specifier = 0; @}; /* * OBJECT DECLARATIONS * * These actions describe how to construct an object declaration. */ : (ds, bt, t, id) -> (d) = @{ if (in_weak_param) { @d = make_param_decl (@ds, @t, @id, CONTEXT_WEAK_PARAM); } else if (type_tag (@t) == type_func_tag) { check_weak_func (@t, 0); @d = make_func_decl (@ds, @t, @id, 0); } else { int def = predict_obj_defn (); @d = make_object_decl (@ds, @t, @id, def); } if (IS_id_type_alias (@d)) { BASE_TYPE bs = DEREF_btype (id_type_alias_rep (@d)); bs |= @bt; COPY_btype (id_type_alias_rep (@d), bs); } have_type_declaration = TYPE_DECL_NONE; have_func_declarator = 0; @}; : (ds, t, id) -> (d) = @{ @d = make_func_decl (@ds, @t, @id, 1); have_type_declaration = TYPE_DECL_NONE; have_func_declarator = 0; @}; : (ds, bt, t, cv) -> () = @{ IGNORE empty_decl (@ds, NULL_type, @bt, @t, @cv, last_lex_token, 0); have_type_declaration = TYPE_DECL_NONE; have_func_declarator = 0; have_type_specifier = 0; @}; : () -> () = @{ report (crt_loc, ERR_dcl_dcl_semicolon ()); @}; : (ds, t, id) -> (d) = @{ @d = make_param_decl (@ds, @t, @id, CONTEXT_PARAMETER); have_type_declaration = TYPE_DECL_NONE; have_func_declarator = 0; @}; : (id) -> () = @{ IGNORE weak_param_decl (@id); have_type_declaration = TYPE_DECL_NONE; have_func_declarator = 0; @}; : (t, id) -> () = @{ IDENTIFIER id = make_member_decl (dspec_none, @t, @id, 0); if (do_dump) dump_declare (id, &decl_loc, 0); have_type_declaration = TYPE_DECL_NONE; have_func_declarator = 0; @}; : (bt, t, cv) -> () = @{ IGNORE empty_decl (dspec_none, NULL_type, @bt, @t, @cv, last_lex_token, 1); have_type_declaration = TYPE_DECL_NONE; have_func_declarator = 0; have_type_specifier = 0; @}; : (t, id) -> () = @{ IDENTIFIER id = make_member_decl (dspec_none, @t, @id, 0); if (do_dump) dump_declare (id, &decl_loc, 0); have_type_declaration = TYPE_DECL_NONE; have_func_declarator = 0; @}; : (t, id, e) -> () = @{ IGNORE make_enumerator (@t, @id, @e); @}; : (id) -> () = @{ IDENTIFIER pid = underlying_id (@id); DEREF_loc (id_loc (pid), decl_loc); @}; : (t) -> () = @{ if (IS_NULL_type (@t)) { report (crt_loc, ERR_dcl_meaning_paren ()); } @}; : (id) -> () = @{ report (crt_loc, ERR_dcl_fct_par_typedef (@id)); @}; : (e) -> () = @{ external_declaration (@e, 1); @}; : () -> (d) = @{ @d = NULL_id; @}; /* * INITIALISERS * * These actions describe the object initialisers. The main action is * initialise_id which initialises d to e (which can be the null * expression). The action initialiser_bad is used to weed out badly * placed function style initialisers caused by their inclusion in the * declarators. */ : (d, e) -> () = @{ int def = init_object (@d, @e); if (do_dump) dump_declare (@d, &decl_loc, def); @}; /* * OFFSETS * * These actions describe the constant offset expressions. */ : (t) -> (ns) = @{ @ns = offset_nspace (@t); @}; : (b, s, id, ns) -> (a, t) = @{ OFFSET off = offset_member (@s, @id, &@t, @ns, 1); @a = offset_add (@b, off); @}; : (b, s, e) -> (a, t) = @{ OFFSET off = offset_index (@s, @e, &@t); @a = offset_add (@b, off); @}; /* * OTHER DECLARATIONS * * These actions describe the declarations not covered above. */ : (a, p) -> (e) = @{ @e = make_asm (@a, @p); @}; : (a) -> () = @{ target_decl (lex_if, @a); @}; : (a) -> () = @{ target_decl (lex_elif, @a); @}; : () -> () = @{ target_decl (lex_else, NULL_exp); @}; : () -> () = @{ target_decl (lex_endif, NULL_exp); @}; : (a) -> (c) = @{ EXP c = crt_hash_cond; crt_hash_cond = make_if_cond (@a, c); @c = c; @}; : (a) -> () = @{ EXP c = make_else_cond (crt_hash_cond); crt_hash_cond = make_if_cond (@a, c); @}; : () -> () = @{ crt_hash_cond = make_else_cond (crt_hash_cond); @}; : (a) -> () = @{ crt_hash_cond = @a; @}; /* * ERROR REPORTING * * These actions describe the error reporting functions for syntax errors * and for weeding out extra constructs which have been allowed in the * grammar to permit for better error reporting. */ : () -> () = @{ /* Unrecoverable syntax errors */ ERROR err = ERR_lex_parse (crt_token); err = concat_error (err, ERR_lex_abort ()); report (crt_loc, err); have_syntax_error = 1; @}; : () -> () = @{ /* Syntax errors */ ERROR err = ERR_lex_parse (crt_token); report (crt_loc, err); have_syntax_error = 1; @}; : () -> () = @{ /* Extra comma at the end of a list */ report (crt_loc, ERR_lex_extra_comma ()); @}; : (t) -> () = @{ /* Expected symbol */ int p = primary_form (crt_lex_token); if (p != @t) report (crt_loc, ERR_lex_expect (@t)); @}; /* * PARSER COUNTERS * * These actions correspond to the various parser counters defined in * predict.c. For example no_side_effects gives the total number of side * effects encountered, while diff_side_effects gives the number defined * since a previous call of no_side_effects. */ : () -> (n) = @{ @n = no_side_effects; @}; : () -> (n) = @{ @n = no_type_defns; @}; : (m) -> (n) = @{ @n = no_side_effects - @m; @}; : (m) -> (n) = @{ @n = no_type_defns - @m; @}; : () -> () = @{ suppress_usage++; @}; : () -> () = @{ suppress_usage--; @}; /* * PREDICATE LITERALS * * These actions give the basic values, true and false, for the type * BOOL. */ : () -> (b) = @{ @b = 0; @}; : () -> (b) = @{ @b = 1; @}; /* * PARSER PREDICATES * * In several places the parser needs some help in order to resolve * ambiguities by means of look-ahead etc. This help is provided by * means of the following predicates. See predict.c for more details. */ : (t) -> (b) = @{ @b = function_params (@t); @}; : () -> (b) = @{ /* Resolve declaration-specifiers from other declarators */ @b = predict_dspec (0); @}; : (d) -> (b) = @{ /* Resolve declaration-statements from expression-statements */ int b = predict_decl (); if (b) { if (!@d) report (crt_loc, ERR_stmt_dcl_start ()); in_declaration++; } @b = b; @}; : () -> (b) = @{ /* Resolve type-ids from expressions */ @b = predict_typeid (0); @}; : () -> (b) = @{ /* Resolve type-ids from expressions */ @b = predict_typeid (1); @}; : () -> (b) = @{ /* Resolve type-specifiers from other declarators */ @b = predict_tspec (0); @}; : () -> (b) = @{ /* Resolve parameter declarators from type names */ @b = predict_param (); @}; /* * PARSER HACKS AND PATCHES * * In a couple of places it is necessary to fool the parser by changing * the next token (or even inserting an extra token) depending on the * current state. */ : () -> () = @{ RESCAN_LEXER; @}; : () -> () = @{ /* A type-name can be a declarator-id */ if (have_type_specifier && crt_lex_token == lex_type_Hname) { crt_lex_token = lex_identifier; } @}; /* * FILE TRAILERS * * These trailers are appended to the parser definition and declaration * output files. */ %trailer% @{ @}, @{ /* * DUMMY LEXICAL TOKEN VALUES * * These values are used as lexical token values in certain circumstances * but do not represent actual tokens. Note that they are all negative. */ #define lex_ignore_token -1 #define lex_end_condition -2 #define lex_included -3 #define lex_placemarker -4 #endif @};