Logo Search packages:      
Sourcecode: u++ version File versions

parse.cc

//                              -*- Mode: C++ -*- 
// 
// uC++ Version 5.0.1, Copyright (C) Peter A. Buhr and Richard A. Stroobosscher 1994
// 
// parse.c -- 
// 
// Author           : Richard A. Stroobosscher
// Created On       : Tue Apr 28 15:10:34 1992
// Last Modified By : Peter A. Buhr
// Last Modified On : Tue Sep  7 11:30:29 2004
// Update Count     : 2407
//
// This  library is free  software; you  can redistribute  it and/or  modify it
// under the terms of the GNU Lesser General Public License as published by the
// Free Software  Foundation; either  version 2.1 of  the License, or  (at your
// option) any later version.
// 
// This library is distributed in the  hope that it will be useful, but WITHOUT
// ANY  WARRANTY;  without even  the  implied  warranty  of MERCHANTABILITY  or
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
// for more details.
// 
// You should  have received a  copy of the  GNU Lesser General  Public License
// along  with this library.
// 

#include "uassert.h"
#include "main.h"
#include "name.h"
#include "key.h"
#include "hash.h"
#include "attribute.h"
#include "symbol.h"
#include "structor.h"
#include "token.h"
#include "table.h"
#include "input.h"
#include "scan.h"
#include "jump.h"
#include "parse.h"
#include "gen.h"

#include <set>

//#define __U_DEBUG_H__

#ifdef __U_DEBUG_H__
static void print_focus_change( char *name, table_t *from, table_t *to ) {
    cerr << " top:" << top << " (" << (top->tbl->symbol != NULL ? top->tbl->symbol->hash->text : (top->tbl == root) ? "root" : "template/compound") << ") " <<
      name << " change focus from:" <<
      from << " (" << (from->symbol != NULL ? from->symbol->hash->text : (from == root) ? "root" : "template/compound") << ") to " <<
      to << " (" << (to->symbol != NULL ? to->symbol->hash->text : (to == root) ? "root" : "template/compound") << ")" << endl;
} // print_focus_change
#endif // __U_DEBUG_H__


#define LC '{'
#define RC '}'

#define LP '('
#define RP ')'

#define LB '['
#define RB ']'

#define LA '<'
#define RA '>'


static const char *kind( symbol_t *symbol ) {
    if ( ( symbol->data->key == STRUCT || symbol->data->key == CLASS || symbol->data->key == UNION ) && ! symbol->data->attribute.Mutex ) {
      if ( symbol->data->key == STRUCT ) return "STRUCT";
      else if ( symbol->data->key == CLASS ) return "CLASS";
      else return "UNION";
    } else if ( ( symbol->data->key == STRUCT || symbol->data->key == CLASS ) && symbol->data->attribute.Mutex ) {
      return "MONITOR";
    } else if ( symbol->data->key == COROUTINE ) {
      if ( ! symbol->data->attribute.Mutex ) return "COROUTINE";
      else return "CORMONITOR";
    } else if ( symbol->data->key == TASK ) {
      return "TASK";
    } else if ( symbol->data->key == DUALEVENT ) {
      return "DUALEVENT";
    } else if ( symbol->data->key == THROWEVENT ) {
      return "THROWEVENT";
    } else if ( symbol->data->key == RAISEEVENT ) {
      return "RAISEEVENT";
    } else {
      return "*UNKNOWN*";
    } // if
} // kind

    
static bool eof() {
    return ahead->value == EOF;
} // eof


static bool check( int token ) {
    return token == ahead->value;
} // check


static bool match( int token ) {
    if ( check( token ) ) {
      scan();
      return true;
    } // if
    return false;
} // match


static token_t *type();


static bool match_closing( char left, char right, bool semicolon = false, bool failLA = false ) {
    // assume starting character is already matched
    token_t *prev2 = ahead->prev_parse_token()->prev_parse_token();

    if ( left != LA || prev2->value == TYPE || prev2->prev_parse_token()->value == OPERATOR || prev2->value == MUTEX || prev2->prev_parse_token()->value == TASK ||
       ( prev2->value == IDENTIFIER && prev2->symbol != NULL && ( prev2->symbol->data->key == MEMBER || prev2->symbol->data->key == ROUTINE ) ) ) {

      // When parsing a template-id, the first non-nested ">" is taken as the
      // end of the template-argument-list rather than a greater-than
      // operator.
      for ( ;; ) {
          if ( eof() ) break;
          if ( ! semicolon && check( ';' ) ) break;
          if ( match( right ) ) {
            return true;
          } else if ( match( LP ) ) {
            if ( ! match_closing( LP, RP ) ) break;
          } else if ( match( LA ) ) {
            if ( ! match_closing( LA, RA, false, true ) ) break;
          } else if ( match( LC ) ) {
            if ( ! match_closing( LC, RC, true ) ) break;
          } else if ( match( LB ) ) {
            if ( ! match_closing( LB, RB ) ) break;
          } else {
            // must correctly parse type-names to allow the above check
            if ( left != LA || ! type() ) {
                scan();
            } // if
          } // if
      } // for
    } else {
      return failLA;
    } // if
    return false;
} // match_closing


static bool template_key() {
    token_t *back = ahead;

    if ( check( LA ) ) {
      match( LA );
      if ( match_closing( LA, RA ) ) {
          return true;
      } // if
    } // if

    ahead = back; return false;
} // template_key


static token_t *type() {
    token_t *back = ahead;
    token_t *token;

    if ( check( COLON_COLON ) ) {               // start search at the root
#ifdef __U_DEBUG_H__
      print_focus_change( "type1", focus, root );
#endif // __U_DEBUG_H__
      focus = root;
      match( COLON_COLON );
    } // if
    for ( ;; ) {
      if ( eof() ) break;
      token = ahead;
      if ( check( TYPE ) ) {
          // reset the focus of the scanner to the top table as the next
          // symbol may not be in this focus.
#ifdef __U_DEBUG_H__
          print_focus_change( "type2", focus, top->tbl );
#endif // __U_DEBUG_H__
          focus = top->tbl;
          match( TYPE );
          template_key();

          if ( check( COLON_COLON ) ) {
            uassert( token != NULL );
            uassert( token->symbol != NULL );
#ifdef __U_DEBUG_H__
            print_focus_change( "type3", focus, token->symbol->data->table );
#endif // __U_DEBUG_H__
            focus = token->symbol->data->table;
            if ( focus == NULL ) break;         // not defined ?
            match( COLON_COLON );
          } else {
            return token;
          } // if
      } else {
          break;
      } // if
    } // for

#ifdef __U_DEBUG_H__
    print_focus_change( "type4", focus, top->tbl );
#endif // __U_DEBUG_H__
    focus = top->tbl;
    ahead = back; return NULL;
} // type


static token_t *nested_name_specifier( bool typname ) {
    token_t *back = ahead;
    token_t *token = NULL;

    // parsing an initial "::" is more than the grammar allows
    if ( check( COLON_COLON ) ) {               // start search at the root
#ifdef __U_DEBUG_H__
      print_focus_change( "nested_name_specifier1", focus, root );
#endif // __U_DEBUG_H__
      focus = root;
      match( COLON_COLON );
    } // if
    for ( ;; ) {
      if ( eof() ) break;
      if ( check( TYPE ) || typname && check( IDENTIFIER ) ) {
          token_t *start = ahead;
          // reset the focus of the scanner to the top table as the next
          // symbol may not be in this focus.
#ifdef __U_DEBUG_H__
          print_focus_change( "nested_name_specifier2", focus, top->tbl );
#endif // __U_DEBUG_H__
          focus = top->tbl;
          scan();                         // type or identifier
          template_key();

          if ( check( COLON_COLON ) ) {
            token = start;
            uassert( token != NULL );
            uassert( token->symbol != NULL );
#ifdef __U_DEBUG_H__
            print_focus_change( "nested_name_specifier3", focus, token->symbol->data->table );
#endif // __U_DEBUG_H__
            focus = token->symbol->data->table;
            match( COLON_COLON );
            if ( match( TEMPLATE ) ) {
                if ( check( IDENTIFIER ) ) {
                  ahead->value = TYPE;
                } // if
            } // if
          } else {
            if ( token == NULL ) break;
            return token;
          } // if
      } else {
          if ( token == NULL ) break;
          return token;
      } // if
    } // for

#ifdef __U_DEBUG_H__
    print_focus_change( "nested_name_specifier4", focus, top->tbl );
#endif // __U_DEBUG_H__
    focus = top->tbl;
    ahead = back; return NULL;
} // nested_name_specifier


static token_t *epyt() {
    token_t *back = ahead;
    token_t *token;

    if ( check( COLON_COLON ) ) {               // start search at the root
#ifdef __U_DEBUG_H__
      print_focus_change( "epyt1", focus, root );
#endif // __U_DEBUG_H__
      focus = root;
      match( COLON_COLON );
    } // if
    for ( ;; ) {
      if ( eof() ) break;
      token = ahead;
      if ( match( '~' ) ) {
          token = ahead;
          if ( check( TYPE ) ) {
            // reset the focus of the scanner to the top table as the next
            // symbol may not be in this focus.
#ifdef __U_DEBUG_H__
            print_focus_change( "epyt2", focus, top->tbl );
#endif // __U_DEBUG_H__
            focus = top->tbl;
            match( TYPE );
            return token;
          } else {
            break;
          } // if
      } else if ( check( TYPE ) ) {
          // reset the focus of the scanner to the top table as the next
          // symbol may not be in this focus.
#ifdef __U_DEBUG_H__
          print_focus_change( "epyt3", focus, top->tbl );
#endif // __U_DEBUG_H__
          focus = top->tbl;
          match( TYPE );
          template_key();

          if ( check( COLON_COLON ) ) {
            uassert( token != NULL );
            uassert( token->symbol != NULL );
#ifdef __U_DEBUG_H__
            print_focus_change( "epyt4", focus, token->symbol->data->table );
#endif // __U_DEBUG_H__
            focus = token->symbol->data->table;
            if ( focus == NULL ) break;         // not defined ?
            match( COLON_COLON );
          } else {
            break;
          } // if
      } else {
          break;
      } // if
    } // for

#ifdef __U_DEBUG_H__
    print_focus_change( "epyt4", focus, top->tbl );
#endif // __U_DEBUG_H__
    focus = top->tbl;
    ahead = back; return NULL;
} // epyt


static token_t *identifier() {
    token_t *back = ahead;
    token_t *token;

    if ( check( COLON_COLON ) ) {               // start search at the root
#ifdef __U_DEBUG_H__
      print_focus_change( "identifier1", focus, root );
#endif // __U_DEBUG_H__
      focus = root;
      match( COLON_COLON );
    } // if
    for ( ;; ) {
      if ( eof() ) break;
      token = ahead;
      if ( check( IDENTIFIER ) ) {
          // reset the focus of the scanner to the top table as the next
          // symbol may not be in this focus.
#ifdef __U_DEBUG_H__
          print_focus_change( "identifier2", focus, top->tbl );
#endif // __U_DEBUG_H__
          focus = top->tbl;
          match( IDENTIFIER );
          template_key();

          // if this identifier has no symbol table entry associated with it,
          // make one

          uassert( token != NULL );
          if ( token->symbol == NULL ) {
            token->symbol = new symbol_t( token->value, token->hash );
          } // if
          return token;
      } else if ( check( TYPE ) ) {
          // reset the focus of the scanner to the top table as the next
          // symbol may not be in this focus.
#ifdef __U_DEBUG_H__
          print_focus_change( "type2", focus, top->tbl );
#endif // __U_DEBUG_H__
          focus = top->tbl;
          match( TYPE );
          template_key();

          if ( check( COLON_COLON ) ) {
            uassert( token != NULL );
            uassert( token->symbol != NULL );
#ifdef __U_DEBUG_H__
            print_focus_change( "identifier3", focus, token->symbol->data->table );
#endif // __U_DEBUG_H__
            focus = token->symbol->data->table;
            if ( focus == NULL ) break;         // not defined ?
            match( COLON_COLON );
          } else {
            break;
          } // if
      } else {
          break;
      } // if
    } // for

#ifdef __U_DEBUG_H__
    print_focus_change( "identifier4", focus, top->tbl );
#endif // __U_DEBUG_H__
    focus = top->tbl;
    ahead = back; return NULL;
} // identifier


// operator: one of
//   new delete new[] delete[]
//   + - * / % ^ & | ~
//   ! = < > += -= *= /= %=
//   ^= &= |= << >> >>= <<= == !=
//   <= >= && || ++ -- , ->* ->
//   () []

static token_t *op() {
    token_t *back = ahead;

    // "operator new" and "operator new[]" are treated as "new", similarly for
    // "delete".

    if ( match( NEW ) ) {
      if ( match( LB ) ) {
          if ( match( RB ) ) return back;
      } else return back;
    } // if
    if ( match( DELETE ) ) {
      if ( match( LB ) ) {
          if ( match( RB ) ) return back;
      } else return back;
    } // if
    if ( match( '+' ) ) return back;
    if ( match( '-' ) ) return back;
    if ( match( '*' ) ) return back;
    if ( match( '/' ) ) return back;
    if ( match( '%' ) ) return back;
    if ( match( '^' ) ) return back;
    if ( match( '&' ) ) return back;
    if ( match( '|' ) ) return back;
    if ( match( '~' ) ) return back;
    if ( match( '!' ) ) return back;
    if ( match( '=' ) ) return back;
    if ( match( '<' ) ) return back;
    if ( match( '>' ) ) return back;
    if ( match( PLUS_ASSIGN ) ) return back;
    if ( match( MINUS_ASSIGN ) ) return back;
    if ( match( MULTIPLY_ASSIGN ) ) return back;
    if ( match( DIVIDE_ASSIGN ) ) return back;
    if ( match( MODULUS_ASSIGN ) ) return back;
    if ( match( XOR_ASSIGN ) ) return back;
    if ( match( AND_ASSIGN ) ) return back;
    if ( match( OR_ASSIGN ) ) return back;
    if ( match( LSH ) ) return back;
    if ( match( RSH ) ) return back;
    if ( match( LSH_ASSIGN ) ) return back;
    if ( match( RSH_ASSIGN ) ) return back;
    if ( match( EQ ) ) return back;
    if ( match( NE ) ) return back;
    if ( match( LE ) ) return back;
    if ( match( GE ) ) return back;
    if ( match( AND_AND ) ) return back;
    if ( match( OR_OR ) ) return back;
    if ( match( PLUS_PLUS ) ) return back;
    if ( match( MINUS_MINUS ) ) return back;
    if ( match( ',' ) ) return back;
    if ( match( ARROW_STAR ) ) return back;
    if ( match( ARROW ) ) return back;
    if ( match( GMAX ) ) return back;
    if ( match( GMIN ) ) return back;

    // because the following operators are denoted by multiple tokens, but only
    // should be represented with single tokens, they are parsed as multiple
    // tokens, but only the first token is passsed back to identify them later

    if ( match( LP ) && match( RP ) ) return back;
    if ( match( LB ) && match( RB ) ) return back;

    ahead = back; return NULL;
} // op


static bool specifier_list( attribute_t &attribute );
static bool pointer();


static token_t *operater() {
    token_t *back = ahead;
    token_t *token;

    if ( check( COLON_COLON ) ) {               // start search at the root
#ifdef __U_DEBUG_H__
      print_focus_change( "operater1", focus, root );
#endif // __U_DEBUG_H__
      focus = root;
      match( COLON_COLON );
    } // if
    for ( ;; ) {
      if ( eof() ) break;
      token = ahead;
      if ( match( OPERATOR ) ) {
          token_t *start = ahead;
          if ( ( token = op() ) != NULL ) {
            template_key();

            // if this operator has no symbol table entry associated with
            // it, make one

            token->symbol = focus->search_table( token->hash );   // look up token
            if ( token->symbol == NULL ) {
                token->symbol = new symbol_t( OPERATOR, token->hash );
            } // if

            // check if this is a fundamental assignment operator so the
            // translator does not generate a null, private assignment
            // operator.

            if ( '=' == token->value && focus->symbol != NULL ) {
                token_t *save = ahead;

                if ( match( LP ) ) {
                  while ( match( CONST ) || match( VOLATILE ) ) {} // eat up const & volatile
                  token_t *temp = type();
                  if ( temp != NULL && temp->symbol == focus->symbol ) {
                      if ( match( '&' ) ) {
                        match( IDENTIFIER );    // optional identifier
                        if ( match( RP ) ) {
                            focus->haseqop = true;
                        } // if
                      } // if
                  } // if
                } // if
                ahead = save;
            } // if

            // reset the scanner's focus and return the current token

#ifdef __U_DEBUG_H__
            print_focus_change( "operater2", focus, top->tbl );
#endif // __U_DEBUG_H__
            focus = top->tbl;
            return token;
          } else {
            table_t *savefocus = focus;         // specifier_list changes focus
            attribute_t attribute;              // dummy

            if ( specifier_list( attribute ) ) {
                pointer();                      // optional

#ifdef __U_DEBUG_H__
                print_focus_change( "operater3", focus, savefocus );
#endif // __U_DEBUG_H__
                focus = savefocus;
                char name[256] = "\0";
                for ( token_t *p = start; ; ) { // build a name for the conversion operator
                  if ( p == ahead ) break;
                  strcat( name, p->hash->text );
                  token_t *c = p;
                  p = p->next_parse_token();
                  if ( p != ahead ) {
                      strcat( name, " " );
                  } // if
                  c->remove_token();            // remove tokens forming the name
                  delete c;
                } // for
                strcat( name, " " );            // add a blank for name mangling

                token = new token_t( TYPE, hash_table->look( name ) );
                token->add_token_before( *ahead );    // insert this new token into the token stream

                token->symbol = focus->search_table( token->hash );     // look up token
                if ( token->symbol == NULL ) {
                  // if the symbol is not defined in the symbol table, define it
                  token->symbol = new symbol_t( OPERATOR, token->hash );
                } else {
                  // if the symbol is already defined but not in this scope => make one for this scope

                  if ( token->symbol->data->found != focus ) {
                      token->symbol = new symbol_t( OPERATOR, token->hash );
                      focus->insert_table( token->symbol );
                  } // if
                } // if

                // reset the scanner's focus and return the current token

#ifdef __U_DEBUG_H__
                print_focus_change( "operater4", focus, top->tbl );
#endif // __U_DEBUG_H__
                focus = top->tbl;
                return token;
            } // if
#ifdef __U_DEBUG_H__
            print_focus_change( "operater5", focus, savefocus );
#endif // __U_DEBUG_H__
            focus = savefocus;
          } // if
      } else if ( check( TYPE ) ) {
          // reset the focus of the scanner to the top table as the next
          // symbol may not be in this focus.
#ifdef __U_DEBUG_H__
          print_focus_change( "operater6", focus, top->tbl );
#endif // __U_DEBUG_H__
          focus = top->tbl;
          match( TYPE );
          template_key();

          if ( check( COLON_COLON ) ) {
            uassert( token != NULL );
            uassert( token->symbol != NULL );
#ifdef __U_DEBUG_H__
            print_focus_change( "operater7", focus, token->symbol->data->table );
#endif // __U_DEBUG_H__
            focus = token->symbol->data->table;
            if ( focus == NULL ) break;         // not defined ?
            match( COLON_COLON );
          } else {
            break;
          } // if
      } else {
          break;
      } // if
    } // for

#ifdef __U_DEBUG_H__
    print_focus_change( "operater7", focus, top->tbl );
#endif // __U_DEBUG_H__
    focus = top->tbl;
    ahead = back; return NULL;
} // operater


