/*
* 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, 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.
*
* $TenDRA: tendra/src/producers/cpp/syntax/syntax.act,v 1.6 2005/10/14 09:52:19 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.
*/
ACCESS -> DECL_SPEC;
ACCESSES -> ACCESS_LIST;
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;
LINKAGE -> DECL_SPEC;
LIST-EXP -> SID_LIST_EXP;
LIST-TYPE -> SID_LIST_TYPE;
NAMESPACE -> NAMESPACE;
NUMBER -> int;
OFFSET -> OFFSET;
QUALIFIER -> QUALIFIER;
TEMPLATE -> TOKEN;
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 "ctype_ops.h"
#include "exp_ops.h"
#include "hashid_ops.h"
#include "id_ops.h"
#include "nspace_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;
typedef LIST (TYPE) SID_LIST_TYPE;
/*
* 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);
crt_templ_qualifier = 1;
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);
crt_templ_qualifier = 1;
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_close_Hround; @};
: () -> (t) = @{ @t = lex_close_Hsquare_H1; @};
: () -> (t) = @{ @t = lex_colon; @};
: () -> (t) = @{ @t = lex_cond_Hop; @};
: () -> (t) = @{ @t = lex_open_Hround; @};
: () -> (t) = @{ @t = lex_semicolon; @};
: () -> (t) = @{ @t = lex_alignof; @};
: () -> (t) = @{ @t = lex_array_Hop; @};
: () -> (t) = @{ @t = lex_func_Hop; @};
: () -> (t) = @{ @t = lex_new; @};
: () -> (t) = @{ @t = lex_delete; @};
: () -> (t) = @{ @t = lex_new_Harray; @};
: () -> (t) = @{ @t = lex_delete_Harray; @};
: () -> (t) = @{ @t = lex_sizeof; @};
: () -> (t) = @{ @t = lex_typeid; @};
: () -> (t) = @{ @t = lex_vtable; @};
/*
* 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.
*/
: () -> (td) = @{
@td = have_type_declaration;
have_type_declaration = TYPE_DECL_NONE;
@};
: (td) -> (d) = @{
int td = have_type_declaration;
@d = 0;
if (td != TYPE_DECL_NONE) {
if (td == TYPE_DECL_ELABORATE && found_elaborate_type) {
/* This is allowed */
/* EMPTY */
} else {
@d = 1;
}
}
have_type_declaration = @td;
@};
: (td) -> () = @{
have_type_declaration = @td;
@};
: (op) -> (id) = @{
/* op will be in its primary form */
HASHID nm = lookup_op (@op);
@id = DEREF_id (hashid_id (nm));
set_hashid_loc (@id, underlying_op);
@};
: (t, d) -> (id) = @{
HASHID nm = lookup_conv (@t);
if (@d) report (crt_loc, ERR_class_conv_fct_typedef (nm));
@id = DEREF_id (hashid_id (nm));
set_hashid_loc (@id, underlying_op);
@};
: (t1, b1, t2, b2) -> (id) = @{
@id = make_pseudo_destr (@t1, @b1, @t2, @b2);
@};
: () -> (id) = @{
@id = NULL_id;
crt_id_qualifier = qual_none;
qual_namespace = NULL_nspace;
@};
: () -> (id) = @{
HASHID nm = lookup_anon ();
@id = DEREF_id (hashid_id (nm));
crt_id_qualifier = qual_none;
qual_namespace = NULL_nspace;
@};
/*
* NAMESPACES AND IDENTIFIER LOOK-UP
*
* These actions are used to identify namespaces and identifiers within
* those namespaces.
*/
: () -> (ns) = @{
@ns = NULL_nspace;
crt_id_qualifier = qual_none;
qual_namespace = NULL_nspace;
@};
: () -> (ns) = @{
@ns = global_namespace;
crt_id_qualifier = qual_top;
qual_namespace = @ns;
@};
: (ns) -> () = @{
crt_id_qualifier = qual_nested;
qual_namespace = @ns;
@};
: (ns) -> () = @{
crt_id_qualifier = qual_full;
qual_namespace = @ns;
@};
: (ns, id) -> (n) = @{
@n = check_id (@ns, @id, 0);
last_namespace = @ns;
@};
: (id) -> (n) = @{
@n = @id;
crt_id_qualifier = qual_none;
last_namespace = crt_namespace;
@};
: (id) -> (n) = @{
@n = check_id (NULL_nspace, @id, 0);
crt_id_qualifier = qual_none;
last_namespace = crt_namespace;
@};
: (ns, id, q) -> (n) = @{
@n = check_id (@ns, @id, @q);
last_namespace = @ns;
@};
: (ns) -> (id) = @{
@id = DEREF_id (nspace_name (@ns));
@};
/*
* IDENTIFIER QUALIFIERS
*
* These actions are used to set crt_id_qualifier to the qualifier of an
* identifier.
*/
: () -> (i, b) = @{
@i = crt_id_qualifier;
@b = crt_templ_qualifier;
@};
: (i, b) -> () = @{
crt_id_qualifier = @i;
crt_templ_qualifier = @b;
@};
: () -> () = @{
crt_id_qualifier = qual_none;
crt_templ_qualifier = 0;
qual_namespace = NULL_nspace;
@};
/*
* 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, q) -> (e) = @{
@e = end_field_exp (lex_arrow, @a, @t, @ns, @id, @q);
@};
: (a, b) -> (e) = @{
@e = make_member_exp (lex_arrow_Hstar, @a, @b);
in_ptr_mem_selector--;
@};
: (a, b) -> (e) = @{
@e = make_assign_exp (@a, @b, 0);
@};
: (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);
@};
: (t, a, n) -> (e) = @{
/* n is the number of type definitions in t */
@e = make_const_cast_exp (@t, @a, @n);
@};
: (b, op, a) -> (e) = @{
@e = make_delete_exp (@op, @b, @a);
@};
: (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, q) -> (e) = @{
@e = end_field_exp (lex_dot, @a, @t, @ns, @id, @q);
@};
: (a, b) -> (e) = @{
@e = make_member_exp (lex_dot_Hstar, @a, @b);
in_ptr_mem_selector--;
@};
: (t, a, n) -> (e) = @{
/* n is the number of type definitions in t */
@e = make_dynamic_cast_exp (@t, @a, @n);
@};
: () -> (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);
@};
: () -> (e) = @{
@e = make_bool_exp (BOOL_FALSE, exp_int_lit_tag);
@};
: (a, p) -> (e) = @{
@e = make_func_exp (@a, @p, 0);
@};
: (t, p) -> (e) = @{
@e = make_func_cast_exp (@t, @p);
@};
: (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);
@};
: (p) -> (e) = @{
MAKE_exp_initialiser (type_void, @p, NULL_list (OFFSET), 0, 0, 0, @e);
@};
: (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);
@};
: (b, p, t, n, d, i) -> (e) = @{
@e = make_new_exp (@t, @n + @d, @b, @p, @i);
@};
: (t, p) -> (e) = @{
@e = make_new_init (@t, @p, 1);
@};
: (t) -> (e) = @{
@e = make_new_init (@t, NULL_list (EXP), 0);
@};
: () -> (e) = @{
@e = begin_new_try ();
@};
: (a, b) -> (e) = @{
@e = end_new_try (@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);
@};
: () -> () = @{
in_ptr_mem_selector++;
@};
: (a) -> (e) = @{
@e = make_ref_exp (@a, 0);
@};
: (t, a, n) -> (e) = @{
/* n is the number of type definitions in t */
@e = make_reinterp_cast_exp (@t, @a, @n);
@};
: (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);
@};
: (t, a, n) -> (e) = @{
@e = make_static_cast_exp (@t, @a, @n);
@};
: () -> (e) = @{
@e = make_this_exp ();
@};
: (a) -> (e) = @{
@e = make_throw_exp (@a, 1);
@};
: (t, n) -> (e) = @{
@e = make_throw_arg (@t, @n);
@};
: () -> (e) = @{
@e = make_bool_exp (BOOL_TRUE, exp_int_lit_tag);
@};
: (a, op, n) -> (e) = @{
@e = make_typeid_exp (@op, @a, @n);
@};
: (t, op, n) -> (e) = @{
@e = make_typeid_type (@op, @t, @n);
@};
: (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);
@};
: (a, d) -> (e) = @{
@e = begin_catch_stmt (@a, @d);
@};
: (a, b) -> () = @{
IGNORE end_catch_stmt (@a, @b);
@};
: () -> (e) = @{
MAKE_exp_thrown (type_void, 1, @e);
@};
: () -> (e) = @{
@e = begin_compound_stmt (1);
@};
: (a) -> () = @{
COPY_int (exp_sequence_block (@a), 2);
@};
: (a) -> () = @{
mark_compound_stmt (@a);
@};
: (a, b) -> (e) = @{
@e = add_compound_stmt (@a, @b);
@};
: (a) -> (e) = @{
@e = end_compound_stmt (@a);
@};
: () -> (e) = @{
@e = make_continue_stmt ();
@};
: (a) -> (e) = @{
@e = @a;
in_declaration--;
@};
: () -> (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) = @{
@e = begin_for_stmt ();
@};
: (a, b) -> (e) = @{
@e = init_for_stmt (@a, &@b);
@};
: (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);
@};
: (a) -> (e) = @{
@e = begin_switch_stmt (@a);
@};
: (a, b, ex) -> (e) = @{
@e = end_switch_stmt (@a, @b, @ex);
@};
: () -> (e) = @{
@e = begin_try_stmt (0);
@};
: () -> (e) = @{
@e = begin_try_stmt (1);
@};
: (a) -> () = @{
inject_try_stmt (@a);
@};
: (a, b) -> (e) = @{
@e = cont_try_stmt (@a, @b);
@};
: (a) -> (e) = @{
@e = end_try_stmt (@a, 0);
@};
: (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);
@};
: () -> () = @{
begin_cond ();
@};
: () -> (e) = @{
@e = end_cond ();
in_declaration--;
@};
: (s) -> (t) = @{
@t = make_cond_type (@s);
@};
: (a, b) -> (e) = @{
@e = inject_cond (@a, @b);
@};
: (a, b) -> (e) = @{
@e = inject_cond (@a, @b);
@};
: (a, b) -> (e) = @{
@e = inject_cond (@a, @b);
@};
/*
* 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--;
@};
: (d) -> () = @{
skip_function (@d);
@};
: (d) -> (e) = @{
@e = skip_default_arg (@d);
@};
: () -> (d) = @{
@d = NULL_id;
@};
: () -> (ns) = @{
@ns = ctor_begin ();
@};
: (ns, c, b) -> (e) = @{
@e = ctor_end (@ns, @c, @b);
@};
: (ns, id, e) -> () = @{
ctor_initialise (@ns, @id, @e);
@};
: (c) -> (e, d) = @{
@d = NULL_exp;
@e = ctor_none (@c, &@d);
@};
: (a, b) -> (e) = @{
@e = ctor_postlude (@a, @b);
@};
: (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;
@};
/*
* 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, crt_id_qualifier, @t);
COPY_id (type_name (@t), @id);
have_type_specifier = 1;
@};
: (id, k) -> (t) = @{
MAKE_type_pre (cv_none, @k, crt_id_qualifier, @t);
COPY_id (type_name (@t), @id);
if (have_type_declaration == TYPE_DECL_NONE) {
have_type_declaration = TYPE_DECL_ELABORATE;
}
have_type_specifier = 1;
@};
: (ns, id) -> (t) = @{
@t = make_typename (@ns, @id);
if (have_type_declaration == TYPE_DECL_NONE) {
have_type_declaration = TYPE_DECL_ELABORATE;
found_elaborate_type = 1;
}
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);
@};
: (cv) -> (p) = @{
/* Can't have const-volatile qualified references */
if (@cv) report (crt_loc, ERR_dcl_ref_cv (@cv));
MAKE_type_ref (cv_none, NULL_type, @p);
@};
: (id, cv) -> (p) = @{
CLASS_TYPE ct = find_class (@id);
if (IS_NULL_ctype (ct)) {
report (crt_loc, ERR_dcl_mptr_type (@id));
MAKE_type_ptr (@cv, NULL_type, @p);
} else {
MAKE_type_ptr_mem (@cv, ct, NULL_type, @p);
}
@};
: (e, w, cv, ex) -> (f) = @{
CV_SPEC cv = func_linkage (@cv);
if (@w) @e |= FUNC_WEAK;
@f = make_func_type (NULL_type, @e, cv, @ex);
@};
: (e) -> (a) = @{
NAT n = make_array_dim (@e);
MAKE_type_array (cv_none, NULL_type, n, @a);
@};
: (e) -> (a) = @{
/* First array bound in a new-declarator */
NAT n = make_new_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));
@};
/*
* LISTS OF TYPES
*
* These actions give the basic constructs for building up lists of
* types. They map directly to the calculus list operations.
*/
: () -> (p) = @{
@p = NULL_list (TYPE);
@};
: (t, q) -> (p) = @{
@p = cons_type_set (@q, @t);
@};
: () -> (p) = @{
@p = empty_type_set;
@};
: () -> (p) = @{
report (crt_loc, ERR_except_spec_ellipsis ());
@p = univ_type_set;
@};
/*
* 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_class; @};
: () -> (key) = @{ @key = btype_struct; @};
: () -> (key) = @{ @key = btype_union; @};
: () -> (key) = @{ @key = btype_enum; @};
/*
* ACCESS SPECIFIERS
*
* These actions describe the access specifiers, private, protected and
* public. Each access specifier is represented by the corresponding
* lexical token number. The current access specifier is held in the
* crt_access variable, which is initialised in begin_class_defn.
*/
: () -> (a) = @{ @a = dspec_private; @};
: () -> (a) = @{ @a = dspec_protected; @};
: () -> (a) = @{ @a = dspec_public; @};
: () -> (a) = @{ @a = dspec_none; @};
: () -> (a) = @{ @a = crt_access; @};
: (a) -> () = @{ crt_access = @a; @};
: () -> () = @{
if (crt_access_list.pending) {
IGNORE report_access (crt_func_id);
}
@};
: () -> () = @{
if (crt_access_list.pending) {
IDENTIFIER id = DEREF_id (ctype_name (crt_class));
IGNORE report_access (id);
}
@};
: (d) -> () = @{
if (crt_access_list.pending) {
IGNORE report_access (@d);
}
@};
: (d, r) -> () = @{
IGNORE clear_access (@d, &@r);
@};
: () -> (r) = @{
save_access (&@r);
@};
: (r) -> () = @{
free_access (&@r);
@};
/*
* 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, q) -> (t, b) = @{
IDENTIFIER id = constr_name (last_namespace, @id);
@t = begin_class_defn (id, @k, cinfo_none, @q);
@b = in_function_defn;
in_function_defn = 0;
in_class_defn++;
really_in_class_defn++;
no_type_defns++;
@};
: (p, b) -> (t) = @{
@t = end_class_defn (@p);
in_function_defn = @b;
in_class_defn--;
really_in_class_defn--;
@};
: (id, a, v) -> () = @{
add_base_class (@id, @a, @v);
@};
: (t) -> () = @{
end_base_class (crt_class, @t);
@};
: (id, q) -> (t) = @{
IDENTIFIER id = constr_name (last_namespace, @id);
@t = begin_enum_defn (id, @q);
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; @};