Subversion Repositories tendra.SVN

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
                 Crown Copyright (c) 1997, 1998
    
    This TenDRA(r) Computer Program is subject to Copyright
    owned by the United Kingdom Secretary of State for Defence
    acting through the Defence Evaluation and Research Agency
    (DERA).  It is made available to Recipients with a
    royalty-free licence for its use, reproduction, transfer
    to other parties and amendment for any purpose not excluding
    product development provided that any such use et cetera
    shall be deemed to be acceptance of the following conditions:-
    
        (1) Its Recipients shall ensure that this Notice is
        reproduced upon any copies or amended versions of it;
    
        (2) Any amended version of it shall be clearly marked to
        show both the nature of and the organisation responsible
        for the relevant amendment or amendments;
    
        (3) Its onward transfer from a recipient to another
        party shall be deemed to be that party's acceptance of
        these conditions;
    
        (4) DERA gives no warranty or assurance as to its
        quality or suitability for any purpose and DERA accepts
        no liability whatsoever in relation to any use to which
        it may be put.
*/


#include "config.h"
#include "c_types.h"
#include "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 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 PROTO_S ( ( 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
    PROTO_Z ()
{
    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
    PROTO_Z ()
{
    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
    PROTO_N ( ( t, empty, depth ) )
    PROTO_T ( int t X int empty X 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
    PROTO_N ( ( t, loc, depth ) )
    PROTO_T ( int t X int loc X 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
    PROTO_Z ()
{
    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
    PROTO_N ( ( t, force ) )
    PROTO_T ( int t X 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
    PROTO_N ( ( force ) )
    PROTO_T ( 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
    PROTO_N ( ( force ) )
    PROTO_T ( 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
    PROTO_N ( ( t, e ) )
    PROTO_T ( int t X 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
    PROTO_N ( ( e ) )
    PROTO_T ( 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
    PROTO_Z ()
{
    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
    PROTO_Z ()
{
#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
    PROTO_N ( ( ns ) )
    PROTO_T ( 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
    PROTO_Z ()
{
    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
    PROTO_N ( ( col ) )
    PROTO_T ( 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
    PROTO_Z ()
{
    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
    PROTO_Z ()
{
    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
    PROTO_N ( ( ref ) )
    PROTO_T ( 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
    PROTO_Z ()
{
#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
    PROTO_Z ()
{
    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
    PROTO_Z ()
{
    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 ) ;
}