/*
* 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/predict.c,v 1.6 2004/08/14 15:15:39 bp Exp $
*/
#include "config.h"
#include "producer.h"
#include "c_types.h"
#include "id_ops.h"
#include "type_ops.h"
#include "namespace.h"
#include "parse.h"
#include "predict.h"
#include "syntax.h"
/*
* PARSING C++ USING SID
*
* The parser for this compiler is generated using the sid tool.
* Basically sid can generate a parser for any grammar it can transform
* into an LL(1) grammar. Unfortunately, C++ is not a LL(1) language,
* so that no such grammar for C++ can be written. In fact, C++ is a
* LL(k) language since a potentially unlimited look-ahead is necessary
* to distinguish declarations from expressions. However the points
* at which C++ is not LL(1) are relatively few, so we have used sid's
* predicate mechanism to enable the look-ahead in these places to be
* done by hand, leaving sid to deal with the rest. This file contains
* the implementation of these predicates. A number of the routines
* contain conditional compilation to handle the differences between
* the C++ and C grammars. Note that if the grammars are changed it
* may also be necessary to modify these routines.
*
* The look-ahead itself is implemented using next_token to read and store
* the next token. Provided crt_token is reset afterwards, this will be
* invisible to the main parser.
*/
/*
* TOKEN LOOK-UP TABLE
*
* This table gives a simple look-up for lexical tokens to predict which
* kind of construct is likely to start with this token. The values
* themselves are built into symbols.h.
*/
#define TOK_NONE 0
#define TOK_DECLARATION 1
#define TOK_DECL_SPEC 2
#define TOK_EXTERN 3
#define TOK_EXP 4
#define TOK_NESTED_NAME 5
#define TOK_FULL_NAME 6
#define TOK_SIMPLE_TYPE 7
#define TOK_STATEMENT 8
#define TOK_TYPE 9
#define TOK_TYPE_KEY 10
#define TOK_TYPE_SPEC 11
#if LANGUAGE_CPP
#define TOK_ASM TOK_DECLARATION
#else
#define TOK_ASM TOK_STATEMENT
#endif
#define lookup_token(T) ((int) tokens [ (T) ])
static unsigned char tokens [] = {
#define LEX_TOKEN(A, B, C) (C),
#include "symbols.h"
#undef LEX_TOKEN
TOK_NONE
};
/*
* PARSER STATE FLAGS
*
* These flags are used to indicate various parser states. The flag
* have_type_specifier is set during reading a sequence of declaration-
* specifiers or type-specifiers to indicate that a type-specifier (other
* than a cv-qualifier) has been read. Similarly have_type_declaration
* is set to indicate an elaborated-type-specifier. in_function_defn
* is used to count nested function definitions.
*/
int have_type_specifier = 0;
int have_type_declaration = TYPE_DECL_NONE;
int have_func_declarator = 0;
int in_function_defn = 0;
int in_class_defn = 0;
int in_declaration = 0;
int in_default_arg = 0;
int in_weak_param = 0;
int in_ptr_mem_selector = 0;
int in_token_decl = 0;
int in_template_decl = 0;
int in_for_decl = 0;
int really_in_function_defn = 0;
int really_in_class_defn = 0;
int is_function_next = 0;
int is_constructor_next = 0;
/*
* PARSER STATE COUNTERS
*
* These variables are used to keep count of various items of interest
* in the parser, such as the number of expressions which have side
* effects and the number of type definitions.
*/
int no_side_effects = 0;
int no_type_defns = 0;
int have_destructor = 0;
unsigned long no_declarations = 0;
unsigned long no_token_defns = 0;
/*
* FEATURE USE FLAGS
*
* These flags are set to indicate that certain features, which require
* the program to perform extra checks, have been used.
*/
int used_extern_volatile = 0;
int used_register = 0;
/*
* FORWARD DECLARATIONS
*
* The following look-ahead functions need to be declared in advance.
*/
#if LANGUAGE_CPP
static int predict_declarator(int, int, int);
#endif
/*
* SKIP OVER A BRACKETED SEQUENCE
*
* This routine is called after reading an open bracket to skip to the
* corresponding close bracket. It returns the number of tokens skipped.
*/
#if LANGUAGE_CPP
static int
skip_brackets(void)
{
int n = 0;
int brackets = 1;
for (;;) {
int t = next_token ();
n++;
switch (t) {
case lex_open_Hround :
case lex_open_Hsquare_H1 :
case lex_open_Hbrace_H1 : {
/* Open bracket */
brackets++;
break;
}
case lex_close_Hround :
case lex_close_Hsquare_H1 :
case lex_close_Hbrace_H1 : {
/* Close bracket */
if (--brackets == 0) return (n);
break;
}
case lex_eof : {
/* Premature end of file */
return (n);
}
}
}
/* NOTREACHED */
}
#endif
/*
* SKIP OVER AN OPERATOR NAME
*
* This routine is called after 'operator' has been read to return the
* token immediately following. It has to deal with both overloaded
* operator function names and conversion function names. Note that
* class and enumeration definitions are allowed in a conversion function
* name by the syntax, but are weeded out later. Skipping over them
* here would therefore seem to be a lot of effort for something which
* is going to prove illegal however it is interpreted.
*/
#if LANGUAGE_CPP
static int
skip_operator(void)
{
int t, c;
int go = 1;
int have_type = 0;
/* Check for conversion function names */
do {
t = next_token ();
c = lookup_token (t);
switch (c) {
case TOK_SIMPLE_TYPE :
case TOK_TYPE_SPEC :
case TOK_TYPE : {
/* These are type-specifiers */
have_type = 1;
break;
}
case TOK_NESTED_NAME :
case TOK_FULL_NAME : {
/* Look for nested type names */
PPTOKEN *p = crt_token;
NAMESPACE np = crt_lookup;
int t2 = next_token ();
c = lookup_token (t2);
if (c != TOK_TYPE) {
crt_lookup = np;
crt_token = p;
return (t);
}
have_type = 1;
break;
}
case TOK_TYPE_KEY : {
/* These are elaborated-type-specifiers */
t = next_token ();
switch (t) {
case lex_identifier :
case lex_type_Hname :
case lex_namespace_Hname :
case lex_statement_Hname :
case lex_template_Htype : {
/* Name present */
t = next_token ();
break;
}
case lex_full_Hname :
case lex_nested_Hname :
case lex_colon_Hcolon : {
/* Allow for nested names */
t = next_token ();
switch (t) {
case lex_identifier :
case lex_type_Hname :
case lex_namespace_Hname :
case lex_statement_Hname :
case lex_template_Htype : {
break;
}
default : {
return (t);
}
}
break;
}
default : {
/* Other characters */
return (t);
}
}
have_type = 1;
break;
}
default : {
/* Other characters */
go = 0;
break;
}
}
} while (go);
/* Step over any conversion function declarators */
if (have_type) {
go = 1;
do {
switch (t) {
case lex_and_H1 :
case lex_full_Hname_Hstar :
case lex_nested_Hname_Hstar :
case lex_star :
case lex_const :
case lex_volatile : {
/* Pointer operators */
t = next_token ();
break;
}
default : {
/* Other characters */
go = 0;
break;
}
}
} while (go);
return (t);
}
/* Check for overloaded operator function names */
switch (t) {
case lex_open_Hround : {
/* Check for 'operator ()' */
t = next_token ();
if (t == lex_close_Hround) t = next_token ();
break;
}
case lex_open_Hsquare_H1 : {
/* Check for 'operator []' */
t = next_token ();
if (t == lex_close_Hsquare_H1) {
t = next_token ();
}
break;
}
case lex_question : {
/* Check for 'operator ?:' */
t = next_token ();
if (t == lex_colon) t = next_token ();
break;
}
case lex_new :
case lex_delete : {
/* Check for 'operator new []' and 'operator delete []' */
t = next_token ();
if (t == lex_open_Hsquare_H1) {
PPTOKEN *p = crt_token;
NAMESPACE np = crt_lookup;
int t2 = next_token ();
if (t2 == lex_close_Hsquare_H1) {
t = next_token ();
} else {
crt_token = p;
crt_lookup = np;
}
}
break;
}
}
return (t);
}
#endif
/*
* LOOK-AHEAD FOR FUNCTION PARAMETERS
*
* This routine is used to distinguish lists of function parameters from
* lists of expressions (such as function arguments or function style
* initialisers. It is called after an initial open bracket has been
* read. It returns 1 if the following list definitely consists of
* function parameters, 0 if it definitely consists of expressions,
* and 2 if it could be either.
*/
#if LANGUAGE_CPP
static int
predict_func_params(int t, int empty, int depth)
{
int c = lookup_token (t);
switch (c) {
case TOK_DECLARATION :
case TOK_DECL_SPEC :
case TOK_EXTERN :
case TOK_TYPE_KEY :
case TOK_TYPE_SPEC : {
/* These are all obviously parameter declarations */
return (1);
}
case TOK_SIMPLE_TYPE :
case TOK_TYPE : {
/* These are simple-type-specifiers */
t = next_token ();
if (t == lex_open_Hround) {
t = next_token ();
return (predict_func_params (t, 1, 1));
}
return (1);
}
case TOK_NESTED_NAME :
case TOK_FULL_NAME : {
/* Look for nested type-names */
t = next_token ();
c = lookup_token (t);
if (c == TOK_TYPE) {
t = next_token ();
if (t == lex_open_Hround) {
t = next_token ();
return (predict_func_params (t, 1, 1));
}
return (1);
}
return (0);
}
}
if (t == lex_ellipsis) return (1);
if (t == lex_ellipsis_Hexp) return (1);
if (t == lex_close_Hround) {
/* Empty pair of brackets */
return (empty);
}
if (depth) {
int d = predict_declarator (t, 2, 1);
if (d == 0) return (0);
if (d == 2) {
/* Comma - check next parameter */
t = next_token ();
return (predict_func_params (t, 1, 0));
}
if (d == 3) return (2);
return (1);
}
return (0);
}
#endif
/*
* LOOK-AHEAD FOR DECLARATORS
*
* This routine is used to distinguish declarators from other constructs,
* including expressions. The argument depth indicates the number of
* open brackets which have been read before the routine is entered.
* The argument loc is 0 to indicate normal declarators, 1 to indicate
* abstract declarators and 2 to indicate parameter declarators. The
* return value is 0 if this is definitely not a declarator, and 1 if it
* definitely is. The return values 2 and 3 are used to indicate possible
* declarators in the parameter case, with 2 indicating a following comma
* and 3 a close bracket.
*/
#if LANGUAGE_CPP
static int
predict_declarator(int t, int loc, int depth)
{
int go = 1;
int res = -1;
int have_init = 0;
NAMESPACE ns = NULL_nspace;
/* Step over open brackets and pointer operations */
while (go) {
switch (t) {
case lex_and_H1 :
case lex_star : {
/* Can be a pointer or reference or a unary operator */
t = next_token ();
if (t == lex_const || t == lex_volatile) {
/* This is definitely a pointer operation */
return (1);
}
break;
}
case lex_full_Hname_Hstar :
case lex_nested_Hname_Hstar : {
/* Definitely a pointer to member */
return (1);
}
case lex_open_Hround : {
/* Nested declarator brackets */
depth++;
t = next_token ();
break;
}
default : {
/* Other tokens */
go = 0;
break;
}
}
}
/* Check for declarator-id */
if (loc != 1) {
switch (t) {
case lex_nested_Hname :
case lex_full_Hname :
case lex_colon_Hcolon : {
/* Allow for qualified identifiers */
ns = crt_lookup;
t = next_token ();
break;
}
}
switch (t) {
case lex_identifier :
case lex_type_Hname :
case lex_namespace_Hname :
case lex_statement_Hname :
case lex_destructor_Hname :
case lex_template_Hid :
case lex_template_Htype : {
/* Identifiers and destructors */
t = next_token ();
break;
}
case lex_operator : {
/* Operator function identifiers */
t = skip_operator ();
break;
}
default : {
/* Anything else isn't a declarator-id */
if (loc == 0 || !IS_NULL_nspace (ns)) return (0);
break;
}
}
}
/* Check for declarator tail and initialiser */
if (!IS_NULL_nspace (ns)) {
IGNORE add_nested_nspace (ns);
}
for (;;) {
switch (t) {
case lex_open_Hround : {
/* Function parameters, function call or initialiser */
int d;
PPTOKEN *p = crt_token;
NAMESPACE np = crt_lookup;
t = next_token ();
d = predict_func_params (t, 1, 0);
if (d == 1) {
/* Definitely function parameters */
res = 1;
} else if (d == 0) {
/* Definitely expression list */
if (depth > 0 || have_init) {
/* Can't be an initialiser in these cases */
res = 0;
} else {
crt_lookup = np;
crt_token = p;
IGNORE skip_brackets ();
have_init = 1;
}
}
break;
}
case lex_open_Hsquare_H1 : {
/* Array dimension or index expression */
int d = skip_brackets ();
if (d == 1) {
/* Only array dimensions can be empty */
res = 1;
}
break;
}
case lex_assign : {
/* Initialiser or assignment expression */
int brackets = 0;
if (loc == 1 || depth > 0) {
/* Can't have initialiser in these cases */
res = 0;
break;
}
t = next_token ();
if (t == lex_open_Hbrace_H1) {
/* Can only have aggregates in initialisers */
if (loc == 0) {
res = 1;
break;
}
}
/* Scan to end of expression */
go = 1;
while (go) {
switch (t) {
case lex_open_Hround :
case lex_open_Hsquare_H1 :
case lex_open_Hbrace_H1 : {
/* Open bracket */
brackets++;
break;
}
case lex_close_Hround :
case lex_close_Hsquare_H1 :
case lex_close_Hbrace_H1 : {
/* Close bracket */
brackets--;
if (brackets < 0 && loc == 2) res = 3;
break;
}
case lex_semicolon : {
/* End of declaration */
if (brackets <= 0) res = 3;
break;
}
case lex_comma : {
/* Comma */
if (brackets <= 0) {
/* Check rest of declaration */
if (loc == 1) {
res = 0;
} else if (loc == 2) {
res = 2;
} else {
t = next_token ();
res = predict_declarator (t, 0, 0);
}
}
break;
}
case lex_ellipsis :
case lex_ellipsis_Hexp : {
/* Ellipsis */
if (loc == 2 && brackets <= 0) res = 1;
break;
}
case lex_eof : {
/* Premature end of file */
res = 1;
break;
}
}
if (res != -1) break;
t = next_token ();
}
break;
}
case lex_semicolon :
case lex_close_Htemplate : {
/* End of declaration (don't worry about depth) */
res = 3;
break;
}
case lex_comma : {
/* Comma */
if (depth <= 0) {
/* Check rest of declaration */
if (loc == 1) {
res = 1;
} else if (loc == 2) {
res = 2;
} else {
t = next_token ();
res = predict_declarator (t, 0, 0);
}
} else {
res = 0;
}
break;
}
case lex_ellipsis :
case lex_ellipsis_Hexp : {
/* Ellipsis */
if (depth <= 0 && loc == 2) {
res = 1;
} else {
res = 0;
}
break;
}
case lex_close_Hround : {
/* Declarator close bracket */
depth--;
if (depth < 0) {
if (loc == 1) {
res = 1;
} else if (loc == 2) {
res = 3;
}
}
break;
}
default : {
/* Nothing else can appear in a declaration */
res = 0;
break;
}
}
if (res != -1) break;
t = next_token ();
}
if (!IS_NULL_nspace (ns)) {
IGNORE remove_nested_nspace (ns);
}
return (res);
}
#endif
/*
* LOOK-AHEAD FOR DECLARATION STATEMENTS
*
* A look-ahead is needed in declaration-statement to distinguish
* declarations from other statements including, in particular, expression
* statements. The disambiguation rule is that anything which looks like
* a declaration is a declaration. Note that the empty statement is
* classified as an expression-statement. Actually the real answer to
* questions like is 'int (a) ;' a declaration or an expression is,
* are flying pigs kosher?
*/
int
predict_decl(void)
{
int t = crt_lex_token;
int c = lookup_token (t);
switch (c) {
case TOK_DECLARATION :
case TOK_DECL_SPEC :
case TOK_EXTERN :
case TOK_TYPE_KEY :
case TOK_TYPE_SPEC : {
/* These are all obviously declarations */
return (1);
}
case TOK_SIMPLE_TYPE :
case TOK_TYPE : {
/* These are simple-type-specifiers */
int d = 1;
PPTOKEN *p = crt_token;
NAMESPACE np = crt_lookup;
t = next_token ();
#if LANGUAGE_CPP
if (t == lex_open_Hround) {
/* This is the tricky case, 'T (...' */
t = next_token ();
d = predict_declarator (t, 0, 1);
} else /* continued ... */
#endif
if (t == lex_colon) {
/* Check for labels */
if (c == TOK_TYPE) d = 0;
}
crt_lookup = np;
crt_token = p;
return (d);
}
#if LANGUAGE_CPP
case TOK_NESTED_NAME :
case TOK_FULL_NAME : {
/* Look for nested type-names */
int d = 0;
PPTOKEN *p = crt_token;
NAMESPACE np = crt_lookup;
t = next_token ();
c = lookup_token (t);
if (c == TOK_TYPE) {
d = 1;
t = next_token ();
if (t == lex_open_Hround) {
/* This is the tricky case, 'N::T (...' */
t = next_token ();
d = predict_declarator (t, 0, 1);
}
}
crt_lookup = np;
crt_token = p;
return (d);
}
#endif
}
/* Nothing else is a declaration */
return (0);
}
/*
* LOOK-AHEAD FOR UNDECLARED TYPES
*
* This look-ahead is used to handle syntax errors following undeclared
* types. The context is in a sequence of declaration specifiers in
* which no type specifier has been encountered. t gives the token read.
*/
static int
predict_undecl_type(int t, int force)
{
switch (t) {
case lex_identifier :
case lex_type_Hname :
case lex_namespace_Hname :
case lex_statement_Hname : {
int d = force;
PPTOKEN *p = crt_token;
NAMESPACE np = crt_lookup;
if (!d) {
t = next_token ();
switch (t) {
#if LANGUAGE_CPP
case lex_and_H1 :
case lex_full_Hname_Hstar :
case lex_nested_Hname_Hstar :
#endif
case lex_star : {
/* These are ptr-operators */
d = 1;
break;
}
case lex_open_Hround : {
/* This is stretching the bounds of possibility */
break;
}
case lex_identifier :
case lex_type_Hname :
case lex_namespace_Hname :
case lex_statement_Hname :
case lex_template_Htype :
case lex_template_Hid :
case lex_full_Hname :
case lex_nested_Hname : {
/* The identifier can't be a declarator */
d = 1;
break;
}
default : {
/* Check for further declaration specifiers */
int c = lookup_token (t);
switch (c) {
case TOK_DECL_SPEC :
case TOK_SIMPLE_TYPE :
case TOK_TYPE_KEY :
case TOK_TYPE_SPEC :
case TOK_EXTERN :
case TOK_TYPE : {
d = 1;
break;
}
}
break;
}
}
}
if (d) p->tok = lex_type_Hname;
crt_lookup = np;
crt_token = p;
return (d);
}
}
return (0);
}
/*
* LOOK-AHEAD FOR DECLARATION SPECIFIERS
*
* A look-ahead is needed to distinguish decl-specifiers from following
* declarators or other constructs. Note that linkage-specifications are
* spotted at this stage. In addition type names are not always what
* they seem. For example in:
*
* typedef int t;
* typedef int t;
*
* the second t is a type-name, but needs to be recognised as a declarator-id
* rather than a decl-specifier. Similarly in:
*
* class c {
* c ();
* };
*
* the second c is a class-name, but is actually a constructor name rather
* than a decl-specifier.
*/
int
predict_dspec(int force)
{
int d = 0;
int t = crt_lex_token;
int c = lookup_token (t);
#if LANGUAGE_CPP
is_constructor_next = 0;
#endif
switch (c) {
case TOK_DECL_SPEC :
case TOK_SIMPLE_TYPE :
case TOK_TYPE_KEY :
case TOK_TYPE_SPEC : {
/* These are declaration-specifiers */
d = 1;
break;
}
case TOK_EXTERN : {
#if LANGUAGE_CPP
/* Explicitly check for linkage-specifications */
PPTOKEN *p = crt_token;
NAMESPACE np = crt_lookup;
t = next_token ();
if (t != lex_string_Hexp && t != lex_wstring_Hexp) d = 1;
crt_lookup = np;
crt_token = p;
#else
d = 1;
#endif
break;
}
case TOK_TYPE : {
/* Only the first type name is counted */
if (t == lex_type_Hname || t == lex_template_Htype) {
if (!have_type_specifier) {
#if LANGUAGE_CPP
PPTOKEN *p = crt_token;
NAMESPACE np = crt_lookup;
d = 1;
t = next_token ();
if (t == lex_open_Hround) {
/* Allow for constructors */
t = next_token ();
if (predict_func_params (t, 1, 0)) {
is_constructor_next = 1;
d = 0;
}
}
crt_lookup = np;
crt_token = p;
#else
d = 1;
#endif
}
} else {
d = 1;
}
break;
}
#if LANGUAGE_CPP
case TOK_NESTED_NAME :
case TOK_FULL_NAME : {
/* Look for nested type names */
if (!have_type_specifier) {
PPTOKEN *p = crt_token;
NAMESPACE np = crt_lookup;
t = next_token ();
c = lookup_token (t);
if (c == TOK_TYPE) {
/* These are simple-type-specifiers */
d = 1;
t = next_token ();
if (t == lex_open_Hround) {
/* Allow for constructors */
IGNORE add_nested_nspace (np);
t = next_token ();
if (predict_func_params (t, 1, 0)) {
is_constructor_next = 1;
d = 0;
}
IGNORE remove_nested_nspace (np);
}
} else {
d = predict_undecl_type (t, force);
}
crt_lookup = np;
crt_token = p;
}
break;
}
#endif
default : {
/* Check for undefined types */
if (!have_type_specifier) {
d = predict_undecl_type (t, force);
if (d) crt_lex_token = lex_type_Hname;
}
break;
}
}
return (d);
}
/*
* LOOK-AHEAD FOR TYPE SPECIFIERS
*
* A look-ahead is needed to distinguish type-specifiers from following
* declarators or other constructs.
*/
int
predict_tspec(int force)
{
int d = 0;
int t = crt_lex_token;
int c = lookup_token (t);
switch (c) {
case TOK_SIMPLE_TYPE :
case TOK_TYPE_KEY :
case TOK_TYPE_SPEC :
case TOK_TYPE : {
/* These are type-specifiers */
d = 1;
break;
}
#if LANGUAGE_CPP
case TOK_NESTED_NAME :
case TOK_FULL_NAME : {
/* Look for nested type names */
PPTOKEN *p = crt_token;
NAMESPACE np = crt_lookup;
t = next_token ();
c = lookup_token (t);
if (c == TOK_TYPE) {
d = 1;
} else {
if (!have_type_specifier) {
d = predict_undecl_type (t, force);
}
}
crt_lookup = np;
crt_token = p;
break;
}
#endif
default : {
/* Check for undefined types */
if (!have_type_specifier) {
d = predict_undecl_type (t, force);
if (d) crt_lex_token = lex_type_Hname;
}
break;
}
}
return (d);
}
/*
* LOOK-AHEAD FOR FUNCTION QUALIFIERS
*
* A further look-ahead is required when distinguishing type-ids from
* expressions after 'T ()' has been read for some type. If the next
* token is '+' for example it is an expression, if it is 'const' it
* is a declaration. t gives the next token and e gives the default
* value.
*/
#if LANGUAGE_CPP
static int
predict_qual(int t, int e)
{
switch (t) {
case lex_const :
case lex_volatile :
case lex_throw : {
/* Function qualifiers */
e = 1;
break;
}
case lex_and_H1 :
case lex_and_Heq_H1 :
case lex_arrow :
case lex_arrow_Hstar :
case lex_assign :
case lex_div :
case lex_div_Heq :
case lex_dot :
case lex_dot_Hstar :
case lex_eq :
case lex_greater :
case lex_greater_Heq :
case lex_less :
case lex_less_Heq :
case lex_logical_Hand_H1 :
case lex_logical_Hor_H1 :
case lex_lshift :
case lex_lshift_Heq :
case lex_minus :
case lex_minus_Heq :
case lex_minus_Hminus :
case lex_not_Heq_H1 :
case lex_or_H1 :
case lex_or_Heq_H1 :
case lex_plus :
case lex_plus_Heq :
case lex_plus_Hplus :
case lex_question :
case lex_rem :
case lex_rem_Heq :
case lex_rshift :
case lex_rshift_Heq :
case lex_star :
case lex_star_Heq :
case lex_xor_H1 :
case lex_xor_Heq_H1 :
case lex_abs :
case lex_max :
case lex_min : {
/* Binary expression operators */
e = 0;
break;
}
case lex_comma : {
/* Comma operators */
if (e == 1) e = 0;
break;
}
}
return (e);
}
#endif
/*
* LOOK-AHEAD FOR TYPE IDENTIFIERS
*
* A look-ahead is needed to distinguish type-ids from expressions in,
* for example, sizeof expressions. A type-id consists of a sequence
* of type-specifiers followed by an optional abstract-declarator,
* whereas the only tricky expressions are those consisting of a
* simple-type-specifier followed by a bracketed list of expressions.
* e gives the value to be returned if the result could be either.
*/
int
predict_typeid(int e)
{
int t = crt_lex_token;
int c = lookup_token (t);
switch (c) {
case TOK_TYPE_KEY :
case TOK_TYPE_SPEC : {
/* These are type-specifiers */
return (1);
}
case TOK_SIMPLE_TYPE :
case TOK_TYPE : {
/* These are simple-type-specifiers */
int d = 1;
#if LANGUAGE_CPP
PPTOKEN *p = crt_token;
NAMESPACE np = crt_lookup;
t = next_token ();
if (t == lex_open_Hround) {
/* This is the tricky case 'T (...' */
PPTOKEN *q;
NAMESPACE nq;
t = next_token ();
q = crt_token;
nq = crt_lookup;
d = predict_func_params (t, 2, 0);
if (d != 1) {
if (t == lex_close_Hround) {
t = next_token ();
d = predict_qual (t, e);
} else {
crt_lookup = nq;
crt_token = q;
d = predict_declarator (t, 1, 1);
}
}
}
crt_lookup = np;
crt_token = p;
#else
UNUSED (e);
#endif
return (d);
}
#if LANGUAGE_CPP
case TOK_NESTED_NAME :
case TOK_FULL_NAME : {
/* Look for nested type-names */
int d = 0;
PPTOKEN *p = crt_token;
NAMESPACE np = crt_lookup;
t = next_token ();
c = lookup_token (t);
if (c == TOK_TYPE) {
d = 1;
t = next_token ();
if (t == lex_open_Hround) {
/* This is the tricky case 'N::T (...' */
PPTOKEN *q;
NAMESPACE nq;
t = next_token ();
q = crt_token;
nq = crt_lookup;
d = predict_func_params (t, 2, 0);
if (d != 1) {
if (t == lex_close_Hround) {
t = next_token ();
d = predict_qual (t, e);
} else {
crt_lookup = nq;
crt_token = q;
d = predict_declarator (t, 1, 1);
}
}
}
}
crt_lookup = np;
crt_token = p;
return (d);
}
#endif
}
return (0);
}
/*
* LOOK-AHEAD FOR TEMPLATE TYPE NAMES
*
* A look-ahead is needed to distinguish template type names from other
* types when parsing template arguments.
*/
int
predict_typename(void)
{
int d = 0;
int t = crt_lex_token;
if (t == lex_type_Hname) {
/* Unqualified type names */
IDENTIFIER id = crt_token->pp_data.id.use;
DECL_SPEC ds = DEREF_dspec (id_storage (id));
if (ds & dspec_template) d = 1;
}
#if LANGUAGE_CPP
if (t == lex_full_Hname || t == lex_nested_Hname || t == lex_colon_Hcolon) {
PPTOKEN *p = crt_token;
NAMESPACE np = crt_lookup;
t = next_token ();
if (t == lex_type_Hname) {
/* Qualified type names */
IDENTIFIER id = crt_token->pp_data.id.use;
DECL_SPEC ds = DEREF_dspec (id_storage (id));
if (ds & dspec_template) d = 1;
}
crt_lookup = np;
crt_token = p;
}
#endif
return (d);
}
/*
* LOOK-AHEAD FOR INITIALISERS
*
* A look-ahead is needed to distinguish function-style initialisers in
* init-declarator from function declarators. This predicate is called
* immediately after an open bracket. Note that anything which could
* possibly be a function declarator is. If the result is an initialiser
* beginning with '(' then this first token is replaced by a dummy to
* prevent further calls to predict_init.
*/
int
predict_init(void)
{
#if LANGUAGE_CPP
PPTOKEN *p = crt_token;
NAMESPACE np = crt_lookup;
int t = crt_lex_token;
int d = predict_func_params (t, 1, 0);
crt_lookup = np;
crt_token = p;
if (d == 0) {
/* Definitely doesn't look like a function declarator */
if (t == lex_open_Hround) {
t = lex_open_Hinit;
crt_lex_token = t;
p->tok = t;
}
return (1);
}
if (t == lex_ellipsis_Hexp) {
t = lex_ellipsis;
crt_lex_token = t;
p->tok = t;
}
#endif
return (0);
}
/*
* LOOK-AHEAD FOR DESTRUCTORS
*
* A look-ahead is required to distinguish a destructor-name from a
* complement operator followed by a class-name. The latter is only the
* case if it is followed by a bracketed list of expressions. The
* really difficult case is when this list is empty. The return value
* is 2 following '::', 3 following '->' or '.', and 1 for other
* destructors.
*/
int
predict_destr(NAMESPACE ns)
{
#if LANGUAGE_CPP
int d = 1;
int t = last_lex_token;
if (!IS_NULL_nspace (ns)) {
if (EQ_nspace (ns, global_namespace)) {
t = lex_colon_Hcolon;
} else {
t = lex_nested_Hname;
}
}
switch (t) {
case lex_nested_Hname :
case lex_full_Hname : {
/* Always have destructor names after these */
if (cache_lookup) {
d = 2;
} else {
/* Can only happen after '.' or '->' */
d = 3;
}
break;
}
case lex_colon_Hcolon : {
/* Never have destructor name after this */
d = 0;
break;
}
case lex_arrow :
case lex_dot : {
/* Always have destructor names after these */
d = 3;
break;
}
default : {
PPTOKEN *p = crt_token;
NAMESPACE np = crt_lookup;
t = next_token ();
if (t == lex_open_Hround) {
t = next_token ();
if (t == lex_close_Hround) {
/* This is the commonest case */
if (in_function_defn) d = 0;
} else {
d = predict_func_params (t, 1, 0);
if (d) d = 1;
}
}
crt_lookup = np;
crt_token = p;
break;
}
}
return (d);
#else
UNUSED (ns);
return (0);
#endif
}
/*
* LOOK-AHEAD FOR FUNCTION PARAMETERS
*
* A look-ahead is needed to distinguish a declarator-id representing a
* function parameter from a type-specifier. The only difficult case is
* a type-name immediately after an open bracket.
*/
int
predict_param(void)
{
int t = crt_lex_token;
switch (t) {
case lex_identifier :
case lex_namespace_Hname :
case lex_statement_Hname :
case lex_destructor_Hname :
case lex_template_Hid :
case lex_operator : {
/* These are all unqualified-ids */
return (1);
}
case lex_type_Hname :
case lex_template_Htype : {
/* Check for type names */
if (last_lex_token != lex_open_Hround) return (1);
break;
}
#if LANGUAGE_CPP
case lex_full_Hname :
case lex_nested_Hname :
case lex_colon_Hcolon : {
/* Check token after a nested name */
int d;
PPTOKEN *p = crt_token;
NAMESPACE np = crt_lookup;
crt_lex_token = next_token ();
d = predict_param ();
crt_lex_token = t;
crt_lookup = np;
crt_token = p;
return (d);
}
#endif
}
return (0);
}
/*
* LOOK-AHEAD FOR CLASS SPECIFICATIONS
*
* A look-ahead of one token is needed in type-specifier to distinguish a
* class-specifier or an enum-specifier from an elaborated-type-specifier.
* This predicate is called after a class-key to check for a class-specifier
* or an enum-specifier. This is recognised by an optional qualified
* identifier followed by an open brace (for the class body) or a colon
* (for a base-clause, if col is true).
*/
int
predict_class(int col)
{
int t = crt_lex_token;
/* Examine the name */
switch (t) {
case lex_identifier :
case lex_type_Hname :
case lex_namespace_Hname :
case lex_statement_Hname :
case lex_template_Htype : {
/* Name present */
PPTOKEN *p = crt_token;
NAMESPACE np = crt_lookup;
t = next_token ();
crt_lookup = np;
crt_token = p;
break;
}
#if LANGUAGE_CPP
case lex_full_Hname :
case lex_nested_Hname :
case lex_colon_Hcolon : {
/* Allow for nested names */
PPTOKEN *p = crt_token;
NAMESPACE np = crt_lookup;
t = next_token ();
switch (t) {
case lex_identifier :
case lex_type_Hname :
case lex_namespace_Hname :
case lex_statement_Hname :
case lex_template_Htype : {
/* Nested name present */
t = next_token ();
crt_lookup = np;
crt_token = p;
break;
}
default : {
/* Invalid name */
crt_lookup = np;
crt_token = p;
return (0);
}
}
break;
}
#endif
}
/* Examine the token following the name */
if (t == lex_open_Hbrace_H1) return (1);
if (t == lex_colon && !in_token_decl) return (col);
return (0);
}
/*
* LOOK-AHEAD FOR FUNCTION DEFINITIONS
*
* A predicate is needed to distinguish function definitions from function
* declarations. A function definition is recognised by means of a '{'
* (starting a function-body), a ':' (starting a ctor-initialiser), or
* a 'try' (starting a function-try-block). It has already been checked
* whether the type of the current declarator is a function.
*/
int
predict_func_defn(void)
{
int t = crt_lex_token;
if (t == lex_open_Hbrace_H1) return (1);
#if LANGUAGE_CPP
if (t == lex_try) return (1);
if (t == lex_colon && !in_token_decl) return (1);
#endif
return (0);
}
/*
* LOOK-AHEAD FOR OBJECT INITIALISERS
*
* A predicate is needed to determine whether an object declaration
* is followed by an initialising expression. Note this is not the
* same as the object being defined.
*/
int
predict_obj_defn(void)
{
int t = crt_lex_token;
if (t == lex_assign) return (1);
#if LANGUAGE_CPP
if (t == lex_open_Hround) return (1);
#endif
return (0);
}
/*
* LOOK-AHEAD FOR POINTER OPERATORS
*
* A look-ahead is needed following a conversion-function-id for possible
* ptr-operators. This is because, for instance 'operator int *' needs
* to be resolved as the conversion function for 'int *' rather than as
* the conversion function for 'int' times something. The argument ref
* indicates whether '&' is a valid pointer operator.
*/
int
predict_ptr(int ref)
{
int t = crt_lex_token;
if (t == lex_star) return (1);
#if LANGUAGE_CPP
if (t == lex_full_Hname_Hstar || t == lex_nested_Hname_Hstar) return (1);
if (t == lex_and_H1) return (ref);
#else
UNUSED (ref);
#endif
return (0);
}
/*
* LOOK-AHEAD FOR OPERATOR NAMES
*
* A look-ahead is needed in the token syntax for overloaded operator
* and conversion function names.
*/
int
predict_operator(void)
{
#if LANGUAGE_CPP
int t = crt_lex_token;
if (t == lex_operator) return (1);
#endif
return (0);
}
/*
* LOOK-AHEAD FOR ARRAY OPERATORS
*
* A look-ahead of one token is needed following 'operator new' and
* 'operator delete'. A following '[' might be the start of an array index,
* or it may introduce 'operator new []' or 'operator delete []'. This
* routine returns true in the latter case.
*/
int
predict_array(void)
{
PPTOKEN *p;
NAMESPACE np;
int t = crt_lex_token;
if (t != lex_open_Hsquare_H1) return (0);
p = crt_token;
np = crt_lookup;
t = next_token ();
crt_lookup = np;
crt_token = p;
if (t != lex_close_Hsquare_H1) return (0);
return (1);
}
/*
* LOOK-AHEAD FOR TEMPLATE PARAMETERS
*
* A look-ahead is required to distinguish type template parameters from
* non-type template parameters.
*/
int
predict_template(void)
{
int d = 0;
int t = crt_lex_token;
if (t == lex_class || t == lex_typename) {
int have_id = 0;
PPTOKEN *p = crt_token;
int s = next_token ();
switch (s) {
case lex_identifier :
case lex_type_Hname :
case lex_namespace_Hname :
case lex_statement_Hname : {
s = next_token ();
have_id = 1;
break;
}
}
if (s == lex_comma || s == lex_close_Htemplate) {
d = 1;
} else if (s == lex_assign) {
if (have_id) {
s = next_token ();
crt_lex_token = s;
d = predict_typeid (2);
} else {
d = 1;
}
}
crt_lex_token = t;
crt_token = p;
} else if (t == lex_template) {
d = 1;
}
return (d);
}
syntax highlighted by Code2HTML, v. 0.9.1