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.
7 #include "DirectiveParser.h"
13 #include "DiagnosticsBase.h"
14 #include "DirectiveHandlerBase.h"
15 #include "ExpressionParser.h"
16 #include "MacroExpander.h"
18 #include "Tokenizer.h"
39 DirectiveType getDirective(const pp::Token *token)
41 const char kDirectiveDefine[] = "define";
42 const char kDirectiveUndef[] = "undef";
43 const char kDirectiveIf[] = "if";
44 const char kDirectiveIfdef[] = "ifdef";
45 const char kDirectiveIfndef[] = "ifndef";
46 const char kDirectiveElse[] = "else";
47 const char kDirectiveElif[] = "elif";
48 const char kDirectiveEndif[] = "endif";
49 const char kDirectiveError[] = "error";
50 const char kDirectivePragma[] = "pragma";
51 const char kDirectiveExtension[] = "extension";
52 const char kDirectiveVersion[] = "version";
53 const char kDirectiveLine[] = "line";
55 if (token->type != pp::Token::IDENTIFIER)
56 return DIRECTIVE_NONE;
58 if (token->text == kDirectiveDefine)
59 return DIRECTIVE_DEFINE;
60 if (token->text == kDirectiveUndef)
61 return DIRECTIVE_UNDEF;
62 if (token->text == kDirectiveIf)
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;
85 return DIRECTIVE_NONE;
88 bool isConditionalDirective(DirectiveType directive)
94 case DIRECTIVE_IFNDEF:
104 // Returns true if the token represents End Of Directive.
105 bool isEOD(const pp::Token *token)
107 return (token->type == '\n') || (token->type == pp::Token::LAST);
110 void skipUntilEOD(pp::Lexer *lexer, pp::Token *token)
118 bool isMacroNameReserved(const std::string &name)
120 // Names prefixed with "GL_" are reserved.
121 if (name.substr(0, 3) == "GL_")
124 // Names containing two consecutive underscores are reserved.
125 if (name.find("__") != std::string::npos)
131 bool isMacroPredefined(const std::string &name,
132 const pp::MacroSet ¯oSet)
134 pp::MacroSet::const_iterator iter = macroSet.find(name);
135 return iter != macroSet.end() ? iter->second.predefined : false;
138 } // namespace anonymous
143 class DefinedParser : public Lexer
146 DefinedParser(Lexer *lexer,
147 const MacroSet *macroSet,
148 Diagnostics *diagnostics)
151 mDiagnostics(diagnostics)
156 virtual void lex(Token *token)
158 const char kDefined[] = "defined";
161 if (token->type != Token::IDENTIFIER)
163 if (token->text != kDefined)
168 if (token->type == '(')
174 if (token->type != Token::IDENTIFIER)
176 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
177 token->location, token->text);
178 skipUntilEOD(mLexer, token);
181 MacroSet::const_iterator iter = mMacroSet->find(token->text);
182 std::string expression = iter != mMacroSet->end() ? "1" : "0";
187 if (token->type != ')')
189 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
190 token->location, token->text);
191 skipUntilEOD(mLexer, token);
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;
204 const MacroSet *mMacroSet;
205 Diagnostics *mDiagnostics;
208 DirectiveParser::DirectiveParser(Tokenizer *tokenizer,
210 Diagnostics *diagnostics,
211 DirectiveHandler *directiveHandler)
212 : mPastFirstStatement(false),
213 mTokenizer(tokenizer),
215 mDiagnostics(diagnostics),
216 mDirectiveHandler(directiveHandler)
220 void DirectiveParser::lex(Token *token)
224 mTokenizer->lex(token);
226 if (token->type == Token::PP_HASH)
228 parseDirective(token);
229 mPastFirstStatement = true;
232 if (token->type == Token::LAST)
234 if (!mConditionalStack.empty())
236 const ConditionalBlock &block = mConditionalStack.back();
237 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNTERMINATED,
238 block.location, block.type);
244 while (skipping() || (token->type == '\n'));
246 mPastFirstStatement = true;
249 void DirectiveParser::parseDirective(Token *token)
251 assert(token->type == Token::PP_HASH);
253 mTokenizer->lex(token);
260 DirectiveType directive = getDirective(token);
262 // While in an excluded conditional block/group,
263 // we only parse conditional directives.
264 if (skipping() && !isConditionalDirective(directive))
266 skipUntilEOD(mTokenizer, token);
273 mDiagnostics->report(Diagnostics::PP_DIRECTIVE_INVALID_NAME,
274 token->location, token->text);
275 skipUntilEOD(mTokenizer, token);
277 case DIRECTIVE_DEFINE:
280 case DIRECTIVE_UNDEF:
286 case DIRECTIVE_IFDEF:
289 case DIRECTIVE_IFNDEF:
298 case DIRECTIVE_ENDIF:
301 case DIRECTIVE_ERROR:
304 case DIRECTIVE_PRAGMA:
307 case DIRECTIVE_EXTENSION:
308 parseExtension(token);
310 case DIRECTIVE_VERSION:
321 skipUntilEOD(mTokenizer, token);
322 if (token->type == Token::LAST)
324 mDiagnostics->report(Diagnostics::PP_EOF_IN_DIRECTIVE,
325 token->location, token->text);
329 void DirectiveParser::parseDefine(Token *token)
331 assert(getDirective(token) == DIRECTIVE_DEFINE);
333 mTokenizer->lex(token);
334 if (token->type != Token::IDENTIFIER)
336 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
337 token->location, token->text);
340 if (isMacroPredefined(token->text, *mMacroSet))
342 mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_REDEFINED,
343 token->location, token->text);
346 if (isMacroNameReserved(token->text))
348 mDiagnostics->report(Diagnostics::PP_MACRO_NAME_RESERVED,
349 token->location, token->text);
354 macro.type = Macro::kTypeObj;
355 macro.name = token->text;
357 mTokenizer->lex(token);
358 if (token->type == '(' && !token->hasLeadingSpace())
360 // Function-like macro. Collect arguments.
361 macro.type = Macro::kTypeFunc;
364 mTokenizer->lex(token);
365 if (token->type != Token::IDENTIFIER)
367 macro.parameters.push_back(token->text);
369 mTokenizer->lex(token); // Get ','.
371 while (token->type == ',');
373 if (token->type != ')')
375 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
380 mTokenizer->lex(token); // Get ')'.
383 while ((token->type != '\n') && (token->type != Token::LAST))
385 // Reset the token location because it is unnecessary in replacement
386 // list. Resetting it also allows us to reuse Token::equals() to
388 token->location = SourceLocation();
389 macro.replacements.push_back(*token);
390 mTokenizer->lex(token);
392 if (!macro.replacements.empty())
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);
399 // Check for macro redefinition.
400 MacroSet::const_iterator iter = mMacroSet->find(macro.name);
401 if (iter != mMacroSet->end() && !macro.equals(iter->second))
403 mDiagnostics->report(Diagnostics::PP_MACRO_REDEFINED,
408 mMacroSet->insert(std::make_pair(macro.name, macro));
411 void DirectiveParser::parseUndef(Token *token)
413 assert(getDirective(token) == DIRECTIVE_UNDEF);
415 mTokenizer->lex(token);
416 if (token->type != Token::IDENTIFIER)
418 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
419 token->location, token->text);
423 MacroSet::iterator iter = mMacroSet->find(token->text);
424 if (iter != mMacroSet->end())
426 if (iter->second.predefined)
428 mDiagnostics->report(Diagnostics::PP_MACRO_PREDEFINED_UNDEFINED,
429 token->location, token->text);
433 mMacroSet->erase(iter);
437 mTokenizer->lex(token);
440 void DirectiveParser::parseIf(Token *token)
442 assert(getDirective(token) == DIRECTIVE_IF);
443 parseConditionalIf(token);
446 void DirectiveParser::parseIfdef(Token *token)
448 assert(getDirective(token) == DIRECTIVE_IFDEF);
449 parseConditionalIf(token);
452 void DirectiveParser::parseIfndef(Token *token)
454 assert(getDirective(token) == DIRECTIVE_IFNDEF);
455 parseConditionalIf(token);
458 void DirectiveParser::parseElse(Token *token)
460 assert(getDirective(token) == DIRECTIVE_ELSE);
462 if (mConditionalStack.empty())
464 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_WITHOUT_IF,
465 token->location, token->text);
466 skipUntilEOD(mTokenizer, token);
470 ConditionalBlock &block = mConditionalStack.back();
473 // No diagnostics. Just skip the whole line.
474 skipUntilEOD(mTokenizer, token);
477 if (block.foundElseGroup)
479 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELSE_AFTER_ELSE,
480 token->location, token->text);
481 skipUntilEOD(mTokenizer, token);
485 block.foundElseGroup = true;
486 block.skipGroup = block.foundValidGroup;
487 block.foundValidGroup = true;
489 // Warn if there are extra tokens after #else.
490 mTokenizer->lex(token);
493 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
494 token->location, token->text);
495 skipUntilEOD(mTokenizer, token);
499 void DirectiveParser::parseElif(Token *token)
501 assert(getDirective(token) == DIRECTIVE_ELIF);
503 if (mConditionalStack.empty())
505 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_WITHOUT_IF,
506 token->location, token->text);
507 skipUntilEOD(mTokenizer, token);
511 ConditionalBlock &block = mConditionalStack.back();
514 // No diagnostics. Just skip the whole line.
515 skipUntilEOD(mTokenizer, token);
518 if (block.foundElseGroup)
520 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ELIF_AFTER_ELSE,
521 token->location, token->text);
522 skipUntilEOD(mTokenizer, token);
525 if (block.foundValidGroup)
527 // Do not parse the expression.
528 // Also be careful not to emit a diagnostic.
529 block.skipGroup = true;
530 skipUntilEOD(mTokenizer, token);
534 int expression = parseExpressionIf(token);
535 block.skipGroup = expression == 0;
536 block.foundValidGroup = expression != 0;
539 void DirectiveParser::parseEndif(Token *token)
541 assert(getDirective(token) == DIRECTIVE_ENDIF);
543 if (mConditionalStack.empty())
545 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_ENDIF_WITHOUT_IF,
546 token->location, token->text);
547 skipUntilEOD(mTokenizer, token);
551 mConditionalStack.pop_back();
553 // Warn if there are tokens after #endif.
554 mTokenizer->lex(token);
557 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
558 token->location, token->text);
559 skipUntilEOD(mTokenizer, token);
563 void DirectiveParser::parseError(Token *token)
565 assert(getDirective(token) == DIRECTIVE_ERROR);
567 std::ostringstream stream;
568 mTokenizer->lex(token);
569 while ((token->type != '\n') && (token->type != Token::LAST))
572 mTokenizer->lex(token);
574 mDirectiveHandler->handleError(token->location, stream.str());
577 // Parses pragma of form: #pragma name[(value)].
578 void DirectiveParser::parsePragma(Token *token)
580 assert(getDirective(token) == DIRECTIVE_PRAGMA);
591 std::string name, value;
592 int state = PRAGMA_NAME;
594 mTokenizer->lex(token);
595 bool stdgl = token->text == "STDGL";
598 mTokenizer->lex(token);
600 while ((token->type != '\n') && (token->type != Token::LAST))
606 valid = valid && (token->type == Token::IDENTIFIER);
609 valid = valid && (token->type == '(');
613 valid = valid && (token->type == Token::IDENTIFIER);
616 valid = valid && (token->type == ')');
622 mTokenizer->lex(token);
625 valid = valid && ((state == PRAGMA_NAME) || // Empty pragma.
626 (state == LEFT_PAREN) || // Without value.
627 (state == RIGHT_PAREN + 1)); // With value.
630 mDiagnostics->report(Diagnostics::PP_UNRECOGNIZED_PRAGMA,
631 token->location, name);
633 else if (state > PRAGMA_NAME) // Do not notify for empty pragma.
635 mDirectiveHandler->handlePragma(token->location, name, value, stdgl);
639 void DirectiveParser::parseExtension(Token *token)
641 assert(getDirective(token) == DIRECTIVE_EXTENSION);
651 std::string name, behavior;
652 int state = EXT_NAME;
654 mTokenizer->lex(token);
655 while ((token->type != '\n') && (token->type != Token::LAST))
660 if (valid && (token->type != Token::IDENTIFIER))
662 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_NAME,
663 token->location, token->text);
666 if (valid) name = token->text;
669 if (valid && (token->type != ':'))
671 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
672 token->location, token->text);
677 if (valid && (token->type != Token::IDENTIFIER))
679 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_BEHAVIOR,
680 token->location, token->text);
683 if (valid) behavior = token->text;
688 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
689 token->location, token->text);
694 mTokenizer->lex(token);
696 if (valid && (state != EXT_BEHAVIOR + 1))
698 mDiagnostics->report(Diagnostics::PP_INVALID_EXTENSION_DIRECTIVE,
699 token->location, token->text);
703 mDirectiveHandler->handleExtension(token->location, name, behavior);
706 void DirectiveParser::parseVersion(Token *token)
708 assert(getDirective(token) == DIRECTIVE_VERSION);
710 if (mPastFirstStatement)
712 mDiagnostics->report(Diagnostics::PP_VERSION_NOT_FIRST_STATEMENT,
713 token->location, token->text);
714 skipUntilEOD(mTokenizer, token);
727 int state = VERSION_NUMBER;
729 mTokenizer->lex(token);
730 while (valid && (token->type != '\n') && (token->type != Token::LAST))
735 if (token->type != Token::CONST_INT)
737 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_NUMBER,
738 token->location, token->text);
741 if (valid && !token->iValue(&version))
743 mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW,
744 token->location, token->text);
749 state = (version < 300) ? VERSION_ENDLINE : VERSION_PROFILE;
752 case VERSION_PROFILE:
753 if (token->type != Token::IDENTIFIER || token->text != "es")
755 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE,
756 token->location, token->text);
759 state = VERSION_ENDLINE;
762 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
763 token->location, token->text);
768 mTokenizer->lex(token);
771 if (valid && (state != VERSION_ENDLINE))
773 mDiagnostics->report(Diagnostics::PP_INVALID_VERSION_DIRECTIVE,
774 token->location, token->text);
780 mDirectiveHandler->handleVersion(token->location, version);
784 void DirectiveParser::parseLine(Token *token)
786 assert(getDirective(token) == DIRECTIVE_LINE);
795 int line = 0, file = 0;
796 int state = LINE_NUMBER;
798 MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics);
799 macroExpander.lex(token);
800 while ((token->type != '\n') && (token->type != Token::LAST))
805 if (valid && (token->type != Token::CONST_INT))
807 mDiagnostics->report(Diagnostics::PP_INVALID_LINE_NUMBER,
808 token->location, token->text);
811 if (valid && !token->iValue(&line))
813 mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW,
814 token->location, token->text);
819 if (valid && (token->type != Token::CONST_INT))
821 mDiagnostics->report(Diagnostics::PP_INVALID_FILE_NUMBER,
822 token->location, token->text);
825 if (valid && !token->iValue(&file))
827 mDiagnostics->report(Diagnostics::PP_INTEGER_OVERFLOW,
828 token->location, token->text);
835 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
836 token->location, token->text);
841 macroExpander.lex(token);
844 if (valid && (state != FILE_NUMBER) && (state != FILE_NUMBER + 1))
846 mDiagnostics->report(Diagnostics::PP_INVALID_LINE_DIRECTIVE,
847 token->location, token->text);
852 mTokenizer->setLineNumber(line);
853 if (state == FILE_NUMBER + 1)
854 mTokenizer->setFileNumber(file);
858 bool DirectiveParser::skipping() const
860 if (mConditionalStack.empty())
863 const ConditionalBlock& block = mConditionalStack.back();
864 return block.skipBlock || block.skipGroup;
867 void DirectiveParser::parseConditionalIf(Token *token)
869 ConditionalBlock block;
870 block.type = token->text;
871 block.location = token->location;
875 // This conditional block is inside another conditional group
876 // which is skipped. As a consequence this whole block is skipped.
877 // Be careful not to parse the conditional expression that might
878 // emit a diagnostic.
879 skipUntilEOD(mTokenizer, token);
880 block.skipBlock = true;
884 DirectiveType directive = getDirective(token);
890 expression = parseExpressionIf(token);
892 case DIRECTIVE_IFDEF:
893 expression = parseExpressionIfdef(token);
895 case DIRECTIVE_IFNDEF:
896 expression = parseExpressionIfdef(token) == 0 ? 1 : 0;
902 block.skipGroup = expression == 0;
903 block.foundValidGroup = expression != 0;
905 mConditionalStack.push_back(block);
908 int DirectiveParser::parseExpressionIf(Token *token)
910 assert((getDirective(token) == DIRECTIVE_IF) ||
911 (getDirective(token) == DIRECTIVE_ELIF));
913 DefinedParser definedParser(mTokenizer, mMacroSet, mDiagnostics);
914 MacroExpander macroExpander(&definedParser, mMacroSet, mDiagnostics);
915 ExpressionParser expressionParser(¯oExpander, mDiagnostics);
918 macroExpander.lex(token);
919 expressionParser.parse(token, &expression);
921 // Warn if there are tokens after #if expression.
924 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
925 token->location, token->text);
926 skipUntilEOD(mTokenizer, token);
932 int DirectiveParser::parseExpressionIfdef(Token *token)
934 assert((getDirective(token) == DIRECTIVE_IFDEF) ||
935 (getDirective(token) == DIRECTIVE_IFNDEF));
937 mTokenizer->lex(token);
938 if (token->type != Token::IDENTIFIER)
940 mDiagnostics->report(Diagnostics::PP_UNEXPECTED_TOKEN,
941 token->location, token->text);
942 skipUntilEOD(mTokenizer, token);
946 MacroSet::const_iterator iter = mMacroSet->find(token->text);
947 int expression = iter != mMacroSet->end() ? 1 : 0;
949 // Warn if there are tokens after #ifdef expression.
950 mTokenizer->lex(token);
953 mDiagnostics->report(Diagnostics::PP_CONDITIONAL_UNEXPECTED_TOKEN,
954 token->location, token->text);
955 skipUntilEOD(mTokenizer, token);