/*
* Copyright (c) 2002, The Tendra Project <http://www.ten15.org/>
* 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/common/parse/parse.c,v 1.12 2005/10/16 15:33:43 stefanf Exp $
*/
#include "config.h"
#include "producer.h"
#include "msgcat.h"
#include "c_types.h"
#include "ctype_ops.h"
#include "hashid_ops.h"
#include "id_ops.h"
#include "member_ops.h"
#include "nspace_ops.h"
#include "tok_ops.h"
#include "type_ops.h"
#include "error.h"
#include "catalog.h"
#include "access.h"
#include "char.h"
#include "class.h"
#include "derive.h"
#include "file.h"
#include "hash.h"
#include "identifier.h"
#include "lex.h"
#include "literal.h"
#include "macro.h"
#include "namespace.h"
#include "option.h"
#include "parse.h"
#include "pragma.h"
#include "predict.h"
#include "preproc.h"
#include "redeclare.h"
#include "symbols.h"
#include "syntax.h"
#include "template.h"
#include "tokdef.h"
/*
* CURRENT LEXICAL TOKEN NUMBERS
*
* These variables are used by the parser to hold the current and former
* lexical token numbers.
*/
int crt_lex_token = lex_unknown;
int last_lex_token = lex_unknown;
int saved_lex_token = lex_unknown;
static int have_template = 0;
int have_syntax_error = 0;
/*
* LIST OF ACTIVE LEXICAL TOKENS
*
* The currently active lexical tokens are formed into a list starting
* with first_token. The position of the current token within this list
* is given by crt_token. The main routine for building up this list
* is expand_token which either advances crt_token one step along the
* list, or, if crt_token points to the end of the list, reads and macro
* expands the next token from the input file, appending the resulting
* tokens to the end of the list. The list is periodically garbage
* collected by setting first_token to crt_token and freeing all the
* tokens from the old first_token.
*/
PPTOKEN *crt_token = NULL;
static PPTOKEN *first_token = NULL;
NAMESPACE crt_lookup = NULL_nspace;
static unsigned long crt_lookup_depth = 0;
static OPTIONS *prev_opts = NULL;
static STACK (int) token_stack = NULL_stack (int);
static STACK (PPTOKEN_P) parser_stack = NULL_stack (PPTOKEN_P);
static STACK (NAMESPACE) lookup_stack = NULL_stack (NAMESPACE);
/*
* INITIALISE ACTIVE TOKEN LIST
*
* This routine initialises a new list of active lexical tokens with the
* value toks by pushing the old values of first_token and crt_token onto
* the stack parser_stack and setting them to point to a new dummy token
* whose next field is toks.
*/
void
init_parser(PPTOKEN *toks)
{
PPTOKEN *q;
PUSH_int (crt_lex_token, token_stack);
PUSH_int (last_lex_token, token_stack);
PUSH_int (saved_lex_token, token_stack);
PUSH_nspace (crt_lookup, lookup_stack);
PUSH_pptok (first_token, parser_stack);
PUSH_pptok (crt_token, parser_stack);
q = new_pptok ();
q->tok = lex_ignore_token;
q->pp_space = 0;
q->next = toks;
first_token = q;
crt_token = q;
crt_lookup = NULL_nspace;
crt_lookup_depth = 0;
crt_lex_token = lex_unknown;
last_lex_token = lex_unknown;
saved_lex_token = lex_unknown;
return;
}
/*
* RESTORE ACTIVE TOKEN LIST
*
* This routine restores the previous list of active lexical tokens by
* popping the values of first_token and crt_token from the stack. The
* previous list is returned.
*/
PPTOKEN *
restore_parser(void)
{
PPTOKEN *p = first_token;
POP_pptok (crt_token, parser_stack);
POP_pptok (first_token, parser_stack);
POP_nspace (crt_lookup, lookup_stack);
POP_int (last_lex_token, token_stack);
POP_int (saved_lex_token, token_stack);
POP_int (crt_lex_token, token_stack);
crt_lookup_depth = 0;
ASSERT (first_token != NULL);
return (p);
}
/*
* REMOVE A LIST OF TOKENS FROM THE CURRENT LIST
*
* This routine removes the tokens from p to q inclusive from the current
* list. crt_token must not be included within this range.
*/
void
snip_tokens(PPTOKEN *p, PPTOKEN *q)
{
PPTOKEN *r = first_token;
if (r == p) {
first_token = q->next;
} else {
while (r->next != p) r = r->next;
r->next = q->next;
}
r = new_pptok ();
r->tok = lex_eof;
q->next = r;
r->next = NULL;
return;
}
/*
* PATCH A NUMBER OF TOKENS INTO THE CURRENT LIST
*
* This routine patches n tokens into the current list immediately after
* crt_token, returning the first token. This is used by the preprocessor
* to pass more than one token to the parser.
*/
PPTOKEN *
patch_tokens(int n)
{
while (n) {
PPTOKEN *p = new_pptok ();
p->tok = lex_ignore_token;
p->next = crt_token->next;
p->pp_space = WHITE_SPACE;
crt_token->next = p;
n--;
}
return (crt_token->next);
}
/*
* CURRENT PARSER STATE DEPTH
*
* This variable is used to record the current depth of saved parser
* states.
*/
int crt_state_depth = 0;
/*
* SAVE PARSER STATE
*
* This routine saves the current parser state into s, it also clears the
* syntax error flag. col is true if column numbers are to be considered
* during the parsing.
*/
void
save_state(PARSE_STATE *s, int col)
{
/* Save current location */
s->loc = crt_loc;
/* Save current namespace */
s->nspace [0] = crt_namespace;
s->nspace [1] = templ_namespace;
s->nstack [0] = namespace_stack;
s->nstack [1] = crt_nspace_stack;
s->nstack [2] = local_nspace_stack;
/* Save flag values */
s->flag [0] = in_class_defn;
s->flag [1] = in_function_defn;
s->flag [2] = really_in_class_defn;
s->flag [3] = really_in_function_defn;
s->flag [4] = in_declaration;
s->flag [5] = in_template_decl;
s->flag [6] = have_syntax_error;
s->flag [7] = cache_lookup;
s->flag [8] = crt_col_changed;
have_syntax_error = 0;
cache_lookup = old_cache_lookup;
crt_col_changed = col;
/* Save declaration specifiers */
s->dspec [0] = crt_access;
s->dspec [1] = crt_linkage;
crt_access = dspec_public;
crt_state_depth++;
bad_crt_loc++;
return;
}
/*
* RESTORE PARSER STATE
*
* This routine restores the parser state from the value stored in s.
* Note that there is some attempt at recovering the state following
* some intervening error, particularly with regard to resetting the
* current namespace.
*/
void
restore_state(PARSE_STATE *s)
{
/* Restore current namespace */
NAMESPACE ns = s->nspace [0];
NAMESPACE cns = crt_namespace;
LIST (NAMESPACE) pns = LIST_stack (s->nstack [0]);
cache_lookup = old_cache_lookup;
while (!EQ_list (pns, LIST_stack (namespace_stack))) {
/* Reset name look-up stack */
remove_namespace ();
}
crt_namespace = ns;
crt_nspace_stack = s->nstack [1];
local_nspace_stack = s->nstack [2];
if (!EQ_nspace (ns, cns)) {
/* Recalculate namespaces if necessary */
update_namespace ();
}
templ_namespace = s->nspace [1];
/* Restore current location */
crt_loc = s->loc;
crt_line_changed = 1;
crt_file_changed = 1;
/* Restore flag values */
in_class_defn = s->flag [0];
in_function_defn = s->flag [1];
really_in_class_defn = s->flag [2];
really_in_function_defn = s->flag [3];
in_declaration = s->flag [4];
in_template_decl = s->flag [5];
have_syntax_error = s->flag [6];
cache_lookup = s->flag [7];
crt_col_changed = s->flag [8];
/* Restore declaration specifiers */
crt_access = s->dspec [0];
crt_linkage = s->dspec [1];
crt_state_depth--;
bad_crt_loc--;
return;
}
/*
* SET UP FILE LOCATION TOKENS
*
* This routine sets up preprocessing tokens recording the current file
* position immediately following p.
*/
static void
make_loc_tokens(PPTOKEN *p)
{
PPTOKEN *q = new_pptok ();
if (crt_file_changed) {
q->tok = lex_builtin_Hfile;
crt_file_changed = 0;
} else {
q->tok = lex_builtin_Hline;
}
crt_line_changed = 0;
q->pp_space = crt_loc.column;
q->pp_data.loc.line = crt_loc.line;
q->pp_data.loc.posn = crt_loc.posn;
q->next = p->next;
p->next = q;
return;
}
/*
* READ FILE LOCATION TOKENS
*
* This routine adjusts the current line number according to the
* preprocessing tokens p.
*/
PPTOKEN *
read_loc_tokens(PPTOKEN *p)
{
if (p) {
int t = p->tok;
if (t == lex_builtin_Hline) {
/* Set line number */
crt_loc.column = p->pp_space;
crt_loc.line = p->pp_data.loc.line;
crt_loc.posn = p->pp_data.loc.posn;
crt_line_changed = 1;
p = p->next;
} else if (t == lex_builtin_Hfile) {
/* Set file name */
crt_loc.column = p->pp_space;
crt_loc.line = p->pp_data.loc.line;
crt_loc.posn = p->pp_data.loc.posn;
crt_line_changed = 1;
crt_file_changed = 1;
p = p->next;
} else if (crt_col_changed) {
unsigned long sp = p->pp_space;
if (sp) crt_loc.column = sp;
}
}
return (p);
}
/*
* FIND A DESTRUCTOR NAME
*
* This routine returns the destructor name for the class name cid or the
* null identifier if cid is not a class name.
*/
#if LANGUAGE_CPP
static IDENTIFIER
find_destr_id(IDENTIFIER cid)
{
CLASS_TYPE ct = NULL_ctype;
if (IS_id_class_name_etc (cid)) {
TYPE t = DEREF_type (id_class_name_etc_defn (cid));
unsigned tag = TAG_type (t);
while (tag == type_templ_tag) {
t = DEREF_type (type_templ_defn (t));
tag = TAG_type (t);
}
if (tag == type_compound_tag) {
ct = DEREF_ctype (type_compound_defn (t));
}
} else {
ct = find_class (cid);
}
if (!IS_NULL_ctype (ct)) {
/* Find destructor name */
IDENTIFIER tid = DEREF_id (ctype_destr (ct));
HASHID nm = DEREF_hashid (id_name (tid));
tid = DEREF_id (hashid_id (nm));
set_hashid_loc (tid, cid);
return (tid);
}
return (NULL_id);
}
#endif
/*
* CHECK A DESTRUCTOR NAME
*
* This routine checks whether the destructor name cid specified using
* nm is legal. For example, nm might be a typedef-name for the class
* rather than the class itself. d is the result of the previous call
* to predict_destr.
*/
#if LANGUAGE_CPP
static void
check_destr_id(IDENTIFIER cid, HASHID nm, int d)
{
if (d <= 2) {
HASHID cnm = DEREF_hashid (id_name (cid));
IDENTIFIER tid = DEREF_id (hashid_destr_tid (cnm));
HASHID tnm = DEREF_hashid (id_name (tid));
if (!EQ_hashid (tnm, nm)) {
/* Destructor names don't match */
IDENTIFIER id = DEREF_id (hashid_id (nm));
report (crt_loc, ERR_dcl_typedef_destr (id, cnm));
}
}
return;
}
#endif
/*
* READ AND EXPAND THE NEXT TOKEN
*
* This routine reads the next token from the list of all active tokens,
* first_token (see above). This consists either of advancing crt_token
* along this list, or reading and expanding a new token from the input
* file, appending the result to the list. The argument store gives the
* context for the token. The usual cases are EXPAND_NORMAL, indicating
* that the token is to be used and then discarded (allowing first_token
* to be garbage collected up to crt_token), and EXPAND_AHEAD, indicating
* that the token is to be stored for use later. The value EXPAND_RESCAN
* can be used to force the current token to be rescanned. Other values
* are used internally. Note that crt_token is set to the token currently
* being defined during all calls to read_token. The routine can be
* considerably simplified for C, and because of the performance critical
* nature of the routine this has been done by conditional compilation.
*
* There is a problem with the look-ahead method in that certain tokens
* are context dependent, and thus may not mean the same in the initial
* scan using expand_token (EXPAND_AHEAD) as they do when the same
* tokens are re-analysed using expand_token (EXPAND_NORMAL). This
* is solved by storing all the tokens in these cases and reinterpreting
* them later. This means in particular than a context dependent
* interpretation such as an identifier being a type name is not set
* in stone by being recorded in the token's tok field. Instead this
* interpretation is returned, but the identifier is only marked as
* an identifier.
*
* Note also that SID is always one token ahead of itself. For example
* in:
*
* void f ()
* {
* {
* extern void g (int);
* g (0);
* }
* g (1);
* }
*
* g goes out of scope after the first close brace, by which time SID has
* already read the following token and resolved it as g. Thus in these
* cases it is necessary to insert an explicit rescan of the current token
* (with a store value of EXPAND_RESCAN) after the close brace so that
* g is seen not to be in scope. This problem only ever occurs one
* token ahead of the current token.
*/
int
expand_token(int store)
{
int t;
int expand;
#if LANGUAGE_CPP
NAMESPACE ns = crt_lookup;
#endif
PPTOKEN *prev_tok = crt_token;
PPTOKEN *this_tok = prev_tok->next;
/* A store value of EXPAND_RESCAN means rescan this token */
if (store == EXPAND_RESCAN) {
this_tok = prev_tok;
#if LANGUAGE_CPP
ns = NULL_nspace;
#endif
}
/* Get the next token */
start_label : {
if (this_tok == NULL) {
/* Read the token from the file */
this_tok = new_pptok ();
this_tok->next = NULL;
prev_tok->next = this_tok;
crt_token = this_tok;
t = read_token ();
update_column ();
this_tok->tok = t;
if (t <= LAST_COMPLEX_TOKEN) {
token_parts (t, this_tok);
}
/* Don't bother with the space field */
if (store == EXPAND_NORMAL) {
/* Garbage collect stored tokens */
prev_tok->next = free_tokens;
free_tokens = first_token;
first_token = this_tok;
}
expand = 1;
} else {
/* Use a previously stored token */
t = this_tok->tok;
if (t == lex_ignore_token) {
/* Step over any ignored tokens */
prev_tok = this_tok;
this_tok = this_tok->next;
goto start_label;
} else if (t == lex_builtin_Hline || t == lex_builtin_Hfile) {
/* Set line number */
prev_tok = this_tok;
this_tok = read_loc_tokens (this_tok);
goto start_label;
} else if (crt_col_changed) {
unsigned long sp = this_tok->pp_space;
if (sp) crt_loc.column = sp;
}
crt_token = this_tok;
expand = 0;
}
}
crt_lookup = NULL_nspace;
/* Deal with context switch */
if (store == EXPAND_NORMAL) {
OPTIONS *opts = prev_opts;
if (opts != crt_opts) set_mode (opts);
prev_opts = this_tok->pp_opts;
}
/* Analyse the token */
switch (t) {
case lex_identifier : {
/* Deal with identifiers */
unsigned tag;
int tt = lex_identifier;
/* Check for macro expansion */
HASHID nm = this_tok->pp_data.id.hash;
IDENTIFIER id = DEREF_id (hashid_id (nm));
expand_label : {
tag = TAG_id (id);
switch (tag) {
case id_obj_macro_tag :
case id_func_macro_tag : {
/* Check for expansion of macros */
if (expand) {
PPTOKEN *toks;
toks = expand_macro (nm, file_loc, 1);
this_tok->tok = lex_ignore_token;
this_tok->next = toks;
prev_tok = this_tok;
this_tok = toks;
goto start_label;
}
id = DEREF_id (id_alias (id));
goto expand_label;
}
case id_keyword_tag : {
/* Check on keywords */
this_tok->pp_data.id.use = id;
t = (int) DEREF_ulong (id_no (id));
this_tok->tok = t;
return (t);
}
case id_iso_keyword_tag : {
/* Check on ISO keywords */
this_tok->pp_data.id.use = id;
if (!in_pragma_dir) {
ERROR err;
t = (int) DEREF_ulong (id_no (id));
t = primary_form (t);
err = ERR_lex_digraph_iso (nm, t);
if (!IS_NULL_err (err)) {
report (crt_loc, err);
}
this_tok->tok = t;
#if LANGUAGE_CPP
if (t == lex_compl_H1) goto compl_label;
#endif
return (t);
}
break;
}
case id_c99_keyword_tag :
case id_reserved_tag : {
/* Report reserved identifiers */
if (store == EXPAND_NORMAL && !in_pragma_dir) {
ERROR err;
if (tag == id_reserved_tag) {
err = ERR_lex_key_reserve (nm);
} else {
err = ERR_lex_key_c99 (nm);
}
report (crt_loc, err);
}
break;
}
}
}
if (find_hashid (nm) == lex_pragma_H2) {
if (operator_pragma ()) {
this_tok = crt_token->next;
/* Continue after the closing ) */
goto start_label;
}
/* Otherwise treat _Pragma as an ordinary identifier */
}
/* Perform name look-up */
#if LANGUAGE_CPP
if (IS_NULL_nspace (ns)) {
id = find_id (nm);
} else {
IDENTIFIER mid = find_qual_id (ns, nm, 0, 0);
if (!IS_NULL_id (mid)) id = mid;
}
#else
id = find_op_id (nm);
#endif
tag = TAG_id (id);
#if LANGUAGE_CPP
/* Look ahead for following '::' (C++ only) */
t = expand_token (EXPAND_CHECK_COLON);
crt_token = this_tok;
#endif
/* Allow for tokens and templates */
if (tag == id_token_tag) {
TOKEN sort = DEREF_tok (id_token_sort (id));
if (IS_tok_proc (sort)) {
/* Procedure token application */
#if LANGUAGE_CPP
/* Following token already read */
#else
/* Check for following '(' */
t = expand_token (EXPAND_CHECK_COLON);
crt_token = this_tok;
#endif
if (t == lex_open_Hround) {
PPTOKEN *args = skip_token_args (id);
id = DEREF_id (id_token_alt (id));
this_tok->pp_data.tok.id = id;
this_tok->pp_data.tok.args = args;
sort = DEREF_tok (tok_proc_res (sort));
switch (TAG_tok (sort)) {
case tok_exp_tag :
case tok_nat_tag :
case tok_snat_tag : {
tt = lex_complex_Hexp;
break;
}
case tok_stmt_tag : {
tt = lex_complex_Hstmt;
break;
}
case tok_member_tag : {
/* NOT YET IMPLEMENTED */
tt = lex_complex_Hexp;
break;
}
default : {
tt = lex_complex_Htype;
#if LANGUAGE_CPP
/* Check again for following '::' */
t = expand_token (EXPAND_CHECK_COLON);
crt_token = this_tok;
#endif
break;
}
}
} else {
tt = DEREF_int (tok_proc_key (sort));
if (store == EXPAND_NORMAL) {
if (tt != lex_identifier && !in_pragma_dir) {
ERROR err = ERR_cpp_replace_arg_none (nm);
report (crt_loc, err);
}
}
}
}
#if LANGUAGE_CPP
} else if (t == lex_less) {
/* Check for templates (C++ only) */
DECL_SPEC ds = DEREF_dspec (id_storage (id));
if (ds & dspec_template) {
/* Template application */
PPTOKEN *args;
if (ds & dspec_implicit) {
/* Allow for injected template names */
IDENTIFIER tid = find_template (id, 0);
if (!IS_NULL_id (tid)) {
id = tid;
tag = TAG_id (id);
}
}
args = skip_template_args (id, 0);
if (store == EXPAND_TEMPLATE) have_template = 1;
switch (tag) {
case id_class_name_tag : {
tt = lex_template_Htype;
goto class_template_lab;
}
case id_class_alias_tag : {
tt = lex_complex_Htype;
goto class_template_lab;
}
case id_type_alias_tag : {
CLASS_TYPE ct = find_class (id);
tt = lex_complex_Htype;
if (!IS_NULL_ctype (ct)) {
goto class_template_lab;
}
break;
}
class_template_lab : {
t = expand_token (EXPAND_CHECK_COLON);
crt_token = this_tok;
if (t == lex_colon_Hcolon) {
/* Expand the template class now */
id = parse_type_template (id, args, 1);
tt = lex_identifier;
}
break;
}
case id_enum_name_tag :
case id_enum_alias_tag : {
tt = lex_complex_Htype;
break;
}
default : {
/* Function template */
tt = lex_template_Hid;
break;
}
}
if (tt != lex_identifier) {
this_tok->pp_data.tok.id = id;
this_tok->pp_data.tok.args = args;
}
} else if (store == EXPAND_TEMPLATE) {
/* Have 'template id < ... >' */
PPTOKEN *args = skip_template_args (id, 0);
this_tok->pp_data.tok.id = id;
this_tok->pp_data.tok.args = args;
tt = lex_template_Hid;
have_template = 1;
}
#endif
}
#if LANGUAGE_CPP
/* Allow for destructors (C++ only) */
if (store == EXPAND_DESTRUCTOR && t != lex_colon_Hcolon) {
int level = 2;
IDENTIFIER cid = id;
do {
switch (TAG_id (cid)) {
case id_class_name_tag :
case id_class_alias_tag :
case id_token_tag : {
IDENTIFIER tid;
if (tt == lex_template_Htype) {
this_tok->tok = tt;
t = lex_destructor_Hname;
return (t);
}
tid = find_destr_id (cid);
if (!IS_NULL_id (tid)) {
this_tok->pp_data.id.use = tid;
t = lex_destructor_Hname;
return (t);
}
level = 0;
break;
}
default : {
if (level == 2 && !IS_NULL_nspace (ns)) {
cid = find_id (nm);
level = 1;
} else {
level = 0;
}
break;
}
}
} while (level);
}
#endif
#if LANGUAGE_CPP
/* Look ahead for further qualifiers (C++ only) */
if (t == lex_colon_Hcolon) {
/* Following token is '::' */
int level = 2;
IDENTIFIER cid = id;
do {
switch (TAG_id (cid)) {
case id_class_name_tag :
case id_class_alias_tag :
case id_nspace_name_tag :
case id_nspace_alias_tag : {
/* Have namespace or class name */
ns = find_namespace (cid);
if (!IS_NULL_nspace (ns)) {
crt_lookup = ns;
t = expand_token (EXPAND_IDENTIFIER);
switch (t) {
case lex_full_Hname :
case lex_colon_Hcolon : {
t = lex_nested_Hname;
this_tok->tok = lex_ignore_token;
crt_token->tok = t;
return (t);
}
case lex_full_Hname_Hstar : {
t = lex_nested_Hname_Hstar;
this_tok->tok = lex_ignore_token;
crt_token->tok = t;
return (t);
}
}
crt_token = this_tok;
}
level = 0;
break;
}
default : {
/* Look up namespace or class name */
if (level == 2) {
CLASS_TYPE ct = find_class (cid);
if (!IS_NULL_ctype (ct)) {
cid = DEREF_id (ctype_name (ct));
} else {
if (IS_NULL_nspace (ns)) {
cid = find_type_id (nm, 3);
} else {
cid = find_qual_id (ns, nm, 0, 3);
}
}
if (IS_NULL_id (cid)) {
level = 0;
} else {
level = 1;
}
} else {
level = 0;
}
break;
}
}
} while (level);
}
#endif
/* Deal with context dependent identifiers */
switch (tag) {
#if LANGUAGE_CPP
case id_class_name_tag :
case id_enum_name_tag : {
/* Type names (C++ only) */
t = lex_type_Hname;
break;
}
#endif
case id_class_alias_tag :
case id_enum_alias_tag :
case id_type_alias_tag : {
/* Type aliases */
t = lex_type_Hname;
break;
}
#if LANGUAGE_CPP
case id_nspace_name_tag :
case id_nspace_alias_tag : {
/* Namespace names (C++ only) */
t = lex_namespace_Hname;
break;
}
#endif
case id_token_tag : {
/* Token names */
TOKEN sort = DEREF_tok (id_token_sort (id));
if (IS_tok_stmt (sort)) {
t = lex_statement_Hname;
} else {
t = lex_identifier;
}
break;
}
default : {
/* Other names */
t = lex_identifier;
break;
}
}
if (tt == lex_identifier) {
this_tok->pp_data.id.use = id;
} else {
this_tok->tok = tt;
t = tt;
}
break;
}
#if LANGUAGE_CPP
case lex_colon_Hcolon : {
/* Deal with qualified names (C++ only) */
int nt;
unsigned long depth;
if (store == EXPAND_CHECK_COLON) {
/* Look ahead for '::' */
return (t);
} else if (IS_NULL_nspace (ns)) {
/* Initial '::' */
ns = global_namespace;
depth = 0;
} else if (store == EXPAND_IDENTIFIER) {
/* Following a namespace identifier */
depth = crt_lookup_depth + 1;
} else {
/* Badly placed '::' */
return (t);
}
/* Look ahead to further tokens */
crt_lookup = ns;
crt_lookup_depth = depth;
nt = expand_token (EXPAND_COLON_COLON);
crt_lookup_depth = 0;
if (nt == lex_nested_Hname) {
nt = lex_full_Hname;
this_tok->tok = lex_ignore_token;
crt_token->tok = nt;
return (nt);
}
if (nt == lex_nested_Hname_Hstar) {
if (crt_token == this_tok->next) {
IGNORE check_value (OPT_VAL_scope_qualifiers, depth);
}
nt = lex_full_Hname_Hstar;
this_tok->tok = lex_ignore_token;
crt_token->tok = nt;
return (nt);
}
IGNORE check_value (OPT_VAL_scope_qualifiers, depth);
this_tok->pp_data.ns = ns;
crt_lookup = ns;
crt_token = this_tok;
break;
}
#endif
#if LANGUAGE_CPP
case lex_full_Hname :
case lex_nested_Hname : {
/* Deal with stored nested names (C++ only) */
int nt;
ns = this_tok->pp_data.ns;
crt_lookup = ns;
crt_lookup_depth++;
nt = expand_token (EXPAND_COLON_COLON);
crt_lookup_depth = 0;
if (nt == lex_nested_Hname) {
this_tok->tok = lex_ignore_token;
crt_token->tok = t;
return (nt);
}
if (nt == lex_nested_Hname_Hstar) {
if (t == lex_full_Hname) nt = lex_full_Hname_Hstar;
this_tok->tok = lex_ignore_token;
crt_token->tok = nt;
return (nt);
}
crt_lookup = ns;
crt_token = this_tok;
break;
}
#endif
#if LANGUAGE_CPP
case lex_star : {
/* Deal with pointer to members (C++ only) */
if (store == EXPAND_COLON_COLON && crt_lookup_depth) {
IDENTIFIER cid = DEREF_id (nspace_name (ns));
t = lex_nested_Hname_Hstar;
this_tok->tok = t;
this_tok->pp_data.id.use = cid;
}
break;
}
#endif
#if LANGUAGE_CPP
case lex_compl_H1 :
compl_label : {
/* Deal with destructors (C++ only) */
if (store != EXPAND_COLON_COLON) {
int nt;
crt_lookup = ns;
nt = expand_token (EXPAND_DESTRUCTOR);
if (nt == lex_destructor_Hname) {
int d = predict_destr (ns);
if (d) {
this_tok->tok = lex_ignore_token;
this_tok = crt_token;
t = this_tok->tok;
if (t == lex_template_Htype) {
/* Template class destructors */
IDENTIFIER id = this_tok->pp_data.tok.id;
PPTOKEN *args = this_tok->pp_data.tok.args;
HASHID nm = DEREF_hashid (id_name (id));
id = parse_type_template (id, args, 1);
id = find_destr_id (id);
this_tok->pp_data.id.hash = nm;
this_tok->pp_data.id.use = id;
} else {
/* Simple destructors */
IDENTIFIER id = this_tok->pp_data.id.use;
HASHID nm = this_tok->pp_data.id.hash;
check_destr_id (id, nm, d);
}
this_tok->tok = nt;
return (nt);
}
}
crt_token = this_tok;
}
break;
}
#endif
case lex_integer_Hlit : {
/* Deal with integer and floating point literals */
int nt;
int pn = pragma_number;
OPTIONS *opts = crt_opts;
OPTIONS *nopts = this_tok->pp_opts;
string n = this_tok->pp_data.text;
if (opts != nopts) set_mode (nopts);
this_tok->pp_data.exp = make_literal_exp (n, &nt, pn);
this_tok->tok = nt;
if (opts != nopts) set_mode (opts);
t = nt;
break;
}
case lex_char_Hlit :
case lex_wchar_Hlit : {
/* Deal with character literals */
STRING s;
OPTIONS *opts = crt_opts;
OPTIONS *nopts = this_tok->pp_opts;
string sb = this_tok->pp_data.str.start;
string se = this_tok->pp_data.str.end;
if (opts != nopts) set_mode (nopts);
s = new_string_lit (sb, se, t);
if (t == lex_char_Hlit) {
t = lex_char_Hexp;
} else {
t = lex_wchar_Hexp;
}
this_tok->pp_data.exp = make_string_exp (s);
this_tok->tok = t;
if (opts != nopts) set_mode (opts);
break;
}
case lex_string_Hlit :
case lex_wstring_Hlit : {
/* Deal with string literals */
int nt;
STRING s;
OPTIONS *opts = crt_opts;
OPTIONS *nopts = this_tok->pp_opts;
string sb = this_tok->pp_data.str.start;
string se = this_tok->pp_data.str.end;
/* Don't concatenate string literals while looking at the tokens
* following _Pragma. String concatenation is done later, in
* translation phase 6. */
if (store == EXPAND_PRAGMA) break;
if (opts != nopts) set_mode (nopts);
s = new_string_lit (sb, se, t);
/* Concatenate adjacent strings */
nt = expand_token (EXPAND_STRING);
if (nt == lex_string_Hlit || nt == lex_wstring_Hlit) {
/* Combine the following string with this one */
if (nt != t) {
/* String types don't match */
report (crt_loc, ERR_lex_string_concat ());
t = lex_wstring_Hlit;
}
s = concat_string_lit (s, crt_token->pp_data.strlit);
crt_token->tok = lex_ignore_token;
}
crt_token = this_tok;
if (store == EXPAND_STRING) {
/* Continue concatenation */
this_tok->pp_data.strlit = s;
} else {
/* Transform string literal into expression */
if (t == lex_string_Hlit) {
t = lex_string_Hexp;
} else {
t = lex_wstring_Hexp;
}
this_tok->pp_data.exp = make_string_exp (s);
this_tok->tok = t;
}
if (opts != nopts) set_mode (opts);
break;
}
case lex_ellipsis : {
/* Ellipses */
if (store == EXPAND_NORMAL) {
OPTION opt = option (OPT_ellipsis_ident);
NAMESPACE cns = crt_namespace;
if (opt != OPTION_DISALLOW && IS_nspace_block (cns)) {
t = lex_ellipsis_Hexp;
this_tok->tok = t;
}
}
break;
}
case lex_hash_H2 :
case lex_hash_Hhash_H2 :
case lex_open_Hbrace_H2 :
case lex_open_Hsquare_H2 :
case lex_close_Hbrace_H2 :
case lex_close_Hsquare_H2 : {
/* Digraphs */
t = get_digraph (t);
this_tok->tok = t;
break;
}
case lex_and_H2 :
case lex_and_Heq_H2 :
case lex_compl_H2 :
case lex_logical_Hand_H2 :
case lex_logical_Hor_H2 :
case lex_not_H2 :
case lex_not_Heq_H2 :
case lex_or_H2 :
case lex_or_Heq_H2 :
case lex_xor_H2 :
case lex_xor_Heq_H2 : {
/* ISO keywords */
int tt;
IDENTIFIER id = this_tok->pp_data.id.use;
t = (int) DEREF_ulong (id_no (id));
tt = primary_form (t);
if (tt != t) {
HASHID nm;
if (in_pragma_dir) break;
nm = this_tok->pp_data.id.hash;
report (crt_loc, ERR_lex_digraph_iso (nm, tt));
t = tt;
}
this_tok->tok = t;
#if LANGUAGE_CPP
if (t == lex_compl_H1) goto compl_label;
#endif
break;
}
case lex_unknown : {
/* Unknown characters */
unsigned long u;
int ch = CHAR_SIMPLE;
u = get_multi_char (this_tok->pp_data.buff, &ch);
if (ch == CHAR_SIMPLE) {
if (is_legal_char (u)) {
if (!is_white_char (u)) break;
} else {
int c = (int) u;
report (crt_loc, ERR_lex_pptoken_unknown (c));
}
} else {
report (crt_loc, ERR_lex_pptoken_unicode (u));
}
this_tok->tok = lex_ignore_token;
t = expand_token (store);
break;
}
}
return (t);
}
/*
* READ AND EXPAND THE NEXT TOKEN (PREPROCESSOR VERSION)
*
* This routine is a cut-down version of expand_token with only the macro
* expansion and keyword actions. This is for use with the stand-alone
* preprocessor and in the rewriting rules.
*/
int
expand_preproc(int store)
{
int t;
int expand;
PPTOKEN *prev_tok = crt_token;
PPTOKEN *this_tok = prev_tok->next;
/* Get the next token */
start_label : {
if (this_tok == NULL) {
/* Read the token from the file */
this_tok = new_pptok ();
this_tok->next = NULL;
prev_tok->next = this_tok;
crt_token = this_tok;
t = read_token ();
update_column ();
this_tok->tok = t;
if (t <= LAST_COMPLEX_TOKEN) token_parts (t, this_tok);
if (store == EXPAND_NORMAL) {
/* Garbage collect stored tokens */
this_tok->pp_space = 0;
prev_tok->next = free_tokens;
free_tokens = first_token;
first_token = this_tok;
} else {
this_tok->pp_space = crt_loc.column;
if (crt_line_changed) {
/* Record file position */
make_loc_tokens (prev_tok);
}
}
expand = 1;
} else {
/* Use a previously stored token */
if (this_tok->pp_space) {
/* Increase space count if necessary */
if (!crt_line_changed) crt_spaces++;
if (store == EXPAND_AHEAD) this_tok->pp_space = 0;
}
t = this_tok->tok;
if (t == lex_ignore_token) {
/* Step over any ignored tokens */
prev_tok = this_tok;
this_tok = this_tok->next;
goto start_label;
}
crt_token = this_tok;
expand = 0;
}
}
/* Deal with context switch */
if (store == EXPAND_NORMAL) {
OPTIONS *opts = prev_opts;
if (opts != crt_opts) set_mode (opts);
prev_opts = this_tok->pp_opts;
}
/* Deal with identifiers */
if (t == lex_identifier) {
HASHID nm = this_tok->pp_data.id.hash;
IDENTIFIER id = DEREF_id (hashid_id (nm));
expand_label : {
switch (TAG_id (id)) {
case id_obj_macro_tag :
case id_func_macro_tag : {
if (expand) {
PPTOKEN *toks = expand_macro (nm, file_loc, 1);
if (!crt_line_changed) crt_spaces++;
this_tok->tok = lex_ignore_token;
this_tok->next = toks;
prev_tok = this_tok;
this_tok = toks;
goto start_label;
}
id = DEREF_id (id_alias (id));
goto expand_label;
}
case id_keyword_tag : {
if (store == EXPAND_AHEAD) {
t = (int) DEREF_ulong (id_no (id));
this_tok->tok = t;
}
break;
}
case id_iso_keyword_tag : {
if (store == EXPAND_AHEAD) {
t = (int) DEREF_ulong (id_no (id));
if (t >= FIRST_SYMBOL && t <= LAST_SYMBOL) {
/* Will be reinterpreted later */
t = lex_and_H2;
}
this_tok->tok = t;
}
break;
}
}
}
if (find_hashid (nm) == lex_pragma_H2) {
if (operator_pragma ()) {
this_tok = crt_token->next;
/* Continue after the closing ) */
goto start_label;
}
/* Otherwise treat _Pragma as an ordinary identifier */
}
this_tok->pp_data.id.use = id;
}
return (t);
}
/*
* PARSE A TEMPLATE IDENTIFIER
*
* This routine is called after the optional 'template' at the start of
* a qualified identifier or a field member selector. It forces the
* following identifier to be treated as a template-id even if it doesn't
* seem to be one.
*/
void
rescan_template(NAMESPACE ns)
{
PPTOKEN *p = crt_token;
crt_lookup = ns;
have_template = 0;
IGNORE expand_token (EXPAND_TEMPLATE);
if (!have_template) {
/* Didn't read template-id */
report (crt_loc, ERR_temp_names_bad ());
}
crt_token = p;
crt_lookup = ns;
return;
}
syntax highlighted by Code2HTML, v. 0.9.1