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