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