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