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
29namespace {
30enum 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
49static 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
98static 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.
115static bool isEOD(const pp::Token *token)
116{
117	return (token->type == '\n') || (token->type == pp::Token::LAST);
118}
119
120static void skipUntilEOD(pp::Lexer *lexer, pp::Token *token)
121{
122	while(!isEOD(token))
123	{
124		lexer->lex(token);
125	}
126}
127
128static bool isMacroNameReserved(const std::string& name)
129{
130	// Names prefixed with "GL_" are reserved.
131	return (name.substr(0, 3) == "GL_");
132}
133
134bool hasDoubleUnderscores(const std::string &name)
135{
136	return (name.find("__") != std::string::npos);
137}
138
139static 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
146namespace pp
147{
148
149class DefinedParser : public Lexer
150{
151public:
152	DefinedParser(Lexer *lexer, const MacroSet *macroSet, Diagnostics *diagnostics)
153		: mLexer(lexer), mMacroSet(macroSet), mDiagnostics(diagnostics)
154	{
155	}
156
157protected:
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
203private:
204	Lexer *mLexer;
205	const MacroSet *mMacroSet;
206	Diagnostics *mDiagnostics;
207};
208
209DirectiveParser::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
225DirectiveParser::~DirectiveParser()
226{
227}
228
229void 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
261void 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
341void 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
437void 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
478void DirectiveParser::parseIf(Token *token)
479{
480	assert(getDirective(token) == DIRECTIVE_IF);
481	parseConditionalIf(token);
482}
483
484void DirectiveParser::parseIfdef(Token *token)
485{
486	assert(getDirective(token) == DIRECTIVE_IFDEF);
487	parseConditionalIf(token);
488}
489
490void DirectiveParser::parseIfndef(Token *token)
491{
492	assert(getDirective(token) == DIRECTIVE_IFNDEF);
493	parseConditionalIf(token);
494}
495
496void 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
537void 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
577void 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
601void 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)].
616void 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
676void 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
759void 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
846void 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
908bool 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
917void 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
958int 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
985int 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