static bool condition( bool semicolon = false ) {
    token_t *back = ahead;

    if ( match( LP ) ) {
      if ( match_closing( LP, RP, semicolon ) ) {     // semicolon allowed in "for" control clause
          return true;
      } // if
    } // if

    ahead = back; return false;
} // condition


static bool wait_statement_body( symbol_t *symbol ) {
    token_t *back = ahead;
    token_t *prefix, *suffix;

    prefix = ahead;                             // remember where to put the prefix
    for ( ;; ) {                          // look for the end of the statement
      if ( eof() ) break;
      if ( match( WITH ) ) {
          suffix = ahead;
          gen_wait_prefix( prefix, suffix );
          prefix = ahead;
          for ( ;; ) {
            if ( eof() ) break;
            if ( match( ';' ) ) {
                suffix = ahead->prev_parse_token();
                if ( prefix == suffix ) {
                  gen_error( suffix, "expected integer value after uWith." );
                  goto fini;
                } // if
                gen_with( prefix, suffix );
                gen_wait_suffix( suffix );
                return true;
            } // if
            scan();
          } // for
      } // if
      if ( match( ';' ) ) {
          suffix = ahead->prev_parse_token();
          if ( prefix == suffix ) {
            gen_error( suffix, "expected condition value after uWait/uAcceptWait." );
            goto fini;
          } // if
          gen_wait_prefix( prefix, suffix );
          gen_wait_suffix( suffix );
          return true;
      } // if
      scan();
    } // for
  fini:
    ahead = back; return false;
} // wait_statement_body


static bool wait_statement( symbol_t *symbol ) {
    token_t *back = ahead;

    if ( match( WAIT ) ) {
      if ( wait_statement_body( symbol ) ) return true;
    } // if

    ahead = back; return false;
} // wait_statement


static bool signal_statement( symbol_t *symbol ) {
    token_t *back = ahead;
    token_t *prefix, *suffix;

    if ( match( SIGNAL ) ) {
      prefix = ahead;                           // remember where to put the prefix
      for ( ;; ) {                              // look for the end of the statement
        if ( eof() ) break;
          if ( match( ';' ) ) {
            suffix = ahead->prev_parse_token();
            if ( prefix == suffix ) {
                gen_error( suffix, "expected condition after uSignal." );
                goto fini;
            } // if
            gen_signal_prefix( prefix );
            gen_signal_suffix( suffix );
            return true;
          } // if
          scan();
      } // for
    } // if
  fini:
    ahead = back; return false;
} // signal_statement


static bool signalblock_statement( symbol_t *symbol ) {
    token_t *back = ahead;
    token_t *prefix, *suffix;

    if ( match( SIGNALBLOCK ) ) {
      prefix = ahead;                           // remember where to put the prefix
      for ( ;; ) {                              // look for the end of the statement
        if ( eof() ) break;
          if ( match( ';' ) ) {
            suffix = ahead->prev_parse_token();
            if ( prefix == suffix ) {
                gen_error( suffix, "expected condition after uSignalBlock." );
                goto fini;
            } // if
            gen_signalblock_prefix( prefix );
            gen_signalblock_suffix( suffix );
            return true;
          } // if
          scan();
      } // for
    } // if
  fini:
    ahead = back; return false;
} // signalblock_statement


static bool suspend_statement( symbol_t *symbol ) {
    token_t *back = ahead;
    token_t *prefix;

    if ( match( SUSPEND ) ) {
      prefix = ahead;
      if ( match( ';' ) ) {
          gen_suspend_prefix( prefix, symbol );
          gen_suspend_suffix( ahead, symbol );
      }  else {
          gen_error( ahead, "expected ';' after uSuspend." );
      } // if
      return true;
    } // if

    ahead = back; return false;
} // suspend_statement


static bool resume_statement( symbol_t *symbol ) {
    token_t *back = ahead;
    token_t *prefix;

    if ( match( RESUME ) ) {
      prefix = ahead;
      if ( match( ';' ) ) {
          gen_resume_prefix( prefix, symbol );
          gen_resume_suffix( ahead, symbol );
      } else {
          gen_error( ahead, "expected ';' after uResume." );
      } // if
      return true;
    } // if

    ahead = back; return false;
} // resume_statement


static bool accept_statement( token_t *startposn, bool uncondaccept, jump_t *&list, symbol_t *symbol );
static bool or_clause( token_t *startposn, bool uncondaccept, jump_t *&list, symbol_t *symbol );
static bool uelse_clause( bool uncondaccept, jump_t *&list, symbol_t *symbol );


static void accept_start( token_t *&startposn, token_t *before, jump_t *&list, symbol_t *symbol  ) {
    if ( list == NULL ) {                       // top level of recursion ?
      gen_code( before, "{" );
      gen_code( before, "uSerial :: uProtectAcceptStmt uProtectAcceptStmtInstance ( uSerialInstance" );
      // broken off from previous code fragment to allow subsequent insertion by timeout
      gen_code( before, ") ;" );
      // remember previous location for subsequent insertion by timeout
      startposn = before->prev_parse_token();
    } // if
} // accept_start


static void accept_end( token_t *before, bool uncondaccept, jump_t *&list, symbol_t *symbol  ) {
    gen_code( before, "switch ( uProtectAcceptStmtInstance . uMutexMaskPosn ) {" );
    for ( jump_t *p = list; p != NULL; p = p->link ) {
      gen_code( before, "case" );
      gen_mask( before, p->index );
      gen_code( before, ": goto" );
      gen_hash( before, p->label );
      gen_code( before, ";" );
    } // for
    gen_code( ahead, "}" );                     // closing brace for switch
} // accept_end


static bool accept_mutex_list( token_t *before, jump_t *&list, symbol_t *symbol, char *tryname = "uAcceptTry" ) {
    token_t *back = ahead;
    token_t *start;
    token_t *finish;
    token_t *member;
    unsigned int index;

    start = ahead;
    gen_code( start, "uSerialInstance ." );
    gen_code( start, tryname );
    gen_code( start, "(" );
    if ( ( member = identifier() ) != NULL || ( member = operater() ) != NULL || ( member = epyt() ) != NULL ) {
      finish = ahead;
      while ( start != finish ) {               // remove the member name from the token stream as it is not printed
          token_t *dump = start;
          start = start->next_parse_token();
          dump->remove_token();
          delete dump;
      } // while

      symbol_t *msymbol = member->symbol;
      uassert( msymbol != NULL );

      if ( msymbol->data->table != NULL || msymbol->data->attribute.Mutex ) {
          if ( msymbol->data->table != NULL ) { // must be the destructor
            uassert( symbol->data->found != NULL );
            // check destructor name is the same as the containing class
            if ( symbol->data->found->symbol != NULL && // destructor may not be defined yet but its name can be used
                 symbol->data->found->symbol != msymbol ) {
                char msg[strlen(symbol->data->found->symbol->hash->text) + 256];

                sprintf( msg, "accepting an invalid destructor; destructor name must be the same as the containing class \"%s\".",
                       symbol->data->found->symbol->hash->text );
                gen_error( ahead, msg );
            } // if
            index = DESTRUCTORPOSN;             // kludge, if previous problem, prevent errors about exceeding maximum number of mutex members
          } else {                              // members other than destructor
            index = msymbol->data->index;
          } // if

          // check if multiple accepts for this member in the accept
          // statement

          for ( jump_t *p = list; p != NULL; p = p->link ) {
            if ( index == p->index ) {
                char msg[strlen(msymbol->hash->text) + 256];
                sprintf( msg, "multiple accepts of mutex member \"%s\" in accept statement.", msymbol->hash->text );
                gen_error( ahead, msg );
                break;
            } // if
          } // for
      } else {
          index = DESTRUCTORPOSN;               // kludge to prevent errors about exceeding maximum number of mutex members
          char msg[strlen(msymbol->hash->text) + 256];
          sprintf( msg, "accept on a non-mutex member \"%s\", possibly caused by uAccept appearing before mutex member definition.", msymbol->hash->text );
          gen_error( ahead, msg );
      } // if

      jump_t *jump = new jump_t;
      jump->index = index;                      // initialize node
      jump->label = hash_table->look( name() );
      jump->link = list;                        // add node to head of list
      list = jump;                              // set top of list

      gen_entry( ahead, index );

      if ( match( ',' ) ) {
          gen_mask( ahead, index );             // use existing comma to separate arguments for call to uAcceptTry
          gen_code( ahead, ") ||" );
          accept_mutex_list( ahead, list, symbol, tryname );
      } else {
          gen_code( ahead, "," );               // separate arguments for call to uAcceptTry
          gen_mask( ahead, index );
      } // if

      if ( match( RP ) ) {                      // last name in the mutex list ?
          gen_code( ahead, ") ) {" );                 // brace starts the completion statement of the accept clause
      } // if

      return true;
    } else {
      gen_error( ahead, "expected mutex member name after parenthesis." );
    } // if

    ahead = back; return false;
} // accept_mutex_list


static bool statement( symbol_t *symbol );


static bool accept_clause( token_t *startposn, bool uncondaccept, jump_t *&list, symbol_t *symbol ) {
    token_t *back = ahead;
    token_t *start;
    jump_t *jump;

    if ( match( LP ) ) {                        // start of mutex member list
      jump = list;                              // save current position on mutex member stack
      if ( accept_mutex_list( ahead, list, symbol ) ) {
          start = ahead;                        // position before completion statement
          statement( symbol );
          if ( or_clause( startposn, uncondaccept, list, symbol ) ) {
          } else if ( uelse_clause( uncondaccept, list, symbol ) ) {
          } else {
            gen_code( ahead, "} else {" );            // end of accept clause list
            if ( ! uncondaccept ) {             // all accepts conditional ?
                gen_code( ahead, "if ( uSerialInstance . uAcceptTestMask ( ) ) { uAbort ( \"all guards false in accept statement\" ) ; }" );
            } // if
            gen_code( ahead, "uSerialInstance . uAcceptPause ( ) ;" );
            accept_end( ahead, uncondaccept, list, symbol );
            gen_code( ahead, "}" );             // closing brace for else
          } // if

          for ( ; jump != list; ) {             // remove mutex member nodes allocated for member list
            gen_hash( start, list->label );           // print completion-statement label before completion statement
            gen_code( start, ":" );
            jump_t *curr = list;
            list = list->link;
            delete curr;
          } // for

          if ( list == NULL ) {                 // top level of recursion ?
            gen_code( ahead, "}" );             // closing brace for accept statement
          } // if

          return true;
      } // if
    } else {
      gen_error( ahead, "expected parenthesized mutex member name after uAccept." );
    } // if

    ahead = back; return false;
} // accept_clause


static bool or_clause( token_t *startposn, bool uncondaccept, jump_t *&list, symbol_t *symbol  ) {
    token_t *back = ahead;

    if ( match( OR ) ) {
      gen_code( ahead, "} else {" );
      if ( ! accept_statement( startposn, uncondaccept, list, symbol ) ) {
          gen_error( ahead, "uAccept or uTimeout clause must follow uOr." );
          goto fini;
      } // if
      gen_code( ahead, "}" );                   // closing brace for else
      return true;
    } // if
  fini:
    ahead = back; return false;
} // or_clause


static bool uelse_clause( bool uncondaccept, jump_t *&list, symbol_t *symbol  ) {
    token_t *back = ahead;

    if ( match( UELSE ) ) {
      gen_code( ahead, "} else {" );                  // end of accept clause list
      gen_code( ahead, "uSerialInstance . uAcceptElse ( ) ;" );
      statement( symbol );
      gen_code( ahead, "}" );                   // closing brace for else
      return true;
    } // if

    ahead = back; return false;
} // uelse_clause


static bool timeout_clause( token_t *startposn, bool conditional, bool uncondaccept, jump_t *&list, symbol_t *symbol  ) {
    token_t *back = ahead;
    token_t *start;

    if ( list == NULL ) {                       // top level of recursion ? => single statement
      start = ahead;
      if ( condition() ) {
          gen_code( start, "{ uThisTask ( ) . uSleep (" ); // insert before timeout expression
          gen_code( ahead, ") ;" );             // insert after timeout expression
          statement( symbol );
          gen_code( ahead, "}" );               // closing brace for timeout clause
          return true;
      } else {
          gen_error( ahead, "expected parenthesized expression after uTimeout." );
      } // if
    } else {
      gen_code( startposn, ", true" );
    
      start = ahead;
      if ( condition() ) {
          gen_code( start, "{ uSerialInstance . uAcceptTry ( ) ; uSerialInstance . uAcceptPause (" ); // insert before timeout expression
          gen_code( ahead, ") ;" );             // insert after timeout expression
          if ( conditional ) {                  // conditional timeout ?
            gen_code( ahead, "} else {" );
            if ( ! uncondaccept ) {             // all accepts conditional ?
                gen_code( ahead, "if ( uSerialInstance . uAcceptTestMask ( ) ) { uAbort ( \"all guards false in accept statement\" ) ; }" );
            } // if
            gen_code( ahead, "uSerialInstance . uAcceptPause ( ) ;" );
          } // if
          gen_code( ahead, "}" );               // closing brace for timeout block (not conditional) or else block (conditional)
          accept_end( ahead, uncondaccept, list, symbol );
          statement( symbol );                  // add timeout case clause after select
          return true;
      } else {
          gen_error( ahead, "expected expression after parenthesis." );
      } // if
    } // if

    ahead = back; return false;
} // timeout_clause


static bool accept_statement( token_t *startposn, bool uncondaccept, jump_t *&list, symbol_t *symbol ) {
    token_t *back = ahead;
    token_t *start;

    if ( match( WHEN ) ) {                      // optional
      start = ahead;
      if ( ! condition() ) {
          gen_error( ahead, "expected parenthesized conditional after uWhen." );
          goto fini;
      } // if

      if ( match( ACCEPT ) ) {
          accept_start( startposn, start, list, symbol ); // insert before condition
          gen_code( start, "if (" );                  // insert before condition
          gen_code( ahead, "&&" );              // insert after condition
          if ( accept_clause( startposn, uncondaccept, list, symbol ) ) {
            return true;
          } // if
      } else if ( match ( TIMEOUT ) ) {
          gen_code( start, "if (" );                  // insert before condition
          gen_code( ahead, ")" );               // insert after condition
          if ( timeout_clause( startposn, true, uncondaccept, list, symbol ) ) {
            return true;
          } // if
      } else {
          gen_error( ahead, "expect uAccept or uTimeout after uWhen." );
      } // if
    } else {
      uncondaccept = true;                      // unconditional accept found
      if ( match( ACCEPT ) ) {
          accept_start( startposn, ahead, list, symbol );
          gen_code( ahead, "if (" );
          if ( accept_clause( startposn, uncondaccept, list, symbol ) ) {
            return true;
          } // if
      } else if ( match( TIMEOUT ) ) {
          if ( timeout_clause( startposn, false, uncondaccept, list, symbol ) ) {
            return true;
          } // if
      } // if
    } // if
  fini:
    ahead = back; return false;
} // accept_statement


static bool acceptreturn_statement( token_t *startposn, bool uncondaccept, jump_t *&list, symbol_t *symbol ) {
    token_t *back = ahead;

    if ( match( ACCEPTRETURN ) ) {
      accept_start( startposn, ahead, list, symbol );
      gen_code( ahead, "if (" );
      if ( match( LP ) ) {                      // start of mutex member list
          if ( ! accept_mutex_list( startposn, list, symbol, "uAcceptTry2" ) ) {
            gen_error( ahead, "invalid mutex member list for uAcceptReturn." );
            goto fini;
          } // if
          gen_code( ahead, "} else {" );        // end of accept clause list
          gen_code( ahead, "uSerialInstance . uAcceptMask ( ) ;" );
          gen_code( ahead, "}" );               // closing brace for else
          gen_code( ahead, "return" );
          for ( ;; ) {                    // optional expression
            if ( eof() ) break;
            if ( match( ';' ) ) break;
            scan();
          } // for

          for ( ; list != NULL; ) {             // remove mutex member nodes allocated for member list
            jump_t *curr = list;
            list = list->link;
            delete curr;
          } // for

          gen_code( ahead, "}" );               // closing brace for accept statement
          return true;
      } else {
          gen_error( ahead, "expected parenthesized mutex member name after uAcceptReturn." );
      } // if
    } // if
  fini:
    ahead = back; return false;
} // acceptreturn_statement


