/*
 * 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