Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed
%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 "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.
*/
<lex_crt> : () -> ( t ) = @{ @t = crt_lex_token ; @} ;
<lex_open_round> : () -> ( t ) = @{ @t = lex_open_Hround ; @} ;
<lex_semicolon> : () -> ( t ) = @{ @t = lex_semicolon ; @} ;
<lex_alignof> : () -> ( t ) = @{ @t = lex_alignof ; @} ;
<lex_sizeof> : () -> ( 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_none> : () -> ( id ) = @{
@id = NULL_id ;
@} ;
<id_anon> : () -> ( 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.
*/
<rescan_member> : ( 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.
*/
<list_exp_null> : () -> ( p ) = @{
@p = NULL_list ( EXP ) ;
@} ;
<list_exp_cons> : ( 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.
*/
<exp_none> : () -> ( e ) = @{
@e = NULL_exp ;
@} ;
<exp_aggregate> : ( p ) -> ( e ) = @{
/* The expression type is a dummy */
MAKE_exp_aggregate ( type_void, @p, NULL_list ( OFFSET ), @e ) ;
@} ;
<exp_and> : ( a, b ) -> ( e ) = @{
@e = make_and_exp ( @a, @b ) ;
@} ;
<exp_arrow_begin> : ( a ) -> ( e, t, ns ) = @{
@e = begin_field_exp ( lex_arrow, @a, &@t, &@ns ) ;
@} ;
<exp_arrow_end> : ( a, t, ns, id ) -> ( e ) = @{
@e = end_field_exp ( lex_arrow, @a, @t, @ns, @id, 0 ) ;
@} ;
<exp_assign> : ( a, b ) -> ( e ) = @{
@e = make_assign_exp ( @a, @b, 1 ) ;
@} ;
<exp_assign_op> : ( op, a, b ) -> ( e ) = @{
/* op will be in its primary form */
@e = make_become_exp ( @op, @a, @b ) ;
@} ;
<exp_cast> : ( t, a, n ) -> ( e ) = @{
/* n is the number of type definitions in t */
@e = make_cast_exp ( @t, @a, @n ) ;
@} ;
<exp_comma> : ( p ) -> ( e ) = @{
@e = make_comma_exp ( @p ) ;
@} ;
<exp_cond> : ( a, b, c ) -> ( e ) = @{
@e = make_cond_exp ( @a, @b, @c ) ;
@} ;
<exp_div> : ( a, b ) -> ( e ) = @{
@e = make_mult_exp ( lex_div, @a, @b ) ;
@} ;
<exp_dot_begin> : ( a ) -> ( e, t, ns ) = @{
@e = begin_field_exp ( lex_dot, @a, &@t, &@ns ) ;
@} ;
<exp_dot_end> : ( a, t, ns, id ) -> ( e ) = @{
@e = end_field_exp ( lex_dot, @a, @t, @ns, @id, 0 ) ;
@} ;
<exp_ellipsis> : () -> ( e ) = @{
@e = make_ellipsis_exp () ;
@} ;
<exp_equality> : ( op, a, b ) -> ( e ) = @{
/* op will be in its primary form */
@e = make_equality_exp ( @op, @a, @b ) ;
@} ;
<exp_eval> : ( a ) -> ( e ) = @{
@e = convert_reference ( @a, REF_NORMAL ) ;
@e = convert_lvalue ( @e ) ;
@} ;
<exp_func> : ( a, p ) -> ( e ) = @{
@e = make_func_exp ( @a, @p, 0 ) ;
@} ;
<exp_identifier> : ( id ) -> ( e ) = @{
@e = make_id_exp ( @id ) ;
@} ;
<exp_ignore> : ( a ) -> ( e ) = @{
@e = make_cast_exp ( type_void, @a, 0 ) ;
@} ;
<exp_index> : ( a, b ) -> ( e ) = @{
@e = make_index_exp ( @a, @b ) ;
@} ;
<exp_indir> : ( a ) -> ( e ) = @{
@e = make_indir_exp ( @a ) ;
@} ;
<exp_location> : ( a ) -> ( e ) = @{
MAKE_exp_location ( type_void, crt_loc, @a, @e ) ;
@} ;
<exp_log_and> : ( a, b ) -> ( e ) = @{
@e = make_log_and_exp ( @a, @b ) ;
@} ;
<exp_log_or> : ( a, b ) -> ( e ) = @{
@e = make_log_or_exp ( @a, @b ) ;
@} ;
<exp_lshift> : ( a, b ) -> ( e ) = @{
@e = make_shift_exp ( lex_lshift, @a, @b ) ;
@} ;
<exp_maxmin> : ( op, a, b ) -> ( e ) = @{
@e = make_mult_exp ( @op, @a, @b ) ;
@} ;
<exp_minus> : ( a, b ) -> ( e ) = @{
@e = make_minus_exp ( @a, @b ) ;
@} ;
<exp_mult> : ( a, b ) -> ( e ) = @{
@e = make_mult_exp ( lex_star, @a, @b ) ;
@} ;
<exp_not> : ( a ) -> ( e ) = @{
@e = make_not_exp ( @a ) ;
@} ;
<exp_or> : ( a, b ) -> ( e ) = @{
@e = make_or_exp ( @a, @b ) ;
@} ;
<exp_paren_begin> : () -> () = @{
IGNORE incr_value ( OPT_VAL_paren_depth ) ;
@} ;
<exp_paren_end> : ( a ) -> ( e ) = @{
@e = make_paren_exp ( @a ) ;
decr_value ( OPT_VAL_paren_depth ) ;
@} ;
<exp_plus> : ( a, b ) -> ( e ) = @{
@e = make_plus_exp ( @a, @b ) ;
@} ;
<exp_postdec> : ( a ) -> ( e ) = @{
@e = make_postfix_exp ( lex_minus_Hminus, @a ) ;
@} ;
<exp_postinc> : ( a ) -> ( e ) = @{
@e = make_postfix_exp ( lex_plus_Hplus, @a ) ;
@} ;
<exp_predec> : ( a ) -> ( e ) = @{
@e = make_prefix_exp ( lex_minus_Hminus, @a ) ;
@} ;
<exp_preinc> : ( a ) -> ( e ) = @{
@e = make_prefix_exp ( lex_plus_Hplus, @a ) ;
@} ;
<exp_ref> : ( a ) -> ( e ) = @{
@e = make_ref_exp ( @a, 0 ) ;
@} ;
<exp_relation> : ( op, a, b ) -> ( e ) = @{
/* op will be in its primary form */
@e = make_relation_exp ( @op, @a, @b ) ;
@} ;
<exp_rem> : ( a, b ) -> ( e ) = @{
@e = make_rem_exp ( @a, @b ) ;
@} ;
<exp_rshift> : ( a, b ) -> ( e ) = @{
@e = make_shift_exp ( lex_rshift, @a, @b ) ;
@} ;
<exp_set> : ( a ) -> ( e ) = @{
@e = make_set_exp ( @a ) ;
@} ;
<exp_sizeof> : ( op, t, a, n ) -> ( e ) = @{
@e = make_sizeof_exp ( @t, @a, @n, @op ) ;
@} ;
<exp_unary> : ( op, a ) -> ( e ) = @{
@e = make_uminus_exp ( @op, @a ) ;
@} ;
<exp_unused> : ( a ) -> ( e ) = @{
@e = make_unused_exp ( @a ) ;
@} ;
<exp_xor> : ( 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.
*/
<stmt_none> : () -> ( e ) = @{
@e = NULL_exp ;
@} ;
<stmt_break> : () -> ( e ) = @{
@e = make_break_stmt () ;
@} ;
<stmt_case_begin> : ( a ) -> ( e ) = @{
@e = begin_case_stmt ( @a, 0 ) ;
@} ;
<stmt_case_end> : ( a, b ) -> ( e ) = @{
@e = end_case_stmt ( @a, @b ) ;
@} ;
<stmt_compound_begin> : () -> ( e ) = @{
@e = begin_compound_stmt ( 1 ) ;
@} ;
<stmt_compound_mark> : ( a ) -> () = @{
mark_compound_stmt ( @a ) ;
@} ;
<stmt_compound_block> : ( a ) -> ( b ) = @{
COPY_int ( exp_sequence_block ( @a ), 2 ) ;
@b = 1 ;
@} ;
<stmt_compound_add> : ( a, b ) -> ( e ) = @{
@e = add_compound_stmt ( @a, @b ) ;
@} ;
<stmt_compound_end> : ( a ) -> ( e ) = @{
@e = end_compound_stmt ( @a ) ;
@} ;
<stmt_continue> : () -> ( e ) = @{
@e = make_continue_stmt () ;
@} ;
<stmt_decl> : () -> ( e ) = @{
in_declaration-- ;
@e = NULL_exp ;
@} ;
<stmt_default_begin> : () -> ( e ) = @{
@e = begin_default_stmt ( 0 ) ;
@} ;
<stmt_default_end> : ( a, b ) -> ( e ) = @{
@e = end_default_stmt ( @a, @b ) ;
@} ;
<stmt_do_begin> : () -> ( e ) = @{
@e = begin_do_stmt () ;
@} ;
<stmt_do_end> : ( a, b, c ) -> ( e ) = @{
@e = end_do_stmt ( @a, @b, @c ) ;
@} ;
<stmt_exp> : ( a ) -> ( e ) = @{
@e = make_exp_stmt ( @a ) ;
@} ;
<stmt_for_begin> : () -> ( e ) = @{
@e = begin_for_stmt () ;
@} ;
<stmt_for_init> : ( a, b ) -> ( e ) = @{
@e = init_for_stmt ( @a, &@b ) ;
@} ;
<stmt_for_cond> : ( a, b, c ) -> ( e ) = @{
@e = cond_for_stmt ( @a, @b, @c ) ;
@} ;
<stmt_for_end> : ( a, b ) -> ( e ) = @{
@e = end_for_stmt ( @a, @b ) ;
@} ;
<stmt_goto> : ( id ) -> ( e ) = @{
@e = make_goto_stmt ( @id ) ;
@} ;
<stmt_goto_case> : ( a ) -> ( e ) = @{
report ( crt_loc, ERR_stmt_goto_case ( lex_case ) ) ;
@e = begin_case_stmt ( @a, 1 ) ;
@} ;
<stmt_goto_default> : () -> ( e ) = @{
report ( crt_loc, ERR_stmt_goto_case ( lex_default ) ) ;
@e = begin_default_stmt ( 1 ) ;
@} ;
<stmt_if_begin> : ( a ) -> ( e ) = @{
@e = begin_if_stmt ( @a ) ;
@} ;
<stmt_if_cont> : ( a, b ) -> ( e ) = @{
@e = cont_if_stmt ( @a, @b ) ;
@} ;
<stmt_if_end> : ( a, b ) -> ( e ) = @{
@e = end_if_stmt ( @a, @b ) ;
@} ;
<stmt_else> : () -> () = @{
check_empty_stmt ( lex_else ) ;
@} ;
<stmt_no_else> : () -> ( e ) = @{
report ( crt_loc, ERR_stmt_if_no_else () ) ;
@e = NULL_exp ;
@} ;
<stmt_label_begin> : ( id ) -> ( e ) = @{
@e = begin_label_stmt ( @id, lex_identifier ) ;
@} ;
<stmt_label_end> : ( a, b ) -> ( e ) = @{
@e = end_label_stmt ( @a, @b ) ;
@} ;
<stmt_label_set> : () -> () = @{
unreached_fall = 0 ;
@} ;
<stmt_label_clear> : () -> () = @{
unreached_fall = 1 ;
@} ;
<stmt_label_mod> : () -> () = @{
if ( unreached_code ) unreached_fall = 0 ;
@} ;
<stmt_return> : ( a ) -> ( e ) = @{
@e = make_return_stmt ( @a, lex_return ) ;
@} ;
<stmt_return_fall> : () -> ( e ) = @{
@e = fall_return_stmt () ;
@} ;
<stmt_switch_begin> : ( a ) -> ( e ) = @{
@e = begin_switch_stmt ( @a ) ;
@} ;
<stmt_switch_end> : ( a, b, ex ) -> ( e ) = @{
@e = end_switch_stmt ( @a, @b, @ex ) ;
@} ;
<stmt_while_begin> : ( a ) -> ( e ) = @{
@e = begin_while_stmt ( @a ) ;
@} ;
<stmt_while_end> : ( a, b ) -> ( e ) = @{
@e = end_while_stmt ( @a, @b ) ;
@} ;
<stmt_hash_if> : ( a, b ) -> ( e ) = @{
@e = begin_hash_if_stmt ( @a, @b ) ;
@} ;
<stmt_hash_elif> : ( a, b, c ) -> ( e ) = @{
@e = cont_hash_if_stmt ( @a, @b, @c ) ;
@} ;
<stmt_hash_endif> : ( a, b ) -> ( e ) = @{
@e = end_hash_if_stmt ( @a, @b ) ;
@} ;
<stmt_reach> : ( a ) -> ( e ) = @{
@e = make_reach_stmt ( @a, 1 ) ;
@} ;
<stmt_unreach> : ( a ) -> ( e ) = @{
@e = make_reach_stmt ( @a, 0 ) ;
@} ;
<bind_temporary> : ( a ) -> ( e ) = @{
@e = bind_temporary ( @a ) ;
@} ;
/*
FLOW ANALYSIS
These actions are concerned with flow and variable analysis.
*/
<reach_check> : () -> ( r ) = @{
@r = unreached_code ;
if ( @r ) {
if ( !unreached_last ) {
report ( crt_loc, ERR_stmt_stmt_unreach () ) ;
unreached_last = 1 ;
}
} else {
unreached_last = 0 ;
}
@} ;
<reach_prev> : ( r ) -> () = @{ unreached_prev = @r ; @} ;
<reach_set> : () -> () = @{ unreached_code = 0 ; @} ;
<reach_unset> : () -> () = @{ unreached_code = 1 ; @} ;
<condition_get> : () -> ( c ) = @{ @c = crt_condition ; @} ;
<condition_set> : ( 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.
*/
<function_begin> : ( d ) -> ( b ) = @{
@b = in_class_defn ;
in_class_defn = 0 ;
in_function_defn++ ;
really_in_function_defn++ ;
begin_function ( @d ) ;
@} ;
<function_end> : ( d, a, b ) -> () = @{
IGNORE end_function ( @d, @a ) ;
in_class_defn = @b ;
in_function_defn-- ;
really_in_function_defn-- ;
@} ;
<param_begin> : ( id ) -> () = @{
func_type_defn ( 0 ) ;
begin_param ( @id ) ;
have_type_declaration = TYPE_DECL_NONE ;
have_func_declarator = 0 ;
@} ;
<param_end> : () -> () = @{
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_none> : () -> ( cv ) = @{ @cv = cv_none ; @} ;
<cv_const> : () -> ( cv ) = @{ @cv = cv_const ; @} ;
<cv_volatile> : () -> ( cv ) = @{ @cv = cv_volatile ; @} ;
<cv_join> : ( 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.
*/
<btype_char> : () -> ( bt ) = @{ @bt = btype_char ; @} ;
<btype_short> : () -> ( bt ) = @{ @bt = btype_short ; @} ;
<btype_int> : () -> ( bt ) = @{ @bt = btype_int ; @} ;
<btype_long> : () -> ( bt ) = @{ @bt = btype_long ; @} ;
<btype_signed> : () -> ( bt ) = @{ @bt = btype_signed ; @} ;
<btype_unsigned> : () -> ( bt ) = @{ @bt = btype_unsigned ; @} ;
<btype_float> : () -> ( bt ) = @{ @bt = btype_float ; @} ;
<btype_double> : () -> ( bt ) = @{ @bt = btype_double ; @} ;
<btype_wchar_t> : () -> ( bt ) = @{ @bt = btype_wchar_t ; @} ;
<btype_size_t> : () -> ( bt ) = @{ @bt = btype_size_t ; @} ;
<btype_ptrdiff_t> : () -> ( bt ) = @{ @bt = btype_ptrdiff_t ; @} ;
<btype_void> : () -> ( bt ) = @{ @bt = btype_void ; @} ;
<btype_bottom> : () -> ( bt ) = @{ @bt = btype_bottom ; @} ;
<btype_none> : () -> ( bt ) = @{ @bt = btype_none ; @} ;
<btype_join> : ( 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).
*/
<type_none> : () -> ( t ) = @{
@t = NULL_type ;
@} ;
<type_pre> : () -> ( t ) = @{
@t = NULL_type ;
have_type_specifier = 1 ;
@} ;
<type_name> : ( id ) -> ( t ) = @{
MAKE_type_pre ( cv_none, btype_alias, qual_none, @t ) ;
COPY_id ( type_name ( @t ), @id ) ;
have_type_specifier = 1 ;
@} ;
<type_elaborate> : ( 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 ;
@} ;
<type_join> : ( 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 ;
}
@} ;
<type_complete> : ( bt, t, cv ) -> ( c ) = @{
@c = complete_pre_type ( @bt, @t, @cv, 1 ) ;
have_type_specifier = 0 ;
@} ;
<type_of> : ( op, e, n ) -> ( t ) = @{
@t = typeof_exp ( &@e, @n, @op ) ;
@} ;
<type_check> : ( 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.
*/
<type_ptr> : ( cv ) -> ( p ) = @{
MAKE_type_ptr ( @cv, NULL_type, @p ) ;
@} ;
<type_func> : ( e ) -> ( f ) = @{
@f = make_func_type ( NULL_type, @e, cv_c, empty_type_set ) ;
@} ;
<type_func_weak> : ( e ) -> ( f ) = @{
@f = make_func_type ( NULL_type, ( @e | FUNC_WEAK ), cv_c, empty_type_set ) ;
@} ;
<type_func_old> : () -> ( f ) = @{
@f = make_func_type ( NULL_type, FUNC_PARAMS, cv_c, empty_type_set ) ;
@} ;
<type_func_none> : () -> ( f ) = @{
@f = make_func_type ( NULL_type, FUNC_NO_PARAMS, cv_c, empty_type_set ) ;
@} ;
<type_array> : ( e ) -> ( a ) = @{
NAT n = make_array_dim ( @e ) ;
MAKE_type_array ( cv_none, NULL_type, n, @a ) ;
@} ;
<type_bitfield> : ( p, q, e ) -> ( a ) = @{
@a = make_bitfield_type ( @p, @q, @e, 0 ) ;
@} ;
<type_bitfield_mem> : ( 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 ) ;
@} ;
<type_inject> : ( p, t ) -> ( c ) = @{
@c = ( IS_NULL_type ( @p ) ? @t : inject_pre_type ( @p, @t, 1 ) ) ;
@} ;
<type_build> : ( 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_struct> : () -> ( key ) = @{ @key = btype_struct ; @} ;
<key_union> : () -> ( key ) = @{ @key = btype_union ; @} ;
<key_enum> : () -> ( 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.
*/
<type_class_begin> : ( 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 ) ;
@} ;
<type_class_end> : ( p, b ) -> ( t ) = @{
@t = end_class_defn ( @p ) ;
in_function_defn = @b ;
in_class_defn-- ;
really_in_class_defn-- ;
@} ;
<type_enum_begin> : ( id ) -> ( t ) = @{
@t = begin_enum_defn ( @id, NULL_type ) ;
no_type_defns++ ;
@} ;
<type_enum_end> : ( 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.
*/
<dspec_none> : () -> ( ds ) = @{ @ds = dspec_none ; @} ;
<dspec_auto> : () -> ( ds ) = @{ @ds = dspec_auto ; @} ;
<dspec_register> : () -> ( ds ) = @{ @ds = dspec_register ; @} ;
<dspec_static> : () -> ( ds ) = @{ @ds = dspec_static ; @} ;
<dspec_extern> : () -> ( ds ) = @{ @ds = dspec_extern ; @} ;
<dspec_typedef> : () -> ( ds ) = @{ @ds = dspec_typedef ; @} ;
<dspec_inline> : () -> ( ds ) = @{ @ds = dspec_inline ; @} ;
<dspec_join> : ( a, b ) -> ( ds ) = @{
/* Combine two declaration specifiers */
DECL_SPEC d = ( ( @a & @b ) & dspec_duplicate ) ;
if ( d ) report ( crt_loc, ERR_dcl_spec_dup ( d ) ) ;
@ds = ( @a | @b ) ;
@} ;
<dspec_check> : ( ds ) -> () = @{
if ( have_type_specifier ) report ( crt_loc, ERR_dcl_spec_order ( @ds ) ) ;
@} ;
<dspec_complete> : ( 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.
*/
<declare_id> : ( 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 ;
@} ;
<define_func> : ( ds, t, id ) -> ( d ) = @{
@d = make_func_decl ( @ds, @t, @id, 1 ) ;
have_type_declaration = TYPE_DECL_NONE ;
have_func_declarator = 0 ;
@} ;
<declare_id_empty> : ( 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 ;
@} ;
<declare_empty> : () -> () = @{
report ( crt_loc, ERR_dcl_dcl_semicolon () ) ;
@} ;
<declare_param> : ( ds, t, id ) -> ( d ) = @{
@d = make_param_decl ( @ds, @t, @id, CONTEXT_PARAMETER ) ;
have_type_declaration = TYPE_DECL_NONE ;
have_func_declarator = 0 ;
@} ;
<declare_weak_param> : ( id ) -> () = @{
IGNORE weak_param_decl ( @id ) ;
have_type_declaration = TYPE_DECL_NONE ;
have_func_declarator = 0 ;
@} ;
<declare_member> : ( 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 ;
@} ;
<declare_member_empty> : ( 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 ;
@} ;
<declare_bitfield> : ( 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 ;
@} ;
<declare_enum> : ( t, id, e ) -> () = @{
IGNORE make_enumerator ( @t, @id, @e ) ;
@} ;
<declarator_begin> : ( id ) -> () = @{
IDENTIFIER pid = underlying_id ( @id ) ;
DEREF_loc ( id_loc ( pid ), decl_loc ) ;
@} ;
<declarator_bad> : ( t ) -> () = @{
if ( IS_NULL_type ( @t ) ) {
report ( crt_loc, ERR_dcl_meaning_paren () ) ;
}
@} ;
<declarator_weak> : ( id ) -> () = @{
report ( crt_loc, ERR_dcl_fct_par_typedef ( @id ) ) ;
@} ;
<declare_extern> : ( e ) -> () = @{
external_declaration ( @e, 1 ) ;
@} ;
<decl_none> : () -> ( 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.
*/
<initialise_id> : ( 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.
*/
<offset_nspace> : ( t ) -> ( ns ) = @{
@ns = offset_nspace ( @t ) ;
@} ;
<offset_member> : ( b, s, id, ns ) -> ( a, t ) = @{
OFFSET off = offset_member ( @s, @id, &@t, @ns, 1 ) ;
@a = offset_add ( @b, off ) ;
@} ;
<offset_index> : ( 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.
*/
<declare_asm> : ( a, p ) -> ( e ) = @{
@e = make_asm ( @a, @p ) ;
@} ;
<decl_hash_if> : ( a ) -> () = @{
target_decl ( lex_if, @a ) ;
@} ;
<decl_hash_elif> : ( a ) -> () = @{
target_decl ( lex_elif, @a ) ;
@} ;
<decl_hash_else> : () -> () = @{
target_decl ( lex_else, NULL_exp ) ;
@} ;
<decl_hash_endif> : () -> () = @{
target_decl ( lex_endif, NULL_exp ) ;
@} ;
<cond_hash_if> : ( a ) -> ( c ) = @{
EXP c = crt_hash_cond ;
crt_hash_cond = make_if_cond ( @a, c ) ;
@c = c ;
@} ;
<cond_hash_elif> : ( a ) -> () = @{
EXP c = make_else_cond ( crt_hash_cond ) ;
crt_hash_cond = make_if_cond ( @a, c ) ;
@} ;
<cond_hash_else> : () -> () = @{
crt_hash_cond = make_else_cond ( crt_hash_cond ) ;
@} ;
<cond_hash_endif> : ( 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.
*/
<error_fatal> : () -> () = @{
/* 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 ;
@} ;
<error_syntax> : () -> () = @{
/* Syntax errors */
ERROR err = ERR_lex_parse ( crt_token ) ;
report ( crt_loc, err ) ;
have_syntax_error = 1 ;
@} ;
<error_comma> : () -> () = @{
/* Extra comma at the end of a list */
report ( crt_loc, ERR_lex_extra_comma () ) ;
@} ;
<expected> : ( 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.
*/
<no_side_effects> : () -> ( n ) = @{
@n = no_side_effects ;
@} ;
<no_type_defns> : () -> ( n ) = @{
@n = no_type_defns ;
@} ;
<diff_side_effects> : ( m ) -> ( n ) = @{
@n = no_side_effects - @m ;
@} ;
<diff_type_defns> : ( m ) -> ( n ) = @{
@n = no_type_defns - @m ;
@} ;
<sizeof_begin> : () -> () = @{
suppress_usage++ ;
@} ;
<sizeof_end> : () -> () = @{
suppress_usage-- ;
@} ;
/*
PREDICATE LITERALS
These actions give the basic values, true and false, for the type
BOOL.
*/
<bool_false> : () -> ( b ) = @{ @b = 0 ; @} ;
<bool_true> : () -> ( 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.
*/
<is_function> : ( t ) -> ( b ) = @{
@b = function_params ( @t ) ;
@} ;
<is_decl_specifier> : () -> ( b ) = @{
/* Resolve declaration-specifiers from other declarators */
@b = predict_dspec ( 0 ) ;
@} ;
<is_decl_statement> : ( 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 ;
@} ;
<is_type_id_false> : () -> ( b ) = @{
/* Resolve type-ids from expressions */
@b = predict_typeid ( 0 ) ;
@} ;
<is_type_id_true> : () -> ( b ) = @{
/* Resolve type-ids from expressions */
@b = predict_typeid ( 1 ) ;
@} ;
<is_type_specifier> : () -> ( b ) = @{
/* Resolve type-specifiers from other declarators */
@b = predict_tspec ( 0 ) ;
@} ;
<is_parameter> : () -> ( 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_token> : () -> () = @{
RESCAN_LEXER ;
@} ;
<check_decl_specifier> : () -> () = @{
/* 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
#endif
@} ;