gfx/angle/src/compiler/preprocessor/DirectiveParser.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 //
     2 // Copyright (c) 2011 The ANGLE Project Authors. All rights reserved.
     3 // Use of this source code is governed by a BSD-style license that can be
     4 // found in the LICENSE file.
     5 //
     7 #include "DirectiveParser.h"
     9 #include <cassert>
    10 #include <cstdlib>
    11 #include <sstream>
    13 #include "DiagnosticsBase.h"
    14 #include "DirectiveHandlerBase.h"
    15 #include "ExpressionParser.h"
    16 #include "MacroExpander.h"
    17 #include "Token.h"
    18 #include "Tokenizer.h"
    20 namespace {
    21 enum DirectiveType
    22 {
    23     DIRECTIVE_NONE,
    24     DIRECTIVE_DEFINE,
    25     DIRECTIVE_UNDEF,
    26     DIRECTIVE_IF,
    27     DIRECTIVE_IFDEF,
    28     DIRECTIVE_IFNDEF,
    29     DIRECTIVE_ELSE,
    30     DIRECTIVE_ELIF,
    31     DIRECTIVE_ENDIF,
    32     DIRECTIVE_ERROR,
    33     DIRECTIVE_PRAGMA,
    34     DIRECTIVE_EXTENSION,
    35     DIRECTIVE_VERSION,
    36     DIRECTIVE_LINE
    37 };
    38 }  // namespace
    40 static DirectiveType getDirective(const pp::Token* token)
    41 {
    42     static const std::string kDirectiveDefine("define");
    43     static const std::string kDirectiveUndef("undef");
    44     static const std::string kDirectiveIf("if");
    45     static const std::string kDirectiveIfdef("ifdef");
    46     static const std::string kDirectiveIfndef("ifndef");
    47     static const std::string kDirectiveElse("else");
    48     static const std::string kDirectiveElif("elif");
    49     static const std::string kDirectiveEndif("endif");
    50     static const std::string kDirectiveError("error");
    51     static const std::string kDirectivePragma("pragma");
    52     static const std::string kDirectiveExtension("extension");
    53     static const std::string kDirectiveVersion("version");
    54     static const std::string kDirectiveLine("line");
    56     if (token->type != pp::Token::IDENTIFIER)
    57         return DIRECTIVE_NONE;
    59     if (token->text == kDirectiveDefine)
    60         return DIRECTIVE_DEFINE;
    61     else if (token->text == kDirectiveUndef)
    62         return DIRECTIVE_UNDEF;
    63     else if (token->text == kDirectiveIf)
    64         return DIRECTIVE_IF;
    65     else if (token->text == kDirectiveIfdef)
    66         return DIRECTIVE_IFDEF;
    67     else if (token->text == kDirectiveIfndef)
    68         return DIRECTIVE_IFNDEF;
    69     else if (token->text == kDirectiveElse)
    70         return DIRECTIVE_ELSE;
    71     else if (token->text == kDirectiveElif)
    72         return DIRECTIVE_ELIF;
    73     else if (token->text == kDirectiveEndif)
    74         return DIRECTIVE_ENDIF;
    75     else if (token->text == kDirectiveError)
    76         return DIRECTIVE_ERROR;
    77     else if (token->text == kDirectivePragma)
    78         return DIRECTIVE_PRAGMA;
    79     else if (token->text == kDirectiveExtension)
    80         return DIRECTIVE_EXTENSION;
    81     else if (token->text == kDirectiveVersion)
    82         return DIRECTIVE_VERSION;
    83     else if (token->text == kDirectiveLine)
    84         return DIRECTIVE_LINE;
    86     return DIRECTIVE_NONE;
    87 }
    89 static bool isConditionalDirective(DirectiveType directive)
    90 {
    91     switch (directive)
    92     {
    93       case DIRECTIVE_IF:
    94       case DIRECTIVE_IFDEF:
    95       case DIRECTIVE_IFNDEF:
    96       case DIRECTIVE_ELSE:
    97       case DIRECTIVE_ELIF:
    98       case DIRECTIVE_ENDIF:
    99         return true;
   100       default:
   101         return false;
   102     }
   103 }
   105 // Returns true if the token represents End Of Directive.
   106 static bool isEOD(const pp::Token* token)
   107 {
   108     return (token->type == '\n') || (token->type == pp::Token::LAST);
   109 }
   111 static void skipUntilEOD(pp::Lexer* lexer, pp::Token* token)
   112 {
   113     while(!isEOD(token))
   114     {
   115         lexer->lex(token);
   116     }
   117 }
   119 static bool isMacroNameReserved(const std::string& name)
   120 {
   121     // Names prefixed with "GL_" are reserved.
   122     if (name.substr(0, 3) == "GL_")
   123         return true;
   125     // Names containing two consecutive underscores are reserved.
   126     if (name.find("__") != std::string::npos)
   127         return true;
   129     return false;
   130 }
   132 static bool isMacroPredefined(const std::string& name,
   133                               const pp::MacroSet& macroSet)
   134 {
   135     pp::MacroSet::const_iterator iter = macroSet.find(name);
   136     return iter != macroSet.end() ? iter->second.predefined : false;
   137 }
   139 namespace pp
   140 {
   142 class DefinedParser : public Lexer
   143 {
   144   public:
   145     DefinedParser(Lexer* lexer,
   146                   const MacroSet* macroSet,
   147                   Diagnostics* diagnostics) :
   148         mLexer(lexer),
   149         mMacroSet(macroSet),
   150         mDiagnostics(diagnostics)
   151     {
   152     }
   154   protected:
   155     virtual void lex(Token* token)
   156     {
   157         static const std::string kDefined("defined");
   159         mLexer->lex(token);
   160         if (token->type != Token::IDENTIFIER)
   161             return;
   162         if (token->text != kDefined)
   163             return;
   165         bool paren = false;
   166         mLexer->lex(token);
   167         if (token->type == '(')
   168         {
   169             paren = true;
   170             mLexer->lex(token);
   171         }
   173         if (token->type != Token::IDENTIFIER)
   174         {
   175             mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
   176                                  token->location, token->text);
   177             skipUntilEOD(mLexer, token);
   178             return;
   179         }
   180         MacroSet::const_iterator iter = mMacroSet->find(token->text);
   181         std::string expression = iter != mMacroSet->end() ? "1" : "0";
   183         if (paren)
   184         {
   185             mLexer->lex(token);
   186             if (token->type != ')')
   187             {
   188                 mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
   189                                      token->location, token->text);
   190                 skipUntilEOD(mLexer, token);
   191                 return;
   192             }
   193         }
   195         // We have a valid defined operator.
   196         // Convert the current token into a CONST_INT token.
   197         token->type = Token::CONST_INT;
   198         token->text = expression;
   199     }
   201   private:
   202     Lexer* mLexer;
   203     const MacroSet* mMacroSet;
   204     Diagnostics* mDiagnostics;
   205 };
   207 DirectiveParser::DirectiveParser(Tokenizer* tokenizer,
   208                                  MacroSet* macroSet,
   209                                  Diagnostics* diagnostics,
   210                                  DirectiveHandler* directiveHandler) :
   211     mPastFirstStatement(false),
   212     mTokenizer(tokenizer),
   213     mMacroSet(macroSet),
   214     mDiagnostics(diagnostics),
   215     mDirectiveHandler(directiveHandler)
   216 {
   217 }
   219 void DirectiveParser::lex(Token* token)
   220 {
   221     do
   222     {
   223         mTokenizer->lex(token);
   225         if (token->type == Token::PP_HASH)
   226         {
   227             parseDirective(token);
   228             mPastFirstStatement = true;
   229         }
   231         if (token->type == Token::LAST)
   232         {
   233             if (!mConditionalStack.empty())
   234             {
   235                 const ConditionalBlock& block = mConditionalStack.back();
   236                 mDiagnostics->report(Diagnostics::CONDITIONAL_UNTERMINATED,
   237                                      block.location, block.type);
   238             }
   239             break;
   240         }
   242     } while (skipping() || (token->type == '\n'));
   244     mPastFirstStatement = true;
   245 }
   247 void DirectiveParser::parseDirective(Token* token)
   248 {
   249     assert(token->type == Token::PP_HASH);
   251     mTokenizer->lex(token);
   252     if (isEOD(token))
   253     {
   254         // Empty Directive.
   255         return;
   256     }
   258     DirectiveType directive = getDirective(token);
   260     // While in an excluded conditional block/group,
   261     // we only parse conditional directives.
   262     if (skipping() && !isConditionalDirective(directive))
   263     {
   264         skipUntilEOD(mTokenizer, token);
   265         return;
   266     }
   268     switch(directive)
   269     {
   270       case DIRECTIVE_NONE:
   271         mDiagnostics->report(Diagnostics::DIRECTIVE_INVALID_NAME,
   272                              token->location, token->text);
   273         skipUntilEOD(mTokenizer, token);
   274         break;
   275       case DIRECTIVE_DEFINE:
   276         parseDefine(token);
   277         break;
   278       case DIRECTIVE_UNDEF:
   279         parseUndef(token);
   280         break;
   281       case DIRECTIVE_IF:
   282         parseIf(token);
   283         break;
   284       case DIRECTIVE_IFDEF:
   285         parseIfdef(token);
   286         break;
   287       case DIRECTIVE_IFNDEF:
   288         parseIfndef(token);
   289         break;
   290       case DIRECTIVE_ELSE:
   291         parseElse(token);
   292         break;
   293       case DIRECTIVE_ELIF:
   294         parseElif(token);
   295         break;
   296       case DIRECTIVE_ENDIF:
   297         parseEndif(token);
   298         break;
   299       case DIRECTIVE_ERROR:
   300         parseError(token);
   301         break;
   302       case DIRECTIVE_PRAGMA:
   303         parsePragma(token);
   304         break;
   305       case DIRECTIVE_EXTENSION:
   306         parseExtension(token);
   307         break;
   308       case DIRECTIVE_VERSION:
   309         parseVersion(token);
   310         break;
   311       case DIRECTIVE_LINE:
   312         parseLine(token);
   313         break;
   314       default:
   315         assert(false);
   316         break;
   317     }
   319     skipUntilEOD(mTokenizer, token);
   320     if (token->type == Token::LAST)
   321     {
   322         mDiagnostics->report(Diagnostics::EOF_IN_DIRECTIVE,
   323                              token->location, token->text);
   324     }
   325 }
   327 void DirectiveParser::parseDefine(Token* token)
   328 {
   329     assert(getDirective(token) == DIRECTIVE_DEFINE);
   331     mTokenizer->lex(token);
   332     if (token->type != Token::IDENTIFIER)
   333     {
   334         mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
   335                              token->location, token->text);
   336         return;
   337     }
   338     if (isMacroPredefined(token->text, *mMacroSet))
   339     {
   340         mDiagnostics->report(Diagnostics::MACRO_PREDEFINED_REDEFINED,
   341                              token->location, token->text);
   342         return;
   343     }
   344     if (isMacroNameReserved(token->text))
   345     {
   346         mDiagnostics->report(Diagnostics::MACRO_NAME_RESERVED,
   347                              token->location, token->text);
   348         return;
   349     }
   351     Macro macro;
   352     macro.type = Macro::kTypeObj;
   353     macro.name = token->text;
   355     mTokenizer->lex(token);
   356     if (token->type == '(' && !token->hasLeadingSpace())
   357     {
   358         // Function-like macro. Collect arguments.
   359         macro.type = Macro::kTypeFunc;
   360         do {
   361             mTokenizer->lex(token);
   362             if (token->type != Token::IDENTIFIER)
   363                 break;
   364             macro.parameters.push_back(token->text);
   366             mTokenizer->lex(token);  // Get ','.
   367         } while (token->type == ',');
   369         if (token->type != ')')
   370         {
   371             mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
   372                                  token->location,
   373                                  token->text);
   374             return;
   375         }
   376         mTokenizer->lex(token);  // Get ')'.
   377     }
   379     while ((token->type != '\n') && (token->type != Token::LAST))
   380     {
   381         // Reset the token location because it is unnecessary in replacement
   382         // list. Resetting it also allows us to reuse Token::equals() to
   383         // compare macros.
   384         token->location = SourceLocation();
   385         macro.replacements.push_back(*token);
   386         mTokenizer->lex(token);
   387     }
   388     if (!macro.replacements.empty())
   389     {
   390         // Whitespace preceding the replacement list is not considered part of
   391         // the replacement list for either form of macro.
   392         macro.replacements.front().setHasLeadingSpace(false);
   393     }
   395     // Check for macro redefinition.
   396     MacroSet::const_iterator iter = mMacroSet->find(macro.name);
   397     if (iter != mMacroSet->end() && !macro.equals(iter->second))
   398     {
   399         mDiagnostics->report(Diagnostics::MACRO_REDEFINED,
   400                              token->location,
   401                              macro.name);
   402         return;
   403     }
   404     mMacroSet->insert(std::make_pair(macro.name, macro));
   405 }
   407 void DirectiveParser::parseUndef(Token* token)
   408 {
   409     assert(getDirective(token) == DIRECTIVE_UNDEF);
   411     mTokenizer->lex(token);
   412     if (token->type != Token::IDENTIFIER)
   413     {
   414         mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
   415                              token->location, token->text);
   416         return;
   417     }
   419     MacroSet::iterator iter = mMacroSet->find(token->text);
   420     if (iter != mMacroSet->end())
   421     {
   422         if (iter->second.predefined)
   423         {
   424             mDiagnostics->report(Diagnostics::MACRO_PREDEFINED_UNDEFINED,
   425                                  token->location, token->text);
   426         }
   427         else
   428         {
   429             mMacroSet->erase(iter);
   430         }
   431     }
   433     mTokenizer->lex(token);
   434 }
   436 void DirectiveParser::parseIf(Token* token)
   437 {
   438     assert(getDirective(token) == DIRECTIVE_IF);
   439     parseConditionalIf(token);
   440 }
   442 void DirectiveParser::parseIfdef(Token* token)
   443 {
   444     assert(getDirective(token) == DIRECTIVE_IFDEF);
   445     parseConditionalIf(token);
   446 }
   448 void DirectiveParser::parseIfndef(Token* token)
   449 {
   450     assert(getDirective(token) == DIRECTIVE_IFNDEF);
   451     parseConditionalIf(token);
   452 }
   454 void DirectiveParser::parseElse(Token* token)
   455 {
   456     assert(getDirective(token) == DIRECTIVE_ELSE);
   458     if (mConditionalStack.empty())
   459     {
   460         mDiagnostics->report(Diagnostics::CONDITIONAL_ELSE_WITHOUT_IF,
   461                              token->location, token->text);
   462         skipUntilEOD(mTokenizer, token);
   463         return;
   464     }
   466     ConditionalBlock& block = mConditionalStack.back();
   467     if (block.skipBlock)
   468     {
   469         // No diagnostics. Just skip the whole line.
   470         skipUntilEOD(mTokenizer, token);
   471         return;
   472     }
   473     if (block.foundElseGroup)
   474     {
   475         mDiagnostics->report(Diagnostics::CONDITIONAL_ELSE_AFTER_ELSE,
   476                              token->location, token->text);
   477         skipUntilEOD(mTokenizer, token);
   478         return;
   479     }
   481     block.foundElseGroup = true;
   482     block.skipGroup = block.foundValidGroup;
   483     block.foundValidGroup = true;
   485     // Warn if there are extra tokens after #else.
   486     mTokenizer->lex(token);
   487     if (!isEOD(token))
   488     {
   489         mDiagnostics->report(Diagnostics::CONDITIONAL_UNEXPECTED_TOKEN,
   490                              token->location, token->text);
   491         skipUntilEOD(mTokenizer, token);
   492     }
   493 }
   495 void DirectiveParser::parseElif(Token* token)
   496 {
   497     assert(getDirective(token) == DIRECTIVE_ELIF);
   499     if (mConditionalStack.empty())
   500     {
   501         mDiagnostics->report(Diagnostics::CONDITIONAL_ELIF_WITHOUT_IF,
   502                              token->location, token->text);
   503         skipUntilEOD(mTokenizer, token);
   504         return;
   505     }
   507     ConditionalBlock& block = mConditionalStack.back();
   508     if (block.skipBlock)
   509     {
   510         // No diagnostics. Just skip the whole line.
   511         skipUntilEOD(mTokenizer, token);
   512         return;
   513     }
   514     if (block.foundElseGroup)
   515     {
   516         mDiagnostics->report(Diagnostics::CONDITIONAL_ELIF_AFTER_ELSE,
   517                              token->location, token->text);
   518         skipUntilEOD(mTokenizer, token);
   519         return;
   520     }
   521     if (block.foundValidGroup)
   522     {
   523         // Do not parse the expression.
   524         // Also be careful not to emit a diagnostic.
   525         block.skipGroup = true;
   526         skipUntilEOD(mTokenizer, token);
   527         return;
   528     }
   530     int expression = parseExpressionIf(token);
   531     block.skipGroup = expression == 0;
   532     block.foundValidGroup = expression != 0;
   533 }
   535 void DirectiveParser::parseEndif(Token* token)
   536 {
   537     assert(getDirective(token) == DIRECTIVE_ENDIF);
   539     if (mConditionalStack.empty())
   540     {
   541         mDiagnostics->report(Diagnostics::CONDITIONAL_ENDIF_WITHOUT_IF,
   542                              token->location, token->text);
   543         skipUntilEOD(mTokenizer, token);
   544         return;
   545     }
   547     mConditionalStack.pop_back();
   549     // Warn if there are tokens after #endif.
   550     mTokenizer->lex(token);
   551     if (!isEOD(token))
   552     {
   553         mDiagnostics->report(Diagnostics::CONDITIONAL_UNEXPECTED_TOKEN,
   554                              token->location, token->text);
   555         skipUntilEOD(mTokenizer, token);
   556     }
   557 }
   559 void DirectiveParser::parseError(Token* token)
   560 {
   561     assert(getDirective(token) == DIRECTIVE_ERROR);
   563     std::ostringstream stream;
   564     mTokenizer->lex(token);
   565     while ((token->type != '\n') && (token->type != Token::LAST))
   566     {
   567         stream << *token;
   568         mTokenizer->lex(token);
   569     }
   570     mDirectiveHandler->handleError(token->location, stream.str());
   571 }
   573 // Parses pragma of form: #pragma name[(value)].
   574 void DirectiveParser::parsePragma(Token* token)
   575 {
   576     assert(getDirective(token) == DIRECTIVE_PRAGMA);
   578     enum State
   579     {
   580         PRAGMA_NAME,
   581         LEFT_PAREN,
   582         PRAGMA_VALUE,
   583         RIGHT_PAREN
   584     };
   586     bool valid = true;
   587     std::string name, value;
   588     int state = PRAGMA_NAME;
   590     mTokenizer->lex(token);
   591     while ((token->type != '\n') && (token->type != Token::LAST))
   592     {
   593         switch(state++)
   594         {
   595           case PRAGMA_NAME:
   596             name = token->text;
   597             valid = valid && (token->type == Token::IDENTIFIER);
   598             break;
   599           case LEFT_PAREN:
   600             valid = valid && (token->type == '(');
   601             break;
   602           case PRAGMA_VALUE:
   603             value = token->text;
   604             valid = valid && (token->type == Token::IDENTIFIER);
   605             break;
   606           case RIGHT_PAREN:
   607             valid = valid && (token->type == ')');
   608             break;
   609           default:
   610             valid = false;
   611             break;
   612         }
   613         mTokenizer->lex(token);
   614     }
   616     valid = valid && ((state == PRAGMA_NAME) ||     // Empty pragma.
   617                       (state == LEFT_PAREN) ||      // Without value.
   618                       (state == RIGHT_PAREN + 1));  // With value.
   619     if (!valid)
   620     {
   621         mDiagnostics->report(Diagnostics::UNRECOGNIZED_PRAGMA,
   622                              token->location, name);
   623     }
   624     else if (state > PRAGMA_NAME)  // Do not notify for empty pragma.
   625     {
   626         mDirectiveHandler->handlePragma(token->location, name, value);
   627     }
   628 }
   630 void DirectiveParser::parseExtension(Token* token)
   631 {
   632     assert(getDirective(token) == DIRECTIVE_EXTENSION);
   634     enum State
   635     {
   636         EXT_NAME,
   637         COLON,
   638         EXT_BEHAVIOR
   639     };
   641     bool valid = true;
   642     std::string name, behavior;
   643     int state = EXT_NAME;
   645     mTokenizer->lex(token);
   646     while ((token->type != '\n') && (token->type != Token::LAST))
   647     {
   648         switch (state++)
   649         {
   650           case EXT_NAME:
   651             if (valid && (token->type != Token::IDENTIFIER))
   652             {
   653                 mDiagnostics->report(Diagnostics::INVALID_EXTENSION_NAME,
   654                                      token->location, token->text);
   655                 valid = false;
   656             }
   657             if (valid) name = token->text;
   658             break;
   659           case COLON:
   660             if (valid && (token->type != ':'))
   661             {
   662                 mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
   663                                      token->location, token->text);
   664                 valid = false;
   665             }
   666             break;
   667           case EXT_BEHAVIOR:
   668             if (valid && (token->type != Token::IDENTIFIER))
   669             {
   670                 mDiagnostics->report(Diagnostics::INVALID_EXTENSION_BEHAVIOR,
   671                                      token->location, token->text);
   672                 valid = false;
   673             }
   674             if (valid) behavior = token->text;
   675             break;
   676           default:
   677             if (valid)
   678             {
   679                 mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
   680                                      token->location, token->text);
   681                 valid = false;
   682             }
   683             break;
   684         }
   685         mTokenizer->lex(token);
   686     }
   687     if (valid && (state != EXT_BEHAVIOR + 1))
   688     {
   689         mDiagnostics->report(Diagnostics::INVALID_EXTENSION_DIRECTIVE,
   690                              token->location, token->text);
   691         valid = false;
   692     }
   693     if (valid)
   694         mDirectiveHandler->handleExtension(token->location, name, behavior);
   695 }
   697 void DirectiveParser::parseVersion(Token* token)
   698 {
   699     assert(getDirective(token) == DIRECTIVE_VERSION);
   701     if (mPastFirstStatement)
   702     {
   703         mDiagnostics->report(Diagnostics::VERSION_NOT_FIRST_STATEMENT,
   704                              token->location, token->text);
   705         skipUntilEOD(mTokenizer, token);
   706         return;
   707     }
   709     enum State
   710     {
   711         VERSION_NUMBER
   712     };
   714     bool valid = true;
   715     int version = 0;
   716     int state = VERSION_NUMBER;
   718     mTokenizer->lex(token);
   719     while ((token->type != '\n') && (token->type != Token::LAST))
   720     {
   721         switch (state++)
   722         {
   723           case VERSION_NUMBER:
   724             if (valid && (token->type != Token::CONST_INT))
   725             {
   726                 mDiagnostics->report(Diagnostics::INVALID_VERSION_NUMBER,
   727                                      token->location, token->text);
   728                 valid = false;
   729             }
   730             if (valid && !token->iValue(&version))
   731             {
   732                 mDiagnostics->report(Diagnostics::INTEGER_OVERFLOW,
   733                                      token->location, token->text);
   734                 valid = false;
   735             }
   736             break;
   737           default:
   738             if (valid)
   739             {
   740                 mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
   741                                      token->location, token->text);
   742                 valid = false;
   743             }
   744             break;
   745         }
   746         mTokenizer->lex(token);
   747     }
   748     if (valid && (state != VERSION_NUMBER + 1))
   749     {
   750         mDiagnostics->report(Diagnostics::INVALID_VERSION_DIRECTIVE,
   751                              token->location, token->text);
   752         valid = false;
   753     }
   754     if (valid)
   755         mDirectiveHandler->handleVersion(token->location, version);
   756 }
   758 void DirectiveParser::parseLine(Token* token)
   759 {
   760     assert(getDirective(token) == DIRECTIVE_LINE);
   762     enum State
   763     {
   764         LINE_NUMBER,
   765         FILE_NUMBER
   766     };
   768     bool valid = true;
   769     int line = 0, file = 0;
   770     int state = LINE_NUMBER;
   772     MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics);
   773     macroExpander.lex(token);
   774     while ((token->type != '\n') && (token->type != Token::LAST))
   775     {
   776         switch (state++)
   777         {
   778           case LINE_NUMBER:
   779             if (valid && (token->type != Token::CONST_INT))
   780             {
   781                 mDiagnostics->report(Diagnostics::INVALID_LINE_NUMBER,
   782                                      token->location, token->text);
   783                 valid = false;
   784             }
   785             if (valid && !token->iValue(&line))
   786             {
   787                 mDiagnostics->report(Diagnostics::INTEGER_OVERFLOW,
   788                                      token->location, token->text);
   789                 valid = false;
   790             }
   791             break;
   792           case FILE_NUMBER:
   793             if (valid && (token->type != Token::CONST_INT))
   794             {
   795                 mDiagnostics->report(Diagnostics::INVALID_FILE_NUMBER,
   796                                      token->location, token->text);
   797                 valid = false;
   798             }
   799             if (valid && !token->iValue(&file))
   800             {
   801                 mDiagnostics->report(Diagnostics::INTEGER_OVERFLOW,
   802                                      token->location, token->text);
   803                 valid = false;
   804             }
   805             break;
   806           default:
   807             if (valid)
   808             {
   809                 mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
   810                                      token->location, token->text);
   811                 valid = false;
   812             }
   813             break;
   814         }
   815         macroExpander.lex(token);
   816     }
   818     if (valid && (state != FILE_NUMBER) && (state != FILE_NUMBER + 1))
   819     {
   820         mDiagnostics->report(Diagnostics::INVALID_LINE_DIRECTIVE,
   821                              token->location, token->text);
   822         valid = false;
   823     }
   824     if (valid)
   825     {
   826         mTokenizer->setLineNumber(line);
   827         if (state == FILE_NUMBER + 1) mTokenizer->setFileNumber(file);
   828     }
   829 }
   831 bool DirectiveParser::skipping() const
   832 {
   833     if (mConditionalStack.empty()) return false;
   835     const ConditionalBlock& block = mConditionalStack.back();
   836     return block.skipBlock || block.skipGroup;
   837 }
   839 void DirectiveParser::parseConditionalIf(Token* token)
   840 {
   841     ConditionalBlock block;
   842     block.type = token->text;
   843     block.location = token->location;
   845     if (skipping())
   846     {
   847         // This conditional block is inside another conditional group
   848         // which is skipped. As a consequence this whole block is skipped.
   849         // Be careful not to parse the conditional expression that might
   850         // emit a diagnostic.
   851         skipUntilEOD(mTokenizer, token);
   852         block.skipBlock = true;
   853     }
   854     else
   855     {
   856         DirectiveType directive = getDirective(token);
   858         int expression = 0;
   859         switch (directive)
   860         {
   861           case DIRECTIVE_IF:
   862             expression = parseExpressionIf(token);
   863             break;
   864           case DIRECTIVE_IFDEF:
   865             expression = parseExpressionIfdef(token);
   866             break;
   867           case DIRECTIVE_IFNDEF:
   868             expression = parseExpressionIfdef(token) == 0 ? 1 : 0;
   869             break;
   870           default:
   871             assert(false);
   872             break;
   873         }
   874         block.skipGroup = expression == 0;
   875         block.foundValidGroup = expression != 0;
   876     }
   877     mConditionalStack.push_back(block);
   878 }
   880 int DirectiveParser::parseExpressionIf(Token* token)
   881 {
   882     assert((getDirective(token) == DIRECTIVE_IF) ||
   883            (getDirective(token) == DIRECTIVE_ELIF));
   885     DefinedParser definedParser(mTokenizer, mMacroSet, mDiagnostics);
   886     MacroExpander macroExpander(&definedParser, mMacroSet, mDiagnostics);
   887     ExpressionParser expressionParser(&macroExpander, mDiagnostics);
   889     int expression = 0;
   890     macroExpander.lex(token);
   891     expressionParser.parse(token, &expression);
   893     // Warn if there are tokens after #if expression.
   894     if (!isEOD(token))
   895     {
   896         mDiagnostics->report(Diagnostics::CONDITIONAL_UNEXPECTED_TOKEN,
   897                              token->location, token->text);
   898         skipUntilEOD(mTokenizer, token);
   899     }
   901     return expression;
   902 }
   904 int DirectiveParser::parseExpressionIfdef(Token* token)
   905 {
   906     assert((getDirective(token) == DIRECTIVE_IFDEF) ||
   907            (getDirective(token) == DIRECTIVE_IFNDEF));
   909     mTokenizer->lex(token);
   910     if (token->type != Token::IDENTIFIER)
   911     {
   912         mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
   913                              token->location, token->text);
   914         skipUntilEOD(mTokenizer, token);
   915         return 0;
   916     }
   918     MacroSet::const_iterator iter = mMacroSet->find(token->text);
   919     int expression = iter != mMacroSet->end() ? 1 : 0;
   921     // Warn if there are tokens after #ifdef expression.
   922     mTokenizer->lex(token);
   923     if (!isEOD(token))
   924     {
   925         mDiagnostics->report(Diagnostics::CONDITIONAL_UNEXPECTED_TOKEN,
   926                              token->location, token->text);
   927         skipUntilEOD(mTokenizer, token);
   928     }
   929     return expression;
   930 }
   932 }  // namespace pp

mercurial