• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &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:
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(&macroExpander, 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