static bool acceptwait_statement( token_t *startposn, bool uncondaccept, jump_t *&list, symbol_t *symbol ) {
    token_t *back = ahead;

    if ( match( ACCEPTWAIT ) ) {
      accept_start( startposn, ahead, list, symbol );
      gen_code( ahead, "if (" );
      if ( match( LP ) ) {                      // start of mutex member list
          if ( ! accept_mutex_list( startposn, list, symbol, "uAcceptTry2" ) ) {
            gen_error( ahead, "invalid mutex member list for uAcceptWait." );
            goto fini;
          } // if
          gen_code( ahead, "} else { uSerialInstance . uAcceptMask ( ) ; }" ); // end of accept clause list

          for ( ; list != NULL; ) {             // remove mutex member nodes allocated for member list
            jump_t *curr = list;
            list = list->link;
            delete curr;
          } // for

          if ( wait_statement_body( symbol ) )  {
            gen_code( ahead, "}" );             // closing brace for accept statement
            return true;
          } // if
      } else {
          gen_error( ahead, "expected parenthesized mutex member name after uAcceptWait." );
      } // if
    } // if
  fini:
    ahead = back; return false;
} // acceptwait_statement


// jump-statement:
//   "break" label_opt ";"
//   "continue" label_opt ";"
//   "return" expression_opt ";"
//   "goto" identifier ";"

static bool break_statement( symbol_t *symbol ) {
    token_t *back = ahead;
    token_t *blocn;

    blocn = ahead;                              // remember start of break
    if ( match( BREAK ) ) {
      token_t *label = ahead;
      if ( match( IDENTIFIER ) ) {
          if ( label->symbol != NULL ) {        // prefix label ?
            // cannot remove "break" token as there may be pointers to it
            blocn->hash = hash_table->look( "goto" ); // change to "goto" token
            blocn->value = blocn->hash->value;
            char name[256];                     // generate new label
            sprintf( name, "U_B_%.252s", label->hash->text );
            label->hash = hash_table->look( name );   // change label
          } else {
            gen_error( ahead, "label is not a prefix of a \"for\", \"while\", \"do\", \"switch\" or compound \"{}\" statement." );
          } // if
      } // if
      if ( match( ';' ) ) return true;          // must end with semi-colon
    } // if

    ahead = back; return false;
} // break_statement


static bool continue_statement( symbol_t *symbol ) {
    token_t *back = ahead;
    token_t *clocn;

    clocn = ahead;                              // remember start of continue
    if ( match( CONTINUE ) ) {
      token_t *label = ahead;
      if ( match( IDENTIFIER ) ) {
          if ( label->symbol != NULL && label->symbol->data->index == 1 ) {         // prefix label ?
            // cannot remove "continue" token as there may be pointers to it
            clocn->hash = hash_table->look( "goto" ); // change to "goto" token
            clocn->value = clocn->hash->value;
            char name[256];                     // generate new label
            sprintf( name, "U_C_%.252s", label->hash->text );
            label->hash = hash_table->look( name );   // change label
          } else {
            gen_error( ahead, "label is not a prefix of a \"for\", \"while\" or \"do\" statement." );
          } // if
      } // if
      if ( match( ';' ) ) return true;          // must end with semi-colon
    } // if

    ahead = back; return false;
} // continue_statement


static void prefix_labels( token_t *before, token_t *after, token_t *label[], int cnt, bool contlabels ) {
    if ( cnt > 0 ) {                            // prefix labels ?
      gen_code( before, "{" );
      char name[256];
      token_t *l;
      if ( contlabels ) {                       // continue labels ?
          for ( int i = 0; i < cnt; i += 1 ) {
            l = label[i];                       // optimization
            if ( l != NULL && l->symbol != NULL ) {   // ignore duplicate and non-prefix labels
                sprintf( name, "U_C_%.248s : ;", l->hash->text );
                gen_code( after, name );
            } // if
          } // for
      } // if
      gen_code( after, "}" );
      for ( int i = 0; i < cnt; i += 1 ) {
          l = label[i];                   // optimization
          if ( l != NULL && l->symbol != NULL ) {     // ignore duplicate and non-prefix labels
            sprintf( name, "U_B_%.248s : ;", l->hash->text );
            gen_code( ahead, name );
          } // if
      } // for
    } // if
} // prefix_labels


// selection-statement:
//   "if" "(" condition ")" statement
//   "if" "(" condition ")" statement else statement
//    "switch" "(" condition ")" statement

static bool if_statement( symbol_t *symbol ) {
    token_t *back = ahead;

    if ( match( IF ) && condition() && statement( symbol ) ) {
      if ( match( ELSE ) ) {
          if ( statement( symbol ) ) {
            return true;
          } // if
      } else {
          return true;
      } // if
    } // if

    ahead = back; return false;
} // if_statement


static bool switch_statement( symbol_t *symbol, token_t *label[], int cnt ) {
    token_t *back = ahead;

    if ( match( SWITCH ) && condition() ) {
      token_t *before = ahead;
      if ( statement( symbol ) ) {
          prefix_labels( before, ahead, label, cnt, false );
          return true;
      } // if
    } // if

    ahead = back; return false;
} // switch_statement


// iteration-statement:
//   "while" "(" condition ")" statement
//   "do" statement "while" "(" expression ")" ";"
//   "for" "(" for-init-statement condition_opt ; expression_opt ) statement
//
// for-init-statement:
//   expression-statement
//   simple-declaration

static bool while_statement( symbol_t *symbol, token_t *label[], int cnt ) {
    token_t *back = ahead;

    if ( match( WHILE ) && condition() ) {
      token_t *before = ahead;
      if ( statement( symbol ) ) {
          prefix_labels( before, ahead, label, cnt, true );
          return true;
      } // if
    } // if

    ahead = back; return false;
} // while_statement


static bool do_statement( symbol_t *symbol, token_t *label[], int cnt ) {
    token_t *back = ahead;

    if ( match( DO ) ) {
      token_t *before = ahead;
      if ( statement( symbol ) ) {
          token_t *after = ahead;
          if ( match( WHILE ) && condition() && match( ';' ) ) {
            prefix_labels( before, after, label, cnt, true );
            return true;
          } // if
      } // if
    } // if

    ahead = back; return false;
} // do_statement


static bool for_statement( symbol_t *symbol, token_t *label[], int cnt ) {
    token_t *back = ahead;

    if ( match( FOR ) && condition( true ) ) {        // parses all 3 expressions, separated by ';'
      token_t *before = ahead;
      if ( statement( symbol ) ) {
          prefix_labels( before, ahead, label, cnt, true );
            return true;
      } // if
    } // if

    ahead = back; return false;
} // for_statement


// compound-statement:
//   "{" statement-seq_opt "}"

static bool compound_statement( symbol_t *symbol, token_t *label[], int cnt ) {
    token_t *back = ahead;

    // check for a {, don't match because a symbol table has to be built
    // before scanning the next token, which may be an identifier

    if ( check( LC ) ) {
#if 0                                     // too expensive
      if ( user ) {
          if ( verify ) gen_verify( ahead );
          if ( Yield ) gen_yield( ahead );
      } // if
#endif
      table_t *table = new table_t( NULL );           // no symbol to connect to
      uassert( focus == top->tbl );
      table->lexical = top->tbl;
      table->push_table();

      match( LC );                              // now scan passed the '{' for the next token

      token_t *before = ahead;
      while ( statement( symbol ) );
      prefix_labels( before, ahead, label, cnt, false );
      delete pop_table();
      if ( match( RC ) ) {
          return true;
      } // if
    } // if

    ahead = back; return false;
} // compound_statement


// labeled-statement:
//   identifier ":" statement
//   "case" constant-expression ":" statement
//   "default" ":" statement

static bool labelled_statement( symbol_t *symbol ) {
    token_t *back = ahead;
    const int labprefix = 32;                   // maximum number of labels prefixing a statement
    token_t *label[labprefix + 1];              // n+1 element holds the error case
    int cnt;

    for ( cnt = 0;; ) {
      label[cnt] = ahead;                       // save current token
      if ( ! match( IDENTIFIER ) || ! match( ':' ) ) break;
      if ( cnt < labprefix ) {
          cnt += 1;
      } else {
          char msg[100];
          sprintf( msg, "more than %d labels prefixing a statement; label \"%s\" ignored.", labprefix, label[cnt]->hash->text );
          gen_error( ahead, msg );
      } // if
    } // for
    if ( cnt > 0 ) {                            // any labels ?
      if ( check( FOR ) || check( WHILE ) || check( DO ) || check( SWITCH ) || check( LC ) ) {
          int targetype;
          if ( check( SWITCH ) || check( LC ) ) targetype = 2;
          else targetype = 1;
          token_t *l;
          for ( int i = 0; i < cnt; i += 1 ) {
            l = label[i];                       // optimization
            // only need to create a symbol table for labels that need to
            // be looked up by break and continue.
            l->symbol = focus->search_table( l->hash );
            if ( l->symbol == NULL ) {          // not defined in this scope ?
                l->symbol = new symbol_t( l->value, l->hash );
                focus->insert_table( l->symbol );
                // SKULLDUGGERY: put label target kind into mutex index field
                l->symbol->data->index = targetype;
            } else {                      // already defined ? => duplicate label
                label[i] = NULL;
            } // if
          } // for
          if ( for_statement( symbol, label, cnt ) ) return true;
          if ( while_statement( symbol, label, cnt ) ) return true;
          if ( do_statement( symbol, label, cnt ) ) return true;
          if ( switch_statement( symbol, label, cnt ) ) return true;
          if ( compound_statement( symbol, label, cnt ) ) return true;
      } else if ( statement( symbol ) ) {
          return true;
      } // if
    } // if

    ahead = back; return false;
} // labelled_statement


static bool case_statement( symbol_t *symbol ) {
    token_t *back = ahead;

    if ( match( CASE ) ) {
      for ( ;; ) {
          if ( eof() ) goto fini;
        if ( match( ':' ) ) break;
          scan();
      } // for
      if ( statement( symbol ) ) {
          return true;
      } // if
    } // if
  fini:
    ahead = back; return false;
} // case_statement


static bool default_statement( symbol_t *symbol ) {
    token_t *back = ahead;

    if ( match( DEFAULT ) && match( ':' ) && statement( symbol ) ) {
      return true;
    } // if

    ahead = back; return false;
} // default_statement


struct bound {
    token_t *oleft, *oright;
    token_t *exbegin;
    symbol_t *extype;
    token_t *idleft, *idright;
};


typedef std::set<symbol_t *> symbolset;
typedef std::list<token_t *> tokenlist;


static bool exception_declaration( attribute_t &attribute );
static bool bound_exception_declaration( bound &b );


static bool catch_statement( symbol_t *symbol, bool &bflag, bool &optimized, hash_t *&para_name, symbol_t *&exception_type, tokenlist &try_catches, tokenlist &if_rethrow ) {
    token_t *back = ahead;
    token_t *prefix;
    bound b;
    bflag = false;
    optimized = false;

    if ( match( CATCH ) ) {
      if ( match( LP ) ) {
          attribute_t attribute;
          if ( exception_declaration( attribute ) || ( match( DOT_DOT_DOT ) && match( RP ) ) ) {
            prefix = ahead;
            if ( compound_statement( symbol, NULL, 0 ) ) {
                exception_type = attribute.typedef_base; // used to check whether splitting is necessary
                gen_code( prefix, "{" );
                gen_code( prefix, "if ( uOrigRethrow ) throw ;" );
                if_rethrow.push_front( prefix->prev_parse_token() ); // possible later deletion if this is the innermost try block
                gen_code( prefix, "try");
                try_catches.push_front( prefix->prev_parse_token() ); // possible later deletion if the try block is not split
                gen_code( ahead, "catch( ... ) { uOrigRethrow = true; throw; }" );
                try_catches.push_front( ahead->prev_parse_token() ); // possible later deletion if the try block is not split
                gen_code( ahead, "}" );
                return true;
            } // if
            para_name = NULL;             // prevent optimization
          } else if ( bound_exception_declaration( b ) ) {
            token_t *p, *next;
            token_t *start_catch;
            hash_t *local_param_name = NULL;
            prefix = ahead;

            if ( compound_statement( symbol, NULL, 0 ) ) {
                gen_code( prefix, "{ ");
                gen_code( prefix, "if ( uOrigRethrow ) throw ;");
                if_rethrow.push_front( prefix->prev_parse_token() ); // possible later deletion if this is the innermost try block
                gen_code( prefix, "const void * _U_bindingVal = (" );
                // look backwards for exception parameter name
                for ( p = b.idright; p != b.exbegin; p = p->prev_parse_token() ) {
                  if ( p->value == IDENTIFIER || p->value == TYPE ) {
                      gen_code( prefix, p->hash->text );
                      local_param_name = p->hash; // remember parameter name for optimization
                      break;
                  } // exit
                } // for
                gen_code( prefix, ") . getOriginalThrower ( ) ;" ); // >= & ( );
                token_t *realend = prefix->prev_parse_token(); // remember for optimization part
                gen_code( prefix, "if ( _U_bindingVal == & (" );
                // Move the tokens for the bound object expression from the
                // catch clause argument to the if statement within the
                // catch body.
                for ( p = b.oleft; p != b.oright; p = next ) {
                  next = p->next_parse_token();
                  p->remove_token();
                  p->add_token_before( *prefix );
                } // for

                gen_code( prefix, ") )" );
                gen_code( prefix, "try ");
                try_catches.push_front( prefix->prev_parse_token() );

                p->remove_token();              // remove and delete the dot
                delete p;
                gen_code( ahead, "catch( ... ) { uOrigRethrow = true; throw; }" );
                try_catches.push_front( ahead->prev_parse_token() );

                gen_code( ahead, "else { throw ; } }" );
                bflag = true;

                // Optimization part, remove catch clause, remove "if
                // uOrigRethrow", remove "getOriginalThrower()", add
                // "else".  It would be more efficient to not insert them
                // in the first place, but I like to keep the optimization
                // code seperate from the normal case.

                if ( exception_type == b.extype && local_param_name == para_name ) {
                  optimized = true;

                  // remove the catch clause and the } and all the other stuff before it
                  for ( start_catch = back->prev_parse_token(); start_catch != realend; start_catch = next ) {
                      next = start_catch->next_parse_token();
                      start_catch->remove_token();
                      delete start_catch;
                  } // for
                  if_rethrow.clear();             // just deleted what was stored here inside the loop, so scratch 
                  gen_code(start_catch, "else" );
                  start_catch->remove_token();
                  delete start_catch;
                } else {
                  exception_type = b.extype;    // return the type of OUR catch clause 
                } // if
                para_name = local_param_name;   // return the name of OUR parameter 
                return true;
            } // if
          } // if
      } // if
    } // if

    ahead = back; return false;
} // catch_statement


static bool resume_handler( symbol_t *symbol, int resume_clauses ) {
    token_t *back = ahead;
    token_t *befparn;
    token_t *startE;
    token_t *endE;
    token_t *startH = NULL;
    token_t *endH = NULL;
    char temp_name[20];

    // storing values inside a uHandlerClause struct
    befparn = ahead;
    if ( match( LA ) ) {
      sprintf( temp_name, "_uHandler%d", resume_clauses );
      startE = ahead;
      token_t *dot = NULL;
      for ( ;; ) {
        if ( check( '.' ) ) {                   // a dot means bound resumption
            dot = ahead;                        // store object address in HandlerClause
            scan();
            continue;
          } // if
        if ( eof() ) goto fini;
        if ( check( ';' ) ) goto fini;
        if ( check( LC ) ) goto fini;
        if ( match( LA ) && ! match_closing( LA, RA ) ) goto fini;
        if ( check( RA ) ) break;
        if ( check( ',' ) ) break;
          scan();
      } // for
      if ( startE == ahead ) goto fini;
      endE = ahead;
      if ( match( ',' ) ) {
          gen_code( befparn, "uHandlerClause" );
          gen_code( ahead, "typeof (" );
          startH = ahead;
          for ( ;; ) {
            if ( eof() ) goto fini;
            if ( check( ';' ) ) goto fini;
            if ( check( LC ) ) goto fini;
            if ( match( LA ) && ! match_closing( LA, RA ) ) goto fini;
            if ( check( RA ) ) break;
            scan();
          } // for
          if ( startH == ahead ) goto fini;
          endH = ahead->prev_parse_token();           // token before '>'
          gen_code( ahead, ")" );
          match( RA );                    // match closing '>'
          gen_code( ahead, temp_name );
      } else {
          match( RA );                    // match closing '>'
          gen_code( befparn, "uNullHandlerClause" );
          gen_code( ahead, temp_name );
      } // if
      gen_code( ahead, "(" );
      if ( dot ) {                              // bound exception ?
          gen_code( ahead, "& (" );
          token_t *next = NULL;
          for ( token_t *p = startE; p != dot; p = next ) {
            next = p->next_parse_token();
            p->remove_token();
            p->add_token_before( *ahead );
          } // for
          next->remove_token();                 // destroy the dot
          delete next;
          gen_code( ahead, ")" );
      } else {
          gen_code( ahead, "( void * ) 0" );
      } // if
      if ( startH != NULL ) {                   // handler ?
          gen_code( ahead, "," );
          token_t *next;
          for ( token_t *p = startH;; p = next ) {
            next = p->next_parse_token();
            gen_code( ahead, p->hash->text );
            if ( p == endH ) break;
          } // for
      } // if
      gen_code( ahead, ") ;" );
      return true;
      fini:
      gen_error( befparn, "incorrectly formed resume clause." );
    } // if

    ahead = back; return false;
} // resume_handler


static bool split_tryblock( symbol_t *sym, symbolset &parents, symbolset &extypes ) {
    // given a symbol sym, and the two sets parents and extypes, decides
    // whether a try-block splitting is necessary or not, by checking if sym is
    // in the parents, or any of its parents have catch clauses in the try
    // block already
    
    if ( sym == NULL ) {
      return ! extypes.empty();                 // if catch_any split, if there were bound clauses before
    } //if

    // first check if any of sym's subtypes appeared 
    if ( parents.count( sym ) != 0 ) {
      return true;
    } //if
    
    // then check if any of sym's base types appeared already
    // only single inheritance for exception types, and exception types on special base list
    for ( symbol_t *tmp = sym; tmp != 0; tmp = tmp->data->base ) {
      if ( extypes.count( tmp ) != 0 ) {
          return true;
      } //if
    } //for

    return false;
} // split_try_block


