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