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