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