static void register_extype( symbol_t *sym, symbolset &parents, symbolset &extypes ) {
    // register sym's ancestors in parents set, and sym in extypes set
    // only single inheritance for exception types, and exception types on special base list
    for ( symbol_t *tmp = sym->data->base; tmp != 0; tmp = tmp->data->base ) {
      parents.insert( tmp );
    } // for

    extypes.insert( sym );
} // register_extype


static bool try_statement( symbol_t *symbol ) {
    token_t *back = ahead;
    token_t *start, *prefix;

    symbolset parents, extypes;
    symbol_t *exception_type = NULL;

    start = ahead;
    if ( match( TRY ) ) {
      int resume_clauses = 0, catch_clauses = 0;

      // bracket try block with flag declaration
      gen_code( start, "{ bool uOrigRethrow = false ;" ); 
      if ( resume_handler( symbol, resume_clauses ) ) {
          gen_code( start->next_parse_token(), "{" );
          do {
            resume_clauses += 1;
          } while ( resume_handler( symbol, resume_clauses ) );
          gen_code( ahead, "uEHM :: uHandlerBase *uHandlerTable [ ] = {" );
          char buffer[20];
          for ( int i = 0; i < resume_clauses; i += 1 ) {
            sprintf( buffer, "& _uHandler%d ,", i );
            gen_code( ahead, buffer );
          } // for
          gen_code( ahead, "} ; uEHM :: uResumptionHandlers uResumptionNode ( uHandlerTable ," );
          sprintf( buffer, "%d", resume_clauses );
          gen_code( ahead, buffer );
          gen_code( ahead, ") ;" );
      } // if
      prefix = ahead;
      if ( compound_statement( symbol, NULL, 0 ) ) {
          if ( resume_clauses > 0 ) {
              gen_code( ahead, "}" );
          } // if
          token_t *prev;
          bool bound;                           // is catch clause bound ?
          prev = ahead;                   // location before catch clause

          hash_t *para_name;
          bool optimized;
          bool split = false;
          tokenlist try_catches;
          tokenlist if_rethrow;
          token_t *t;

          while ( catch_statement( symbol, bound, optimized, para_name, exception_type, try_catches, if_rethrow ) ) {
            catch_clauses += 1;
            if ( split_tryblock( exception_type, parents, extypes ) && ! optimized ) {
                split = true;                       // indicate following catch clauses are split off
                try_catches.clear();                // split => forget about removing the additional try/catch tokens
                parents.clear();
                extypes.clear();
                gen_code( start, "try {" );
                gen_code( prev, "}" );
            } // if
            if ( ! split ) {
                while ( ! if_rethrow.empty() ) {      // remove unneeded "if (uOrigRethrow) throw" tokens, i.e., the ones before the first split
                  t = if_rethrow.front();
                  t->remove_token();        
                  delete(t);
                  if_rethrow.pop_front();
                } // while
            } // if
            if ( bound ) {
                register_extype( exception_type, parents, extypes );
            } // if
            prev = ahead;
          } // while
          while ( ! try_catches.empty() ) {           // remove unneeded try/catch tokens, i.e., the ones after the last split
            t = try_catches.front();
            t->remove_token();        
            delete(t);
            try_catches.pop_front();
          } // while
          if ( resume_clauses != 0 && catch_clauses == 0 ) {
            // If no catch clause for a resume try block, remove the "try"
            // keyword before the compound statement, as it is unnecessary.
            start->remove_token();
          } // if
          if ( split ) {
            gen_code( ahead, "}" );             // close uOrigRethrow block
          } else {
            t = start->prev_parse_token();          // if we don't split, we don't need the "bool uOrigRethrow = false"
            t->remove_token();
            delete t;
          } // if
          return true;
      } // if
    } // if

    ahead = back; return false;
} // try_statement


static bool throw_statement( symbol_t *symbol ) {
    token_t *back = ahead;
    token_t *start, *prefix;

    start = ahead;
    if ( match( THROW ) ) {
      prefix = ahead;
      for ( ;; ) {                              // look for the end of the statement
        if ( eof() ) break;
          if ( match( ';' ) ) {
            return true;
          } // if
          scan();
      } // for
    } // if

    ahead = back; return false;
} // throw_statement


static bool uthrow_statement( symbol_t *symbol ) {
    token_t *back = ahead;
    token_t *start, *prefix, *suffix;

    start = ahead;
    if ( match( UTHROW ) ) {
      prefix = ahead;                           // remember where to put the prefix
      for ( ;; ) {                              // look for the end of the statement
        if ( eof() ) break;
          if ( match( AT ) ) {
            suffix = ahead;
            gen_uthrow_uat_prefix( prefix, suffix );
            prefix = ahead;

            for ( ;; ) {
              if ( eof() ) break;
                if ( match( ';' ) ) {
                  suffix = ahead->prev_parse_token();
                  if ( prefix == suffix ) {
                      gen_error( suffix, "expected task value after uAt." );
                      goto fini;
                  } // if
                  gen_uthrow_suffix( suffix );
                  return true;
                } // if
                scan();
            } // for
          } // if
          if ( match( ';' ) ) {
            suffix = ahead->prev_parse_token();
            if ( prefix == suffix ) {           // rethrow ?
                gen_code( suffix, "throw ;" );
            } else {
                gen_code(prefix, "* ( ( ( void ) 1 ,"); // hack because of gcc parser bug: class fred; (fred()).foo() doesn't compile
                prefix = prefix->prev_parse_token();
                if ( symbol->data->found->symbol && ! symbol->data->attribute.dclqual.qual.STATIC ) {
                  gen_code(suffix, ") . setOriginalThrower( this ) )");
                } else {
                  gen_code(suffix, ") . setOriginalThrower( ( void * ) 0 ) )");
                } // if
                gen_uthrow_prefix( prefix, suffix );
                gen_uthrow_suffix( suffix );
            } // if
            return true;
          } // if
          scan();
      } // for
    } // if
  fini:
    ahead = back; return false;
} // uthrow_statement


static bool raise_statement( symbol_t *symbol ) {
    token_t *back = ahead;
    token_t *prefix, *suffix;

    if ( match( RAISE ) ) {
      prefix = ahead;                           // remember where to put the prefix

      for ( ;; ) {                              // look for the end of the statement
        if ( eof() ) break;
          if ( match( AT ) ) {
            suffix = ahead;
            gen_raise_uat_prefix( prefix, suffix );
            prefix = ahead;
            for ( ;; ) {
              if ( eof() ) break;
                if ( match( ';' ) ) {
                  suffix = ahead->prev_parse_token();
                  if ( prefix == suffix ) {
                      gen_error( suffix, "expected task value after uAt." );
                      goto fini;
                  } // if
                  gen_raise_suffix( suffix );
                  return true;
                } // if
                scan();
            } // for
          } // if
          if ( match( ';' ) ) {
            suffix = ahead->prev_parse_token();
            if ( prefix == suffix ) {
                gen_code( prefix, "uEHM :: uReRaise( )" );
                return true;
            } // if

            gen_code( prefix, "* ( ( ( void ) 1 ,"); // hack because of gcc parser bug: class fred; (fred()).foo() doesn't compile
            prefix = prefix->prev_parse_token();
            if ( symbol->data->found->symbol && ! symbol->data->attribute.dclqual.qual.STATIC  ) {
                gen_code(suffix, ") . setOriginalThrower( this ) )");
            } else {
                gen_code(suffix, ") . setOriginalThrower( ( void * ) 0 ) )");
            } // if

            gen_raise_prefix( prefix, suffix );
            gen_raise_suffix( suffix );
            return true;
          } // if
          scan();
      } // for
    } // if
  fini:
    ahead = back; return false;
} // raise_statement


static bool event_handler( symbol_t *symbol ) {
    token_t *back = ahead;
    token_t *befparn;
    token_t *startE;
    token_t *endE;

    befparn = ahead;
    if ( match( LA ) ) {
      gen_code( befparn, "( void * ) &" );
      befparn->value = LP;                      // change '<' into '('
      befparn->hash = hash_table->look( "(" );
      startE = ahead;
      for ( ;; ) {
        if ( eof() ) goto fini;
        if ( check( ';' ) ) goto fini;
        if ( check( LC ) ) goto fini;
        if ( match( LA ) && ! match_closing( LA, RA ) ) goto fini;
        if ( check( RA ) ) break;
          scan();
      } // for
      if ( startE == ahead ) goto fini;
      endE = ahead;
      gen_code( endE, ":: uId" );
      endE = endE->aft;                   // ignore added text
      befparn = ahead;
      match( RA );                              // match closing '>'
      befparn->value = RP;                      // change '>' into ')'
      befparn->hash = hash_table->look( ")" );
      return true;
      fini:
      gen_error( befparn, "incorrectly formed uEnable/uDisable clause." );
    } // if

    ahead = back; return false;
} // event_handler


static bool disable_statement( symbol_t *symbol ) {
    token_t *back = ahead;
    token_t *prefix;
    int event_clauses = 0;

    if ( match( DISABLE ) ) {
      prefix = ahead;
      gen_code( prefix->prev_parse_token(), "{" );
      if ( event_handler( symbol ) ) {
          gen_code( prefix->prev_parse_token(), "static void * uEventTable [ ] = {" );
          do {
            event_clauses += 1;
            gen_code( ahead, "," );
          } while ( event_handler( symbol ) );
          gen_code( ahead, "} ; uEHM :: uDeliverAEStack uNoName ( false, uEventTable ," );
          char buffer[20];
          sprintf( buffer, "%d", event_clauses );
          gen_code( ahead, buffer );
          gen_code( ahead, ") ;" );
      } else {
          gen_code( ahead, "uEHM :: uDeliverAEStack uNoName ( false ) ;" );
      } // if
      if ( statement( symbol ) ) {
          gen_code( ahead, "}" );
          return true;
      } // if
    } // if

    ahead = back; return false;
} // disable_statement


static bool enable_statement( symbol_t *symbol ) {
    token_t *back = ahead;
    token_t *prefix;
    int event_clauses = 0;

    if ( match( ENABLE ) ) {
      prefix = ahead;
      gen_code( prefix->prev_parse_token(), "{" );
      if ( event_handler( symbol ) ) {
          gen_code( prefix->prev_parse_token(), "static void * uEventTable [ ] = {" );
          do {
            event_clauses += 1;
            gen_code( ahead, "," );
          } while ( event_handler( symbol ) );
          gen_code( ahead, "} ; uEHM :: uDeliverAEStack uNoName ( true, uEventTable ," );
          char buffer[20];
          sprintf( buffer, "%d", event_clauses );
          gen_code( ahead, buffer );
          gen_code( ahead, ") ;" );
      } else {
          gen_code( ahead, "uEHM :: uDeliverAEStack uNoName ( true ) ;" );
      } // if
      if ( statement( symbol ) ) {
          gen_code( ahead, "}" );
          return true;
      } // if
    } // if

    ahead = back; return false;
} // enable_statement


static bool object_declaration();

// statement:
//   labeled-statement
//   compound-statement
//   selection-statement
//   iteration-statement
//   jump-statement
//   try-block
//   declaration-statement
//   expression-statement

static bool statement( symbol_t *symbol ) {
    token_t *back = ahead;
    jump_t *list = NULL;

    if ( labelled_statement( symbol ) ) return true;
    if ( case_statement( symbol ) ) return true;
    if ( default_statement( symbol ) ) return true;

    if ( compound_statement( symbol, NULL, 0 ) ) return true;

    if ( if_statement( symbol ) ) return true;
    if ( switch_statement( symbol, NULL, 0 ) ) return true;

    if ( while_statement( symbol, NULL, 0 ) ) return true;
    if ( do_statement( symbol, NULL, 0 ) ) return true;
    if ( for_statement( symbol, NULL, 0 ) ) return true;

    if ( break_statement( symbol ) ) return true;
    if ( continue_statement( symbol ) ) return true;

    if ( suspend_statement( symbol ) ) return true;
    if ( resume_statement( symbol ) ) return true;

    if ( wait_statement( symbol ) ) return true;
    if ( signal_statement( symbol ) ) return true;
    if ( signalblock_statement( symbol ) ) return true;
    if ( accept_statement( NULL, false, list, symbol ) ) return true;
    if ( acceptreturn_statement( NULL, false, list, symbol ) ) return true;
    if ( acceptwait_statement( NULL, false, list, symbol ) ) return true;

    if ( disable_statement( symbol ) ) return true;
    if ( enable_statement( symbol ) ) return true;
    
    if ( try_statement( symbol ) ) return true;
    if ( throw_statement( symbol ) ) return true;
    if ( uthrow_statement( symbol ) ) return true;
    if ( raise_statement( symbol ) ) return true;

    if ( object_declaration() ) return true;

    // handles statements currently not parsed: expression, goto, return.

    for ( ;; ) {
      if ( eof() ) break;
      if ( match( ';' ) ) return true;
      if ( compound_statement( symbol, NULL, 0 ) ) return true;
      if ( check( RC ) ) return false;
      scan();
    } // for

    ahead = back; return false;
} // statement


// access-specifier:
//   "private"
//   "protected"
//   "public"

static unsigned int access_specifier() {
    token_t *back = ahead;

    if ( match( PRIVATE ) ) return PRIVATE;
    if ( match( PROTECTED ) ) return PROTECTED;
    if ( match( PUBLIC ) ) return PUBLIC;

    ahead = back; return 0;
} // access_specifier


// base-specifier:
//   "::"_opt nested-name-specifier_opt class-name
//   virtual access-specifier_opt "::"_opt nested-name-specifier_opt class-name
//   access-specifier virtual_opt "::"_opt nested-name-specifier_opt class-name

static token_t *base_specifier( unsigned int &access ) {
    token_t *back = ahead;
    token_t *base;

    if ( ( base = type() ) != NULL ) {
      base->left = back;
      base->right = ahead->prev_parse_token();
      access = PRIVATE;                   // default
      return base;
    } else if ( match( VIRTUAL ) ) {
      access = access_specifier();
      token_t *temp = ahead;
      if ( ( base = type() ) != NULL ) {
          base->left = temp;
          base->right = ahead->prev_parse_token();
          return base;
      } // if
    } else if ( ( access = access_specifier() ) != 0 ) {
      match( VIRTUAL );
      token_t *temp = ahead;
      if ( ( base = type() ) != NULL ) {
          base->left = temp;
          base->right = ahead->prev_parse_token();
          return base;
      } // if
    } // if

    ahead = back; return NULL;
} // base_specifier


// base-specifier-list:
//   base-specifier
//   base-specifier-list "," base-specifier

static bool base_specifier_list( symbol_t *symbol ) {
    token_t *back = ahead;
    token_t *token;
    symbol_t *base;
    unsigned int access;

    uassert( symbol != NULL );

    if ( ( token = base_specifier( access ) ) != NULL && symbol != token->symbol ) { // prevent inheriting from oneself, e.g., class x : public x
      base = token->symbol;
      uassert( base != NULL );
#if 0
      printf( "base_specifier_list, symbol:%s, symbol->data->key:%s (%d), symbol->data->Mutex:%d, symbol->data->index:%d, "
            "base:%s, base->key:%s (%d), base->Mutex:%d, base->index:%d\n",
            symbol->hash->text, kind( symbol ), symbol->data->key, symbol->data->attribute.Mutex, symbol->data->index,
            base->hash->text, kind( base ), base->data->key, base->data->attribute.Mutex, base->data->index );
#endif
      if ( base->data->key == COROUTINE || base->data->key == TASK || base->data->attribute.Mutex ||
           base->data->key == DUALEVENT || base->data->key == RAISEEVENT || base->data->key == THROWEVENT ) {

          // copy the left and right template delimiters from the scanned token

          symbol->data->left = token->left;
          symbol->data->right = token->right;

          if ( ( base->data->key == DUALEVENT || base->data->key == RAISEEVENT || base->data->key == THROWEVENT ) &&
             ( symbol->data->key != base->data->key || access != PUBLIC ) || symbol->data->base != NULL ) {
            if ( symbol->data->base != NULL ) {
                char msg[strlen(symbol->data->base->hash->text) + strlen(base->hash->text) + 256];
                sprintf( msg, "multiple inheritance disallowed between base type \"%s\" of kind \"%s\" and base type \"%s\" of kind \"%s\"; inheritance ignored.",
                       symbol->data->base->hash->text, kind( symbol->data->base ), base->hash->text, kind( base ) );
                gen_error( ahead, msg );
            } else {
                char msg[strlen(symbol->hash->text) + strlen(base->hash->text) + 256];
                if ( symbol->data->key != base->data->key ) {
                  sprintf( msg, "derived type \"%s\" of kind \"%s\" is incompatible with the base type \"%s\" of kind \"%s\"; inheritance ignored.",
                         symbol->hash->text, kind( symbol ), base->hash->text, kind( base ) );
                } else {
                  sprintf( msg, "non-public inheritance disallowed between the derived type \"%s\" of kind \"%s\" and the base type \"%s\" of kind \"%s\"; inheritance ignored.",
                         symbol->hash->text, kind( symbol ), base->hash->text, kind( base ) );
                } // if
                gen_error( ahead, msg );
            } // if

            // More error checking is done for coroutine, monitor, comonitor
            // and task in class_specifier, after the type's members are parsed
            // because mutex members affect a type's kind.
          } else {
            symbol->data->base = base;          // now set the base

            // inherit the number of mutex members defined in the base
            // class so that new mutex members in the derived class are
            // numbered correctly

            symbol->data->index = base->data->index;
          } // if
      } // if

      if ( symbol->data->attribute.startE != NULL || symbol->data->attribute.startP != NULL ) {
          gen_error( ahead, "base kind has already specified mutex/task data-structure arguments." );
      } // if

      symbol->data->base_list.push_back( base );
    } // if
#if 0
    printf( "base_specifier_list, symbol:%s, symbol->data->key:%s (%d), symbol->data->Mutex:%d, symbol->data->index:%d, "
          "base:%s, base->key:%s (%d), base->Mutex:%d, base->index:%d\n",
          symbol->hash->text, kind( symbol ), symbol->data->key, symbol->data->attribute.Mutex, symbol->data->index,
          base->hash->text, kind( base ), base->data->key, base->data->attribute.Mutex, base->data->index );
#endif
    if ( match( ',' ) ) {
      if ( base_specifier_list( symbol ) ) {
          return true;
      } // if
    } else {
      return true;
    } // if

    ahead = back; return false;
} // base_specifier_list


