/*
* 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
@};