Path: blob/main_old/src/compiler/preprocessor/DirectiveParser.cpp
1693 views
//1// Copyright 2011 The ANGLE Project Authors. All rights reserved.2// Use of this source code is governed by a BSD-style license that can be3// found in the LICENSE file.4//56#include "compiler/preprocessor/DirectiveParser.h"78#include <algorithm>9#include <cstdlib>10#include <sstream>1112#include "GLSLANG/ShaderLang.h"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"2021namespace angle22{2324namespace25{26enum DirectiveType27{28DIRECTIVE_NONE,29DIRECTIVE_DEFINE,30DIRECTIVE_UNDEF,31DIRECTIVE_IF,32DIRECTIVE_IFDEF,33DIRECTIVE_IFNDEF,34DIRECTIVE_ELSE,35DIRECTIVE_ELIF,36DIRECTIVE_ENDIF,37DIRECTIVE_ERROR,38DIRECTIVE_PRAGMA,39DIRECTIVE_EXTENSION,40DIRECTIVE_VERSION,41DIRECTIVE_LINE42};4344DirectiveType getDirective(const pp::Token *token)45{46const char kDirectiveDefine[] = "define";47const char kDirectiveUndef[] = "undef";48const char kDirectiveIf[] = "if";49const char kDirectiveIfdef[] = "ifdef";50const char kDirectiveIfndef[] = "ifndef";51const char kDirectiveElse[] = "else";52const char kDirectiveElif[] = "elif";53const char kDirectiveEndif[] = "endif";54const char kDirectiveError[] = "error";55const char kDirectivePragma[] = "pragma";56const char kDirectiveExtension[] = "extension";57const char kDirectiveVersion[] = "version";58const char kDirectiveLine[] = "line";5960if (token->type != pp::Token::IDENTIFIER)61return DIRECTIVE_NONE;6263if (token->text == kDirectiveDefine)64return DIRECTIVE_DEFINE;65if (token->text == kDirectiveUndef)66return DIRECTIVE_UNDEF;67if (token->text == kDirectiveIf)68return DIRECTIVE_IF;69if (token->text == kDirectiveIfdef)70return DIRECTIVE_IFDEF;71if (token->text == kDirectiveIfndef)72return DIRECTIVE_IFNDEF;73if (token->text == kDirectiveElse)74return DIRECTIVE_ELSE;75if (token->text == kDirectiveElif)76return DIRECTIVE_ELIF;77if (token->text == kDirectiveEndif)78return DIRECTIVE_ENDIF;79if (token->text == kDirectiveError)80return DIRECTIVE_ERROR;81if (token->text == kDirectivePragma)82return DIRECTIVE_PRAGMA;83if (token->text == kDirectiveExtension)84return DIRECTIVE_EXTENSION;85if (token->text == kDirectiveVersion)86return DIRECTIVE_VERSION;87if (token->text == kDirectiveLine)88return DIRECTIVE_LINE;8990return DIRECTIVE_NONE;91}9293bool isConditionalDirective(DirectiveType directive)94{95switch (directive)96{97case DIRECTIVE_IF:98case DIRECTIVE_IFDEF:99case DIRECTIVE_IFNDEF:100case DIRECTIVE_ELSE:101case DIRECTIVE_ELIF:102case DIRECTIVE_ENDIF:103return true;104default:105return false;106}107}108109// Returns true if the token represents End Of Directive.110bool isEOD(const pp::Token *token)111{112return (token->type == '\n') || (token->type == pp::Token::LAST);113}114115void skipUntilEOD(pp::Lexer *lexer, pp::Token *token)116{117while (!isEOD(token))118{119lexer->lex(token);120}121}122123bool isMacroNameReserved(const std::string &name)124{125// Names prefixed with "GL_" and the name "defined" are reserved.126return name == "defined" || (name.substr(0, 3) == "GL_");127}128129bool hasDoubleUnderscores(const std::string &name)130{131return (name.find("__") != std::string::npos);132}133134bool isMacroPredefined(const std::string &name, const pp::MacroSet ¯oSet)135{136pp::MacroSet::const_iterator iter = macroSet.find(name);137return iter != macroSet.end() ? iter->second->predefined : false;138}139140} // namespace141142namespace pp143{144DirectiveParser::DirectiveParser(Tokenizer *tokenizer,145MacroSet *macroSet,146Diagnostics *diagnostics,147DirectiveHandler *directiveHandler,148const PreprocessorSettings &settings)149: mPastFirstStatement(false),150mSeenNonPreprocessorToken(false),151mTokenizer(tokenizer),152mMacroSet(macroSet),153mDiagnostics(diagnostics),154mDirectiveHandler(directiveHandler),155mShaderVersion(100),156mSettings(settings)157{}158159DirectiveParser::~DirectiveParser() {}160161void DirectiveParser::lex(Token *token)162{163do164{165mTokenizer->lex(token);166167if (token->type == Token::PP_HASH)168{169parseDirective(token);170mPastFirstStatement = true;171}172else if (!isEOD(token) && !skipping())173{174mSeenNonPreprocessorToken = true;175}176177if (token->type == Token::LAST)178{179if (!mConditionalStack.empty())180{181const ConditionalBlock &block = mConditionalStack.back();182mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNTERMINATED, block.location,183block.type);184}185break;186}187188} while (skipping() || (token->type == '\n'));189190mPastFirstStatement = true;191}192193void DirectiveParser::parseDirective(Token *token)194{195ASSERT(token->type == Token::PP_HASH);196197mTokenizer->lex(token);198if (isEOD(token))199{200// Empty Directive.201return;202}203204DirectiveType directive = getDirective(token);205206// While in an excluded conditional block/group,207// we only parse conditional directives.208if (skipping() && !isConditionalDirective(directive))209{210skipUntilEOD(mTokenizer, token);211return;212}213214switch (directive)215{216case DIRECTIVE_NONE:217mDiagnostics->report(Diagnostics::PP_DIRECTIVE_INVALID_NAME, token->location,218token->text);219skipUntilEOD(mTokenizer, token);220break;221case DIRECTIVE_DEFINE:222parseDefine(token);223break;224case DIRECTIVE_UNDEF:225parseUndef(token);226break;227case DIRECTIVE_IF:228parseIf(token);229break;230case DIRECTIVE_IFDEF:231parseIfdef(token);232break;233case DIRECTIVE_IFNDEF:234parseIfndef(token);235break;236case DIRECTIVE_ELSE:237parseElse(token);238break;239case DIRECTIVE_ELIF:240parseElif(token);241break;242case DIRECTIVE_ENDIF:243parseEndif(token);244break;245case DIRECTIVE_ERROR:246parseError(token);247break;248case DIRECTIVE_PRAGMA:249parsePragma(token);250break;251case DIRECTIVE_EXTENSION:252parseExtension(token);253break;254case DIRECTIVE_VERSION:255parseVersion(token);256break;257case DIRECTIVE_LINE:258parseLine(token);259break;260default:261UNREACHABLE();262break;263}264265skipUntilEOD(mTokenizer, token);266if (token->type == Token::LAST)267{268mDiagnostics->report(Diagnostics::PP_EOF_IN_DIRECTIVE, token->location, token->text);269}270}271272void DirectiveParser::parseDefine(Token *token)273{274ASSERT(getDirective(token) == DIRECTIVE_DEFINE);275276mTokenizer->lex(token);277if (token->type != Token::IDENTIFIER)278{279mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text);280return;281}282if (isMacroPredefined(token->text, *mMacroSet))283{284mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_REDEFINED, token->location,285token->text);286return;287}288if (isMacroNameReserved(token->text))289{290mDiagnostics->report(Diagnostics::PP_MACRO_NAME_RESERVED, token->location, token->text);291return;292}293// Using double underscores is allowed, but may result in unintended294// behavior, so a warning is issued. At the time of writing this was295// specified in ESSL 3.10, but the intent judging from Khronos296// discussions and dEQP tests was that double underscores should be297// allowed in earlier ESSL versions too.298if (hasDoubleUnderscores(token->text))299{300mDiagnostics->report(Diagnostics::PP_WARNING_MACRO_NAME_RESERVED, token->location,301token->text);302}303304std::shared_ptr<Macro> macro = std::make_shared<Macro>();305macro->type = Macro::kTypeObj;306macro->name = token->text;307308mTokenizer->lex(token);309if (token->type == '(' && !token->hasLeadingSpace())310{311// Function-like macro. Collect arguments.312macro->type = Macro::kTypeFunc;313do314{315mTokenizer->lex(token);316if (token->type != Token::IDENTIFIER)317break;318319if (std::find(macro->parameters.begin(), macro->parameters.end(), token->text) !=320macro->parameters.end())321{322mDiagnostics->report(Diagnostics::PP_MACRO_DUPLICATE_PARAMETER_NAMES,323token->location, token->text);324return;325}326327macro->parameters.push_back(token->text);328329mTokenizer->lex(token); // Get ','.330} while (token->type == ',');331332if (token->type != ')')333{334mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text);335return;336}337mTokenizer->lex(token); // Get ')'.338}339340while ((token->type != '\n') && (token->type != Token::LAST))341{342// Reset the token location because it is unnecessary in replacement343// list. Resetting it also allows us to reuse Token::equals() to344// compare macros.345token->location = SourceLocation();346macro->replacements.push_back(*token);347mTokenizer->lex(token);348}349if (!macro->replacements.empty())350{351// Whitespace preceding the replacement list is not considered part of352// the replacement list for either form of macro.353macro->replacements.front().setHasLeadingSpace(false);354}355356// Check for macro redefinition.357MacroSet::const_iterator iter = mMacroSet->find(macro->name);358if (iter != mMacroSet->end() && !macro->equals(*iter->second))359{360mDiagnostics->report(Diagnostics::PP_MACRO_REDEFINED, token->location, macro->name);361return;362}363mMacroSet->insert(std::make_pair(macro->name, macro));364}365366void DirectiveParser::parseUndef(Token *token)367{368ASSERT(getDirective(token) == DIRECTIVE_UNDEF);369370mTokenizer->lex(token);371if (token->type != Token::IDENTIFIER)372{373mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text);374return;375}376377MacroSet::iterator iter = mMacroSet->find(token->text);378if (iter != mMacroSet->end())379{380if (iter->second->predefined)381{382mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_UNDEFINED, token->location,383token->text);384return;385}386else if (iter->second->expansionCount > 0)387{388mDiagnostics->report(Diagnostics::PP_MACRO_UNDEFINED_WHILE_INVOKED, token->location,389token->text);390return;391}392else393{394mMacroSet->erase(iter);395}396}397398mTokenizer->lex(token);399if (!isEOD(token))400{401mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text);402skipUntilEOD(mTokenizer, token);403}404}405406void DirectiveParser::parseIf(Token *token)407{408ASSERT(getDirective(token) == DIRECTIVE_IF);409parseConditionalIf(token);410}411412void DirectiveParser::parseIfdef(Token *token)413{414ASSERT(getDirective(token) == DIRECTIVE_IFDEF);415parseConditionalIf(token);416}417418void DirectiveParser::parseIfndef(Token *token)419{420ASSERT(getDirective(token) == DIRECTIVE_IFNDEF);421parseConditionalIf(token);422}423424void DirectiveParser::parseElse(Token *token)425{426ASSERT(getDirective(token) == DIRECTIVE_ELSE);427428if (mConditionalStack.empty())429{430mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_WITHOUT_IF, token->location,431token->text);432skipUntilEOD(mTokenizer, token);433return;434}435436ConditionalBlock &block = mConditionalStack.back();437if (block.skipBlock)438{439// No diagnostics. Just skip the whole line.440skipUntilEOD(mTokenizer, token);441return;442}443if (block.foundElseGroup)444{445mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_AFTER_ELSE, token->location,446token->text);447skipUntilEOD(mTokenizer, token);448return;449}450451block.foundElseGroup = true;452block.skipGroup = block.foundValidGroup;453block.foundValidGroup = true;454455// Check if there are extra tokens after #else.456mTokenizer->lex(token);457if (!isEOD(token))458{459mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, token->location,460token->text);461skipUntilEOD(mTokenizer, token);462}463}464465void DirectiveParser::parseElif(Token *token)466{467ASSERT(getDirective(token) == DIRECTIVE_ELIF);468469if (mConditionalStack.empty())470{471mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_WITHOUT_IF, token->location,472token->text);473skipUntilEOD(mTokenizer, token);474return;475}476477ConditionalBlock &block = mConditionalStack.back();478if (block.skipBlock)479{480// No diagnostics. Just skip the whole line.481skipUntilEOD(mTokenizer, token);482return;483}484if (block.foundElseGroup)485{486mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_AFTER_ELSE, token->location,487token->text);488skipUntilEOD(mTokenizer, token);489return;490}491if (block.foundValidGroup)492{493// Do not parse the expression.494// Also be careful not to emit a diagnostic.495block.skipGroup = true;496skipUntilEOD(mTokenizer, token);497return;498}499500int expression = parseExpressionIf(token);501block.skipGroup = expression == 0;502block.foundValidGroup = expression != 0;503}504505void DirectiveParser::parseEndif(Token *token)506{507ASSERT(getDirective(token) == DIRECTIVE_ENDIF);508509if (mConditionalStack.empty())510{511mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ENDIF_WITHOUT_IF, token->location,512token->text);513skipUntilEOD(mTokenizer, token);514return;515}516517mConditionalStack.pop_back();518519// Check if there are tokens after #endif.520mTokenizer->lex(token);521if (!isEOD(token))522{523mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, token->location,524token->text);525skipUntilEOD(mTokenizer, token);526}527}528529void DirectiveParser::parseError(Token *token)530{531ASSERT(getDirective(token) == DIRECTIVE_ERROR);532533std::ostringstream stream;534mTokenizer->lex(token);535while ((token->type != '\n') && (token->type != Token::LAST))536{537stream << *token;538mTokenizer->lex(token);539}540mDirectiveHandler->handleError(token->location, stream.str());541}542543// Parses pragma of form: #pragma name[(value)].544void DirectiveParser::parsePragma(Token *token)545{546ASSERT(getDirective(token) == DIRECTIVE_PRAGMA);547548enum State549{550PRAGMA_NAME,551LEFT_PAREN,552PRAGMA_VALUE,553RIGHT_PAREN554};555556bool valid = true;557std::string name, value;558int state = PRAGMA_NAME;559560mTokenizer->lex(token);561bool stdgl = token->text == "STDGL";562if (stdgl)563{564mTokenizer->lex(token);565}566while ((token->type != '\n') && (token->type != Token::LAST))567{568switch (state++)569{570case PRAGMA_NAME:571name = token->text;572valid = valid && (token->type == Token::IDENTIFIER);573break;574case LEFT_PAREN:575valid = valid && (token->type == '(');576break;577case PRAGMA_VALUE:578value = token->text;579valid = valid && (token->type == Token::IDENTIFIER);580break;581case RIGHT_PAREN:582valid = valid && (token->type == ')');583break;584default:585valid = false;586break;587}588mTokenizer->lex(token);589}590591valid = valid && ((state == PRAGMA_NAME) || // Empty pragma.592(state == LEFT_PAREN) || // Without value.593(state == RIGHT_PAREN + 1)); // With value.594if (!valid)595{596mDiagnostics->report(Diagnostics::PP_UNRECOGNIZED_PRAGMA, token->location, name);597}598else if (state > PRAGMA_NAME) // Do not notify for empty pragma.599{600mDirectiveHandler->handlePragma(token->location, name, value, stdgl);601}602}603604void DirectiveParser::parseExtension(Token *token)605{606ASSERT(getDirective(token) == DIRECTIVE_EXTENSION);607608enum State609{610EXT_NAME,611COLON,612EXT_BEHAVIOR613};614615bool valid = true;616std::string name, behavior;617int state = EXT_NAME;618619mTokenizer->lex(token);620while ((token->type != '\n') && (token->type != Token::LAST))621{622switch (state++)623{624case EXT_NAME:625if (valid && (token->type != Token::IDENTIFIER))626{627mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_NAME, token->location,628token->text);629valid = false;630}631if (valid)632name = token->text;633break;634case COLON:635if (valid && (token->type != ':'))636{637mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location,638token->text);639valid = false;640}641break;642case EXT_BEHAVIOR:643if (valid && (token->type != Token::IDENTIFIER))644{645mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_BEHAVIOR,646token->location, token->text);647valid = false;648}649if (valid)650behavior = token->text;651break;652default:653if (valid)654{655mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location,656token->text);657valid = false;658}659break;660}661mTokenizer->lex(token);662}663if (valid && (state != EXT_BEHAVIOR + 1))664{665mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_DIRECTIVE, token->location,666token->text);667valid = false;668}669if (valid && mSeenNonPreprocessorToken)670{671if (mShaderVersion >= 300)672{673mDiagnostics->report(Diagnostics::PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL3,674token->location, token->text);675valid = false;676}677else678{679if (mSettings.shaderSpec == SH_WEBGL_SPEC)680{681mDiagnostics->report(Diagnostics::PP_NON_PP_TOKEN_BEFORE_EXTENSION_WEBGL,682token->location, token->text);683}684else685{686mDiagnostics->report(Diagnostics::PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL1,687token->location, token->text);688// This is just a warning on CHROME OS http://anglebug.com/4023689#if !defined(ANGLE_PLATFORM_CHROMEOS)690valid = false;691#endif692}693}694}695if (valid)696mDirectiveHandler->handleExtension(token->location, name, behavior);697}698699void DirectiveParser::parseVersion(Token *token)700{701ASSERT(getDirective(token) == DIRECTIVE_VERSION);702703if (mPastFirstStatement)704{705mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_STATEMENT, token->location,706token->text);707skipUntilEOD(mTokenizer, token);708return;709}710711enum State712{713VERSION_NUMBER,714VERSION_PROFILE_ES,715VERSION_PROFILE_GL,716VERSION_ENDLINE717};718719bool valid = true;720int version = 0;721int state = VERSION_NUMBER;722723mTokenizer->lex(token);724while (valid && (token->type != '\n') && (token->type != Token::LAST))725{726switch (state)727{728case VERSION_NUMBER:729if (token->type != Token::CONST_INT)730{731mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_NUMBER, token->location,732token->text);733valid = false;734}735if (valid && !token->iValue(&version))736{737mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW, token->location,738token->text);739valid = false;740}741if (valid)742{743if (sh::IsDesktopGLSpec(mSettings.shaderSpec))744{745state = VERSION_PROFILE_GL;746}747else if (version < 300)748{749state = VERSION_ENDLINE;750}751else752{753state = VERSION_PROFILE_ES;754}755}756break;757case VERSION_PROFILE_ES:758ASSERT(!sh::IsDesktopGLSpec(mSettings.shaderSpec));759if (token->type != Token::IDENTIFIER || token->text != "es")760{761mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE, token->location,762token->text);763valid = false;764}765state = VERSION_ENDLINE;766break;767case VERSION_PROFILE_GL:768ASSERT(sh::IsDesktopGLSpec(mSettings.shaderSpec));769if (token->type != Token::IDENTIFIER || token->text != "core")770{771mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE, token->location,772token->text);773valid = false;774}775state = VERSION_ENDLINE;776break;777default:778mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location,779token->text);780valid = false;781break;782}783784mTokenizer->lex(token);785786if (token->type == '\n' && state == VERSION_PROFILE_GL)787{788state = VERSION_ENDLINE;789}790}791792if (valid && (state != VERSION_ENDLINE))793{794mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE, token->location,795token->text);796valid = false;797}798799if (valid && version >= 300 && token->location.line > 1)800{801mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_LINE_ESSL3, token->location,802token->text);803valid = false;804}805806if (valid)807{808mDirectiveHandler->handleVersion(token->location, version, mSettings.shaderSpec);809mShaderVersion = version;810PredefineMacro(mMacroSet, "__VERSION__", version);811}812}813814void DirectiveParser::parseLine(Token *token)815{816ASSERT(getDirective(token) == DIRECTIVE_LINE);817818bool valid = true;819bool parsedFileNumber = false;820int line = 0, file = 0;821822MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics, mSettings, false);823824// Lex the first token after "#line" so we can check it for EOD.825macroExpander.lex(token);826827if (isEOD(token))828{829mDiagnostics->report(Diagnostics::PP_INVALID_LINE_DIRECTIVE, token->location, token->text);830valid = false;831}832else833{834ExpressionParser expressionParser(¯oExpander, mDiagnostics);835ExpressionParser::ErrorSettings errorSettings;836837// See GLES3 section 12.42838errorSettings.integerLiteralsMustFit32BitSignedRange = true;839840errorSettings.unexpectedIdentifier = Diagnostics::PP_INVALID_LINE_NUMBER;841// The first token was lexed earlier to check if it was EOD. Include842// the token in parsing for a second time by setting the843// parsePresetToken flag to true.844expressionParser.parse(token, &line, true, errorSettings, &valid);845if (!isEOD(token) && valid)846{847errorSettings.unexpectedIdentifier = Diagnostics::PP_INVALID_FILE_NUMBER;848// After parsing the line expression expressionParser has also849// advanced to the first token of the file expression - this is the850// token that makes the parser reduce the "input" rule for the line851// expression and stop. So we're using parsePresetToken = true here852// as well.853expressionParser.parse(token, &file, true, errorSettings, &valid);854parsedFileNumber = true;855}856if (!isEOD(token))857{858if (valid)859{860mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location,861token->text);862valid = false;863}864skipUntilEOD(mTokenizer, token);865}866}867868if (valid)869{870mTokenizer->setLineNumber(line);871if (parsedFileNumber)872mTokenizer->setFileNumber(file);873}874}875876bool DirectiveParser::skipping() const877{878if (mConditionalStack.empty())879return false;880881const ConditionalBlock &block = mConditionalStack.back();882return block.skipBlock || block.skipGroup;883}884885void DirectiveParser::parseConditionalIf(Token *token)886{887ConditionalBlock block;888block.type = token->text;889block.location = token->location;890891if (skipping())892{893// This conditional block is inside another conditional group894// which is skipped. As a consequence this whole block is skipped.895// Be careful not to parse the conditional expression that might896// emit a diagnostic.897skipUntilEOD(mTokenizer, token);898block.skipBlock = true;899}900else901{902DirectiveType directive = getDirective(token);903904int expression = 0;905switch (directive)906{907case DIRECTIVE_IF:908expression = parseExpressionIf(token);909break;910case DIRECTIVE_IFDEF:911expression = parseExpressionIfdef(token);912break;913case DIRECTIVE_IFNDEF:914expression = parseExpressionIfdef(token) == 0 ? 1 : 0;915break;916default:917UNREACHABLE();918break;919}920block.skipGroup = expression == 0;921block.foundValidGroup = expression != 0;922}923mConditionalStack.push_back(block);924}925926int DirectiveParser::parseExpressionIf(Token *token)927{928ASSERT((getDirective(token) == DIRECTIVE_IF) || (getDirective(token) == DIRECTIVE_ELIF));929930MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics, mSettings, true);931ExpressionParser expressionParser(¯oExpander, mDiagnostics);932933int expression = 0;934ExpressionParser::ErrorSettings errorSettings;935errorSettings.integerLiteralsMustFit32BitSignedRange = false;936errorSettings.unexpectedIdentifier = Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN;937938bool valid = true;939expressionParser.parse(token, &expression, false, errorSettings, &valid);940941// Check if there are tokens after #if expression.942if (!isEOD(token))943{944mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, token->location,945token->text);946skipUntilEOD(mTokenizer, token);947}948949return expression;950}951952int DirectiveParser::parseExpressionIfdef(Token *token)953{954ASSERT((getDirective(token) == DIRECTIVE_IFDEF) || (getDirective(token) == DIRECTIVE_IFNDEF));955956mTokenizer->lex(token);957if (token->type != Token::IDENTIFIER)958{959mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN, token->location, token->text);960skipUntilEOD(mTokenizer, token);961return 0;962}963964MacroSet::const_iterator iter = mMacroSet->find(token->text);965int expression = iter != mMacroSet->end() ? 1 : 0;966967// Check if there are tokens after #ifdef expression.968mTokenizer->lex(token);969if (!isEOD(token))970{971mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN, token->location,972token->text);973skipUntilEOD(mTokenizer, token);974}975return expression;976}977978} // namespace pp979980} // namespace angle981982983