// base-clause:
//   ":" base-specifier-list

static bool base_clause( symbol_t *symbol ) {
    token_t *back = ahead;

    if ( match( ':' ) ) {
      base_specifier_list( symbol );

      // make sure base_specifier_list terminates with one of ';', '{', or
      // EOF before continuing parse. Without this check, many spurious
      // paring errors can result.

      while ( ! check( ';' ) && ! check( LC ) && ! eof() ) {
          scan();
      } // while
      return true;
    } // if

    ahead = back; return false;
} // base_clause


static bool task_parameter_list( attribute_t &attribute );


// class-key:
//   class
//   struct
//   union
//   uCoroutine
//   uTask
//   uPeriodicTask
//   uRealTimeTask
//   uSporadicTask
//   uDualEvent
//   uRaiseEvent
//   uThrowEvent

static int class_key( attribute_t &attribute ) {
    token_t *back = ahead;

    if ( match( CLASS ) ) return CLASS;
    if ( match( STRUCT ) ) return STRUCT;
    if ( match( UNION ) ) return UNION;

    if ( match( COROUTINE ) ) {
      gen_class( ahead );
      return COROUTINE;
    } // if

    if ( match( TASK ) ) {
      gen_class( ahead );
      if ( check( LA ) && ! task_parameter_list( attribute ) ) goto fini;
      return TASK;
    } // if

    if ( match( PTASK ) ) {
      gen_class( ahead );
      attribute.rttskkind.kind.PERIODIC = true;
      if ( check( LA ) && ! task_parameter_list( attribute ) ) goto fini;
      return TASK;
    } // if

    if ( match( RTASK ) ) {
      gen_class( ahead );
      attribute.rttskkind.kind.APERIODIC = true;
      if ( check( LA ) && ! task_parameter_list( attribute ) ) goto fini;
      return TASK;
    } // if

    if ( match( STASK ) ) {
      gen_class( ahead );
      attribute.rttskkind.kind.SPORADIC = true;
      if ( check( LA ) && ! task_parameter_list( attribute ) ) goto fini;
      return TASK;
    } // if

    if ( match( DUALEVENT ) ) {
      gen_class( ahead );
      return DUALEVENT;
    } // if

    if ( match( RAISEEVENT ) ) {
      gen_class( ahead );
      return RAISEEVENT;
    } // if

    if ( match( THROWEVENT ) ) {
      gen_class( ahead );
      return THROWEVENT;
    } // if
  fini:
    ahead = back; return 0;
} // class_key


static void make_type( token_t *token, symbol_t *&symbol, table_t *locn = focus ) { // symbol is in/out parameter because it may be changed
    uassert( token != NULL );
    uassert( symbol != NULL );

    if ( symbol->data->found == focus ) {
      // if the symbol already exists in the current symbol table as an
      // identifier, make it a type

      token->value = symbol->value = TYPE;
    } else {
      if ( symbol->data->found != NULL ) {
          // if the symbol exists in some other symbol table, make a copy of
          // the symbol

          token->symbol = symbol = new symbol_t( symbol->value, symbol->hash );
      } // if

      // change the token and symbol value to type

      token->value = symbol->value = TYPE;

      // insert the symbol into the current symbol table

      locn->insert_table( symbol );
    } // if
} // make_type


static bool template_qualifier( attribute_t &attribute );

    
static bool template_parameter( attribute_t &attribute ) {
    token_t *back = ahead;
    unsigned int ckey;
    token_t *token;
    symbol_t *symbol;

    template_qualifier( attribute );                  // optional

    if ( match( CLASS ) || match( TYPENAME ) ) {
      ckey = CLASS;

      // if a class key is found

      if ( ( token = identifier() ) != NULL ) {
          symbol = token->symbol;

          // change the token's and symbol's value to TYPE

          if ( symbol->data->found == focus ) {
            // if the symbol already exists in the current symbol table as
            // an identifier, make it a type

            token->value = symbol->value = TYPE;
          } else {
            if ( symbol->data->found != NULL && symbol->data->found != focus ) {
                // if the symbol exists in some other symbol table, make a
                // copy of the symbol

                token->symbol = symbol = new symbol_t( symbol->value, symbol->hash );
            } // if

            // change the token and symbol value to type

            token->value = symbol->value = TYPE;

            // insert the symbol into the current symbol table

            attribute.plate->insert_table( symbol );
          } // if

          // set the symbol's class key to the class key

          symbol->data->key = ckey;
      } else if ( ( token = type() ) != NULL ) {
          // if a type token is found, grab the symbol associated with the
          // token and prepare to do some analysis

          symbol = token->symbol;
          uassert( symbol != NULL );

          if ( symbol->data->found == attribute.plate ) {
            // if the symbol already exists in the current symbol table as
            // a type, verify that its kind is the same as the previous
            // definition

            if ( symbol->data->key != ckey ) {
                // struct and class are equivalent for prototype
                if ( ! ( symbol->data->key == STRUCT && ckey == CLASS || symbol->data->key == CLASS && ckey == STRUCT ) ) {
                  char msg[strlen(symbol->hash->text) + 256];
                  sprintf( msg, "\"%s\" redeclared with different kind.", symbol->hash->text );
                  gen_error( ahead, msg );
                } else {
                  symbol->data->key = ckey;
                } // if
            } // if
          } else {
            if ( symbol->data->found != NULL && symbol->data->found != focus ) {
                // if the symbol exists in some other symbol table make a
                // new symbol for the current symbol table

                token->symbol = symbol = new symbol_t( token->value, token->hash );
            } // if

            // set the symbol's class to the class key

            symbol->data->key = ckey;

            // insert the symbol into the template symbol 

            attribute.plate->insert_table( symbol );
          } // if
      } // if

      // scan off any initialization value.

      if ( match( '=' ) ) {
          for ( ;; ) {
            if ( eof() ) break;
            if ( match( LA ) && ! match_closing( LA, RA ) ) goto fini;
            if ( check( ',' ) ) break;
            if ( check( RA ) ) break;
            scan();
          } // for
      } // if

      return true;
    } else if ( ! check( RA ) ) {
      // template arguments come in two forms.  the first type of arguments
      // are always prefixed by a class key and introduces a new type into
      // the definition of the class. this is handled by the first clause in
      // this if statement.  the second form of arguments do not introduce
      // new types, and the translator can simply eat them up without
      // interpreting them.

      for ( ;; ) {
        if ( eof() ) break;
        if ( check( ',' ) ) break;
        if ( check( RA ) ) break;
          scan();
      } // for

      return true;
    } // if
  fini: ;
    ahead = back; return false;
} // template_parameter


static bool template_parameter_list( attribute_t &attribute ) {
    token_t *back = ahead;

    if ( attribute.plate == NULL ) {
      attribute.plate = new table_t( NULL );
    } // if

    if ( template_parameter( attribute ) ) {
      while ( match( ',' ) ) {
          template_parameter( attribute );
      } // while
      return true;
    } // if

    delete attribute.plate;
    attribute.plate = NULL;

    ahead = back; return false;
} // template_parameter_list


static bool task_parameter_list( attribute_t &attribute ) {
    token_t *back = ahead;
    token_t *startP;
    token_t *endP;

    if ( match( LA ) ) {
      startP = ahead;
      for ( ;; ) {
        if ( eof() ) goto fini;
        if ( check( ';' ) ) goto fini;
        if ( check( LC ) ) goto fini;
        if ( match( LA ) && ! match_closing( LA, RA ) ) goto fini;
        if ( check( RA ) ) break;
        if ( check( ',' ) ) break;
          scan();
      } // for
      if ( startP == ahead ) goto fini;
      endP = ahead;
      if ( ! match( RA ) ) goto fini;                 // match closing '>'

      attribute.startP = startP;
      attribute.endP = endP;
      return true;
      fini:
      ahead = startP;                           // attempt local error recovery
      match_closing( LA, RA );
      if ( startP->value != ERROR ) {                 // only one error message
          gen_error( startP , "incorrectly formed task argument, argument list ignored." );
      } // if
      return true;
    } // if

    ahead = back; return false;
} // task_parameter_list


static bool mutex_parameter_list( attribute_t &attribute ) {
    token_t *back = ahead;
    token_t *startE;
    token_t *startM;
    token_t *endM;

    if ( match( LA ) ) {
      startE = ahead;
      for ( ;; ) {
        if ( eof() ) goto fini;
        if ( check( ';' ) ) goto fini;
        if ( check( LC ) ) goto fini;
        if ( match( LA ) && ! match_closing( LA, RA ) ) goto fini;
        if ( check( RA ) ) break;
        if ( check( ',' ) ) break;
          scan();
      } // for
      if ( startE == ahead ) goto fini;
      if ( match( ',' ) ) {
          startM = ahead;
          for ( ;; ) {
            if ( eof() ) goto fini;
            if ( check( ';' ) ) goto fini;
            if ( check( LC ) ) goto fini;
            if ( match( LA ) && ! match_closing( LA, RA ) ) goto fini;
            if ( check( RA ) ) break;
            if ( check( ',' ) ) break;
            scan();
          } // for
          if ( startM == ahead ) goto fini;
          endM = ahead;
          if ( ! match( RA ) ) goto fini;       // match closing '>'

          if ( attribute.startE != NULL && attribute.startE != startE ) {
            gen_error( startE, "multiple mutex qualifiers specified, only one allowed." );
          } // if

          attribute.startE = startE;
          attribute.startM = startM;
          attribute.endM = endM;
          return true;
      } // if
      fini:
      ahead = startE;                           // attempt local error recovery
      match_closing( LA, RA );
      if ( startE->value != ERROR ) {                 // only one error message
          gen_error( startE, "incorrectly formed mutex argument list, argument list ignored." );
      } // if
      return true;
    } // if

    ahead = back; return false;
} // mutex_parameter_list


static bool type_qualifier( attribute_t &attribute ) {
    token_t *back = ahead;

    if ( match( AUTO ) ) { attribute.dclqual.qual.AUTO = true; return true; }
    if ( match( REGISTER ) ) { attribute.dclqual.qual.REGISTER = true; return true; }
    if ( match( STATIC ) ) { attribute.dclqual.qual.STATIC = true; return true; }
    if ( match( EXTERN ) ) { attribute.dclqual.qual.EXTERN = true; return true; }
    if ( match( MUTABLE ) ) { attribute.dclqual.qual.MUTABLE = true; return true; }

    if ( match( EXTENSION ) ) { attribute.dclqual.qual.EXTENSION = true; return true; }; // gcc specific

    if ( match( INLINE ) ) { attribute.dclqual.qual.INLINE = true; return true; }
    if ( match( VIRTUAL ) ) { attribute.dclqual.qual.VIRTUAL = true; return true; }
    if ( match( EXPLICIT ) ) { attribute.dclqual.qual.EXPLICIT = true; return true; }

    if ( match( CONST ) ) { attribute.dclqual.qual.CONST = true; return true; }
    if ( match( VOLATILE ) ) { attribute.dclqual.qual.VOLATILE = true; return true; }

    if ( match( TYPEDEF ) ) { attribute.dclkind.kind.TYPEDEF = true; return true; }
    if ( match( FRIEND ) ) { attribute.dclkind.kind.FRIEND = true; return true; }

    if ( match( MUTEX ) ) {
      if ( check( LA ) && ! mutex_parameter_list( attribute ) ) goto fini;
      attribute.dclmutex.qual.MUTEX = true;
      return true;
    } // if
    if ( match( NOMUTEX ) ) {
      if ( check( LA ) && ! mutex_parameter_list( attribute ) ) goto fini;
      attribute.dclmutex.qual.NOMUTEX = true;
      return true;
    } // if
  fini:
    ahead = back; return false;
} // type_qualifier


static bool template_qualifier( attribute_t &attribute ) {
    token_t *back = ahead;

    match( EXPORT );                            // optional export clause

    if ( match( TEMPLATE ) ) {
      if ( match( LA ) ) {
          if ( template_parameter_list( attribute ) ) { // can be empty
            // must push this table on the lookup stack as types in the
            // table can be used immediately.
            if ( focus != attribute.plate ) {
                attribute.focus = focus;        // save current focus
                attribute.plate->lexical = focus;     // temporarily connect to current lexical scope
                attribute.plate->push_table();
            } // if
          } // if
          if ( match( RA ) ) {
            return true;
          } // if
      } else {
          return true;
      } // if
    } // if

    ahead = back; return false;
} // template_qualifier


static token_t *class_head( attribute_t &attribute ) {
    token_t *back = ahead;
    token_t *token;
    symbol_t *symbol;
    unsigned int key;

    if ( ( key = class_key( attribute ) ) != 0 ) {    // class key found ?
      if ( attribute.dclkind.kind.FRIEND ) {          // friend declaration ?
          if ( ( token = identifier() ) != NULL ) {   // undefined ?
            // Undefined friend declarations are moved to the root scope.
            symbol = token->symbol;
            uassert( symbol != NULL );
            make_type( token, symbol, root );
            symbol->data->key = key;            // set the symbol's class key to the class key
          } else if ( ( token = type() ) != NULL ) {
          } // if
          return token;
      } // if

      if ( ( token = identifier() ) != NULL ) {
          symbol = token->symbol;
          uassert( symbol != NULL );
          // if the top of the lexical stack is a template, add this type to
          // the actual table below it.
          make_type( token, symbol, top->tbl == attribute.plate ? top->link->tbl : top->tbl );
          symbol->data->key = key;              // set the symbol's class key to the class key
      } else if ( ( token = type() ) != NULL ) {
          // if a type token is found, grab the symbol associated with the
          // token and do some analysis

          symbol = token->symbol;
          uassert( symbol != NULL );

          // look ahead for old style C struct declarations.
          if ( ( symbol->data->key == STRUCT || symbol->data->key == UNION ) && ( ! check( ':' ) && ! check( LC ) && ! check( ';' ) ) ) return token;
          
          uassert( symbol->data->found != NULL );

          table_t *containing = focus == attribute.plate ? focus->lexical : focus;
          symbol_t *checksym;
          
          // lookup the type name again to determine if it was specified using a nested name (qualified).
          // (this could have been accomplished by creating a flag in attribute to indicate a nested name.)
          if ( containing != symbol->data->found &&
             ( checksym = containing->search_table( symbol->hash ) ) != NULL &&
             ( checksym->data->found == symbol->data->found ) ) {
            
            // if found in the same previous table => no nested naming => hiding => create a new entry
            token->symbol = symbol = new symbol_t( token->value, token->hash );
            containing->insert_table( symbol ); // insert the symbol into the current symbol table
            symbol->data->key = key;            // set the symbol's class to the class key
          } else {
            // if not found in search => nested naming => augmenting existing type definition
            // if found in a different table => augmenting existing type definition
            
            // verify that its kind is the same as the previous definition
            if ( symbol->data->key != key ) {
                // struct and class are equivalent for prototype
                if ( ! ( symbol->data->key == STRUCT && key == CLASS || symbol->data->key == CLASS && key == STRUCT ) ) {
                  char msg[strlen(symbol->hash->text) + 256];
                  sprintf( msg, "\"%s\" redeclared with different kind.", symbol->hash->text );
                  gen_error( ahead, msg );
                } else {
                  symbol->data->key = key;
                } // if
            } // if
          } // if
      } else {
          // Cannot generate anonymous types for coroutine or task because
          // constructors and destructors are needed.  If there is no name
          // for the type, unlike the compiler, we can't generated one
          // because the order of includes may cause us to generated
          // different names for different compilations.

          token = new token_t( TYPE, hash_table->look( "" ) );

          // insert this token into the token stream

          token->add_token_before( *ahead );

          // create a symbol that must accompany this token as a type

          token->symbol = symbol = new symbol_t( token->value, token->hash );

          // insert the symbol into the current symbol table

          focus->insert_table( symbol );

          if ( key == COROUTINE || key == TASK ) {
            gen_error( ahead, "cannot create anonymous coroutine or task because of the need for named constructors and destructors." );
            // By making this type look like a class, it will not generate
            // additional bogus tokens that might cause problems later on.
            symbol->data->key = CLASS;
          } else {
            symbol->data->key = key;
          } // if
      } // if

      // save a pointer to the next token so that if we have to insert a base
      // class definition later, it be done

      symbol->data->base_token = ahead;

      return token;
    } // if

    ahead = back; return NULL;
} // class_head


static bool access_declaration() {
    token_t *back = ahead;
    unsigned int access;

    if ( ( access = access_specifier() ) != 0 ) {
      if ( match( ':' ) ) {
          // modify the access privileges of member functions added to the
          // symbol table after this point

          uassert( top != NULL );
          focus->access = access;

          return true;
      } // if
    } // if

    ahead = back; return false;
} // access_declaration


static bool member_module() {
    token_t *back = ahead;

    if ( access_declaration() ) return true;
    if ( object_declaration() ) return true;

    ahead = back; return false;
} // member_module


static void make_mutex_class( symbol_t *clss );
static bool attribute_clause();


