LCOV - code coverage report
Current view: top level - gfx/angle/src/compiler/preprocessor - DirectiveParser.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 523 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 31 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13