Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / angle / src / compiler / preprocessor / DirectiveParser.cpp
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
39 DirectiveType getDirective(const pp::Token *token)
40 {
41     const char kDirectiveDefine[] = "define";
42     const char kDirectiveUndef[] = "undef";
43     const char kDirectiveIf[] = "if";
44     const char kDirectiveIfdef[] = "ifdef";
45     const char kDirectiveIfndef[] = "ifndef";
46     const char kDirectiveElse[] = "else";
47     const char kDirectiveElif[] = "elif";
48     const char kDirectiveEndif[] = "endif";
49     const char kDirectiveError[] = "error";
50     const char kDirectivePragma[] = "pragma";
51     const char kDirectiveExtension[] = "extension";
52     const char kDirectiveVersion[] = "version";
53     const char 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
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.
105 bool isEOD(const pp::Token *token)
106 {
107     return (token->type == '\n') || (token->type == pp::Token::LAST);
108 }
109
110 void skipUntilEOD(pp::Lexer *lexer, pp::Token *token)
111 {
112     while(!isEOD(token))
113     {
114         lexer->lex(token);
115     }
116 }
117
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
131 bool isMacroPredefined(const std::string &name,
132                        const pp::MacroSet &macroSet)
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:
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:
156     virtual void lex(Token *token)
157     {
158         const char 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
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
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
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
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
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
440 void DirectiveParser::parseIf(Token *token)
441 {
442     assert(getDirective(token) == DIRECTIVE_IF);
443     parseConditionalIf(token);
444 }
445
446 void DirectiveParser::parseIfdef(Token *token)
447 {
448     assert(getDirective(token) == DIRECTIVE_IFDEF);
449     parseConditionalIf(token);
450 }
451
452 void DirectiveParser::parseIfndef(Token *token)
453 {
454     assert(getDirective(token) == DIRECTIVE_IFNDEF);
455     parseConditionalIf(token);
456 }
457
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
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
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
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)].
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     bool stdgl = token->text == "STDGL";
596     if (stdgl)
597     {
598         mTokenizer->lex(token);
599     }
600     while ((token->type != '\n') && (token->type != Token::LAST))
601     {
602         switch(state++)
603         {
604           case PRAGMA_NAME:
605             name = token->text;
606             valid = valid && (token->type == Token::IDENTIFIER);
607             break;
608           case LEFT_PAREN:
609             valid = valid && (token->type == '(');
610             break;
611           case PRAGMA_VALUE:
612             value = token->text;
613             valid = valid && (token->type == Token::IDENTIFIER);
614             break;
615           case RIGHT_PAREN:
616             valid = valid && (token->type == ')');
617             break;
618           default:
619             valid = false;
620             break;
621         }
622         mTokenizer->lex(token);
623     }
624
625     valid = valid && ((state == PRAGMA_NAME) ||     // Empty pragma.
626                       (state == LEFT_PAREN) ||      // Without value.
627                       (state == RIGHT_PAREN + 1));  // With value.
628     if (!valid)
629     {
630         mDiagnostics->report(Diagnostics::PP_UNRECOGNIZED_PRAGMA,
631                              token->location, name);
632     }
633     else if (state > PRAGMA_NAME)  // Do not notify for empty pragma.
634     {
635         mDirectiveHandler->handlePragma(token->location, name, value, stdgl);
636     }
637 }
638
639 void DirectiveParser::parseExtension(Token *token)
640 {
641     assert(getDirective(token) == DIRECTIVE_EXTENSION);
642
643     enum State
644     {
645         EXT_NAME,
646         COLON,
647         EXT_BEHAVIOR
648     };
649
650     bool valid = true;
651     std::string name, behavior;
652     int state = EXT_NAME;
653
654     mTokenizer->lex(token);
655     while ((token->type != '\n') && (token->type != Token::LAST))
656     {
657         switch (state++)
658         {
659           case EXT_NAME:
660             if (valid && (token->type != Token::IDENTIFIER))
661             {
662                 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_NAME,
663                                      token->location, token->text);
664                 valid = false;
665             }
666             if (valid) name = token->text;
667             break;
668           case COLON:
669             if (valid && (token->type != ':'))
670             {
671                 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
672                                      token->location, token->text);
673                 valid = false;
674             }
675             break;
676           case EXT_BEHAVIOR:
677             if (valid && (token->type != Token::IDENTIFIER))
678             {
679                 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_BEHAVIOR,
680                                      token->location, token->text);
681                 valid = false;
682             }
683             if (valid) behavior = token->text;
684             break;
685           default:
686             if (valid)
687             {
688                 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
689                                      token->location, token->text);
690                 valid = false;
691             }
692             break;
693         }
694         mTokenizer->lex(token);
695     }
696     if (valid && (state != EXT_BEHAVIOR + 1))
697     {
698         mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_DIRECTIVE,
699                              token->location, token->text);
700         valid = false;
701     }
702     if (valid)
703         mDirectiveHandler->handleExtension(token->location, name, behavior);
704 }
705
706 void DirectiveParser::parseVersion(Token *token)
707 {
708     assert(getDirective(token) == DIRECTIVE_VERSION);
709
710     if (mPastFirstStatement)
711     {
712         mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_STATEMENT,
713                              token->location, token->text);
714         skipUntilEOD(mTokenizer, token);
715         return;
716     }
717
718     enum State
719     {
720         VERSION_NUMBER,
721         VERSION_PROFILE,
722         VERSION_ENDLINE
723     };
724
725     bool valid = true;
726     int version = 0;
727     int state = VERSION_NUMBER;
728
729     mTokenizer->lex(token);
730     while (valid && (token->type != '\n') && (token->type != Token::LAST))
731     {
732         switch (state)
733         {
734           case VERSION_NUMBER:
735             if (token->type != Token::CONST_INT)
736             {
737                 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_NUMBER,
738                                      token->location, token->text);
739                 valid = false;
740             }
741             if (valid && !token->iValue(&version))
742             {
743                 mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW,
744                                      token->location, token->text);
745                 valid = false;
746             }
747             if (valid)
748             {
749                 state = (version < 300) ? VERSION_ENDLINE : VERSION_PROFILE;
750             }
751             break;
752           case VERSION_PROFILE:
753             if (token->type != Token::IDENTIFIER || token->text != "es")
754             {
755                 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE,
756                                      token->location, token->text);
757                 valid = false;
758             }
759             state = VERSION_ENDLINE;
760             break;
761           default:
762             mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
763                                  token->location, token->text);
764             valid = false;
765             break;
766         }
767
768         mTokenizer->lex(token);
769     }
770
771     if (valid && (state != VERSION_ENDLINE))
772     {
773         mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE,
774                              token->location, token->text);
775         valid = false;
776     }
777
778     if (valid)
779     {
780         mDirectiveHandler->handleVersion(token->location, version);
781     }
782 }
783
784 void DirectiveParser::parseLine(Token *token)
785 {
786     assert(getDirective(token) == DIRECTIVE_LINE);
787
788     enum State
789     {
790         LINE_NUMBER,
791         FILE_NUMBER
792     };
793
794     bool valid = true;
795     int line = 0, file = 0;
796     int state = LINE_NUMBER;
797
798     MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics);
799     macroExpander.lex(token);
800     while ((token->type != '\n') && (token->type != Token::LAST))
801     {
802         switch (state++)
803         {
804           case LINE_NUMBER:
805             if (valid && (token->type != Token::CONST_INT))
806             {
807                 mDiagnostics->report(Diagnostics::PP_INVALID_LINE_NUMBER,
808                                      token->location, token->text);
809                 valid = false;
810             }
811             if (valid && !token->iValue(&line))
812             {
813                 mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW,
814                                      token->location, token->text);
815                 valid = false;
816             }
817             break;
818           case FILE_NUMBER:
819             if (valid && (token->type != Token::CONST_INT))
820             {
821                 mDiagnostics->report(Diagnostics::PP_INVALID_FILE_NUMBER,
822                                      token->location, token->text);
823                 valid = false;
824             }
825             if (valid && !token->iValue(&file))
826             {
827                 mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW,
828                                      token->location, token->text);
829                 valid = false;
830             }
831             break;
832           default:
833             if (valid)
834             {
835                 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
836                                      token->location, token->text);
837                 valid = false;
838             }
839             break;
840         }
841         macroExpander.lex(token);
842     }
843
844     if (valid && (state != FILE_NUMBER) && (state != FILE_NUMBER + 1))
845     {
846         mDiagnostics->report(Diagnostics::PP_INVALID_LINE_DIRECTIVE,
847                              token->location, token->text);
848         valid = false;
849     }
850     if (valid)
851     {
852         mTokenizer->setLineNumber(line);
853         if (state == FILE_NUMBER + 1)
854             mTokenizer->setFileNumber(file);
855     }
856 }
857
858 bool DirectiveParser::skipping() const
859 {
860     if (mConditionalStack.empty())
861         return false;
862
863     const ConditionalBlock& block = mConditionalStack.back();
864     return block.skipBlock || block.skipGroup;
865 }
866
867 void DirectiveParser::parseConditionalIf(Token *token)
868 {
869     ConditionalBlock block;
870     block.type = token->text;
871     block.location = token->location;
872
873     if (skipping())
874     {
875         // This conditional block is inside another conditional group
876         // which is skipped. As a consequence this whole block is skipped.
877         // Be careful not to parse the conditional expression that might
878         // emit a diagnostic.
879         skipUntilEOD(mTokenizer, token);
880         block.skipBlock = true;
881     }
882     else
883     {
884         DirectiveType directive = getDirective(token);
885
886         int expression = 0;
887         switch (directive)
888         {
889           case DIRECTIVE_IF:
890             expression = parseExpressionIf(token);
891             break;
892           case DIRECTIVE_IFDEF:
893             expression = parseExpressionIfdef(token);
894             break;
895           case DIRECTIVE_IFNDEF:
896             expression = parseExpressionIfdef(token) == 0 ? 1 : 0;
897             break;
898           default:
899             assert(false);
900             break;
901         }
902         block.skipGroup = expression == 0;
903         block.foundValidGroup = expression != 0;
904     }
905     mConditionalStack.push_back(block);
906 }
907
908 int DirectiveParser::parseExpressionIf(Token *token)
909 {
910     assert((getDirective(token) == DIRECTIVE_IF) ||
911            (getDirective(token) == DIRECTIVE_ELIF));
912
913     DefinedParser definedParser(mTokenizer, mMacroSet, mDiagnostics);
914     MacroExpander macroExpander(&definedParser, mMacroSet, mDiagnostics);
915     ExpressionParser expressionParser(&macroExpander, mDiagnostics);
916
917     int expression = 0;
918     macroExpander.lex(token);
919     expressionParser.parse(token, &expression);
920
921     // Warn if there are tokens after #if expression.
922     if (!isEOD(token))
923     {
924         mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
925                              token->location, token->text);
926         skipUntilEOD(mTokenizer, token);
927     }
928
929     return expression;
930 }
931
932 int DirectiveParser::parseExpressionIfdef(Token *token)
933 {
934     assert((getDirective(token) == DIRECTIVE_IFDEF) ||
935            (getDirective(token) == DIRECTIVE_IFNDEF));
936
937     mTokenizer->lex(token);
938     if (token->type != Token::IDENTIFIER)
939     {
940         mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
941                              token->location, token->text);
942         skipUntilEOD(mTokenizer, token);
943         return 0;
944     }
945
946     MacroSet::const_iterator iter = mMacroSet->find(token->text);
947     int expression = iter != mMacroSet->end() ? 1 : 0;
948
949     // Warn if there are tokens after #ifdef expression.
950     mTokenizer->lex(token);
951     if (!isEOD(token))
952     {
953         mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
954                              token->location, token->text);
955         skipUntilEOD(mTokenizer, token);
956     }
957     return expression;
958 }
959
960 }  // namespace pp