static bool class_specifier( attribute_t &attribute ) {
    token_t *back = ahead;
    token_t *clss;
    table_t *table;
    symbol_t *symbol;

    if ( ( clss = class_head( attribute ) ) != NULL ) {
      symbol = clss->symbol;
      uassert( symbol != NULL );

      attribute.typedef_base = symbol;

      // check that only one of the mutex attributes is specified for symbol
      // and current definition

      if ( ( symbol->data->attribute.dclmutex.qual.MUTEX | attribute.dclmutex.qual.MUTEX ) &&
           ( symbol->data->attribute.dclmutex.qual.NOMUTEX | attribute.dclmutex.qual.NOMUTEX ) ) {
          gen_error( ahead, "may not specify both uMutex and uNoMutex attributes for a class; uNoMutex attribute ignored." );
          attribute.dclmutex.qual.NOMUTEX = false;
      } // if

      // compute the attribute of this class based on explicit specification
      // and default rules

      if ( ! symbol->data->attribute.dclmutex.qual.MUTEX && ! attribute.dclmutex.qual.MUTEX &&
           ! symbol->data->attribute.dclmutex.qual.NOMUTEX && ! attribute.dclmutex.qual.NOMUTEX &&
           symbol->data->key == TASK ) {
          symbol->data->attribute.dclmutex.qual.MUTEX = true;
      } else {
          symbol->data->attribute.dclmutex.value |= attribute.dclmutex.value;
      } // if

      // if mutex attribute specified or task => this is a mutex type so
      // destructor is mutex

      if ( symbol->data->attribute.dclmutex.qual.MUTEX || symbol->data->key == TASK ) {
          symbol->data->attribute.Mutex = true;
      } // if

      if ( attribute.startE != NULL ) {
          symbol->data->attribute.startE = attribute.startE;
          symbol->data->attribute.startM = attribute.startM;
          symbol->data->attribute.endM = attribute.endM;
      } // if
      if ( attribute.startP != NULL ) {
          symbol->data->attribute.startP = attribute.startP;
          symbol->data->attribute.endP = attribute.endP;
      } // if

      // copy these fields to complete symbol attribute

      symbol->data->attribute.rttskkind = attribute.rttskkind;
      symbol->data->attribute.plate = attribute.plate;

      template_key();
      base_clause( symbol );

      // check for a {, don't match because a symbol table has to be built
      // before scanning the next token, which may be an identifier

      if ( check( LC ) ) {
          // define the base class

          gen_base_clause( symbol->data->base_token, symbol );

          if ( symbol->data->attribute.plate != NULL ) {
            // use the template table as the symbol table for this class

            symbol->data->table = table = symbol->data->attribute.plate; // already pushed

            // link the symbol and table together because it was not
            // originally done when the template table was created because
            // the class symbol was not yet known.

            table->symbol = symbol;
          } else {
            // create a new symbol table

            symbol->data->table = table = new table_t( symbol );
            table->push_table();
          } // if

          // set the search path to the current lexical context (table).

          table->lexical = symbol->data->found;

          table->access = PRIVATE;
          table->defined = false;

          match( LC );                    // now scan passed the '{' for the next token

          // generate the class prefix

          gen_class_prefix( ahead, symbol );

          // if type is a TASK, generate PIQ instance

          if ( symbol->data->key == TASK ) {
            gen_PIQ( table->protected_area, symbol );
          } // if

          // if type is mutex, generate uSerial instance

          if ( symbol->data->attribute.Mutex ) {
            make_mutex_class( symbol );
          } // if

          while ( member_module() );

          table->defined = true;
          table->access = PRIVATE;

          if ( symbol->data->base != NULL ) {         // check inheritance matching
            symbol_t *base = symbol->data->base;

            // check that derived kind only inherits from appropriate base kind

            bool err = false;
            if ( ( symbol->data->key == STRUCT || symbol->data->key == CLASS ) && ! symbol->data->attribute.Mutex ) {
                if ( ! ( ( base->data->key == STRUCT || base->data->key == CLASS ) && ! base->data->attribute.Mutex ) ) err = true; // only struct/class
            } else if ( symbol->data->key == COROUTINE && ! symbol->data->attribute.Mutex ) { // coroutine
                if ( ! ( base->data->key == COROUTINE && ! base->data->attribute.Mutex ) ) err = true; // only coroutine
            } else if ( ( symbol->data->key == STRUCT || symbol->data->key == CLASS ) && symbol->data->attribute.Mutex ) { // monitor
                if ( ! ( base->data->key == STRUCT || base->data->key == CLASS ) ) err = true; // only struct/class/monitor
            } else if ( symbol->data->key == COROUTINE && symbol->data->attribute.Mutex ) { // comonitor
                if ( ! ( base->data->key == COROUTINE || ( ( base->data->key == STRUCT || base->data->key == CLASS ) && base->data->attribute.Mutex ) ) ) err = true; // only coroutine/monitor/comonitor
            } else if ( symbol->data->key == TASK ) {
                if ( ! ( ( ( base->data->key == STRUCT || base->data->key == CLASS ) && base->data->attribute.Mutex ) || base->data->key == TASK ) ) err = true; // only monitor/task
            } // if

            if ( err ) {
                char msg[strlen(symbol->hash->text) + strlen(base->hash->text) + 256];
                sprintf( msg, "derived type \"%s\" of kind \"%s\" is incompatible with the base type \"%s\" of kind \"%s\"; inheritance ignored.",
                       symbol->hash->text, kind( symbol ), base->hash->text, kind( base ) );
                gen_error( ahead, msg );
                symbol->data->base = NULL;
            } // if
          } // if

          gen_class_suffix( ahead, symbol );

          match( RC );

          attribute_clause();                   // optional

          pop_table();
          attribute.plate = NULL;
      } else if ( check( ';' ) ) {
          if ( attribute.plate != NULL ) {
            delete pop_table();
            attribute.plate = NULL;
          } // if
      } // if

      return true;
    } // if

    ahead = back; return false;
} // class_specifier


static bool enumerator() {
    token_t *back = ahead;

    if ( identifier() != NULL ) {
      for ( ;; ) {                              // scan off optional enumerator initializer
          if ( eof() ) return false;
        if ( check( ',' ) ) break;
        if ( check( RC ) ) break;
          scan();
        } // for
      return true;
    } // if

    ahead = back; return false;
} // enumerator


static bool enumerator_list() {
    token_t *back = ahead;

    if ( enumerator() ) {
      if ( match( ',' ) ) {
          if ( enumerator_list() ) {
            return true;
          } else {
            return true;
          } // if
      } else {
          return true;
      } // if
    } // if

    ahead = back; return false;
} // enumerator_list


static bool enumerator_specifier() {
    token_t *back = ahead;
    token_t *token;

    if ( match( ENUM ) ) {
      if ( ( token = identifier() ) != NULL || ( token = type() ) != NULL ) {
          make_type( token, token->symbol );
      } // if

      if ( match( LC ) ) {
          enumerator_list();
          if ( match( RC ) ) {
            return true;
          } // if
      } else {
          return true;
      } // if

    } // if

    ahead = back; return false;
} // enumerator_specifier


static bool specifier( attribute_t &attribute, bool &rt );
static bool exception_list();


static bool formal_parameter_empty( attribute_t &attribute ) {
    token_t *back = ahead;

    if ( match( RP ) || ( match( VOID ) && match( RP ) ) ) {
      attribute.emptyparms = true;
      return true;
    } // if

    ahead = back; return false;
} // formal_parameter_empty


static bool formal_parameter( bool ctordtor, token_t *token, attribute_t &attribute ) {
    token_t *back = ahead;
    bool pushflag = false;
    symbol_t *symbol;

    // check for a (, don't match because the focus has to be set before
    // scanning the next token, which may be a type
    
    symbol = token->symbol;
    if ( check( LP ) ) {
      if ( ctordtor ) {                   // constructor/destructor routine ?
          uassert( symbol->value == TYPE );
          if ( symbol != focus->symbol && ( focus->lexical == NULL || ( focus->lexical != NULL && symbol != focus->lexical->symbol ) ) ) { // not inlined definition ?
             if ( attribute.plate == NULL ) {   // non-template constructor ?
                 pushflag = true;
                 // place class containing constructor above current lexical context
                 symbol->data->table->push_table();
             } else {
                 // place class containing constructor below template lexical context
                 attribute.plate->lexical = symbol->data->table;
             } // if
           } // if
      } else if ( symbol->data->found != NULL ) {     // not inlined definition ?
          // if a template function, use the enclosing scope to store the symbol.
          table_t *containing = focus == attribute.plate ? focus->lexical : focus;

          // lookup the function name again to determine if it was specified using a nested name (qualified).
          // (this could have been accomplished by creating a flag in attribute to indicate a nested name.)
          symbol_t *checksym = containing->search_table( symbol->hash );

          // if not found or found in a different table => nested naming => push table identifier found in
          if ( checksym == NULL || checksym->data->found != symbol->data->found ) {
            if ( symbol->data->found != focus && symbol->data->found != focus->lexical ) { // not inlined definition ?
                if ( attribute.plate == NULL ) {      // non-template routine ?
                  pushflag = true;
                  // place class/namespace containing routine above current lexical context
                  symbol->data->found->push_table();
                } else {
                  // place class/namespace containing routine below template lexical context
                  attribute.plate->lexical = symbol->data->found;
                } // if
            } // if
          } // if
      } // if

      match( LP );
      // special case to detect default constructor
      if ( formal_parameter_empty( attribute ) ) {
          if ( pushflag ) {
            pop_table();
            //cerr << "formal_parameter pop2:" << endl;
          } // if
          return true;
      } // if

      // Quick check to determine if this is a formal parameter list by
      // looking at the first token. If the first token forms any part of a
      // parameter declaration, this must be a formal declaration context. If
      // the first token is a type name nested in a class containing this
      // member routine, the symbol table focus has to be correct. It should
      // have been set when the function name was looked up.

      bool ts = false;                    // dummy variables for this check
      attribute_t attr;
      if ( specifier( attr, ts ) || match( DOT_DOT_DOT ) ) {
          if ( pushflag ) {
            pop_table();
            //cerr << "formal_parameter pop2:" << endl;
          } // if

          // Having determined that that this construct is a formal argument
          // list, simply scan for the closing parentheses.

          if ( match_closing( LP, RP ) ) return true;
      } else {
          if ( pushflag ) {
            pop_table();
            //cerr << "formal_parameter pop3:" << endl;
          } // if
      } // if
    } // if

    ahead = back; return false;
} // formal_parameter


static bool pointer_qualifier() {
    token_t *back = ahead;

    if ( match( CONST ) ) return true;
    if ( match( VOLATILE ) ) return true;

    ahead = back; return false;
} // pointer_qualifier


static bool pointer() {
    token_t *back = ahead;

    if ( match( '*' ) || match( '&' ) ) {
      while ( pointer_qualifier() );
      return true;
    } else if ( nested_name_specifier( false ) != NULL ) { // must be type names
      if ( match( '*' ) || match( '&' ) ) {
          while ( pointer_qualifier() );
          return true;
      } // if
    } // if

    ahead = back; return false;
} // pointer


static bool typeof_specifier() {                // gcc typeof specifier
    token_t *back = ahead;

    if ( match( TYPEOF ) && match( LP ) && ( identifier() != NULL || type() != NULL ) && match( RP ) ) return true;

    ahead = back; return false;
} // typeof


static bool attribute_clause() {                // gcc attribute clause
    token_t *back = ahead;

    if ( match( ATTRIBUTE ) && match( LP ) && match_closing( LP, RP ) ) return true;

    ahead = back; return false;
} // attribute_clause


static bool asm_clause() {                      // gcc asm clause
    token_t *back = ahead;

    if ( match( ASM ) && match( LP ) && match_closing( LP, RP ) ) return true;

    ahead = back; return false;
} // asm_clause


static bool cv_qualifier_list() {
    while ( match( CONST ) || match( VOLATILE ) || attribute_clause() || asm_clause() || exception_list() );
    return true;
} // cv_qualifier_list


static bool exception_list() {
    token_t *back = ahead;

    if ( match( THROW ) && match( LP ) && match_closing( LP, RP ) ) return true;

    ahead = back; return false;
} // exception_list


static bool array_dimension() {
    token_t *back = ahead;

    if ( match( LB ) && match_closing( LB, RB ) ) {
      array_dimension();                        // 1 or more
      return true;
    } // if

    ahead = back; return false;
} // array_dimension


static bool more_declarator( token_t *token, attribute_t &attribute ) {
    token_t *back = ahead;

    if ( array_dimension() ) {                        // array dimension
      more_declarator( token, attribute );
      return true;
    } else if ( match( LP ) ) {                       // parameter list
      if ( match_closing( LP, RP ) ) {
          more_declarator( token, attribute );
      } // if
      return true;
    } else if ( match( ':' ) ) {                // bit slice declarator
      if ( match( NUMBER ) ) {                  // should really be constant expression
          return true;
      } // if
    } else if ( cv_qualifier_list() ) {
      return true;
    } // if

    ahead = back; return false;
} // more_declarator


static token_t *declarator( attribute_t &attribute ) {
    token_t *back = ahead;
    token_t *token;

    if ( match( LP ) ) {
      if ( ( token = declarator( attribute ) ) != NULL ) {
          if ( match( RP ) ) {
            more_declarator( token, attribute );
            return token;
          } // if
      } // if
    } else if ( pointer() ) {
      if ( ( token = declarator( attribute ) ) != NULL ) {
          more_declarator( token, attribute );
          return token;
      } // if
    } else if ( ( token = identifier() ) != NULL || ( token = operater() ) != NULL || ( token = type() ) != NULL ) {
      more_declarator( token, attribute );
      return token;
    } else if ( match( ':' ) ) {                // anonymous bit slice declarator
      if ( match( NUMBER ) ) {                  // should really be constant expression
          return new token_t( IDENTIFIER, hash_table->look( "" ) );
      } // if
    } // if

    ahead = back; return NULL;
} // declarator


static token_t *paren_identifier( attribute_t &attribute ) {
    token_t *back = ahead;
    token_t *token;

    if ( ( token = identifier() ) != NULL || ( token = operater() ) != NULL || ( token = type() ) != NULL ) {
      return token;
    } else if ( match( '(' ) && ( token = paren_identifier( attribute ) ) && match( ')' ) ) return token; /* redundant parenthesis */

    ahead = back; return NULL;
} // paren_identifier


static token_t *function_ptr( attribute_t &attribute );
static token_t *function_no_ptr( attribute_t &attribute );
static token_t *function_array( attribute_t &attribute );


static token_t *function_declarator( attribute_t &attribute ) {
    token_t *back = ahead;
    token_t *token;

    // reset the focus of the scanner to the top table, and return the token
    // that points to the type.

    if ( ( token = function_no_ptr( attribute ) ) || ( token = function_array( attribute ) ) || ( token = function_ptr( attribute ) ) ) {
      return token;
    } // if

    ahead = back; return NULL;
} // function_declarator
      

static token_t *function_no_ptr( attribute_t &attribute ) {
    token_t *back = ahead;
    token_t *token;

    if ( ( token = paren_identifier( attribute ) ) && formal_parameter( false, token, attribute ) ) return token;
    else {
      ahead = back;
      if ( match( '(' ) ) {
          token_t *back = ahead;
          if ( ( token = function_ptr( attribute ) ) && match( ')' ) && formal_parameter( false, token, attribute ) ) return token;
          else {
            ahead = back;
            if ( ( token = function_no_ptr( attribute ) ) && match( ')' ) ) return token; /* redundant parenthesis */
          } // if
      } // if
    } // if

    ahead = back; return NULL;
} // function_no_ptr


static token_t *function_ptr( attribute_t &attribute ) {
    token_t *back = ahead;
    token_t *token;

    if ( pointer() ) {
      if ( ( token = function_declarator( attribute ) ) ) return token;
    } else {
      ahead = back;
      if ( match( '(' ) && ( token = function_ptr( attribute ) ) && match( ')' ) ) return token;
    } // if

    ahead = back; return NULL;
} // function_ptr

static token_t *function_array( attribute_t &attribute ) {
    token_t *back = ahead;
    token_t *token;

    if ( match( '(' ) ) {
      token_t *back = ahead;
      if ( ( token = function_ptr( attribute ) ) && match( ')' ) && array_dimension() ) return token;
      else {
          ahead = back;
          if ( ( token = function_array( attribute ) ) && match( ')' ) ) { // redundant parenthesis
            array_dimension();                  // optional
            return token;
          } // if
      } // if
    } // if

    ahead = back; return NULL;
} // function_array


static bool copy_constructor( const token_t *token, attribute_t &attribute ) {
    token_t *back = ahead;
    symbol_t *symbol;
    bool pushflag = false;

    symbol = token->symbol;
    if ( symbol == NULL || symbol->data->table == NULL ) return false;

    if ( check( LP ) ) {
      if ( symbol != focus->symbol && ( focus->lexical == NULL || ( focus->lexical != NULL && symbol != focus->lexical->symbol ) ) ) { // not inlined definition ?
          if ( attribute.plate == NULL ) {            // non-template constructor ?
            pushflag = true;
            // place class containing constructor above current lexical context
            symbol->data->table->push_table();
          } else {
            // place class containing constructor below template lexical context
            attribute.plate->lexical = symbol->data->table;
          } // if
      } // if

      match( LP );

      while ( match( CONST ) || match( VOLATILE ) );  // eat up const and volatile specifiers
      token_t *temp = type();
      if ( temp != NULL && temp->symbol == token->symbol ) {
          if ( match( '&' ) ) {                 // looks good so far
            int commas = 0;                     // if a copy constructor, every comma has a corresponding '=' after it
            int level = 1;
            match( IDENTIFIER );                // optional identifier
            for ( ;; ) {
                if ( eof() ) goto fini;
                    if ( match( ',' ) ) {
                    commas += 1;
                } else if ( match( '=' ) ) {
                  // ignore an '=' in something like X(X & a = b)
                  if ( commas > 0 ) {
                      commas -= 1;
                  } // if
                } else if ( match( LP ) ) {           // match parentheses
                  level += 1;
                    } else if ( match( RP ) ) {
                  level -= 1;
                  if ( level == 0 ) break;
                    } else
                  scan();                       // ignore everything else
                } // for
            if ( commas == 0 ) {
                token->symbol->data->table->hascopy = true;
                exception_list();               // optional exception list
                if ( pushflag ) pop_table();
                return true;
            } // if
          } // if
      } // if
    } // if
  fini:
    if ( pushflag ) pop_table();
    ahead = back; return false;
} // copy_constructor


