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 ¯oSet)
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(¯oExpander, 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(¯oExpander, 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