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 <cassert>
18 #include <cstdlib>
19 #include <sstream>
20 
21 #include "Diagnostics.h"
22 #include "DirectiveHandler.h"
23 #include "ExpressionParser.h"
24 #include "MacroExpander.h"
25 #include "Token.h"
26 #include "Tokenizer.h"
27 
28 namespace {
29 enum DirectiveType
30 {
31 	DIRECTIVE_NONE,
32 	DIRECTIVE_DEFINE,
33 	DIRECTIVE_UNDEF,
34 	DIRECTIVE_IF,
35 	DIRECTIVE_IFDEF,
36 	DIRECTIVE_IFNDEF,
37 	DIRECTIVE_ELSE,
38 	DIRECTIVE_ELIF,
39 	DIRECTIVE_ENDIF,
40 	DIRECTIVE_ERROR,
41 	DIRECTIVE_PRAGMA,
42 	DIRECTIVE_EXTENSION,
43 	DIRECTIVE_VERSION,
44 	DIRECTIVE_LINE
45 };
46 }  // namespace
47 
getDirective(const pp::Token * token)48 static DirectiveType getDirective(const pp::Token* token)
49 {
50 	static const std::string kDirectiveDefine("define");
51 	static const std::string kDirectiveUndef("undef");
52 	static const std::string kDirectiveIf("if");
53 	static const std::string kDirectiveIfdef("ifdef");
54 	static const std::string kDirectiveIfndef("ifndef");
55 	static const std::string kDirectiveElse("else");
56 	static const std::string kDirectiveElif("elif");
57 	static const std::string kDirectiveEndif("endif");
58 	static const std::string kDirectiveError("error");
59 	static const std::string kDirectivePragma("pragma");
60 	static const std::string kDirectiveExtension("extension");
61 	static const std::string kDirectiveVersion("version");
62 	static const std::string kDirectiveLine("line");
63 
64 	if (token->type != pp::Token::IDENTIFIER)
65 		return DIRECTIVE_NONE;
66 
67 	if (token->text == kDirectiveDefine)
68 		return DIRECTIVE_DEFINE;
69 	else if (token->text == kDirectiveUndef)
70 		return DIRECTIVE_UNDEF;
71 	else if (token->text == kDirectiveIf)
72 		return DIRECTIVE_IF;
73 	else if (token->text == kDirectiveIfdef)
74 		return DIRECTIVE_IFDEF;
75 	else if (token->text == kDirectiveIfndef)
76 		return DIRECTIVE_IFNDEF;
77 	else if (token->text == kDirectiveElse)
78 		return DIRECTIVE_ELSE;
79 	else if (token->text == kDirectiveElif)
80 		return DIRECTIVE_ELIF;
81 	else if (token->text == kDirectiveEndif)
82 		return DIRECTIVE_ENDIF;
83 	else if (token->text == kDirectiveError)
84 		return DIRECTIVE_ERROR;
85 	else if (token->text == kDirectivePragma)
86 		return DIRECTIVE_PRAGMA;
87 	else if (token->text == kDirectiveExtension)
88 		return DIRECTIVE_EXTENSION;
89 	else if (token->text == kDirectiveVersion)
90 		return DIRECTIVE_VERSION;
91 	else if (token->text == kDirectiveLine)
92 		return DIRECTIVE_LINE;
93 
94 	return DIRECTIVE_NONE;
95 }
96 
isConditionalDirective(DirectiveType directive)97 static bool isConditionalDirective(DirectiveType directive)
98 {
99 	switch (directive)
100 	{
101 	case DIRECTIVE_IF:
102 	case DIRECTIVE_IFDEF:
103 	case DIRECTIVE_IFNDEF:
104 	case DIRECTIVE_ELSE:
105 	case DIRECTIVE_ELIF:
106 	case DIRECTIVE_ENDIF:
107 		return true;
108 	default:
109 		return false;
110 	}
111 }
112 
113 // Returns true if the token represents End Of Directive.
isEOD(const pp::Token * token)114 static bool isEOD(const pp::Token* token)
115 {
116 	return (token->type == '\n') || (token->type == pp::Token::LAST);
117 }
118 
skipUntilEOD(pp::Lexer * lexer,pp::Token * token)119 static void skipUntilEOD(pp::Lexer* lexer, pp::Token* token)
120 {
121 	while(!isEOD(token))
122 	{
123 		lexer->lex(token);
124 	}
125 }
126 
isMacroNameReserved(const std::string & name)127 static bool isMacroNameReserved(const std::string& name)
128 {
129 	// Names prefixed with "GL_" are reserved.
130 	if (name.substr(0, 3) == "GL_")
131 		return true;
132 
133 	// Names containing two consecutive underscores are reserved.
134 	if (name.find("__") != std::string::npos)
135 		return true;
136 
137 	return false;
138 }
139 
isMacroPredefined(const std::string & name,const pp::MacroSet & macroSet)140 static bool isMacroPredefined(const std::string& name,
141                               const pp::MacroSet& macroSet)
142 {
143 	pp::MacroSet::const_iterator iter = macroSet.find(name);
144 	return iter != macroSet.end() ? iter->second.predefined : false;
145 }
146 
147 namespace pp
148 {
149 
DirectiveParser(Tokenizer * tokenizer,MacroSet * macroSet,Diagnostics * diagnostics,DirectiveHandler * directiveHandler)150 DirectiveParser::DirectiveParser(Tokenizer* tokenizer,
151                                  MacroSet* macroSet,
152                                  Diagnostics* diagnostics,
153                                  DirectiveHandler* directiveHandler) :
154 	mPastFirstStatement(false),
155 	mTokenizer(tokenizer),
156 	mMacroSet(macroSet),
157 	mDiagnostics(diagnostics),
158 	mDirectiveHandler(directiveHandler)
159 {
160 }
161 
lex(Token * token)162 void DirectiveParser::lex(Token* token)
163 {
164 	do
165 	{
166 		mTokenizer->lex(token);
167 
168 		if (token->type == Token::PP_HASH)
169 		{
170 			parseDirective(token);
171 			mPastFirstStatement = true;
172 		}
173 
174 		if (token->type == Token::LAST)
175 		{
176 			if (!mConditionalStack.empty())
177 			{
178 				const ConditionalBlock& block = mConditionalStack.back();
179 				mDiagnostics->report(Diagnostics::CONDITIONAL_UNTERMINATED,
180 				                     block.location, block.type);
181 			}
182 			break;
183 		}
184 
185 	} while (skipping() || (token->type == '\n'));
186 
187 	mPastFirstStatement = true;
188 }
189 
parseDirective(Token * token)190 void DirectiveParser::parseDirective(Token* token)
191 {
192 	assert(token->type == Token::PP_HASH);
193 
194 	mTokenizer->lex(token);
195 	if (isEOD(token))
196 	{
197 		// Empty Directive.
198 		return;
199 	}
200 
201 	DirectiveType directive = getDirective(token);
202 
203 	// While in an excluded conditional block/group,
204 	// we only parse conditional directives.
205 	if (skipping() && !isConditionalDirective(directive))
206 	{
207 		skipUntilEOD(mTokenizer, token);
208 		return;
209 	}
210 
211 	switch(directive)
212 	{
213 	case DIRECTIVE_NONE:
214 		mDiagnostics->report(Diagnostics::DIRECTIVE_INVALID_NAME,
215 		                     token->location, token->text);
216 		skipUntilEOD(mTokenizer, token);
217 		break;
218 	case DIRECTIVE_DEFINE:
219 		parseDefine(token);
220 		break;
221 	case DIRECTIVE_UNDEF:
222 		parseUndef(token);
223 		break;
224 	case DIRECTIVE_IF:
225 		parseIf(token);
226 		break;
227 	case DIRECTIVE_IFDEF:
228 		parseIfdef(token);
229 		break;
230 	case DIRECTIVE_IFNDEF:
231 		parseIfndef(token);
232 		break;
233 	case DIRECTIVE_ELSE:
234 		parseElse(token);
235 		break;
236 	case DIRECTIVE_ELIF:
237 		parseElif(token);
238 		break;
239 	case DIRECTIVE_ENDIF:
240 		parseEndif(token);
241 		break;
242 	case DIRECTIVE_ERROR:
243 		parseError(token);
244 		break;
245 	case DIRECTIVE_PRAGMA:
246 		parsePragma(token);
247 		break;
248 	case DIRECTIVE_EXTENSION:
249 		parseExtension(token);
250 		break;
251 	case DIRECTIVE_VERSION:
252 		parseVersion(token);
253 		break;
254 	case DIRECTIVE_LINE:
255 		parseLine(token);
256 		break;
257 	default:
258 		assert(false);
259 		break;
260 	}
261 
262 	skipUntilEOD(mTokenizer, token);
263 	if (token->type == Token::LAST)
264 	{
265 		mDiagnostics->report(Diagnostics::EOF_IN_DIRECTIVE,
266 		                     token->location, token->text);
267 	}
268 }
269 
parseDefine(Token * token)270 void DirectiveParser::parseDefine(Token* token)
271 {
272 	assert(getDirective(token) == DIRECTIVE_DEFINE);
273 
274 	mTokenizer->lex(token);
275 	if (token->type != Token::IDENTIFIER)
276 	{
277 		mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
278 		                     token->location, token->text);
279 		return;
280 	}
281 	if (isMacroPredefined(token->text, *mMacroSet))
282 	{
283 		mDiagnostics->report(Diagnostics::MACRO_PREDEFINED_REDEFINED,
284 		                     token->location, token->text);
285 		return;
286 	}
287 	if (isMacroNameReserved(token->text))
288 	{
289 		mDiagnostics->report(Diagnostics::MACRO_NAME_RESERVED,
290 		                     token->location, token->text);
291 		return;
292 	}
293 
294 	Macro macro;
295 	macro.type = Macro::kTypeObj;
296 	macro.name = token->text;
297 
298 	mTokenizer->lex(token);
299 	if (token->type == '(' && !token->hasLeadingSpace())
300 	{
301 		// Function-like macro. Collect arguments.
302 		macro.type = Macro::kTypeFunc;
303 		do {
304 			mTokenizer->lex(token);
305 			if (token->type != Token::IDENTIFIER)
306 				break;
307 
308 			if (std::find(macro.parameters.begin(), macro.parameters.end(), token->text) != macro.parameters.end())
309 			{
310 				mDiagnostics->report(Diagnostics::MACRO_DUPLICATE_PARAMETER_NAMES,
311 				                     token->location, token->text);
312 				return;
313 			}
314 
315 			macro.parameters.push_back(token->text);
316 
317 			mTokenizer->lex(token);  // Get ','.
318 		} while (token->type == ',');
319 
320 		if (token->type != ')')
321 		{
322 			mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
323 			                     token->location,
324 			                     token->text);
325 			return;
326 		}
327 		mTokenizer->lex(token);  // Get ')'.
328 	}
329 
330 	while ((token->type != '\n') && (token->type != Token::LAST))
331 	{
332 		// Reset the token location because it is unnecessary in replacement
333 		// list. Resetting it also allows us to reuse Token::equals() to
334 		// compare macros.
335 		token->location = SourceLocation();
336 		macro.replacements.push_back(*token);
337 		mTokenizer->lex(token);
338 	}
339 	if (!macro.replacements.empty())
340 	{
341 		// Whitespace preceding the replacement list is not considered part of
342 		// the replacement list for either form of macro.
343 		macro.replacements.front().setHasLeadingSpace(false);
344 	}
345 
346 	// Check for macro redefinition.
347 	MacroSet::const_iterator iter = mMacroSet->find(macro.name);
348 	if (iter != mMacroSet->end() && !macro.equals(iter->second))
349 	{
350 		mDiagnostics->report(Diagnostics::MACRO_REDEFINED,
351 		                     token->location,
352 		                     macro.name);
353 		return;
354 	}
355 	mMacroSet->insert(std::make_pair(macro.name, macro));
356 }
357 
parseUndef(Token * token)358 void DirectiveParser::parseUndef(Token* token)
359 {
360 	assert(getDirective(token) == DIRECTIVE_UNDEF);
361 
362 	mTokenizer->lex(token);
363 	if (token->type != Token::IDENTIFIER)
364 	{
365 		mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
366 		                     token->location, token->text);
367 		return;
368 	}
369 
370 	MacroSet::iterator iter = mMacroSet->find(token->text);
371 	if (iter != mMacroSet->end())
372 	{
373 		if (iter->second.predefined)
374 		{
375 			mDiagnostics->report(Diagnostics::MACRO_PREDEFINED_UNDEFINED,
376 			                     token->location, token->text);
377 		}
378 		else
379 		{
380 			mMacroSet->erase(iter);
381 		}
382 	}
383 
384 	mTokenizer->lex(token);
385 }
386 
parseIf(Token * token)387 void DirectiveParser::parseIf(Token* token)
388 {
389 	assert(getDirective(token) == DIRECTIVE_IF);
390 	parseConditionalIf(token);
391 }
392 
parseIfdef(Token * token)393 void DirectiveParser::parseIfdef(Token* token)
394 {
395 	assert(getDirective(token) == DIRECTIVE_IFDEF);
396 	parseConditionalIf(token);
397 }
398 
parseIfndef(Token * token)399 void DirectiveParser::parseIfndef(Token* token)
400 {
401 	assert(getDirective(token) == DIRECTIVE_IFNDEF);
402 	parseConditionalIf(token);
403 }
404 
parseElse(Token * token)405 void DirectiveParser::parseElse(Token* token)
406 {
407 	assert(getDirective(token) == DIRECTIVE_ELSE);
408 
409 	if (mConditionalStack.empty())
410 	{
411 		mDiagnostics->report(Diagnostics::CONDITIONAL_ELSE_WITHOUT_IF,
412 		                     token->location, token->text);
413 		skipUntilEOD(mTokenizer, token);
414 		return;
415 	}
416 
417 	ConditionalBlock& block = mConditionalStack.back();
418 	if (block.skipBlock)
419 	{
420 		// No diagnostics. Just skip the whole line.
421 		skipUntilEOD(mTokenizer, token);
422 		return;
423 	}
424 	if (block.foundElseGroup)
425 	{
426 		mDiagnostics->report(Diagnostics::CONDITIONAL_ELSE_AFTER_ELSE,
427 		                     token->location, token->text);
428 		skipUntilEOD(mTokenizer, token);
429 		return;
430 	}
431 
432 	block.foundElseGroup = true;
433 	block.skipGroup = block.foundValidGroup;
434 	block.foundValidGroup = true;
435 
436 	// Check if there are extra tokens after #else.
437 	mTokenizer->lex(token);
438 	if (!isEOD(token))
439 	{
440 		mDiagnostics->report(Diagnostics::CONDITIONAL_UNEXPECTED_TOKEN,
441 		                     token->location, token->text);
442 		skipUntilEOD(mTokenizer, token);
443 	}
444 }
445 
parseElif(Token * token)446 void DirectiveParser::parseElif(Token* token)
447 {
448 	assert(getDirective(token) == DIRECTIVE_ELIF);
449 
450 	if (mConditionalStack.empty())
451 	{
452 		mDiagnostics->report(Diagnostics::CONDITIONAL_ELIF_WITHOUT_IF,
453 		                     token->location, token->text);
454 		skipUntilEOD(mTokenizer, token);
455 		return;
456 	}
457 
458 	ConditionalBlock& block = mConditionalStack.back();
459 	if (block.skipBlock)
460 	{
461 		// No diagnostics. Just skip the whole line.
462 		skipUntilEOD(mTokenizer, token);
463 		return;
464 	}
465 	if (block.foundElseGroup)
466 	{
467 		mDiagnostics->report(Diagnostics::CONDITIONAL_ELIF_AFTER_ELSE,
468 		                     token->location, token->text);
469 		skipUntilEOD(mTokenizer, token);
470 		return;
471 	}
472 	if (block.foundValidGroup)
473 	{
474 		// Do not parse the expression.
475 		// Also be careful not to emit a diagnostic.
476 		block.skipGroup = true;
477 		skipUntilEOD(mTokenizer, token);
478 		return;
479 	}
480 
481 	int expression = parseExpressionIf(token);
482 	block.skipGroup = expression == 0;
483 	block.foundValidGroup = expression != 0;
484 }
485 
parseEndif(Token * token)486 void DirectiveParser::parseEndif(Token* token)
487 {
488 	assert(getDirective(token) == DIRECTIVE_ENDIF);
489 
490 	if (mConditionalStack.empty())
491 	{
492 		mDiagnostics->report(Diagnostics::CONDITIONAL_ENDIF_WITHOUT_IF,
493 		                     token->location, token->text);
494 		skipUntilEOD(mTokenizer, token);
495 		return;
496 	}
497 
498 	mConditionalStack.pop_back();
499 
500 	// Check if there are tokens after #endif.
501 	mTokenizer->lex(token);
502 	if (!isEOD(token))
503 	{
504 		mDiagnostics->report(Diagnostics::CONDITIONAL_UNEXPECTED_TOKEN,
505 		                     token->location, token->text);
506 		skipUntilEOD(mTokenizer, token);
507 	}
508 }
509 
parseError(Token * token)510 void DirectiveParser::parseError(Token* token)
511 {
512 	assert(getDirective(token) == DIRECTIVE_ERROR);
513 
514 	std::ostringstream stream;
515 	mTokenizer->lex(token);
516 	while ((token->type != '\n') && (token->type != Token::LAST))
517 	{
518 		stream << *token;
519 		mTokenizer->lex(token);
520 	}
521 	mDirectiveHandler->handleError(token->location, stream.str());
522 }
523 
524 // Parses pragma of form: #pragma name[(value)].
parsePragma(Token * token)525 void DirectiveParser::parsePragma(Token* token)
526 {
527 	assert(getDirective(token) == DIRECTIVE_PRAGMA);
528 
529 	enum State
530 	{
531 		PRAGMA_NAME,
532 		LEFT_PAREN,
533 		PRAGMA_VALUE,
534 		RIGHT_PAREN
535 	};
536 
537 	bool valid = true;
538 	std::string name, value;
539 	int state = PRAGMA_NAME;
540 
541 	mTokenizer->lex(token);
542 	while ((token->type != '\n') && (token->type != Token::LAST))
543 	{
544 		switch(state++)
545 		{
546 		case PRAGMA_NAME:
547 			name = token->text;
548 			valid = valid && (token->type == Token::IDENTIFIER);
549 			break;
550 		case LEFT_PAREN:
551 			valid = valid && (token->type == '(');
552 			break;
553 		case PRAGMA_VALUE:
554 			value = token->text;
555 			valid = valid && (token->type == Token::IDENTIFIER);
556 			break;
557 		case RIGHT_PAREN:
558 			valid = valid && (token->type == ')');
559 			break;
560 		default:
561 			valid = false;
562 			break;
563 		}
564 		mTokenizer->lex(token);
565 	}
566 
567 	valid = valid && ((state == PRAGMA_NAME) ||     // Empty pragma.
568 	                  (state == LEFT_PAREN) ||      // Without value.
569 	                  (state == RIGHT_PAREN + 1));  // With value.
570 	if (!valid)
571 	{
572 		mDiagnostics->report(Diagnostics::UNRECOGNIZED_PRAGMA,
573 		                     token->location, name);
574 	}
575 	else if (state > PRAGMA_NAME)  // Do not notify for empty pragma.
576 	{
577 		mDirectiveHandler->handlePragma(token->location, name, value);
578 	}
579 }
580 
parseExtension(Token * token)581 void DirectiveParser::parseExtension(Token* token)
582 {
583 	assert(getDirective(token) == DIRECTIVE_EXTENSION);
584 
585 	enum State
586 	{
587 		EXT_NAME,
588 		COLON,
589 		EXT_BEHAVIOR
590 	};
591 
592 	bool valid = true;
593 	std::string name, behavior;
594 	int state = EXT_NAME;
595 
596 	mTokenizer->lex(token);
597 	while ((token->type != '\n') && (token->type != Token::LAST))
598 	{
599 		switch (state++)
600 		{
601 		case EXT_NAME:
602 			if (valid && (token->type != Token::IDENTIFIER))
603 			{
604 				mDiagnostics->report(Diagnostics::INVALID_EXTENSION_NAME,
605 				                     token->location, token->text);
606 				valid = false;
607 			}
608 			if (valid) name = token->text;
609 			break;
610 		case COLON:
611 			if (valid && (token->type != ':'))
612 			{
613 				mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
614 				                     token->location, token->text);
615 				valid = false;
616 			}
617 			break;
618 		case EXT_BEHAVIOR:
619 			if (valid && (token->type != Token::IDENTIFIER))
620 			{
621 				mDiagnostics->report(Diagnostics::INVALID_EXTENSION_BEHAVIOR,
622 				                     token->location, token->text);
623 				valid = false;
624 			}
625 			if (valid) behavior = token->text;
626 			break;
627 		default:
628 			if (valid)
629 			{
630 				mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
631 				                     token->location, token->text);
632 				valid = false;
633 			}
634 			break;
635 		}
636 		mTokenizer->lex(token);
637 	}
638 	if (valid && (state != EXT_BEHAVIOR + 1))
639 	{
640 		mDiagnostics->report(Diagnostics::INVALID_EXTENSION_DIRECTIVE,
641 		                     token->location, token->text);
642 		valid = false;
643 	}
644 	if (valid)
645 		mDirectiveHandler->handleExtension(token->location, name, behavior);
646 }
647 
parseVersion(Token * token)648 void DirectiveParser::parseVersion(Token* token)
649 {
650 	assert(getDirective(token) == DIRECTIVE_VERSION);
651 
652 	if (mPastFirstStatement)
653 	{
654 		mDiagnostics->report(Diagnostics::VERSION_NOT_FIRST_STATEMENT,
655 		                     token->location, token->text);
656 		skipUntilEOD(mTokenizer, token);
657 		return;
658 	}
659 
660 	enum State
661 	{
662 		VERSION_NUMBER,
663 		VERSION_PROFILE,
664 		VERSION_ENDLINE
665 	};
666 
667 	bool valid = true;
668 	int version = 0;
669 	int state = VERSION_NUMBER;
670 
671 	mTokenizer->lex(token);
672 	while (valid && (token->type != '\n') && (token->type != Token::LAST))
673 	{
674 		switch (state)
675 		{
676 		case VERSION_NUMBER:
677 			if (token->type != Token::CONST_INT)
678 			{
679 				mDiagnostics->report(Diagnostics::INVALID_VERSION_NUMBER,
680 				                     token->location, token->text);
681 				valid = false;
682 			}
683 			if (valid && !token->iValue(&version))
684 			{
685 				mDiagnostics->report(Diagnostics::INTEGER_OVERFLOW,
686 				                     token->location, token->text);
687 				valid = false;
688 			}
689 			if (valid)
690 			{
691 				state = (version < 300) ? VERSION_ENDLINE : VERSION_PROFILE;
692 			}
693 			break;
694 		case VERSION_PROFILE:
695 			if (token->type != Token::IDENTIFIER || token->text != "es")
696 			{
697 				mDiagnostics->report(Diagnostics::INVALID_VERSION_DIRECTIVE,
698 				                     token->location, token->text);
699 				valid = false;
700 			}
701 			state = VERSION_ENDLINE;
702 			break;
703 		default:
704 			mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
705 			                     token->location, token->text);
706 			valid = false;
707 			break;
708 		}
709 
710 		mTokenizer->lex(token);
711 	}
712 
713 	if (valid && (state != VERSION_ENDLINE))
714 	{
715 		mDiagnostics->report(Diagnostics::INVALID_VERSION_DIRECTIVE,
716 		                     token->location, token->text);
717 		valid = false;
718 	}
719 
720 	if (valid)
721 	{
722 		mDirectiveHandler->handleVersion(token->location, version);
723 	}
724 }
725 
parseLine(Token * token)726 void DirectiveParser::parseLine(Token* token)
727 {
728 	assert(getDirective(token) == DIRECTIVE_LINE);
729 
730 	enum State
731 	{
732 		LINE_NUMBER,
733 		FILE_NUMBER
734 	};
735 
736 	bool valid = true;
737 	int line = 0, file = 0;
738 	int state = LINE_NUMBER;
739 
740 	MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics, false);
741 	macroExpander.lex(token);
742 	while ((token->type != '\n') && (token->type != Token::LAST))
743 	{
744 		switch (state++)
745 		{
746 		case LINE_NUMBER:
747 			if (valid && (token->type != Token::CONST_INT))
748 			{
749 				mDiagnostics->report(Diagnostics::INVALID_LINE_NUMBER,
750 				                     token->location, token->text);
751 				valid = false;
752 			}
753 			if (valid && !token->iValue(&line))
754 			{
755 				mDiagnostics->report(Diagnostics::INTEGER_OVERFLOW,
756 				                     token->location, token->text);
757 				valid = false;
758 			}
759 			break;
760 		case FILE_NUMBER:
761 			if (valid && (token->type != Token::CONST_INT))
762 			{
763 				mDiagnostics->report(Diagnostics::INVALID_FILE_NUMBER,
764 				                     token->location, token->text);
765 				valid = false;
766 			}
767 			if (valid && !token->iValue(&file))
768 			{
769 				mDiagnostics->report(Diagnostics::INTEGER_OVERFLOW,
770 				                     token->location, token->text);
771 				valid = false;
772 			}
773 			break;
774 		default:
775 			if (valid)
776 			{
777 				mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
778 				                     token->location, token->text);
779 				valid = false;
780 			}
781 			break;
782 		}
783 		macroExpander.lex(token);
784 	}
785 
786 	if (valid && (state != FILE_NUMBER) && (state != FILE_NUMBER + 1))
787 	{
788 		mDiagnostics->report(Diagnostics::INVALID_LINE_DIRECTIVE,
789 		                     token->location, token->text);
790 		valid = false;
791 	}
792 	if (valid)
793 	{
794 		mTokenizer->setLineNumber(line);
795 		if (state == FILE_NUMBER + 1) mTokenizer->setFileNumber(file);
796 	}
797 }
798 
skipping() const799 bool DirectiveParser::skipping() const
800 {
801 	if (mConditionalStack.empty()) return false;
802 
803 	const ConditionalBlock& block = mConditionalStack.back();
804 	return block.skipBlock || block.skipGroup;
805 }
806 
parseConditionalIf(Token * token)807 void DirectiveParser::parseConditionalIf(Token* token)
808 {
809 	ConditionalBlock block;
810 	block.type = token->text;
811 	block.location = token->location;
812 
813 	if (skipping())
814 	{
815 		// This conditional block is inside another conditional group
816 		// which is skipped. As a consequence this whole block is skipped.
817 		// Be careful not to parse the conditional expression that might
818 		// emit a diagnostic.
819 		skipUntilEOD(mTokenizer, token);
820 		block.skipBlock = true;
821 	}
822 	else
823 	{
824 		DirectiveType directive = getDirective(token);
825 
826 		int expression = 0;
827 		switch (directive)
828 		{
829 		case DIRECTIVE_IF:
830 			expression = parseExpressionIf(token);
831 			break;
832 		case DIRECTIVE_IFDEF:
833 			expression = parseExpressionIfdef(token);
834 			break;
835 		case DIRECTIVE_IFNDEF:
836 			expression = parseExpressionIfdef(token) == 0 ? 1 : 0;
837 			break;
838 		default:
839 			assert(false);
840 			break;
841 		}
842 		block.skipGroup = expression == 0;
843 		block.foundValidGroup = expression != 0;
844 	}
845 	mConditionalStack.push_back(block);
846 }
847 
parseExpressionIf(Token * token)848 int DirectiveParser::parseExpressionIf(Token* token)
849 {
850 	assert((getDirective(token) == DIRECTIVE_IF) ||
851 	       (getDirective(token) == DIRECTIVE_ELIF));
852 
853 	MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics, true);
854 	ExpressionParser expressionParser(&macroExpander, mDiagnostics);
855 
856 	int expression = 0;
857 	macroExpander.lex(token);
858 	expressionParser.parse(token, &expression);
859 
860 	// Check if there are tokens after #if expression.
861 	if (!isEOD(token))
862 	{
863 		mDiagnostics->report(Diagnostics::CONDITIONAL_UNEXPECTED_TOKEN,
864 		                     token->location, token->text);
865 		skipUntilEOD(mTokenizer, token);
866 	}
867 
868 	return expression;
869 }
870 
parseExpressionIfdef(Token * token)871 int DirectiveParser::parseExpressionIfdef(Token* token)
872 {
873 	assert((getDirective(token) == DIRECTIVE_IFDEF) ||
874 		   (getDirective(token) == DIRECTIVE_IFNDEF));
875 
876 	mTokenizer->lex(token);
877 	if (token->type != Token::IDENTIFIER)
878 	{
879 		mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
880 		                     token->location, token->text);
881 		skipUntilEOD(mTokenizer, token);
882 		return 0;
883 	}
884 
885 	MacroSet::const_iterator iter = mMacroSet->find(token->text);
886 	int expression = iter != mMacroSet->end() ? 1 : 0;
887 
888 	// Check if there are tokens after #ifdef expression.
889 	mTokenizer->lex(token);
890 	if (!isEOD(token))
891 	{
892 		mDiagnostics->report(Diagnostics::CONDITIONAL_UNEXPECTED_TOKEN,
893 		                     token->location, token->text);
894 		skipUntilEOD(mTokenizer, token);
895 	}
896 	return expression;
897 }
898 
899 }  // namespace pp
900