static token_t *constructor_declarator( attribute_t &attribute ) {
    token_t *back = ahead;
    token_t *token;

    if ( ( token = type() ) != NULL ) {
      // constructors and destructors are not put in the symbol table.  the
      // class symbol table is the one set for further name look ups.

      if ( copy_constructor( token, attribute ) || formal_parameter( true, token, attribute ) ) {
          cv_qualifier_list();                  // optional post qualifiers
          return token;
      } // if
    } // if

    ahead = back; return NULL;
} // constructor_declarator


static token_t *destructor_declarator( attribute_t &attribute ) {
    token_t *back = ahead;
    token_t *token;

    if ( ( token = epyt() ) != NULL ) {
      if ( formal_parameter( true, token, attribute ) ) { // should be empty
          cv_qualifier_list();                  // optional post qualifiers
          return token;
      } // if
    } // if

    ahead = back; return NULL;
} // destructor_declarator


static bool body( table_t *search, token_t *function, attribute_t &attribute, symbol_t *symbol ) {
    token_t *back = ahead;

    // check for a {, don't match because a symbol table has to be built
    // before scanning the next token, which may be an identifier

    if ( check( LC ) ) {
      uassert( symbol != NULL );
      table_t *table;

      if ( attribute.plate != NULL ) {
          table = attribute.plate;              // already allocated & pushed
          table->symbol = symbol;               // connect routine table temporarily to routine symbol
      } else {
          table = new table_t( NULL );
          table->symbol = symbol;               // connect routine table temporarily to routine symbol
          table->push_table();
      } // if

      if ( function ) {
          table->lexical = symbol->data->found;
      } else {
          // Constructor/destructor do not have symbol-table entries in the
          // class (unlike member routines), so use class symbol-table.
          table->lexical = symbol->data->table;
      } // if

      match( LC );                              // now scan passed the '{' for the next token

      if ( function ) {
          if ( user &&                    // user code ? (see #pragma __U_USER_CODE__)
             // Since these routines are used at boot time, they cannot be annotated.
             strcmp( function->hash->text, "uDefaultHeapExpansion" ) != 0 &&
             strcmp( function->hash->text, "uDefaultStackSize" ) != 0 &&
             strcmp( function->hash->text, "uMainStackSize" ) != 0 &&
             strcmp( function->hash->text, "uDefaultSpin" ) != 0 &&
             strcmp( function->hash->text, "uDefaultPreemption" ) != 0
            ) {
            if ( verify ) gen_verify( ahead );
            if ( Yield ) gen_yield( ahead );
          } // if
      } // if

      while ( statement( symbol ) );                  // declarations/statements in routine body

      // Must remove the current function scope *before* looking up the next
      // identifier after the RC, as in:
      //
      //   foo f() {} bar b() {}
      //              ^- look up bar in outer scope
      //
      // otherwise the serach starts in the function scope.

      delete pop_table();
      attribute.plate = NULL;

      match( RC );
      return true;
    } // if

    ahead = back; return false;
} // body


static bool pure() {
    token_t *back = ahead;

    if ( match( '=' ) ) {
      if ( match( NUMBER ) ) {
          return true;
      } // if
    } // if

    ahead = back; return false;
} // pure


static void make_mutex_class( symbol_t *clss ) {
    uassert( clss != NULL );

    // If there are no mutex members, make the type mutex (should be checked by
    // caller). Notice, a derived type may find existing mutex members from the
    // base type, and hence, does not recreate declarations that appear in the
    // root base type of the inheritance chain.

    if ( clss->data->base == NULL || ! clss->data->base->data->attribute.Mutex ) {
      table_t *table = clss->data->table;
      uassert( table != NULL );

      gen_mutex( table->protected_area, clss );
      gen_mutex_entry( table->protected_area, clss );
      clss->data->index += 1;                   // advance to next bit in the mutex mask for mutex type (for mutex destructor)
    } // if
} // make_mutex_class


static void make_mutex_member( symbol_t *symbol ) {
    table_t *table;
    symbol_t *clss;

    uassert( symbol != NULL );
    table = symbol->data->found;
    uassert( table != NULL );
    clss = table->symbol;
    uassert( clss != NULL );

    // if the containing type is not mutex, make it so now to ensure the
    // destructor mutex is numbered DESTRUCTORPOSN
    
    if ( ! clss->data->attribute.Mutex ) {
      clss->data->attribute.Mutex = true;
      make_mutex_class( clss );
    } // if

    symbol->data->attribute.Mutex = true;       // mark routine as mutex member
    symbol->data->index = clss->data->index;          // copy current position in mutex bit mask
    gen_mutex_entry( table->protected_area, symbol );
    clss->data->index += 1;                     // advance to next bit in the mutex mask for mutex type
} // make_mutex_member


// Constructs a string corresponding to the attribute.

static const char *attr_string( attribute_t &attribute ) {
    if ( attribute.dclkind.kind.TYPEDEF ) return "typedef";
    if ( attribute.dclkind.kind.FRIEND ) return "friend";
    if ( attribute.dclmutex.qual.MUTEX ) return "uMutex";
    if ( attribute.dclmutex.qual.NOMUTEX ) return "uNoMutex";
    return "(none)";
} // attr_string


static bool function_declaration( int explict, attribute_t &attribute ) {
    token_t *back = ahead;
    token_t *function;
    symbol_t *symbol;
    table_t *table;
    token_t *prefix, *suffix;

    // template qualifier removed by specifier

    // if the declarator is a function declarator with an explicit type
    // specifier (return type) or an operator routine (conversion routines do
    // not have explicit return types).

    uassert( top != NULL );

    function = function_declarator( attribute );
    if ( ( function != NULL && explict ) || ( function != NULL && function->symbol->value == OPERATOR ) ) {
      cv_qualifier_list();                      // optional post qualifiers
      pure();                                   // optional pure specifier for virtual functions

      symbol = function->symbol;                // grab the symbol associated with the token

      // if a template function, use the enclosing scope to store the symbol.
      table_t *containing = focus == attribute.plate ? focus->lexical : focus;

      if ( symbol->data->found == NULL ) {
          // the symbol is not defined in the symbol table so define it
          if ( attribute.dclkind.kind.FRIEND ) {      // friend routines are placed into the root namespace
            root->insert_table( symbol );
          } else {
            containing->insert_table( symbol );
          } // if
      } else if ( containing != symbol->data->found ) {
          // lookup the function name again to determine if it was specified using a nested name (qualified).
          // (this could have been accomplished by creating a flag in attribute to indicate a nested name.)
          symbol_t *checksym = containing->search_table( symbol->hash );

          // if not found => nested naming => augmenting existing function definition
          // if found in the same previous table => no nested naming => hiding => create a new entry
          if ( checksym != NULL && checksym->data->found == symbol->data->found ) {
            symbol = new symbol_t( IDENTIFIER, symbol->hash );
            containing->insert_table( symbol );
          } // if
          // if found in a different table => nested naming => augmenting existing function definition
      } // if

      if ( symbol->value != TYPE ) {                  // already defined as a struct/class so ignore this definition
          if ( symbol->data->found->symbol != NULL &&
             ( symbol->data->found->symbol->data->key == STRUCT || symbol->data->found->symbol->data->key == CLASS ) ) { // member routine ?
            symbol->data->key = MEMBER;
          } else {
            symbol->data->key = ROUTINE;
          } // if
      } // if

      symbol->data->attribute.dclqual.value |= attribute.dclqual.value; // merge declaraton qualifiers into the symbol

      table = symbol->data->found;              // grab the table in which this symbol is found
      uassert( table != NULL );

      // spend some time determining what attributes are attached to this
      // function.  attributes can be explicitly specified, inherited from
      // the class in which a member function is defined, or specified by the
      // default rules of the language.

      if ( table->symbol != NULL ) {
          // if this symbol is found in a table that has a symbol associated
          // with it, this table must be a class table.  follow the default
          // rules for other members, constructors and destructors

          if ( ! attribute.dclmutex.qual.MUTEX && ! attribute.dclmutex.qual.NOMUTEX ) {
            attribute.dclmutex.qual.MUTEX = symbol->data->attribute.dclmutex.qual.MUTEX;
            attribute.dclmutex.qual.NOMUTEX = symbol->data->attribute.dclmutex.qual.NOMUTEX;
          } // if

          if ( ! attribute.dclmutex.qual.MUTEX && ! attribute.dclmutex.qual.NOMUTEX ) { // still don't know ?
            // if no attribute is specified explicitly, infer the attribute
            // of this symbol

            if ( table->access == PUBLIC &&
                 strcmp( symbol->hash->text, "new" ) != 0 && strcmp( symbol->hash->text, "delete" ) != 0 ) {
                // if in the public area of a class, use the attribute
                // associated with the class except for the new or delete
                // operators

                uassert( table->symbol != NULL );
                attribute.dclmutex.qual.MUTEX = table->symbol->data->attribute.dclmutex.qual.MUTEX;
                attribute.dclmutex.qual.NOMUTEX = table->symbol->data->attribute.dclmutex.qual.NOMUTEX;
            } else {
                // if in the private or protected area of a class, use the
                // no mutex attribute

                attribute.dclmutex.qual.NOMUTEX = true;
            } // if
          } else if ( attribute.dclmutex.qual.MUTEX ) {
            if ( strcmp(symbol->hash->text, "new") == 0 || strcmp(symbol->hash->text, "delete") == 0 ) { // new and delete operators can't be mutex
                char msg[strlen(symbol->hash->text) + 256];
                sprintf( msg, "\"%s\" operator cannot be mutex, uMutex attribute ignored.", symbol->hash->text );
                gen_error( ahead, msg );
                attribute.dclmutex.qual.MUTEX = false;
            } // if
            if ( attribute.startE != NULL ) {
                char msg[strlen(symbol->hash->text) + 256];
                sprintf( msg, "mutex qualifier on member \"%s\" can only specify queue types when modifying a class or task, queue types ignored.",
                       symbol->hash->text );
                gen_error( ahead, msg );
            } // if
          } // if

          if ( symbol->data->attribute.dclqual.qual.STATIC && attribute.dclmutex.qual.MUTEX ) {
            char msg[strlen(symbol->hash->text) + 256];
            sprintf( msg, "static member \"%s\" cannot be mutex, uMutex attribute ignored.", symbol->hash->text );
            gen_error( ahead, msg );
            attribute.dclmutex.qual.MUTEX = false;
          } // if

          // once an attribute is determined, assign this attribute to the
          // symbol if it does not have an attribute yet, else check that the
          // attributes match

          if ( ! symbol->data->attribute.dclmutex.qual.MUTEX && ! symbol->data->attribute.dclmutex.qual.NOMUTEX ) {
            symbol->data->attribute.dclmutex.qual.MUTEX = attribute.dclmutex.qual.MUTEX;
            symbol->data->attribute.dclmutex.qual.NOMUTEX = attribute.dclmutex.qual.NOMUTEX;
          } else if ( symbol->data->attribute.dclmutex.qual.MUTEX != attribute.dclmutex.qual.MUTEX &&
                  symbol->data->attribute.dclmutex.qual.NOMUTEX != attribute.dclmutex.qual.NOMUTEX ) {
            // conflicting attributes 
            char msg[strlen(attr_string(attribute)) + strlen(table->symbol->hash->text) + strlen(symbol->hash->text) +
                   strlen(attr_string(symbol->data->attribute)) + 256];
            sprintf( msg, "%s attribute of \"%s::%s\" conflicts with previously declared",
                   attr_string(attribute), table->symbol->hash->text, symbol->hash->text );
            sprintf( &msg[strlen(msg)], " %s attribute.",
                   attr_string(symbol->data->attribute) );
            gen_error( ahead, msg );
          } // if

          // if the symbol has a mutex attribute, make it a mutex member
          // unless it has already been defined in the inheritance hierarchy
          // as mutex, as any mutex redefinition inherits the same mutex bit
          // from the original definition.

          if ( symbol->data->attribute.dclmutex.qual.MUTEX && ! symbol->data->attribute.Mutex ) {
            make_mutex_member( symbol );
          } // if
      } else if ( attribute.dclmutex.qual.MUTEX || attribute.dclmutex.qual.NOMUTEX ) {
          // assigning a (no)Mutex attribute to a function that's not a class
          // member

          char msg[strlen(symbol->hash->text) + 256];
          sprintf( msg, "routine \"%s\" not a class member, u%sMutex attribute ignored.",
                 symbol->hash->text, attribute.dclmutex.qual.MUTEX ? "" : "No" );
          gen_error( ahead, msg );
          symbol->data->attribute.dclmutex.qual.MUTEX = false;
          symbol->data->attribute.dclmutex.qual.NOMUTEX = false;
      } // if

      prefix = ahead;
      if ( body( table, function, attribute, symbol ) ) {
          suffix = ahead;
          uassert( table != NULL );
          uassert( function != NULL );
          uassert( function->hash != NULL );
          if ( symbol->data->attribute.Mutex ) {
            gen_member_prefix( prefix, symbol );
            // must be contained between member prefix and suffix
            if ( table->symbol != NULL && strcmp( function->hash->text, "main" ) == 0 ) {
                gen_main_prefix( prefix, symbol );
                gen_main_suffix( suffix, symbol );
            } // if
            gen_member_suffix( suffix, symbol );
          } else if ( table->symbol != NULL && strcmp( function->hash->text, "main" ) == 0 ) {
            gen_main_prefix( prefix, symbol );
            gen_main_suffix( suffix, symbol );
          } // if
          return true;
      } else if ( match( ';' ) ) {
          if ( attribute.plate != NULL ) {
            delete pop_table();
            attribute.plate = NULL;
          } // if
          if ( attribute.dclkind.kind.TYPEDEF ) {
            make_type( function, symbol );
          } // if
          return true;
      } // if
    } // if

    ahead = back; return false;
} // function_declaration


static bool member_initializer( symbol_t *symbol, token_t *&start ) {
    token_t *back = ahead;
    token_t *token;
    token_t *rp;

    if ( ( token = type() ) != NULL ) {
      if ( condition() ) {                      // argument list
          uassert( symbol != NULL );
          if ( symbol->data->key == COROUTINE || symbol->data->key == TASK || symbol->data->attribute.Mutex ) {
            symbol_t *base = token->symbol;
            if ( symbol->data->base == base ) {
                uassert( base != NULL );
                base->data->used = true;
                if ( base->data->key == COROUTINE || base->data->key == TASK || base->data->attribute.Mutex ) {
                  rp = ahead->prev_parse_token();
                  if ( rp->prev_parse_token()->value == LP ) {
                      gen_code( rp, "uNo" );
                  } else {
                      gen_code( rp, ", uNo" );
                  } // if
                } // if
            } // if
          } // if
          return true;
      } // if
    } else if ( ( token = identifier() ) != NULL ) {
      if ( condition() ) {
          // first non-base-class constructor
          if ( start == NULL ) start = token;
          return true;
      } // if
    } // if

    ahead = back; return false;
} // member_initializer


static bool member_initializer_list( symbol_t *symbol, token_t *&start ) {
    token_t *back = ahead;

    if ( member_initializer( symbol, start ) ) {
      if ( match( ',' ) ) {
          if ( member_initializer_list( symbol, start ) ) {
            return true;
          } // if
      } else {
          return true;
      } // if
    } // if

    ahead = back; return false;
} // member_initializer_list


static bool constructor_initializer( symbol_t *symbol, token_t *&start ) {
    token_t *back = ahead;

    if ( match( ':' ) ) {
      uassert( symbol != NULL );

      // if a base class exists, clear the used flag for now

      if ( symbol->data->base != NULL ) {
          symbol->data->base->data->used = false;
      } // if

      if ( member_initializer_list( symbol, start ) ) {
          // if a base class exists, and the used flags is still cleared, it
          // means the user has not called its constructor explicitly.  that
          // means the translator has to add a call to its constructor.

          if ( symbol->data->base != NULL && ! symbol->data->base->data->used ) {
            gen_initializer( ahead, symbol, ',' );
          } // if

          return true;
      } // if
    } // if

    ahead = back; return false;
} // constructor_initializer


static bool constructor_declaration( attribute_t &attribute ) {
    token_t *back = ahead;
    token_t *constructor;
    symbol_t *symbol;
    table_t *table;
    token_t *prefix, *suffix;
    token_t *start = NULL;
    token_t *rp;

    bool initializer;

    while ( type_qualifier( attribute ) || template_qualifier( attribute ) );

    if ( ( constructor = constructor_declarator( attribute ) ) != NULL ) {
      symbol = constructor->symbol;
      uassert( symbol != NULL );
      table = symbol->data->table;

      if ( table != NULL ) {                    // must be complete type
          // remember where the right parenthese of the argument list of the
          // constructor is

          rp = ahead->prev_parse_token();

          if ( attribute.emptyparms ) {         // default constructor ?
            symbol->data->table->hasdefault = true;
          } // if

          if ( match( TRY ) ) {                 // exceptions for constructor body ?
            gen_error( ahead, "try block for constructor body not supported." );
          } // if
          
          // eat the constructor initializers.  remember if we saw one

          initializer = constructor_initializer( symbol, start );
          prefix = ahead;

          if ( attribute.dclmutex.qual.MUTEX ) {      // can only be NOMUTEX
            gen_error( ahead, "constructor must be non-mutex, uMutex attribute ignored." );
          } // if

          // there is no reason to assign the mutex qualifier to this symbol
          // because it is always NO_ATTRIBUTE.
          
          if ( body( symbol->data->table, NULL, attribute, symbol ) ) {
            bool dummy;
            bool d1;
            hash_t *d2;
            symbol_t *d3;
            tokenlist d4,d5;
            catch_statement( symbol, dummy, d1, d2, d3, d4, d5 ); // exception for initializers

            if ( ! initializer ) {
                // if there was no initializer, may have some work to do to
                // initialize the class

                gen_initializer( prefix, symbol, ':' );
            } // if
    
            suffix = ahead->prev_parse_token();

            if ( table->defined ) {
                gen_constructor_parameter( rp, symbol, false );
                gen_serial_initializer( rp, prefix, start, symbol );
                gen_constructor_prefix( prefix, symbol );
                gen_constructor_suffix( suffix, symbol );
            } else {
                structor_t *structor = new structor_t;
                uassert( structor != NULL );
                structor->rp = rp;
                structor->defarg = false;
                structor->prefix = prefix;
                structor->suffix = suffix;
                table->constructor.add_structor( structor );

                gen_serial_initializer( rp, prefix, start, symbol );
            } // if
            return true;
          } else if ( match( ';' ) ) {
            if ( attribute.plate != NULL ) {
                delete pop_table();
                attribute.plate = NULL;
            } // if

            uassert( table != NULL );

            if ( table->defined ) {
                gen_constructor_parameter( rp, symbol, true );
            } else {
                structor_t *structor = new structor_t;
                uassert( structor != NULL );
                structor->rp = rp;
                structor->defarg = true;
                structor->prefix = NULL;
                structor->suffix = NULL;
                table->constructor.add_structor( structor );
            } // if

            return true;
          } // if
      } // if
    } // if

    ahead = back; return false;
} // constructor_declaration


