• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
getDirective(const pp::Token * token)49 static DirectiveType getDirective(const pp::Token *token)
50 {
51 	static const char kDirectiveDefine[] = "define";
52 	static const char kDirectiveUndef[] = "undef";
53 	static const char kDirectiveIf[] = "if";
54 	static const char kDirectiveIfdef[] = "ifdef";
55 	static const char kDirectiveIfndef[] = "ifndef";
56 	static const char kDirectiveElse[] = "else";
57 	static const char kDirectiveElif[] = "elif";
58 	static const char kDirectiveEndif[] = "endif";
59 	static const char kDirectiveError[] = "error";
60 	static const char kDirectivePragma[] = "pragma";
61 	static const char kDirectiveExtension[] = "extension";
62 	static const char kDirectiveVersion[] = "version";
63 	static const char 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 
isConditionalDirective(DirectiveType directive)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.
isEOD(const pp::Token * token)115 static bool isEOD(const pp::Token *token)
116 {
117 	return (token->type == '\n') || (token->type == pp::Token::LAST);
118 }
119 
skipUntilEOD(pp::Lexer * lexer,pp::Token * token)120 static void skipUntilEOD(pp::Lexer *lexer, pp::Token *token)
121 {
122 	while(!isEOD(token))
123 	{
124 		lexer->lex(token);
125 	}
126 }
127 
isMacroNameReserved(const std::string & name)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 
hasDoubleUnderscores(const std::string & name)134 bool hasDoubleUnderscores(const std::string &name)
135 {
136 	return (name.find("__") != std::string::npos);
137 }
138 
isMacroPredefined(const std::string & name,const pp::MacroSet & macroSet)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:
DefinedParser(Lexer * lexer,const MacroSet * macroSet,Diagnostics * diagnostics)152 	DefinedParser(Lexer *lexer, const MacroSet *macroSet, Diagnostics *diagnostics)
153 		: mLexer(lexer), mMacroSet(macroSet), mDiagnostics(diagnostics)
154 	{
155 	}
156 
157 protected:
lex(Token * token)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 
DirectiveParser(Tokenizer * tokenizer,MacroSet * macroSet,Diagnostics * diagnostics,DirectiveHandler * directiveHandler,int maxMacroExpansionDepth)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 
~DirectiveParser()225 DirectiveParser::~DirectiveParser()
226 {
227 }
228 
lex(Token * token)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 
parseDirective(Token * token)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 
parseDefine(Token * token)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 
parseUndef(Token * token)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 
parseIf(Token * token)478 void DirectiveParser::parseIf(Token *token)
479 {
480 	assert(getDirective(token) == DIRECTIVE_IF);
481 	parseConditionalIf(token);
482 }
483 
parseIfdef(Token * token)484 void DirectiveParser::parseIfdef(Token *token)
485 {
486 	assert(getDirective(token) == DIRECTIVE_IFDEF);
487 	parseConditionalIf(token);
488 }
489 
parseIfndef(Token * token)490 void DirectiveParser::parseIfndef(Token *token)
491 {
492 	assert(getDirective(token) == DIRECTIVE_IFNDEF);
493 	parseConditionalIf(token);
494 }
495 
parseElse(Token * token)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 
parseElif(Token * token)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 
parseEndif(Token * token)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 
parseError(Token * token)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)].
parsePragma(Token * token)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 
parseExtension(Token * token)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 
parseVersion(Token * token)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 
parseLine(Token * token)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 
skipping() const908 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 
parseConditionalIf(Token * token)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 
parseExpressionIf(Token * token)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 
parseExpressionIfdef(Token * token)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