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(¯oExpander, 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