tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

DirectiveParser.cpp (29687B)


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