Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members  

dtool/src/cppparser/cppPreprocessor.cxx

Go to the documentation of this file.
00001 // Filename: cppPreprocessor.cxx
00002 // Created by:  drose (22Oct99)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
00008 //
00009 // All use of this software is subject to the terms of the Panda 3d
00010 // Software license.  You should have received a copy of this license
00011 // along with this source code; you will also find a current copy of
00012 // the license at http://www.panda3d.org/license.txt .
00013 //
00014 // To contact the maintainers of this program write to
00015 // panda3d@yahoogroups.com .
00016 //
00017 ////////////////////////////////////////////////////////////////////
00018 
00019 
00020 #include "cppPreprocessor.h"
00021 #include "cppExpressionParser.h"
00022 #include "cppExpression.h"
00023 #include "cppScope.h"
00024 #include "cppIdentifier.h"
00025 #include "cppTemplateScope.h"
00026 #include "cppTemplateParameterList.h"
00027 #include "cppSimpleType.h"
00028 #include "cppGlobals.h"
00029 #include "cppCommentBlock.h"
00030 #include "cppBison.h"
00031 #include "indent.h"
00032 
00033 #include <assert.h>
00034 #include <ctype.h>
00035 
00036 // We manage our own visibility counter, in addition to that managed
00037 // by cppBison.y.  We do this just so we can define manifests with the
00038 // correct visibility when they are declared.  (Asking the parser for
00039 // the current visibility is prone to error, since the parser might be
00040 // several tokens behind the preprocessor.)
00041 static CPPVisibility preprocessor_vis = V_public;
00042 
00043 static int
00044 hex_val(int c) {
00045   switch (c) {
00046   case '0':
00047   case '1':
00048   case '2':
00049   case '3':
00050   case '4':
00051   case '5':
00052   case '6':
00053   case '7':
00054   case '8':
00055   case '9':
00056     return (c - '0');
00057 
00058   default:
00059     return (tolower(c) - 'a' + 10);
00060   }
00061 }
00062 
00063 static string
00064 trim_blanks(const string &str) {
00065   size_t first, last;
00066 
00067   if(str.empty())
00068       return str;
00069 
00070   first = 0;
00071   while (first < str.length() && isspace(str[first])) {
00072     first++;
00073   }
00074 
00075   last = str.length() - 1;
00076   while (last > first && isspace(str[last])) {
00077     last--;
00078   }
00079 
00080   return str.substr(first, last - first + 1);
00081 }
00082 
00083 ////////////////////////////////////////////////////////////////////
00084 //     Function: CPPPreprocessor::InputFile::Constructor
00085 //       Access: Public
00086 //  Description:
00087 ////////////////////////////////////////////////////////////////////
00088 CPPPreprocessor::InputFile::
00089 InputFile() {
00090   _in = NULL;
00091   _ignore_manifest = NULL;
00092   _line_number = 1;
00093   _col_number = 1;
00094   _lock_position = false;
00095 }
00096 
00097 ////////////////////////////////////////////////////////////////////
00098 //     Function: CPPPreprocessor::InputFile::Destructor
00099 //       Access: Public
00100 //  Description:
00101 ////////////////////////////////////////////////////////////////////
00102 CPPPreprocessor::InputFile::
00103 ~InputFile() {
00104   if (_in != NULL) {
00105     delete _in;
00106   }
00107 }
00108 
00109 ////////////////////////////////////////////////////////////////////
00110 //     Function: CPPPreprocessor::InputFile::open
00111 //       Access: Public
00112 //  Description:
00113 ////////////////////////////////////////////////////////////////////
00114 bool CPPPreprocessor::InputFile::
00115 open(const CPPFile &file) {
00116   assert(_in == NULL);
00117 
00118   _file = file;
00119   ifstream *in = new ifstream;
00120   _in = in;
00121 
00122   return _file._filename.open_read(*in);
00123 }
00124 
00125 ////////////////////////////////////////////////////////////////////
00126 //     Function: CPPPreprocessor::InputFile::connect_input
00127 //       Access: Public
00128 //  Description:
00129 ////////////////////////////////////////////////////////////////////
00130 bool CPPPreprocessor::InputFile::
00131 connect_input(const string &input) {
00132   assert(_in == NULL);
00133 
00134   _input = input;
00135   _in = new istringstream(_input);
00136   return !_in->fail();
00137 }
00138 
00139 ////////////////////////////////////////////////////////////////////
00140 //     Function: CPPPreprocessor::InputFile::get
00141 //       Access: Public
00142 //  Description:
00143 ////////////////////////////////////////////////////////////////////
00144 int CPPPreprocessor::InputFile::
00145 get() {
00146   assert(_in != NULL);
00147   int c = _in->get();
00148 
00149   // Quietly skip over embedded carriage-return characters.  We
00150   // shouldn't see any of these unless there was some DOS-to-Unix file
00151   // conversion problem.
00152   while (c == '\r') {
00153     c = _in->get();
00154   }
00155 
00156   switch (c) {
00157   case EOF:
00158     break;
00159 
00160   case '\n':
00161     if (!_lock_position) {
00162       _line_number++;
00163       _col_number = 1;
00164     }
00165     break;
00166 
00167   default:
00168     if (!_lock_position) {
00169       _col_number++;
00170     }
00171   }
00172 
00173   return c;
00174 }
00175 
00176 ////////////////////////////////////////////////////////////////////
00177 //     Function: CPPPreprocessor::Constructor
00178 //       Access: Public
00179 //  Description:
00180 ////////////////////////////////////////////////////////////////////
00181 CPPPreprocessor::
00182 CPPPreprocessor() {
00183   _state = S_eof;
00184   _paren_nesting = 0;
00185   _angle_bracket_found = false;
00186   _unget = '\0';
00187   _last_c = '\0';
00188   _start_of_line = true;
00189   _last_cpp_comment = false;
00190   _save_comments = true;
00191 
00192   _resolve_identifiers = true;
00193 
00194   _warning_count = 0;
00195   _error_count = 0;
00196 #ifdef CPP_VERBOSE_LEX
00197   _token_index = 0;
00198 #endif
00199   _verbose = 1;
00200 }
00201 
00202 ////////////////////////////////////////////////////////////////////
00203 //     Function: CPPPreprocessor::set_verbose
00204 //       Access: Public
00205 //  Description: Sets the verbosity level of the parser.  At 0, no
00206 //               warnings will be reported; at 1 or higher, expect to
00207 //               get spammed.
00208 ////////////////////////////////////////////////////////////////////
00209 void CPPPreprocessor::
00210 set_verbose(int verbose) {
00211   _verbose = verbose;
00212 }
00213 
00214 ////////////////////////////////////////////////////////////////////
00215 //     Function: CPPPreprocessor::get_verbose
00216 //       Access: Public
00217 //  Description: Returns the verbosity level of the parser.
00218 ////////////////////////////////////////////////////////////////////
00219 int CPPPreprocessor::
00220 get_verbose() const {
00221   return _verbose;
00222 }
00223 
00224 ////////////////////////////////////////////////////////////////////
00225 //     Function: CPPPreprocessor::copy_filepos
00226 //       Access: Public
00227 //  Description:
00228 ////////////////////////////////////////////////////////////////////
00229 void CPPPreprocessor::
00230 copy_filepos(const CPPPreprocessor &other) {
00231   assert(!_files.empty());
00232   _files.back()._file = other.get_file();
00233   _files.back()._line_number = other.get_line_number();
00234   _files.back()._col_number = other.get_col_number();
00235 }
00236 
00237 ////////////////////////////////////////////////////////////////////
00238 //     Function: CPPPreprocessor::get_file
00239 //       Access: Public
00240 //  Description:
00241 ////////////////////////////////////////////////////////////////////
00242 CPPFile CPPPreprocessor::
00243 get_file() const {
00244   if (_files.empty()) {
00245     return CPPFile("");
00246   }
00247   return _files.back()._file;
00248 }
00249 
00250 ////////////////////////////////////////////////////////////////////
00251 //     Function: CPPPreprocessor::get_line_number
00252 //       Access: Public
00253 //  Description:
00254 ////////////////////////////////////////////////////////////////////
00255 int CPPPreprocessor::
00256 get_line_number() const {
00257   if (_files.empty()) {
00258     return 0;
00259   }
00260   return _files.back()._line_number;
00261 }
00262 
00263 ////////////////////////////////////////////////////////////////////
00264 //     Function: CPPPreprocessor::get_col_number
00265 //       Access: Public
00266 //  Description:
00267 ////////////////////////////////////////////////////////////////////
00268 int CPPPreprocessor::
00269 get_col_number() const {
00270   if (_files.empty()) {
00271     return 0;
00272   }
00273   return _files.back()._col_number;
00274 }
00275 
00276 ////////////////////////////////////////////////////////////////////
00277 //     Function: CPPPreprocessor::get_next_token
00278 //       Access: Public
00279 //  Description:
00280 ////////////////////////////////////////////////////////////////////
00281 CPPToken CPPPreprocessor::
00282 get_next_token() {
00283 
00284 #ifdef CPP_VERBOSE_LEX
00285   CPPToken tok = get_next_token0();
00286   indent(cerr, _files.size() * 2)
00287     << _token_index++ << ". " << tok << "\n";
00288   return tok;
00289 }
00290 
00291 CPPToken CPPPreprocessor::
00292 get_next_token0() {
00293 #endif
00294 
00295   // We make a nested call to internal_get_next_token(), so we can
00296   // combine sequences of identifiers and scoping symbols into a
00297   // single identifier, for yacc's convenience.
00298 
00299   CPPToken token(0);
00300   if (!_saved_tokens.empty()) {
00301     token = _saved_tokens.back();
00302     _saved_tokens.pop_back();
00303   } else {
00304     token = internal_get_next_token();
00305   }
00306 
00307   int first_line = token._lloc.first_line;
00308   int first_col = token._lloc.first_column;
00309   CPPFile first_file = token._lloc.file;
00310 
00311   if (token._token == '#') {
00312     // Stringify.
00313     token = internal_get_next_token();
00314     if (token._token == SIMPLE_IDENTIFIER || token._token == STRING) {
00315       token._token = STRING;
00316     } else {
00317       // Stringify nothing.
00318 
00319       _saved_tokens.push_back(token);
00320       token._token = STRING;
00321       token._lval.str = "";
00322     }
00323   }
00324 
00325   if (_resolve_identifiers &&
00326       (token._token == SIMPLE_IDENTIFIER || token._token == SCOPE)) {
00327     // We will be returning a scoped identifier, or a scoping.  Keep
00328     // pulling off tokens until we reach the end of the
00329     // scope/identifier sequence.
00330 
00331     string name;
00332 
00333     // If we started the ball with an identifier, use it and get the
00334     // next token.  Otherwise, we started with :: (global scope), and
00335     // we indicate this with an empty string at the beginning of the
00336     // scoping sequence.
00337     if (token._token == SIMPLE_IDENTIFIER) {
00338       name = token._lval.str;
00339       token = internal_get_next_token();
00340     }
00341 
00342     CPPIdentifier *ident = new CPPIdentifier(name, token._lloc.file);
00343     YYSTYPE result;
00344     result.u.identifier = ident;
00345 
00346     if (token._token == '<') {
00347       // If the next token is an angle bracket and the current
00348       // identifier wants template instantiation, assume the angle
00349       // bracket begins the instantiation and call yacc recursively to
00350       // parse the template parameters.
00351       CPPDeclaration *decl = ident->find_template(current_scope, global_scope);
00352       if (decl != NULL) {
00353         ident->_names.back().set_templ
00354           (nested_parse_template_instantiation(decl->get_template_scope()));
00355         token = internal_get_next_token();
00356       }
00357     }
00358 
00359     while (token._token == SCOPE || token._token == TOKENPASTE) {
00360       if (token._token == TOKENPASTE) {
00361         // The token-pasting operator creates one continuous
00362         // identifier across whitespace.
00363         token = internal_get_next_token();
00364         if (token._token == SIMPLE_IDENTIFIER) {
00365           name += token._lval.str;
00366           ident->_names.back().append_name(token._lval.str);
00367 
00368           token = internal_get_next_token();
00369 
00370         } else {
00371           // Token-paste with nothing.
00372         }
00373 
00374       } else { // token._token == SCOPE
00375         name += "::";
00376         token = internal_get_next_token();
00377         string token_prefix;
00378 
00379         if (token._token == '~') {
00380           // A scoping operator followed by a tilde can only be the
00381           // start of a scoped destructor name.  Make the tilde be part
00382           // of the name.
00383           name += "~";
00384           token_prefix = "~";
00385           token = internal_get_next_token();
00386         }
00387 
00388         if (token._token != SIMPLE_IDENTIFIER) {
00389           // The last useful token was a SCOPE, thus this is a scoping
00390           // token.
00391 
00392           if (token._token == KW_OPERATOR) {
00393             // Unless the last token we came across was the "operator"
00394             // keyword.  We make a special case for this, because it's
00395             // occasionally scoped in normal use.
00396             token._lval = result;
00397             return token;
00398           }
00399           _saved_tokens.push_back(token);
00400           return CPPToken(SCOPING, first_line, first_col, first_file,
00401                           name, result);
00402         }
00403 
00404         name += token._lval.str;
00405         ident->_names.push_back(token_prefix + token._lval.str);
00406 
00407         token = internal_get_next_token();
00408       }
00409 
00410       if (token._token == '<') {
00411         // If the next token is an angle bracket and the current
00412         // indentifier wants template instantiation, assume the angle
00413         // bracket begins the instantiation and call yacc recursively to
00414         // parse the template parameters.
00415         CPPDeclaration *decl =
00416           ident->find_template(current_scope, global_scope);
00417         if (decl != NULL) {
00418           ident->_names.back().set_templ
00419             (nested_parse_template_instantiation(decl->get_template_scope()));
00420           token = internal_get_next_token();
00421         }
00422       }
00423     }
00424     // The last useful token was a SIMPLE_IDENTIFIER, thus this is a
00425     // normal scoped identifier.
00426     _saved_tokens.push_back(token);
00427 
00428     int token_type = IDENTIFIER;
00429     CPPDeclaration *decl = ident->find_symbol(current_scope, global_scope);
00430     if (decl != NULL &&
00431         (decl->as_typedef() != NULL || decl->as_type() != NULL)) {
00432       token_type = TYPENAME_IDENTIFIER;
00433     }
00434 
00435     return CPPToken(token_type, first_line, first_col, first_file,
00436                     name, result);
00437   }
00438 
00439   // This is the normal case: just pass through whatever token we got.
00440   return token;
00441 }
00442 
00443 ////////////////////////////////////////////////////////////////////
00444 //     Function: CPPPreprocessor::warning
00445 //       Access: Public
00446 //  Description:
00447 ////////////////////////////////////////////////////////////////////
00448 void CPPPreprocessor::
00449 warning(const string &message, int line, int col, CPPFile file) {
00450   if (_verbose >= 2) {
00451     if (line == 0) {
00452       line = get_line_number();
00453       col = get_col_number();
00454     }
00455     if (file.empty()) {
00456       file = get_file();
00457     }
00458     indent(cerr, _files.size() * 2)
00459       << "*** Warning in " << file
00460       << " near line " << line << ", column " << col << ":\n";
00461     indent(cerr, _files.size() * 2)
00462       << message << "\n";
00463   }
00464   _warning_count++;
00465 }
00466 
00467 ////////////////////////////////////////////////////////////////////
00468 //     Function: CPPPreprocessor::error
00469 //       Access: Public
00470 //  Description:
00471 ////////////////////////////////////////////////////////////////////
00472 void CPPPreprocessor::
00473 error(const string &message, int line, int col, CPPFile file) {
00474   if (_state == S_nested || _state == S_end_nested) {
00475     // Don't report or log errors in the nested state.  These will be
00476     // reported when the nesting level collapses.
00477     return;
00478   };
00479 
00480   if (_verbose >= 1) {
00481     if (line == 0) {
00482       line = get_line_number();
00483       col = get_col_number();
00484     }
00485     if (file.empty()) {
00486       file = get_file();
00487     }
00488     indent(cerr, _files.size() * 2)
00489       << "*** Error in " << file
00490       << " near line " << line << ", column " << col << ":\n";
00491     indent(cerr, _files.size() * 2)
00492       << message << "\n";
00493   }
00494   _error_count++;
00495 }
00496 
00497 ////////////////////////////////////////////////////////////////////
00498 //     Function: CPPPreprocessor::get_warning_count
00499 //       Access: Public
00500 //  Description:
00501 ////////////////////////////////////////////////////////////////////
00502 int CPPPreprocessor::
00503 get_warning_count() const {
00504   return _warning_count;
00505 }
00506 
00507 ////////////////////////////////////////////////////////////////////
00508 //     Function: CPPPreprocessor::get_error_count
00509 //       Access: Public
00510 //  Description:
00511 ////////////////////////////////////////////////////////////////////
00512 int CPPPreprocessor::
00513 get_error_count() const {
00514   return _error_count;
00515 }
00516 
00517 ////////////////////////////////////////////////////////////////////
00518 //     Function: CPPPreprocessor::get_comment_before
00519 //       Access: Public
00520 //  Description: Returns the CPPCommentBlock immediately preceding the
00521 //               indicated line, if any.  If there is no such comment,
00522 //               returns NULL.
00523 ////////////////////////////////////////////////////////////////////
00524 CPPCommentBlock *CPPPreprocessor::
00525 get_comment_before(int line, CPPFile file) {
00526   CPPComments::reverse_iterator ci;
00527   ci = _comments.rbegin();
00528 
00529   int wrong_file_count = 0;
00530   while (ci != _comments.rend()) {
00531     CPPCommentBlock *comment = (*ci);
00532     if (comment->_file == file) {
00533       wrong_file_count = 0;
00534       if (comment->_last_line == line || comment->_last_line == line - 1) {
00535         return comment;
00536       }
00537 
00538       if (comment->_last_line < line) {
00539         return (CPPCommentBlock *)NULL;
00540       }
00541     } else {
00542       wrong_file_count++;
00543       if (wrong_file_count > 10) {
00544         return (CPPCommentBlock *)NULL;
00545       }
00546     }
00547 
00548     ++ci;
00549   }
00550 
00551   return (CPPCommentBlock *)NULL;
00552 }
00553 
00554 ////////////////////////////////////////////////////////////////////
00555 //     Function: CPPPreprocessor::init_cpp
00556 //       Access: Protected
00557 //  Description:
00558 ////////////////////////////////////////////////////////////////////
00559 bool CPPPreprocessor::
00560 init_cpp(const CPPFile &file) {
00561   _state = S_normal;
00562   _saved_tokens.push_back(CPPToken(START_CPP));
00563   _last_c = '\0';
00564 
00565   return push_file(file);
00566 }
00567 
00568 ////////////////////////////////////////////////////////////////////
00569 //     Function: CPPPreprocessor::init_const_expr
00570 //       Access: Protected
00571 //  Description:
00572 ////////////////////////////////////////////////////////////////////
00573 bool CPPPreprocessor::
00574 init_const_expr(const string &expr) {
00575   _state = S_normal;
00576   _saved_tokens.push_back(CPPToken(START_CONST_EXPR));
00577 
00578   return push_string(expr, false);
00579 }
00580 
00581 ////////////////////////////////////////////////////////////////////
00582 //     Function: CPPPreprocessor::init_type
00583 //       Access: Protected
00584 //  Description:
00585 ////////////////////////////////////////////////////////////////////
00586 bool CPPPreprocessor::
00587 init_type(const string &type) {
00588   _state = S_normal;
00589   _saved_tokens.push_back(CPPToken(START_TYPE));
00590 
00591   return push_string(type, false);
00592 }
00593 
00594 ////////////////////////////////////////////////////////////////////
00595 //     Function: CPPPreprocessor::push_file
00596 //       Access: Protected
00597 //  Description:
00598 ////////////////////////////////////////////////////////////////////
00599 bool CPPPreprocessor::
00600 push_file(const CPPFile &file) {
00601   if (_verbose >= 2) {
00602     indent(cerr, _files.size() * 2)
00603       << "Reading " << file << "\n";
00604   }
00605   _files.push_back(InputFile());
00606   InputFile &infile = _files.back();
00607 
00608   if (infile.open(file)) {
00609     // Record the fact that we opened the file for the benefit of user
00610     // code.
00611     _parsed_files.insert(file);
00612 
00613     infile._prev_last_c = _last_c;
00614     _last_c = '\0';
00615     _start_of_line = true;
00616     return true;
00617   }
00618 
00619   _files.pop_back();
00620   return false;
00621 }
00622 
00623 ////////////////////////////////////////////////////////////////////
00624 //     Function: CPPPreprocessor::push_string
00625 //       Access: Protected
00626 //  Description:
00627 ////////////////////////////////////////////////////////////////////
00628 bool CPPPreprocessor::
00629 push_string(const string &input, bool lock_position) {
00630 #ifdef CPP_VERBOSE_LEX
00631   indent(cerr, _files.size() * 2)
00632     << "Pushing to string \"" << input
00633     << "\"\nlock_position = " << lock_position << "\n";
00634 #endif
00635   CPPFile first_file = get_file();
00636   int first_line = get_line_number();
00637   int first_col = get_col_number();
00638 
00639   _files.push_back(InputFile());
00640   InputFile &infile = _files.back();
00641 
00642   if (infile.connect_input(input)) {
00643     if (lock_position) {
00644       infile._file = first_file;
00645       infile._line_number = first_line;
00646       infile._col_number = first_col;
00647       infile._lock_position = true;
00648     }
00649 
00650     infile._prev_last_c = _last_c;
00651     _last_c = '\0';
00652     return true;
00653   }
00654 
00655 #ifdef CPP_VERBOSE_LEX
00656   indent(cerr, _files.size() * 2)
00657     << "Unable to read string\n";
00658 #endif
00659 
00660   _files.pop_back();
00661   return false;
00662 }
00663 
00664 ////////////////////////////////////////////////////////////////////
00665 //     Function: CPPPreprocessor::expand_manifests
00666 //       Access: Protected
00667 //  Description: Given a string, expand all manifests within the
00668 //               string and return the new string.
00669 ////////////////////////////////////////////////////////////////////
00670 string CPPPreprocessor::
00671 expand_manifests(const string &input_expr) {
00672   // Get a copy of the expression string we can modify.
00673   string expr = input_expr;
00674 
00675   // Repeatedly scan the expr for any manifest names or defined()
00676   // function.
00677 
00678   // We'll need to save the set of manifests we've already expanded,
00679   // to guard against recursive references.
00680   set<const CPPManifest *> already_expanded;
00681 
00682   bool manifest_found;
00683   do {
00684     manifest_found = false;
00685     size_t p = 0;
00686     while (p < expr.size()) {
00687       if (isalpha(expr[p]) || expr[p] == '_') {
00688         size_t q = p;
00689         while (p < expr.size() && (isalnum(expr[p]) || expr[p] == '_')) {
00690           p++;
00691         }
00692         string ident = expr.substr(q, p - q);
00693 
00694         // Here's an identifier.  Is it "defined"?
00695         if (ident == "defined") {
00696           expand_defined_function(expr, q, p);
00697         } else {
00698           // Is it a manifest?
00699           Manifests::const_iterator mi = _manifests.find(ident);
00700           if (mi != _manifests.end()) {
00701             const CPPManifest *manifest = (*mi).second;
00702             if (already_expanded.insert(manifest).second) {
00703               expand_manifest_inline(expr, q, p, (*mi).second);
00704               manifest_found = true;
00705             }
00706           }
00707         }
00708       } else {
00709         p++;
00710       }
00711     }
00712 
00713     // If we expanded any manifests at all that time, then go back
00714     // through the string and look again--we might have a manifest
00715     // that expands to another manifest.
00716   } while (manifest_found);
00717 
00718   return expr;
00719 }
00720 
00721 ////////////////////////////////////////////////////////////////////
00722 //     Function: CPPPreprocessor::parse_expr
00723 //       Access: Protected
00724 //  Description: Given a string, expand all manifests within the
00725 //               string and evaluate it as an expression.  Returns
00726 //               NULL if the string is not a valid expression.
00727 //
00728 //               This is an internal support function for
00729 //               CPPPreprocessor; however, there is a public variant
00730 //               of this function defined for CPPParser.
00731 ////////////////////////////////////////////////////////////////////
00732 CPPExpression *CPPPreprocessor::
00733 parse_expr(const string &input_expr, CPPScope *current_scope,
00734            CPPScope *global_scope) {
00735   string expr = expand_manifests(input_expr);
00736 
00737   CPPExpressionParser ep(current_scope, global_scope);
00738   ep._verbose = 0;
00739   if (ep.parse_expr(expr, *this)) {
00740     return ep._expr;
00741   } else {
00742     return (CPPExpression *)NULL;
00743   }
00744 }
00745 
00746 ////////////////////////////////////////////////////////////////////
00747 //     Function: CPPPreprocessor::internal_get_next_token
00748 //       Access: Private
00749 //  Description:
00750 ////////////////////////////////////////////////////////////////////
00751 CPPToken CPPPreprocessor::
00752 internal_get_next_token() {
00753   if (_state == S_eof || _state == S_end_nested) {
00754     return CPPToken::eof();
00755   }
00756 
00757   int c = _last_c;
00758   _last_c = '\0';
00759   if (c == '\0' || c == EOF) {
00760     c = get();
00761   }
00762 
00763   // Skip any whitespace, comments, and preprocessor directives before
00764   // the token.
00765   c = skip_whitespace(c);
00766   while (c == '#' && _start_of_line && !should_ignore_preprocessor()) {
00767     c = skip_whitespace(process_directive(c));
00768   }
00769 
00770   if (c == '\'') {
00771     return get_quoted_char(c);
00772   } else if (c == '"') {
00773     return get_quoted_string(c);
00774   } else if (isalpha(c) || c == '_') {
00775     return get_identifier(c);
00776   } else if (isdigit(c)) {
00777     return get_number(c);
00778   }
00779 
00780   _last_c = c;
00781   if (c == EOF) {
00782     _state = S_eof;
00783     return CPPToken::eof();
00784   }
00785 
00786   CPPFile first_file = get_file();
00787   int first_line = get_line_number();
00788   int first_col = get_col_number();
00789 
00790   // Check for a number beginning with a decimal point.
00791   int next_c = get();
00792   if (c == '.' && isdigit(next_c)) {
00793     return get_number(c, next_c);
00794   }
00795 
00796   // Check for two- or three-character tokens.
00797   _last_c = get();
00798 
00799   switch (c) {
00800   case '+':
00801     if (next_c == '+') return CPPToken(PLUSPLUS, first_line, first_col, first_file);
00802     if (next_c == '=') return CPPToken(PLUSEQUAL, first_line, first_col, first_file);
00803     break;
00804 
00805   case '-':
00806     if (next_c == '-') return CPPToken(MINUSMINUS, first_line, first_col, first_file);
00807     if (next_c == '=') return CPPToken(MINUSEQUAL, first_line, first_col, first_file);
00808     if (next_c == '>' && _last_c == '*') {
00809       _last_c = get();
00810       return CPPToken(POINTSAT_STAR, first_line, first_col, first_file);
00811     }
00812     if (next_c == '>') return CPPToken(POINTSAT, first_line, first_col, first_file);
00813     break;
00814 
00815   case '<':
00816     if (next_c == '<' && _last_c == '=') {
00817       _last_c = get();
00818       return CPPToken(LSHIFTEQUAL, first_line, first_col, first_file);
00819     }
00820     if (next_c == '<') return CPPToken(LSHIFT, first_line, first_col, first_file);
00821     if (next_c == '=') return CPPToken(LECOMPARE, first_line, first_col, first_file);
00822     break;
00823 
00824   case '>':
00825     if (next_c == '>' && _last_c == '=') {
00826       _last_c = get();
00827       return CPPToken(RSHIFTEQUAL, first_line, first_col, first_file);
00828     }
00829     if (next_c == '>') return CPPToken(RSHIFT, first_line, first_col, first_file);
00830     if (next_c == '=') return CPPToken(GECOMPARE, first_line, first_col, first_file);
00831     break;
00832 
00833   case '|':
00834     if (next_c == '|') return CPPToken(OROR, first_line, first_col, first_file);
00835     if (next_c == '=') return CPPToken(OREQUAL, first_line, first_col, first_file);
00836     break;
00837 
00838   case '&':
00839     if (next_c == '&') return CPPToken(ANDAND, first_line, first_col, first_file);
00840     if (next_c == '=') return CPPToken(ANDEQUAL, first_line, first_col, first_file);
00841     break;
00842 
00843   case '^':
00844     if (next_c == '=') return CPPToken(XOREQUAL, first_line, first_col, first_file);
00845     break;
00846 
00847   case '=':
00848     if (next_c == '=') return CPPToken(EQCOMPARE, first_line, first_col, first_file);
00849     break;
00850 
00851   case '!':
00852     if (next_c == '=') return CPPToken(NECOMPARE, first_line, first_col, first_file);
00853     break;
00854 
00855   case '.':
00856     if (next_c == '*') return CPPToken(DOT_STAR, first_line, first_col, first_file);
00857     if (next_c == '.' && _last_c == '.') {
00858       _last_c = get();
00859       return CPPToken(ELLIPSIS, first_line, first_col, first_file);
00860     }
00861     break;
00862 
00863   case ':':
00864     if (next_c == ':') return CPPToken(SCOPE, first_line, first_col, first_file);
00865     break;
00866 
00867   case '*':
00868     if (next_c == '=') return CPPToken(TIMESEQUAL, first_line, first_col, first_file);
00869     break;
00870 
00871   case '/':
00872     if (next_c == '=') return CPPToken(DIVIDEEQUAL, first_line, first_col, first_file);
00873     break;
00874 
00875   case '%':
00876     if (next_c == '=') return CPPToken(MODEQUAL, first_line, first_col, first_file);
00877     break;
00878 
00879     // These are actually preprocessor operators, but it's useful to
00880     // treat them as tokens.
00881   case '#':
00882     if (next_c == '#') return CPPToken(TOKENPASTE, first_line, first_col, first_file);
00883   }
00884 
00885   // It wasn't any of the two- or three-character tokens, so put back
00886   // the lookahead character and return the one-character token.
00887   unget(_last_c);
00888   _last_c = next_c;
00889 
00890   if (_state == S_nested) {
00891     // If we're running a nested lexer, keep track of the paren
00892     // levels.  When we encounter a comma or closing angle bracket at
00893     // the bottom level, we stop.
00894 
00895     switch (c) {
00896     case '(':
00897     case '[':
00898       _paren_nesting++;
00899       break;
00900 
00901     case ')':
00902     case ']':
00903       _paren_nesting--;
00904       break;
00905 
00906     case ',':
00907       if (_paren_nesting <= 0) {
00908         _state = S_end_nested;
00909         return CPPToken::eof();
00910       }
00911       break;
00912 
00913     case '>':
00914       if (_paren_nesting <= 0) {
00915         _angle_bracket_found = true;
00916         _state = S_end_nested;
00917         return CPPToken::eof();
00918       }
00919     }
00920   }
00921 
00922   return CPPToken(c, first_line, first_col, first_file);
00923 }
00924 
00925 ////////////////////////////////////////////////////////////////////
00926 //     Function: CPPPreprocessor::skip_whitespace
00927 //       Access: Private
00928 //  Description:
00929 ////////////////////////////////////////////////////////////////////
00930 int CPPPreprocessor::
00931 skip_whitespace(int c) {
00932   while (c != EOF) {
00933     c = skip_comment(c);
00934 
00935     if (c == '\\') {
00936       // A backslash character is an unusual thing to encounter in the
00937       // middle of unquoted C++ code.  But it seems to be legal, and
00938       // it seems to mean the same thing it does within quotes: to
00939       // escape the following character.  We simply ignore it.
00940       c = get();
00941     }
00942 
00943     if (!isspace(c)) {
00944       return c;
00945     }
00946     c = get();
00947   }
00948   return c;
00949 }
00950 
00951 ////////////////////////////////////////////////////////////////////
00952 //     Function: CPPPreprocessor::skip_comment
00953 //       Access: Private
00954 //  Description:
00955 ////////////////////////////////////////////////////////////////////
00956 int CPPPreprocessor::
00957 skip_comment(int c) {
00958   if (c == '/') {
00959     int next_c = get();
00960     if (next_c == '*') {
00961       _last_cpp_comment = false;
00962       c = skip_c_comment(get());
00963     } else if (next_c == '/') {
00964       c = skip_cpp_comment(get());
00965     } else {
00966       _last_cpp_comment = false;
00967       unget(next_c);
00968       return c;
00969     }
00970   }
00971   if (!isspace(c)) {
00972     _last_cpp_comment = false;
00973   }
00974   return c;
00975 }
00976 
00977 ////////////////////////////////////////////////////////////////////
00978 //     Function: CPPPreprocessor::skip_c_comment
00979 //       Access: Private
00980 //  Description:
00981 ////////////////////////////////////////////////////////////////////
00982 int CPPPreprocessor::
00983 skip_c_comment(int c) {
00984   if (_save_comments) {
00985     CPPCommentBlock *comment = new CPPCommentBlock;
00986     _comments.push_back(comment);
00987 
00988     comment->_file = get_file();
00989     comment->_line_number = get_line_number();
00990     comment->_last_line = get_line_number();
00991     comment->_col_number = get_col_number() - 2;
00992     comment->_c_style = true;
00993     comment->_comment = "/*";
00994 
00995     while (c != EOF) {
00996       if (c == '*') {
00997         comment->_comment += c;
00998         c = get();
00999         if (c == '/') {
01000           comment->_comment += c;
01001           comment->_last_line = get_line_number();
01002           return get();
01003         }
01004       } else {
01005         comment->_comment += c;
01006         c = get();
01007       }
01008     }
01009 
01010     warning("Comment is unterminated",
01011             comment->_line_number, comment->_col_number,
01012             comment->_file);
01013 
01014   } else {
01015     CPPFile first_file = get_file();
01016     int first_line_number = get_line_number();
01017     int first_col_number = get_col_number() - 2;
01018 
01019     while (c != EOF) {
01020       if (c == '*') {
01021         c = get();
01022         if (c == '/') {
01023           return get();
01024         }
01025       } else {
01026         c = get();
01027       }
01028     }
01029 
01030     warning("Comment is unterminated",
01031             first_line_number, first_col_number,
01032             first_file);
01033   }
01034 
01035   return c;
01036 }
01037 
01038 ////////////////////////////////////////////////////////////////////
01039 //     Function: CPPPreprocessor::skip_cpp_comment
01040 //       Access: Private
01041 //  Description:
01042 ////////////////////////////////////////////////////////////////////
01043 int CPPPreprocessor::
01044 skip_cpp_comment(int c) {
01045   if (_save_comments) {
01046     CPPCommentBlock *comment;
01047 
01048     if (_last_cpp_comment) {
01049       // If the last non-whitespace character read was also part of a
01050       // C++ comment, then this is just a continuation of that comment
01051       // block.
01052       assert(!_comments.empty());
01053       comment = _comments.back();
01054       assert(!comment->_c_style);
01055       comment->_comment += "//";
01056 
01057     } else {
01058       // Otherwise, this begins a new comment block.
01059       comment = new CPPCommentBlock;
01060 
01061       comment->_file = get_file();
01062       comment->_line_number = get_line_number();
01063       comment->_last_line = get_line_number();
01064       comment->_col_number = get_col_number() - 2;
01065       comment->_c_style = false;
01066       comment->_comment = "//";
01067 
01068       _comments.push_back(comment);
01069     }
01070 
01071     while (c != EOF && c != '\n') {
01072       comment->_comment += c;
01073       c = get();
01074     }
01075 
01076     comment->_comment += '\n';
01077     comment->_last_line = get_line_number();
01078 
01079     _last_cpp_comment = true;
01080 
01081   } else {
01082     while (c != EOF && c != '\n') {
01083       c = get();
01084     }
01085   }
01086 
01087   return c;
01088 }
01089 
01090 ////////////////////////////////////////////////////////////////////
01091 //     Function: CPPPreprocessor::process_directive
01092 //       Access: Private
01093 //  Description:
01094 ////////////////////////////////////////////////////////////////////
01095 int CPPPreprocessor::
01096 process_directive(int c) {
01097   CPPFile first_file = get_file();
01098   int first_line = get_line_number();
01099   int first_col = get_col_number();
01100 
01101   string command, args;
01102   c = get_preprocessor_command(c, command);
01103   c = get_preprocessor_args(c, args);
01104 
01105 #ifdef CPP_VERBOSE_LEX
01106   indent(cerr, _files.size() * 2)
01107     << "#" << command << " " << args << "\n";
01108 #endif
01109 
01110   if (command == "define") {
01111     handle_define_directive(args, first_line, first_col, first_file);
01112   } else if (command == "undef") {
01113     handle_undef_directive(args, first_line, first_col, first_file);
01114   } else if (command == "ifdef") {
01115     handle_ifdef_directive(args, first_line, first_col, first_file);
01116   } else if (command == "ifndef") {
01117     handle_ifndef_directive(args, first_line, first_col, first_file);
01118   } else if (command == "if") {
01119     handle_if_directive(args, first_line, first_col, first_file);
01120   } else if (command == "else" || command == "elif") {
01121     // Presumably this follows some #if or #ifdef.  We don't bother to
01122     // check this, however.
01123     skip_false_if_block(false);
01124   } else if (command == "endif") {
01125     // Presumably this follows some #if or #ifdef.  We don't bother to
01126     // check this, however.
01127   } else if (command == "include") {
01128     handle_include_directive(args, first_line, first_col, first_file);
01129   } else if (command == "pragma") {
01130     // Quietly ignore pragmas.
01131   } else if (command == "ident") {
01132     // Quietly ignore idents.
01133   } else if (command == "error") {
01134     handle_error_directive(args, first_line, first_col, first_file);
01135   } else {
01136     warning("Ignoring unknown directive #" + command,
01137             first_line, first_col, first_file);
01138   }
01139 
01140   _start_of_line = true;
01141   return '\n';
01142 }
01143 
01144 ////////////////////////////////////////////////////////////////////
01145 //     Function: CPPPreprocessor::get_preprocessor_command
01146 //       Access: Private
01147 //  Description:
01148 ////////////////////////////////////////////////////////////////////
01149 int CPPPreprocessor::
01150 get_preprocessor_command(int c, string &command) {
01151   // Skip the hash mark.
01152   assert(c == '#');
01153   c = get();
01154 
01155   // Also skip any whitespace following the hash mark--but don't skip
01156   // past a newline.
01157   while (c != EOF && (c == ' ' || c == '\t')) {
01158     c = get();
01159   }
01160 
01161   // The next sequence of characters is the command.
01162   while (c != EOF && (isalnum(c) || c == '_')) {
01163     command += c;
01164     c = get();
01165   }
01166 
01167   return c;
01168 }
01169 
01170 ////////////////////////////////////////////////////////////////////
01171 //     Function: CPPPreprocessor::get_preprocessor_args
01172 //       Access: Private
01173 //  Description:
01174 ////////////////////////////////////////////////////////////////////
01175 int CPPPreprocessor::
01176 get_preprocessor_args(int c, string &args) {
01177   // Following the command, the rest of the line, as well as any text
01178   // on successive lines, is part of the arguments to the command.
01179 
01180   while (c != EOF && c != '\n') {
01181     if (c == '\\') {
01182       int next_c = get();
01183       if (next_c == '\n') {
01184         // Here we have an escaped newline: a continuation.
01185         args += '\n';
01186       } else {
01187         // Just a backslash followed by some non-backslash, keep both.
01188         args += c;
01189         if (next_c != EOF) {
01190           args += next_c;
01191         }
01192       }
01193     } else {
01194       args += c;
01195     }
01196     c = skip_comment(get());
01197   }
01198 
01199   // Remove any leading and trailing whitespace from the args.
01200   args = trim_blanks(args);
01201 
01202   return c;
01203 }
01204 
01205 ////////////////////////////////////////////////////////////////////
01206 //     Function: CPPPreprocessor::handle_define_directive
01207 //       Access: Private
01208 //  Description:
01209 ////////////////////////////////////////////////////////////////////
01210 void CPPPreprocessor::
01211 handle_define_directive(const string &args, int first_line,
01212                         int first_col, const CPPFile &first_file) {
01213   if (args.empty()) {
01214     warning("Ignoring empty #define directive",
01215             first_line, first_col, first_file);
01216   } else {
01217     CPPManifest *manifest = new CPPManifest(args, first_file);
01218     manifest->_vis = preprocessor_vis;
01219     if (!manifest->_has_parameters) {
01220       string expr_string = manifest->expand();
01221       if (!expr_string.empty()) {
01222         manifest->_expr = parse_expr(expr_string, global_scope, global_scope);
01223       }
01224     }
01225     _manifests[manifest->_name] = manifest;
01226   }
01227 }
01228 
01229 ////////////////////////////////////////////////////////////////////
01230 //     Function: CPPPreprocessor::handle_undef_directive
01231 //       Access: Private
01232 //  Description:
01233 ////////////////////////////////////////////////////////////////////
01234 void CPPPreprocessor::
01235 handle_undef_directive(const string &args, int first_line,
01236                        int first_col, const CPPFile &first_file) {
01237   if (args.empty()) {
01238     warning("Ignoring empty #undef directive",
01239             first_line, first_col, first_file);
01240   } else {
01241     Manifests::iterator mi = _manifests.find(args);
01242     if (mi != _manifests.end()) {
01243       _manifests.erase(mi);
01244     }
01245   }
01246 }
01247 
01248 ////////////////////////////////////////////////////////////////////
01249 //     Function: CPPPreprocessor::handle_ifdef_directive
01250 //       Access: Private
01251 //  Description:
01252 ////////////////////////////////////////////////////////////////////
01253 void CPPPreprocessor::
01254 handle_ifdef_directive(const string &args, int, int, const CPPFile &) {
01255   Manifests::const_iterator mi = _manifests.find(args);
01256   if (mi != _manifests.end()) {
01257     // The macro is defined.  We continue.
01258     return;
01259   }
01260 
01261   // The macro is undefined.  Skip stuff.
01262   skip_false_if_block(true);
01263 }
01264 
01265 ////////////////////////////////////////////////////////////////////
01266 //     Function: CPPPreprocessor::handle_ifndef_directive
01267 //       Access: Private
01268 //  Description:
01269 ////////////////////////////////////////////////////////////////////
01270 void CPPPreprocessor::
01271 handle_ifndef_directive(const string &args, int, int, const CPPFile &) {
01272   Manifests::const_iterator mi = _manifests.find(args);
01273   if (mi == _manifests.end()) {
01274     // The macro is undefined.  We continue.
01275     return;
01276   }
01277 
01278   // The macro is defined.  Skip stuff.
01279   skip_false_if_block(true);
01280 }
01281 
01282 
01283 ////////////////////////////////////////////////////////////////////
01284 //     Function: CPPPreprocessor::handle_if_directive
01285 //       Access: Private
01286 //  Description:
01287 ////////////////////////////////////////////////////////////////////
01288 void CPPPreprocessor::
01289 handle_if_directive(const string &args, int first_line,
01290                     int first_col, const CPPFile &first_file) {
01291   CPPExpression *expr = parse_expr(args, global_scope, global_scope);
01292 
01293   int expression_result = 0;
01294 
01295   if (expr != (CPPExpression *)NULL) {
01296     CPPExpression::Result result = expr->evaluate();
01297     if (result._type == CPPExpression::RT_error) {
01298       warning("Ignoring invalid expression " + args,
01299               first_line, first_col, first_file);
01300     } else {
01301       expression_result = result.as_integer();
01302     }
01303   } else {
01304     warning("Ignoring invalid expression " + args,
01305             first_line, first_col, first_file);
01306   }
01307 
01308   if (expression_result) {
01309     // The expression result is true.  We continue.
01310     return;
01311   }
01312 
01313   // The expression result is false.  Skip stuff.
01314   skip_false_if_block(true);
01315 }
01316 
01317 ////////////////////////////////////////////////////////////////////
01318 //     Function: CPPPreprocessor::handle_include_directive
01319 //       Access: Private
01320 //  Description:
01321 ////////////////////////////////////////////////////////////////////
01322 void CPPPreprocessor::
01323 handle_include_directive(const string &args, int first_line,
01324                          int first_col, const CPPFile &first_file) {
01325   bool okflag = false;
01326   Filename filename;
01327   Filename filename_as_referenced;
01328   bool angle_quotes = false;
01329 
01330   string expr = args;
01331 
01332   // The filename to include might actually be hidden within a
01333   // manifest definition.  Wow.  FreeType depends on this.
01334 
01335   // Just to play things safe, since our manifest-expansion logic
01336   // might not filter out quotes and angle brackets properly, we'll
01337   // only expand manifests if we don't begin with a quote or bracket.
01338   if (!expr.empty() && (expr[0] != '"' && expr[0] != '<')) {
01339     expr = expand_manifests(expr);
01340   }
01341 
01342   if (!expr.empty()) {
01343     if (expr[0] == '"' && expr[expr.size() - 1] == '"') {
01344       filename = expr.substr(1, expr.size() - 2);
01345       okflag = true;
01346 
01347       if (_files.size() == 1) {
01348         // If we're currently processing a top-level file, record the
01349         // include directive.  We don't need to record includes from
01350         // included files.
01351         _quote_includes.insert(filename);
01352       }
01353     } else if (expr[0] == '<' && expr[expr.size() - 1] == '>') {
01354       filename = expr.substr(1, expr.size() - 2);
01355       angle_quotes = true;
01356       okflag = true;
01357 
01358       if (_files.size() == 1) {
01359         // If we're currently processing a top-level file, record the
01360         // include directive.  We don't need to record includes from
01361         // included files.
01362         _angle_includes.insert(filename);
01363       }
01364     }
01365   }
01366 
01367   filename.set_text();
01368   filename_as_referenced = filename;
01369 
01370   // Now look for the filename.  If we didn't use angle quotes, look
01371   // first in the current directory.
01372   bool found_file = false;
01373   CPPFile::Source source = CPPFile::S_none;
01374 
01375   if (okflag) {
01376     if (!angle_quotes) {
01377       found_file = filename.exists();
01378       source = CPPFile::S_local;
01379     }
01380 
01381     // Now look for it on the include path.
01382     if (!found_file && filename.resolve_filename(_system_include_path)) {
01383       found_file = true;
01384       source = CPPFile::S_system;
01385     }
01386 
01387     if (!found_file && filename.resolve_filename(_include_path)) {
01388       found_file = true;
01389       source = CPPFile::S_alternate;
01390     }
01391 
01392     if (!found_file) {
01393       warning("Cannot find " + filename.get_fullpath(),
01394               first_line, first_col, first_file);
01395     } else {
01396       _last_c = '\0';
01397       if (!push_file(CPPFile(filename, filename_as_referenced, source))) {
01398         warning("Unable to read " + filename.get_fullpath(),
01399                 first_line, first_col, first_file);
01400       }
01401     }
01402   } else {
01403     warning("Ignoring invalid #include directive",
01404             first_line, first_col, first_file);
01405   }
01406 }
01407 
01408 ////////////////////////////////////////////////////////////////////
01409 //     Function: CPPPreprocessor::handle_error_directive
01410 //       Access: Private
01411 //  Description:
01412 ////////////////////////////////////////////////////////////////////
01413 void CPPPreprocessor::
01414 handle_error_directive(const string &args, int first_line,
01415                        int first_col, const CPPFile &first_file) {
01416   error(args, first_line, first_col, first_file);
01417 }
01418 
01419 ////////////////////////////////////////////////////////////////////
01420 //     Function: CPPPreprocessor::skip_false_if_block
01421 //       Access: Private
01422 //  Description: We come here when we fail an #if or an #ifdef test,
01423 //               or when we reach the #else clause to something we
01424 //               didn't fail.  This function skips all text up until
01425 //               the matching #endif.
01426 ////////////////////////////////////////////////////////////////////
01427 void CPPPreprocessor::
01428 skip_false_if_block(bool consider_elifs) {
01429   int level = 0;
01430   _save_comments = false;
01431 
01432   int c = skip_comment(get());
01433   while (c != EOF) {
01434     if (c == '#' && _start_of_line) {
01435       CPPFile first_file = get_file();
01436       int first_line = get_line_number();
01437       int first_col = get_col_number();
01438 
01439       // Is this it?
01440       string command;
01441       c = get_preprocessor_command(c, command);
01442       if (command == "if" || command == "ifdef" || command == "ifndef") {
01443         // Hmm, a nested if block.  Even more to skip.
01444         level++;
01445       } else if (command == "else") {
01446         if (level == 0 && consider_elifs) {
01447           // This will do!
01448           _save_comments = true;
01449           return;
01450         }
01451       } else if (command == "elif") {
01452         if (level == 0 && consider_elifs) {
01453           // If we pass this test, we're in.
01454           _save_comments = true;
01455           string args;
01456           c = get_preprocessor_args(c, args);
01457           handle_if_directive(args, first_line, first_col, first_file);
01458           return;
01459         }
01460       } else if (command == "endif") {
01461         if (level == 0) {
01462           // Here's the end!
01463           _save_comments = true;
01464           return;
01465         }
01466         level--;
01467       }
01468     } else {
01469       c = skip_comment(get());
01470     }
01471   }
01472 
01473   _save_comments = true;
01474 }
01475 
01476 ////////////////////////////////////////////////////////////////////
01477 //     Function: CPPPreprocessor::get_quoted_char
01478 //       Access: Private
01479 //  Description:
01480 ////////////////////////////////////////////////////////////////////
01481 CPPToken CPPPreprocessor::
01482 get_quoted_char(int c) {
01483   CPPFile first_file = get_file();
01484   int first_line = get_line_number();
01485   int first_col = get_col_number();
01486   string str = scan_quoted(c);
01487 
01488   YYSTYPE result;
01489   if (!str.empty()) {
01490     result.u.integer = (int)str[0];
01491   } else {
01492     result.u.integer = 0;
01493   }
01494   return CPPToken(CHAR, first_line, first_col, first_file, str, result);
01495 }
01496 
01497 ////////////////////////////////////////////////////////////////////
01498 //     Function: CPPPreprocessor::get_quoted_string
01499 //       Access: Private
01500 //  Description:
01501 ////////////////////////////////////////////////////////////////////
01502 CPPToken CPPPreprocessor::
01503 get_quoted_string(int c) {
01504   CPPFile first_file = get_file();
01505   int first_line = get_line_number();
01506   int first_col = get_col_number();
01507   string str = scan_quoted(c);
01508   return CPPToken(STRING, first_line, first_col, first_file, str);
01509 }
01510 
01511 ////////////////////////////////////////////////////////////////////
01512 //     Function: CPPPreprocessor::get_identifier
01513 //       Access: Private
01514 //  Description:
01515 ////////////////////////////////////////////////////////////////////
01516 CPPToken CPPPreprocessor::
01517 get_identifier(int c) {
01518   CPPFile first_file = get_file();
01519   int first_line = get_line_number();
01520   int first_col = get_col_number();
01521   string name(1, (char)c);
01522 
01523   c = get();
01524   while (c != EOF && (isalnum(c) || c == '_')) {
01525     name += c;
01526     c = get();
01527   }
01528 
01529   _last_c = c;
01530 
01531   // Is it a manifest?
01532   Manifests::const_iterator mi = _manifests.find(name);
01533   if (mi != _manifests.end() && !should_ignore_manifest((*mi).second)) {
01534     return expand_manifest((*mi).second);
01535   }
01536 
01537   // Check for keywords.
01538   int kw = check_keyword(name);
01539 
01540   // Update our internal visibility flag.
01541   switch (kw) {
01542   case KW_BEGIN_PUBLISH:
01543     preprocessor_vis = V_published;
01544     break;
01545 
01546   case KW_END_PUBLISH:
01547     preprocessor_vis = V_public;
01548     break;
01549   }
01550 
01551   if (kw != 0) {
01552     YYSTYPE result;
01553     result.u.identifier = (CPPIdentifier *)NULL;
01554     return CPPToken(kw, first_line, first_col, first_file, name, result);
01555   }
01556 
01557   return CPPToken(SIMPLE_IDENTIFIER, first_line, first_col, first_file,
01558                   name);
01559 }
01560 
01561 ////////////////////////////////////////////////////////////////////
01562 //     Function: CPPPreprocessor::expand_manifest
01563 //       Access: Private
01564 //  Description:
01565 ////////////////////////////////////////////////////////////////////
01566 CPPToken CPPPreprocessor::
01567 expand_manifest(const CPPManifest *manifest) {
01568   vector_string args;
01569 
01570   if (manifest->_has_parameters) {
01571     // Hmm, we're expecting arguments.
01572     extract_manifest_args(manifest->_name, manifest->_num_parameters, args);
01573   }
01574 
01575   string expanded = " " + manifest->expand(args) + " ";
01576   push_string(expanded, true);
01577 
01578   if (!manifest->_has_parameters) {
01579     // If the manifest does not use arguments, then disallow recursive
01580     // expansion.
01581     _files.back()._ignore_manifest = manifest;
01582   }
01583 
01584 #ifdef CPP_VERBOSE_LEX
01585   indent(cerr, _files.size() * 2)
01586     << "Expanding " << manifest->_name << " to " << expanded << "\n";
01587 #endif
01588 
01589   return internal_get_next_token();
01590 }
01591 
01592 ////////////////////////////////////////////////////////////////////
01593 //     Function: CPPPreprocessor::extract_manifest_args
01594 //       Access: Private
01595 //  Description:
01596 ////////////////////////////////////////////////////////////////////
01597 void CPPPreprocessor::
01598 extract_manifest_args(const string &name, int num_args,
01599                       vector_string &args) {
01600   CPPFile first_file = get_file();
01601   int first_line = get_line_number();
01602   int first_col = get_col_number();
01603 
01604   // Skip whitespace till paren.
01605   int c = _last_c;
01606   _last_c = '\0';
01607   while (c != EOF && isspace(c)) {
01608     c = get();
01609   }
01610 
01611   if (c != '(') {
01612     // No paren, so we have only one arg.
01613     string arg;
01614     while (c != EOF && (isalnum(c) || c == '_')) {
01615       arg += c;
01616       c = get();
01617     }
01618     args.push_back(arg);
01619   } else {
01620     // Skip paren.
01621     c = get();
01622     string arg;
01623     while (c != EOF && c != ')') {
01624       if (c == ',') {
01625         args.push_back(arg);
01626         arg = "";
01627 
01628       } else if (c == '(') {
01629         // Nested parens.
01630         int paren_level = 1;
01631         while (c != EOF && paren_level > 0) {
01632           arg += c;
01633           c = get();
01634           if (c == '(') {
01635             paren_level++;
01636           } else if (c == ')') {
01637             paren_level--;
01638           }
01639         }
01640         if (c != EOF) {
01641           arg += c;
01642         }
01643 
01644       } else {
01645         arg += c;
01646       }
01647       c = get();
01648     }
01649     if (num_args != 0 || !arg.empty()) {
01650       args.push_back(arg);
01651     }
01652   }
01653 
01654   if ((int)args.size() != num_args) {
01655     warning("Wrong number of arguments for manifest " + name,
01656             first_line, first_col, first_file);
01657   }
01658 }
01659 
01660 ////////////////////////////////////////////////////////////////////
01661 //     Function: CPPPreprocessor::expand_defined_function
01662 //       Access: Private
01663 //  Description:
01664 ////////////////////////////////////////////////////////////////////
01665 void CPPPreprocessor::
01666 expand_defined_function(string &expr, size_t q, size_t &p) {
01667   string result;
01668 
01669   vector_string args;
01670   extract_manifest_args_inline("defined", 1, args, expr, p);
01671   if (args.size() >= 1) {
01672     const string &manifest_name = args[0];
01673     Manifests::const_iterator mi = _manifests.find(manifest_name);
01674     if (mi != _manifests.end()) {
01675       // The macro is defined; the result is "1".
01676       result = "1";
01677     } else {
01678       // The macro is undefined; the result is "0".
01679       result = "0";
01680     }
01681   }
01682 
01683   expr = expr.substr(0, q) + result + expr.substr(p);
01684   p = q + result.size();
01685 }
01686 
01687 ////////////////////////////////////////////////////////////////////
01688 //     Function: CPPPreprocessor::expand_manifest_inline
01689 //       Access: Private
01690 //  Description:
01691 ////////////////////////////////////////////////////////////////////
01692 void CPPPreprocessor::
01693 expand_manifest_inline(string &expr, size_t q, size_t &p,
01694                        const CPPManifest *manifest) {
01695   vector_string args;
01696   if (manifest->_has_parameters) {
01697     extract_manifest_args_inline(manifest->_name, manifest->_num_parameters,
01698                                  args, expr, p);
01699   }
01700   string result = manifest->expand(args);
01701 
01702   expr = expr.substr(0, q) + result + expr.substr(p);
01703   p = q + result.size();
01704 }
01705 
01706 ////////////////////////////////////////////////////////////////////
01707 //     Function: CPPPreprocessor::extract_manifest_args_inline
01708 //       Access: Private
01709 //  Description:
01710 ////////////////////////////////////////////////////////////////////
01711 void CPPPreprocessor::
01712 extract_manifest_args_inline(const string &name, int num_args,
01713                              vector_string &args,
01714                              const string &expr, size_t &p) {
01715   // Skip whitespace till paren.
01716   while (p < expr.size() && isspace(expr[p])) {
01717     p++;
01718   }
01719   if (p >= expr.size() || expr[p] != '(') {
01720     // No paren, so we have only one arg.
01721     size_t q = p;
01722     while (p < expr.size() && (isalnum(expr[p]) || expr[p] == '_')) {
01723       p++;
01724     }
01725     args.push_back(expr.substr(q, p - q));
01726   } else {
01727     // Skip paren.
01728     p++;
01729     size_t q = p;
01730     while (p < expr.size() && expr[p] != ')') {
01731       if (expr[p] == ',') {
01732         args.push_back(expr.substr(q, p - q));
01733         q = p+1;
01734 
01735       } else if (expr[p] == '(') {
01736         // Nested parens.
01737         int paren_level = 1;
01738         while (p+1 < expr.size() && paren_level > 0) {
01739           p++;
01740           if (expr[p] == '(') {
01741             paren_level++;
01742           } else if (expr[p] == ')') {
01743             paren_level--;
01744           }
01745         }
01746       }
01747       p++;
01748     }
01749     args.push_back(expr.substr(q, p - q));
01750 
01751     if (p < expr.size() && expr[p] == ')') {
01752       p++;
01753     }
01754   }
01755 
01756   if ((int)args.size() != num_args) {
01757     warning("Wrong number of arguments for manifest " + name);
01758   }
01759 }
01760 
01761 ////////////////////////////////////////////////////////////////////
01762 //     Function: CPPPreprocessor::get_number
01763 //       Access: Private
01764 //  Description:
01765 ////////////////////////////////////////////////////////////////////
01766 CPPToken CPPPreprocessor::
01767 get_number(int c, int c2) {
01768   CPPFile first_file = get_file();
01769   int first_line = get_line_number();
01770   int first_col = get_col_number();
01771 
01772   string num(1, (char)c);
01773   bool leading_zero = (c == '0');
01774   bool decimal_point = (c == '.');
01775 
01776   if (c2 == 0) {
01777     c = get();
01778   } else {
01779     c = c2;
01780   }
01781   if (leading_zero && c == 'x') {
01782     // Here we have a hex number.
01783     num += c;
01784     c = get();
01785 
01786     while (c != EOF && (isdigit(c) || (tolower(c) >= 'a' && tolower(c) <= 'f'))) {
01787       num += c;
01788       c = get();
01789     }
01790 
01791     while (c == 'L' || c == 'U') {
01792       // We allow (and ignore) an 'L' and/or 'U' following the number.
01793       c = get();
01794     }
01795 
01796     _last_c = c;
01797 
01798     YYSTYPE result;
01799     result.u.integer = strtol(num.c_str(), (char **)NULL, 16);
01800     return CPPToken(INTEGER, first_line, first_col, first_file, num, result);
01801   }
01802 
01803   while (c != EOF && isdigit(c)) {
01804     num += c;
01805     c = get();
01806   }
01807 
01808   if (c == '.' && !decimal_point) {
01809     // Now we have a floating-point number.
01810     decimal_point = true;
01811     num += c;
01812     c = get();
01813 
01814     while (c != EOF && isdigit(c)) {
01815       num += c;
01816       c = get();
01817     }
01818   }
01819 
01820   if (decimal_point) {
01821     if (tolower(c) == 'e') {
01822       // An exponent is allowed.
01823       num += c;
01824       c = get();
01825       if (c == '-' || c == '+') {
01826         num += c;
01827         c = get();
01828       }
01829       while (c != EOF && isdigit(c)) {
01830         num += c;
01831         c = get();
01832       }
01833     }
01834 
01835     if (c == 'f') {
01836       // We allow (and ignore) an 'f' following the number.
01837       c = get();
01838     }
01839 
01840     _last_c = c;
01841     YYSTYPE result;
01842     result.u.real = strtod(num.c_str(), (char **)NULL);
01843     return CPPToken(REAL, first_line, first_col, first_file, num, result);
01844   }
01845 
01846   // This is a decimal or octal integer number.
01847 
01848   while (c == 'L' || c == 'U') {
01849     // We allow (and ignore) an 'L' and/or 'U' following the number.
01850     c = get();
01851   }
01852 
01853   _last_c = c;
01854   YYSTYPE result;
01855 
01856   if (leading_zero) {
01857     // A leading zero implies an octal number.  strtol() is supposed
01858     // to be able to make this distinction by itself, but we'll do it
01859     // explicitly just to be sure.
01860     result.u.integer = strtol(num.c_str(), (char **)NULL, 8);
01861 
01862   } else {
01863     // A decimal (base 10) integer.
01864     result.u.integer = strtol(num.c_str(), (char **)NULL, 10);
01865   }
01866 
01867   return CPPToken(INTEGER, first_line, first_col, first_file, num, result);
01868 }
01869 
01870 ////////////////////////////////////////////////////////////////////
01871 //     Function: CPPPreprocessor::check_keyword
01872 //       Access: Private, Static
01873 //  Description:
01874 ////////////////////////////////////////////////////////////////////
01875 int CPPPreprocessor::
01876 check_keyword(const string &name) {
01877   if (name == "__begin_publish") return KW_BEGIN_PUBLISH;
01878   if (name == "bool") return KW_BOOL;
01879   if (name == "catch") return KW_CATCH;
01880   if (name == "char") return KW_CHAR;
01881   if (name == "class") return KW_CLASS;
01882   if (name == "const") return KW_CONST;
01883   if (name == "delete") return KW_DELETE;
01884   if (name == "double") return KW_DOUBLE;
01885   if (name == "dynamic_cast") return KW_DYNAMIC_CAST;
01886   if (name == "else") return KW_ELSE;
01887   if (name == "__end_publish") return KW_END_PUBLISH;
01888   if (name == "enum") return KW_ENUM;
01889   if (name == "extern") return KW_EXTERN;
01890   if (name == "explicit") return KW_EXPLICIT;
01891   if (name == "__published") return KW_PUBLISHED;
01892   if (name == "false") return KW_FALSE;
01893   if (name == "float") return KW_FLOAT;
01894   if (name == "friend") return KW_FRIEND;
01895   if (name == "for") return KW_FOR;
01896   if (name == "goto") return KW_GOTO;
01897   if (name == "if") return KW_IF;
01898   if (name == "inline") return KW_INLINE;
01899   if (name == "int") return KW_INT;
01900   if (name == "long") return KW_LONG;
01901   if (name == "mutable") return KW_MUTABLE;
01902   if (name == "namespace") return KW_NAMESPACE;
01903   if (name == "new") return KW_NEW;
01904   if (name == "operator") return KW_OPERATOR;
01905   if (name == "private") return KW_PRIVATE;
01906   if (name == "protected") return KW_PROTECTED;
01907   if (name == "public") return KW_PUBLIC;
01908   if (name == "register") return KW_REGISTER;
01909   if (name == "return") return KW_RETURN;
01910   if (name == "short") return KW_SHORT;
01911   if (name == "signed") return KW_SIGNED;
01912   if (name == "sizeof") return KW_SIZEOF;
01913   if (name == "static") return KW_STATIC;
01914   if (name == "static_cast") return KW_STATIC_CAST;
01915   if (name == "struct") return KW_STRUCT;
01916   if (name == "template") return KW_TEMPLATE;
01917   if (name == "throw") return KW_THROW;
01918   if (name == "true") return KW_TRUE;
01919   if (name == "try") return KW_TRY;
01920   if (name == "typedef") return KW_TYPEDEF;
01921   if (name == "typename") return KW_TYPENAME;
01922   if (name == "union") return KW_UNION;
01923   if (name == "unsigned") return KW_UNSIGNED;
01924   if (name == "using") return KW_USING;
01925   if (name == "virtual") return KW_VIRTUAL;
01926   if (name == "void") return KW_VOID;
01927   if (name == "volatile") return KW_VOLATILE;
01928   if (name == "while") return KW_WHILE;
01929 
01930   if (!cpp_longlong_keyword.empty() && name == cpp_longlong_keyword) {
01931     return KW_LONGLONG;
01932   }
01933 
01934   return 0;
01935 }
01936 
01937 ////////////////////////////////////////////////////////////////////
01938 //     Function: CPPPreprocessor::scan_quoted
01939 //       Access: Private
01940 //  Description:
01941 ////////////////////////////////////////////////////////////////////
01942 string CPPPreprocessor::
01943 scan_quoted(int c) {
01944   int quote_mark = c;
01945 
01946   string str;
01947   c = get();
01948   while (c != EOF && c != '\n' && c != quote_mark) {
01949     if (c == '\\') {
01950       // Backslash means a special character follows.
01951       c = get();
01952       switch (c) {
01953       case 'n':
01954         c = '\n';
01955         break;
01956 
01957       case 't':
01958         c = '\t';
01959         break;
01960 
01961       case 'r':
01962         c = '\r';
01963         break;
01964 
01965       case 'x':
01966         // hex character.
01967         c = get();
01968         if (isxdigit(c)) {
01969           int val = hex_val(c);
01970           c = get();
01971           if (isxdigit(c)) {
01972             val = (val << 4) | hex_val(c);
01973           } else {
01974             unget(c);
01975           }
01976           c = val;
01977         }
01978         break;
01979 
01980       case '0':
01981       case '1':
01982       case '2':
01983       case '3':
01984       case '4':
01985       case '5':
01986       case '6':
01987       case '7':
01988         // Octal character.
01989         {
01990           int val = (c - '0');
01991           c = get();
01992           if (c >= '0' && c <= '7') {
01993             val = (val << 3) | (c - '0');
01994             c = get();
01995             if (c >= '0' && c <= '7') {
01996               val = (val << 3) | (c - '0');
01997             } else {
01998               unget(c);
01999             }
02000           } else {
02001             unget(c);
02002           }
02003           c = val;
02004         }
02005         break;
02006       }
02007     }
02008 
02009     str += c;
02010     c = get();
02011   }
02012 
02013   if (c != quote_mark) {
02014     warning("Unclosed string");
02015   }
02016   return str;
02017 }
02018 
02019 
02020 ////////////////////////////////////////////////////////////////////
02021 //     Function: CPPPreprocessor::should_ignore_manifest
02022 //       Access: Public
02023 //  Description: Returns true if the manifest is one that is being
02024 //               ignored right now (presumably because we are
02025 //               presently expanding it).
02026 ////////////////////////////////////////////////////////////////////
02027 bool CPPPreprocessor::
02028 should_ignore_manifest(const CPPManifest *manifest) const {
02029   Files::const_iterator fi;
02030   for (fi = _files.begin(); fi != _files.end(); ++fi) {
02031     if ((*fi)._ignore_manifest == manifest) {
02032       return true;
02033     }
02034   }
02035 
02036   return false;
02037 }
02038 
02039 ////////////////////////////////////////////////////////////////////
02040 //     Function: CPPPreprocessor::should_ignore_preprocessor
02041 //       Access: Public
02042 //  Description: Returns true if we should ignore any preprocessor
02043 //               directives (e.g. we're presently expanding a
02044 //               manifest).
02045 ////////////////////////////////////////////////////////////////////
02046 bool CPPPreprocessor::
02047 should_ignore_preprocessor() const {
02048   Files::const_iterator fi;
02049   for (fi = _files.begin(); fi != _files.end(); ++fi) {
02050     if ((*fi)._ignore_manifest != NULL) {
02051       return true;
02052     }
02053   }
02054 
02055   return false;
02056 }
02057 
02058 ////////////////////////////////////////////////////////////////////
02059 //     Function: CPPPreprocessor::get
02060 //       Access: Private
02061 //  Description:
02062 ////////////////////////////////////////////////////////////////////
02063 int CPPPreprocessor::
02064 get() {
02065   if (_unget != '\0') {
02066     int c = _unget;
02067     _unget = '\0';
02068     return c;
02069   }
02070 
02071   if (_files.empty()) {
02072     return EOF;
02073   }
02074 
02075   int c = _files.back().get();
02076 
02077   while (c == EOF && !_files.empty()) {
02078 #ifdef CPP_VERBOSE_LEX
02079     indent(cerr, _files.size() * 2)
02080       << "End of input stream, restoring to previous input\n";
02081 #endif
02082     int last_c = _files.back()._prev_last_c;
02083     _files.pop_back();
02084 
02085     if (last_c != '\0') {
02086       c = last_c;
02087     } else if (!_files.empty()) {
02088       c = _files.back().get();
02089     }
02090   }
02091 
02092   if (c == '\n') {
02093     _start_of_line = true;
02094   } else if (!isspace(c) && c != '#') {
02095     _start_of_line = false;
02096   }
02097 
02098   return c;
02099 }
02100 
02101 ////////////////////////////////////////////////////////////////////
02102 //     Function: CPPPreprocessor::unget
02103 //       Access: Private
02104 //  Description:
02105 ////////////////////////////////////////////////////////////////////
02106 void CPPPreprocessor::
02107 unget(int c) {
02108   assert(_unget == '\0');
02109   _unget = c;
02110 }
02111 
02112 
02113 ////////////////////////////////////////////////////////////////////
02114 //     Function: CPPPreprocessor::nested_parse_template_instantiation
02115 //       Access: Private
02116 //  Description: Recursively invokes yacc to parse the stuff within
02117 //               angle brackets that's the template instantiation part
02118 //               of an identifier.  This involves setting and
02119 //               restoring some state flags so we can return EOF when
02120 //               we reach the closing bracket.
02121 ////////////////////////////////////////////////////////////////////
02122 CPPTemplateParameterList *CPPPreprocessor::
02123 nested_parse_template_instantiation(CPPTemplateScope *scope) {
02124 #ifdef CPP_VERBOSE_LEX
02125   indent(cerr, _files.size() * 2)
02126     << "Beginning nested parse\n";
02127 #endif
02128   assert(scope != NULL);
02129 
02130   State old_state = _state;
02131   int old_nesting = _paren_nesting;
02132 
02133   const CPPTemplateParameterList &formal_params = scope->_parameters;
02134   CPPTemplateParameterList::Parameters::const_iterator pi;
02135   _angle_bracket_found = false;
02136 
02137   CPPToken token = internal_get_next_token();
02138   if (token._token == '>') {
02139     _angle_bracket_found = true;
02140   } else {
02141     _saved_tokens.push_back(token);
02142   }
02143 
02144   CPPTemplateParameterList *actual_params = new CPPTemplateParameterList;
02145 
02146   for (pi = formal_params._parameters.begin();
02147        pi != formal_params._parameters.end() && !_angle_bracket_found;
02148        ++pi) {
02149     _state = S_nested;
02150     _paren_nesting = 0;
02151 
02152     CPPFile first_file = get_file();
02153     int first_line = get_line_number();
02154     int first_col = get_col_number();
02155 
02156     CPPDeclaration *decl = (*pi);
02157     if (decl->as_type()) {
02158       _saved_tokens.push_back(CPPToken(START_TYPE));
02159       CPPType *type = ::parse_type(this, current_scope, global_scope);
02160       if (type == NULL) {
02161         warning("Invalid type", first_line, first_col, first_file);
02162         skip_to_end_nested();
02163         type = CPPType::new_type(new CPPSimpleType(CPPSimpleType::T_unknown));
02164       }
02165       actual_params->_parameters.push_back(type);
02166     } else {
02167       _saved_tokens.push_back(CPPToken(START_CONST_EXPR));
02168       CPPExpression *expr = parse_const_expr(this, current_scope, global_scope);
02169       if (expr == NULL) {
02170         warning("Invalid expression", first_line, first_col, first_file);
02171         skip_to_end_nested();
02172         expr = new CPPExpression(0);
02173       }
02174       actual_params->_parameters.push_back(expr);
02175     }
02176   }
02177 
02178   if (!_angle_bracket_found) {
02179     warning("Ignoring extra parameters in template instantiation");
02180     skip_to_angle_bracket();
02181   }
02182 
02183   _state = old_state;
02184   _paren_nesting = old_nesting;
02185   _angle_bracket_found = false;
02186 
02187 #ifdef CPP_VERBOSE_LEX
02188   indent(cerr, _files.size() * 2)
02189     << "Ending nested parse\n";
02190 #endif
02191   return actual_params;
02192 }
02193 
02194 
02195 ////////////////////////////////////////////////////////////////////
02196 //     Function: CPPPreprocessor::skip_to_end_nested
02197 //       Access: Private
02198 //  Description: This is an error-recovery function, called after
02199 //               returning from a nested parse.  If the state is not
02200 //               S_end_nested, there was an error in parsing the
02201 //               nested tokens, and not all of the nested tokens may
02202 //               have been consumed.  This function will consume the
02203 //               rest of the nested tokens.
02204 ////////////////////////////////////////////////////////////////////
02205 void CPPPreprocessor::
02206 skip_to_end_nested() {
02207 #ifdef CPP_VERBOSE_LEX
02208   indent(cerr, _files.size() * 2)
02209     << "Skipping tokens:\n";
02210 #endif
02211 
02212   // Eat any eof tokens on the pushback stack.
02213   while (!_saved_tokens.empty() && _saved_tokens.back().is_eof()) {
02214     _saved_tokens.pop_back();
02215   }
02216 
02217   while (_state != S_end_nested && _state != S_eof) {
02218     get_next_token();
02219   }
02220 
02221 #ifdef CPP_VERBOSE_LEX
02222   indent(cerr, _files.size() * 2)
02223     << "Done skipping tokens.\n";
02224 #endif
02225 }
02226 
02227 ////////////////////////////////////////////////////////////////////
02228 //     Function: CPPPreprocessor::skip_to_angle_bracket
02229 //       Access: Private
02230 //  Description: This is an error-recovery function, called after
02231 //               returning from a nested parse.  If we haven't yet
02232 //               consumed the closing angle bracket on the template
02233 //               instantiation, keep consuming tokens until we do.
02234 ////////////////////////////////////////////////////////////////////
02235 void CPPPreprocessor::
02236 skip_to_angle_bracket() {
02237 #ifdef CPP_VERBOSE_LEX
02238   indent(cerr, _files.size() * 2)
02239     << "Skipping tokens:\n";
02240 #endif
02241 
02242   while (!_angle_bracket_found && _state != S_eof) {
02243     _state = S_nested;
02244     while (_state != S_end_nested && _state != S_eof) {
02245       get_next_token();
02246     }
02247   }
02248 
02249   // Eat any eof tokens on the pushback stack.
02250   while (!_saved_tokens.empty() && _saved_tokens.back().is_eof()) {
02251     _saved_tokens.pop_back();
02252   }
02253 
02254 #ifdef CPP_VERBOSE_LEX
02255   indent(cerr, _files.size() * 2)
02256     << "Done skipping tokens.\n";
02257 #endif
02258 }

Generated on Thu May 1 22:12:54 2003 for DTool by doxygen1.3