static bool destructor_declaration( attribute_t &attribute ) {
    token_t *back = ahead;
    token_t *destructor;
    symbol_t *symbol;
    table_t *table;
    token_t *prefix, *suffix;

    while ( type_qualifier( attribute ) || template_qualifier( attribute ) );

    if ( ( destructor = destructor_declarator( attribute ) ) != NULL ) {
      symbol = destructor->symbol;
      uassert( symbol != NULL );
      table = symbol->data->table;
      uassert( table != NULL );

      prefix = ahead;
      if ( attribute.dclmutex.qual.MUTEX ) {
          if ( ! symbol->data->attribute.Mutex ) {
            symbol->data->attribute.Mutex = true;
            make_mutex_class( symbol );
          } // if
      } // if

      // check for incorrect mutex qualifier of the destructor is performed
      // during destructor code generation because a (non-mutex) class may
      // become mutex if it has a mutex member.

      if ( body( symbol->data->table, NULL, attribute, symbol ) ) {
          suffix = ahead->prev_parse_token();

          if ( table->defined ) {
            gen_destructor_prefix( prefix, symbol );
            gen_destructor_suffix( suffix, symbol );
          } else {
            structor_t *structor = new structor_t();

            uassert( structor != NULL );
            structor->prefix = prefix;
            structor->suffix = suffix;
            structor->dclmutex.value = attribute.dclmutex.value;
            table->destructor.add_structor( structor );
          } // if
          return true;
      } else if ( match( ';' ) ) {
          if ( attribute.plate != NULL ) {
            delete pop_table();
            attribute.plate = NULL;
          } // if

          uassert( table != NULL );

          if ( ! table->defined ) {
            structor_t *structor = new structor_t();
            uassert( structor != NULL );

            structor->prefix = NULL;
            structor->suffix = NULL;
            structor->dclmutex.value = attribute.dclmutex.value;
            table->destructor.add_structor( structor );
          } // if

          return true;
      } // if
    } // if

    ahead = back; return false;
} // destructor_declaration


static bool string_literal() {
    token_t *back = ahead;

    if ( match( STRING ) ) {
      while ( match( STRING ) );
      return true;
    } // if

    ahead = back; return false;
} // string_literal


static bool simple_type_specifier() {
    token_t *back = ahead;

    if ( match( CHAR ) ) return true;
    if ( match( WCHAR_T ) ) return true;
    if ( match( BOOL ) ) return true;
    if ( match( SHORT ) ) return true;
    if ( match( INT ) ) return true;
    if ( match( LONG ) ) return true;
    if ( match( SIGNED ) ) return true;
    if ( match( UNSIGNED ) ) return true;
    if ( match( FLOAT ) ) return true;
    if ( match( DOUBLE ) ) return true;
    if ( match( VOID ) ) return true;
    if ( match( COMPLEX ) ) return true;        // gcc specific
    if ( typeof_specifier() ) return true;            // gcc specific
    if ( attribute_clause() ) return true;            // gcc specific

    ahead = back; return false;
} // simple_type_specifier


static bool elaborated_type_specifier( attribute_t &attribute ) {
    token_t *back = ahead;
    token_t *token;

    if ( class_key( attribute ) || match( ENUM ) || match( TYPENAME ) ) {
      if ( check( COLON_COLON ) ) {             // start search at the root
#ifdef __U_DEBUG_H__
          print_focus_change( "elaborated_type_specifier1", focus, root );
#endif // __U_DEBUG_H__
          focus = root;
          match( COLON_COLON );
      } // if
      for ( ;; ) {
        if ( eof() ) break;
          token = ahead;
          if ( check( IDENTIFIER ) || check( TYPE ) ) {
            // reset the focus of the scanner to the top table as the next
            // symbol may not be in this focus.
#ifdef __U_DEBUG_H__
            print_focus_change( "type2", focus, top->tbl );
#endif // __U_DEBUG_H__
            focus = top->tbl;
            scan();                             // handles IDENTIFIER or TYPE
            template_key();

            if ( check( COLON_COLON ) ) {
                // for typename, the qualification list is not always defined
                if ( token->symbol != NULL && token->symbol->data->table != NULL ) {
#ifdef __U_DEBUG_H__
                  print_focus_change( "elaborated_type_specifier2", focus, token->symbol->data->table );
#endif // __U_DEBUG_H__
                  focus = token->symbol->data->table;
                } // if
                match( COLON_COLON );
            } else {
                return true;
            } // if
          } else {
            if ( match( TEMPLATE ) ) {
                if ( check( IDENTIFIER ) ) {
                  ahead->value = TYPE;
                } // if
                continue;                       // restart for the template name
            } // if
            break;
          } // if
      } // for
    } // if

#ifdef __U_DEBUG_H__
    print_focus_change( "elaborated_type_specifier5", focus, top->tbl );
#endif // __U_DEBUG_H__
    focus = top->tbl;
    ahead = back; return false;
} // elaborated_type_specifier


static bool type_specifier( attribute_t &attribute, bool &ts ) {
    token_t *back = ahead;
    token_t *name;

    if ( simple_type_specifier() ) { ts = true; return true; }
    if ( ! ts && ( name = type() ) != NULL ) { attribute.typedef_base = name->symbol; ts = true; return true; }
    if ( ! ts && enumerator_specifier() ) { ts = true; return true; }
    if ( ! ts && class_specifier( attribute ) ) { ts = true; return true; }
    if ( ! ts && elaborated_type_specifier( attribute ) ) { ts = true; return true; }

    ahead = back; return false;
} // type_specifier


static bool specifier( attribute_t &attribute, bool &ts ) {
    token_t *back = ahead;

    if ( template_qualifier( attribute ) ) return true;
    if ( type_qualifier( attribute ) ) return true;
    if ( type_specifier( attribute, ts ) ) return true;

    ahead = back; return false;
} // specifier


static bool specifier_list( attribute_t &attribute ) {
    token_t *back = ahead;
    bool ts = false;                            // indicates when a type specifier is found

    if ( specifier( attribute, ts ) ) {
      while ( specifier( attribute, ts ) );
      return true;
    } // if

    ahead = back; return false;
} // specifier_list


static bool initializer() {
    token_t *back = ahead;

    if ( match( '=' ) ) {
      for ( ;; ) {                              // scan off the expression
        if ( eof() ) break;
        if ( match( LP ) && match_closing( LP, RP ) ) continue;
        if ( match( LC ) && match_closing( LC, RC ) ) continue;
        if ( match( LA ) && match_closing( LA, RA ) ) continue;
        if ( check( ';' ) ) return true;
        if ( check( ',' ) ) return true;
          scan();
      } // for
    } else if ( match( LP ) && match_closing( LP, RP ) ) {
      return true;
    } // if

    ahead = back; return false;
} // initializer


static bool declarator_list( attribute_t &attribute ) {
    token_t *back = ahead;
    token_t *token;
    symbol_t *symbol;

    if ( ( token = declarator( attribute ) ) != NULL ) {
      symbol = token->symbol;
      if ( symbol != NULL ) {                   // ignore generated name for anonymous bit slice declarator
          // There is no separate namespace for structures so if target
          // symbol of the typedef is already defined, assume it is a type,
          // which is sufficient to parse declarations.
          if ( attribute.dclkind.kind.TYPEDEF &&
             ( symbol->data->key == 0 || symbol->data->found != NULL ) ) {
            make_type( token, symbol );

            if ( attribute.typedef_base != NULL ) {   // null => base type without substructure (e.g., "int")
                // deleting does not work because "struct"s are not is
                // separate name space, so storage is leaked.

                //delete symbol->data;
                symbol->data = attribute.typedef_base->data;
                symbol->copied = true;
            } // if
          } // if
      } // if
      initializer();
      if ( match( ',' ) ) {
          if ( declarator_list( attribute ) ) {
            return true;
          } // if
      } else {
          return true;
      } // if
    } // if

    ahead = back; return false;
} // declarator_list


static bool exception_declaration( attribute_t &attribute ) {
    token_t *back = ahead;

    if ( specifier_list( attribute ) ) {
      declarator( attribute );
      if ( match( RP ) ) return true;
    } // if

    ahead = back; return false;
} // exception_declaration


static bool bound_exception_declaration( bound &b ) {
    token_t *back = ahead;
    token_t *prefix;

    prefix = ahead;
    if ( match_closing( LP, RP ) ) {                  // match entire catch argument
      ahead = ahead->prev_parse_token();        // backup so closing RP is not matched
      token_t *p;
      // Looking for T1 in: catch( d.T1::T2 e ) by scanning backwards from
      // the closing ')' of the catch clause.
      for ( p = ahead; ; p = p->prev_parse_token() ) {
        if ( p == prefix ) goto fini;                 // at start so not a bound exception
        if ( p->prev_parse_token()->value == '.' && ( p->value == TYPE || p->value == NAMESPACE || p->value == COLON_COLON ) ) break;
          // SKULLDUGGERY: When parsing statements, identifiers are just
          // scanned. Scanning looks up the tokens without handling type
          // qualification (e.g., T1::T2). Therefore, tokens in the statement
          // stream may have incorrect symbol pointers. To get correct lookup
          // for the bound exception type, the "type" tokens are reset to
          // "identifier" with NULL symbols, and looked up again correctly in
          // exception_declaration.
        if ( p->value == TYPE ) { p->value = IDENTIFIER; p->symbol = NULL; }
      } // for
      b.idright = ahead;                        // end of exception parameter (')')
      ahead = prefix;                           // backup to the start of the exception declaration, excluding '('
      attribute_t attribute;
      while ( type_qualifier( attribute ) );          // scan off initial type qualifiers
      b.oleft = ahead;                    // start of bound object
      b.oright = p->prev_parse_token();         // end of bound object, including dot
      b.exbegin = p;                            // start of exception type
      ahead = b.exbegin;                        // backup to the start of the exception type
      token_t *name = type();                   // properly parse the exception type (could contain '::')
      if ( name == NULL ) goto fini;                  // bad type ?
      b.extype = name->symbol;                  // set the type of the exception parameter
      b.idleft = ahead;                   // start of exception parameter
      if ( b.idleft == b.idright ) {                  // no exception parameter ?
          // add a dummy exception parameter name to access the thrown object
          b.idleft = new token_t( IDENTIFIER, hash_table->look( "U_BOUND_PARM" ) );
          b.idleft->add_token_before( *ahead );
      } // if
      ahead = b.idright->next_parse_token();          // reset the parse location to after ')'
      return true;
    } // if
  fini:
    ahead = back; return false;
} // bound_exception_declaration


static bool using_definition();
static bool using_directive();


static bool object_declaration() {
    token_t *back = ahead;
    attribute_t attribute;
    int explict;

    if ( using_definition() ) return true;
    if ( using_directive() ) return true;
    if ( constructor_declaration( attribute ) ) return true;
    if ( destructor_declaration( attribute ) ) return true;

    explict = specifier_list( attribute );
    if ( function_declaration( explict, attribute ) ) {
      return true;
    } else {
      while ( declarator_list( attribute ) );
      if ( match( ';' ) ) {
          if ( attribute.plate != NULL ) {
            delete pop_table();
          } // if
          return true;
      } // if
    } // if

    ahead = back; return false;
} // declaration


static bool asm_declaration() {
    token_t *back = ahead;

    if ( match( ASM ) && match( LP ) && match_closing( LP, RP ) && match( ';' ) ) return true;

    ahead = back; return false;
} // asm_declaration


static bool declaration();


// namespace-definition:
//    named-namespace-definition unnamed-namespace-definition

static bool namespace_definition() {
    token_t *back = ahead;
    token_t *token;
    symbol_t *symbol;

    if ( match( NAMESPACE ) ) {
      if ( ( token = identifier() ) == NULL )   token = type();   // optional name
      // check for a {, don't match because a symbol table has to be built
        // before scanning the next token, which may be a type
      if ( check( LC ) ) {
          if ( token != NULL ) {                // named ?
            symbol = token->symbol;
            if ( symbol->data->key != NAMESPACE ) {
                make_type( token, symbol );
                symbol->data->key = NAMESPACE;
                if ( symbol->data->table == NULL ) {
                  symbol->data->table = new table_t( symbol ); // create a new symbol table
                } // if
                symbol->data->table->lexical = focus; // connect lexical chain
            } // if
            symbol->data->table->push_table();
          } // if
          match( LC );                    // now scan passed the '{' for the next token
          while ( declaration() );
          if ( token != NULL ) pop_table();
          if ( match( RC ) ) return true;
      } // if
    } // if

    ahead = back; return false;
} // namespace_definition


// namespace-alias-definition:
//    "namespace" identifier "=" qualified-namespace-specifier ";"

static bool namespace_alias_definition() {
    token_t *back = ahead;
    token_t *lhs, *rhs;
    symbol_t *symbol;

    if ( match( NAMESPACE ) && ( lhs = identifier() ) != NULL && match( '=' ) && ( rhs = type() ) != NULL && match( ';' ) ) {
      symbol = lhs->symbol;
      make_type( lhs, symbol );
      symbol->data->key = NAMESPACE;
      if ( symbol->data->table == NULL ) {
          uassert( symbol->data == NULL );
          symbol->data = rhs->symbol->data;           // set to exisitng symbol table
      } // if
      return true;
    } // if

    ahead = back; return false;
} // namespace_alias_definition


// using-declaration:
//    "using" typename_opt "::"_opt nested-name-specifier unqualified-id ";"
//    "using" "::" unqualified-id ";"

static bool using_definition() {
    token_t *back = ahead;
    token_t *token;

    if ( match( USING ) && ( token = identifier() ) != NULL || ( token = type() ) != NULL ) {
      if ( check( ';' ) ) {                     // don't scan ahead yet
          symbol_t *ns = token->symbol;
          if ( ns != NULL ) {
            local_t *use = new local_t;
            use->useing = true;
            use->tblsym = false;
            use->kind.sym = ns;
            use->link = focus->list;
            //cerr << "adding using symbol:" << use << " (" << ns->hash->text << ") to:" << focus << " ("
            //     << (focus->symbol != NULL ? focus->symbol->hash->text : (focus == root) ? "root" : "template/compound") << ")" << endl;
            focus->useing = true;               // using entries in this list
            focus->list = use;
          } // if
          match( ';' );
          return true;
      } // if
    } // if

    ahead = back; return false;
} // using_definition


// using-directive:
//    "using" "namespace" "::"_opt nested-name-specifier_opt namespace-name ";"

static bool using_directive() {
    token_t *back = ahead;
    token_t *token;

    if ( match( USING ) && match( NAMESPACE ) && ( token = identifier() ) != NULL || ( token = type() ) != NULL ) {
      if ( check( ';' ) ) {                     // don't scan ahead yet
          symbol_t *ns = token->symbol;
          if ( ns != NULL && ns->data->table != NULL ) {
            local_t *use = new local_t;
            use->useing = true;
            use->tblsym = true;
            use->kind.tbl = ns->data->table;
            use->link = focus->list;
            //cerr << "adding using table:" << use << " (" << ns->hash->text << ") to:" << focus
            //     << " (" << (focus->symbol != NULL ? focus->symbol->hash->text : (focus == root) ? "root" : "template/compound") << ")" << endl;
            focus->useing = true;               // using entries in this list
            focus->list = use;
          } // if
          match( ';' );
          return true;
      } // if
    } // if

    ahead = back; return false;
} // using_directive


// linkage-specification:
//    "extern" string-literal "{" declaration-seq_opt "}"
//    "extern" string-literal declaration

static bool linkage_specification() {
    token_t *back = ahead;

    if ( match( EXTERN ) && string_literal() ) {      // should be "C" or "C++"
      if ( match( LC ) ) {
          while ( declaration() );
          if ( match( RC ) ) return true;
      } else {
          if ( declaration() ) return true;
      } // if
    } // if

    ahead = back; return false;
} // linkage_specification


static bool declaration() {
    if ( eof() ) return false;

    if ( asm_declaration() ) return true;
    if ( linkage_specification() ) return true;
    if ( namespace_definition() ) return true;
    if ( namespace_alias_definition() ) return true;
    if ( using_definition() ) return true;
    if ( using_directive() ) return true;
    if ( object_declaration() ) return true;

    return false;
} // declaration


// translation-unit:
//    declaration-seq_opt
//
// declaration-seq:
//   declaration
//   declaration-seq declaration

void translation_unit() {
    ahead = list->get_head();

    scan();

    while ( ! eof() ) {
      if ( ! declaration() ) {

          // Did not recognize something.  It is probably an error or some
          // construct added to the language that was not anticipated.  In
          // any case, simply scan for the next synchronizing token and
          // continue parsing from there.

          gen_warning( ahead, "unrecognizable text, possible CC syntax problem, skipping text to allow the CC compiler to print an appropriate error" );
//        printf( "\n\"" );
          while ( ! ( eof() || match( ';' ) || match( LC ) || match( RC ) ) ) {
//          printf( "%s ", ahead->hash->text );
            scan();
          } // while
//        printf( "\"\n" );

      } // if
    } // while
} // translation_unit


// Local Variables: //
// compile-command: "gmake install" //
// End: //

Generated by  Doxygen 1.6.0   Back to index