1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/angle/src/compiler/preprocessor/DirectiveParser.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,932 @@ 1.4 +// 1.5 +// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved. 1.6 +// Use of this source code is governed by a BSD-style license that can be 1.7 +// found in the LICENSE file. 1.8 +// 1.9 + 1.10 +#include "DirectiveParser.h" 1.11 + 1.12 +#include <cassert> 1.13 +#include <cstdlib> 1.14 +#include <sstream> 1.15 + 1.16 +#include "DiagnosticsBase.h" 1.17 +#include "DirectiveHandlerBase.h" 1.18 +#include "ExpressionParser.h" 1.19 +#include "MacroExpander.h" 1.20 +#include "Token.h" 1.21 +#include "Tokenizer.h" 1.22 + 1.23 +namespace { 1.24 +enum DirectiveType 1.25 +{ 1.26 + DIRECTIVE_NONE, 1.27 + DIRECTIVE_DEFINE, 1.28 + DIRECTIVE_UNDEF, 1.29 + DIRECTIVE_IF, 1.30 + DIRECTIVE_IFDEF, 1.31 + DIRECTIVE_IFNDEF, 1.32 + DIRECTIVE_ELSE, 1.33 + DIRECTIVE_ELIF, 1.34 + DIRECTIVE_ENDIF, 1.35 + DIRECTIVE_ERROR, 1.36 + DIRECTIVE_PRAGMA, 1.37 + DIRECTIVE_EXTENSION, 1.38 + DIRECTIVE_VERSION, 1.39 + DIRECTIVE_LINE 1.40 +}; 1.41 +} // namespace 1.42 + 1.43 +static DirectiveType getDirective(const pp::Token* token) 1.44 +{ 1.45 + static const std::string kDirectiveDefine("define"); 1.46 + static const std::string kDirectiveUndef("undef"); 1.47 + static const std::string kDirectiveIf("if"); 1.48 + static const std::string kDirectiveIfdef("ifdef"); 1.49 + static const std::string kDirectiveIfndef("ifndef"); 1.50 + static const std::string kDirectiveElse("else"); 1.51 + static const std::string kDirectiveElif("elif"); 1.52 + static const std::string kDirectiveEndif("endif"); 1.53 + static const std::string kDirectiveError("error"); 1.54 + static const std::string kDirectivePragma("pragma"); 1.55 + static const std::string kDirectiveExtension("extension"); 1.56 + static const std::string kDirectiveVersion("version"); 1.57 + static const std::string kDirectiveLine("line"); 1.58 + 1.59 + if (token->type != pp::Token::IDENTIFIER) 1.60 + return DIRECTIVE_NONE; 1.61 + 1.62 + if (token->text == kDirectiveDefine) 1.63 + return DIRECTIVE_DEFINE; 1.64 + else if (token->text == kDirectiveUndef) 1.65 + return DIRECTIVE_UNDEF; 1.66 + else if (token->text == kDirectiveIf) 1.67 + return DIRECTIVE_IF; 1.68 + else if (token->text == kDirectiveIfdef) 1.69 + return DIRECTIVE_IFDEF; 1.70 + else if (token->text == kDirectiveIfndef) 1.71 + return DIRECTIVE_IFNDEF; 1.72 + else if (token->text == kDirectiveElse) 1.73 + return DIRECTIVE_ELSE; 1.74 + else if (token->text == kDirectiveElif) 1.75 + return DIRECTIVE_ELIF; 1.76 + else if (token->text == kDirectiveEndif) 1.77 + return DIRECTIVE_ENDIF; 1.78 + else if (token->text == kDirectiveError) 1.79 + return DIRECTIVE_ERROR; 1.80 + else if (token->text == kDirectivePragma) 1.81 + return DIRECTIVE_PRAGMA; 1.82 + else if (token->text == kDirectiveExtension) 1.83 + return DIRECTIVE_EXTENSION; 1.84 + else if (token->text == kDirectiveVersion) 1.85 + return DIRECTIVE_VERSION; 1.86 + else if (token->text == kDirectiveLine) 1.87 + return DIRECTIVE_LINE; 1.88 + 1.89 + return DIRECTIVE_NONE; 1.90 +} 1.91 + 1.92 +static bool isConditionalDirective(DirectiveType directive) 1.93 +{ 1.94 + switch (directive) 1.95 + { 1.96 + case DIRECTIVE_IF: 1.97 + case DIRECTIVE_IFDEF: 1.98 + case DIRECTIVE_IFNDEF: 1.99 + case DIRECTIVE_ELSE: 1.100 + case DIRECTIVE_ELIF: 1.101 + case DIRECTIVE_ENDIF: 1.102 + return true; 1.103 + default: 1.104 + return false; 1.105 + } 1.106 +} 1.107 + 1.108 +// Returns true if the token represents End Of Directive. 1.109 +static bool isEOD(const pp::Token* token) 1.110 +{ 1.111 + return (token->type == '\n') || (token->type == pp::Token::LAST); 1.112 +} 1.113 + 1.114 +static void skipUntilEOD(pp::Lexer* lexer, pp::Token* token) 1.115 +{ 1.116 + while(!isEOD(token)) 1.117 + { 1.118 + lexer->lex(token); 1.119 + } 1.120 +} 1.121 + 1.122 +static bool isMacroNameReserved(const std::string& name) 1.123 +{ 1.124 + // Names prefixed with "GL_" are reserved. 1.125 + if (name.substr(0, 3) == "GL_") 1.126 + return true; 1.127 + 1.128 + // Names containing two consecutive underscores are reserved. 1.129 + if (name.find("__") != std::string::npos) 1.130 + return true; 1.131 + 1.132 + return false; 1.133 +} 1.134 + 1.135 +static bool isMacroPredefined(const std::string& name, 1.136 + const pp::MacroSet& macroSet) 1.137 +{ 1.138 + pp::MacroSet::const_iterator iter = macroSet.find(name); 1.139 + return iter != macroSet.end() ? iter->second.predefined : false; 1.140 +} 1.141 + 1.142 +namespace pp 1.143 +{ 1.144 + 1.145 +class DefinedParser : public Lexer 1.146 +{ 1.147 + public: 1.148 + DefinedParser(Lexer* lexer, 1.149 + const MacroSet* macroSet, 1.150 + Diagnostics* diagnostics) : 1.151 + mLexer(lexer), 1.152 + mMacroSet(macroSet), 1.153 + mDiagnostics(diagnostics) 1.154 + { 1.155 + } 1.156 + 1.157 + protected: 1.158 + virtual void lex(Token* token) 1.159 + { 1.160 + static const std::string kDefined("defined"); 1.161 + 1.162 + mLexer->lex(token); 1.163 + if (token->type != Token::IDENTIFIER) 1.164 + return; 1.165 + if (token->text != kDefined) 1.166 + return; 1.167 + 1.168 + bool paren = false; 1.169 + mLexer->lex(token); 1.170 + if (token->type == '(') 1.171 + { 1.172 + paren = true; 1.173 + mLexer->lex(token); 1.174 + } 1.175 + 1.176 + if (token->type != Token::IDENTIFIER) 1.177 + { 1.178 + mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN, 1.179 + token->location, token->text); 1.180 + skipUntilEOD(mLexer, token); 1.181 + return; 1.182 + } 1.183 + MacroSet::const_iterator iter = mMacroSet->find(token->text); 1.184 + std::string expression = iter != mMacroSet->end() ? "1" : "0"; 1.185 + 1.186 + if (paren) 1.187 + { 1.188 + mLexer->lex(token); 1.189 + if (token->type != ')') 1.190 + { 1.191 + mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN, 1.192 + token->location, token->text); 1.193 + skipUntilEOD(mLexer, token); 1.194 + return; 1.195 + } 1.196 + } 1.197 + 1.198 + // We have a valid defined operator. 1.199 + // Convert the current token into a CONST_INT token. 1.200 + token->type = Token::CONST_INT; 1.201 + token->text = expression; 1.202 + } 1.203 + 1.204 + private: 1.205 + Lexer* mLexer; 1.206 + const MacroSet* mMacroSet; 1.207 + Diagnostics* mDiagnostics; 1.208 +}; 1.209 + 1.210 +DirectiveParser::DirectiveParser(Tokenizer* tokenizer, 1.211 + MacroSet* macroSet, 1.212 + Diagnostics* diagnostics, 1.213 + DirectiveHandler* directiveHandler) : 1.214 + mPastFirstStatement(false), 1.215 + mTokenizer(tokenizer), 1.216 + mMacroSet(macroSet), 1.217 + mDiagnostics(diagnostics), 1.218 + mDirectiveHandler(directiveHandler) 1.219 +{ 1.220 +} 1.221 + 1.222 +void DirectiveParser::lex(Token* token) 1.223 +{ 1.224 + do 1.225 + { 1.226 + mTokenizer->lex(token); 1.227 + 1.228 + if (token->type == Token::PP_HASH) 1.229 + { 1.230 + parseDirective(token); 1.231 + mPastFirstStatement = true; 1.232 + } 1.233 + 1.234 + if (token->type == Token::LAST) 1.235 + { 1.236 + if (!mConditionalStack.empty()) 1.237 + { 1.238 + const ConditionalBlock& block = mConditionalStack.back(); 1.239 + mDiagnostics->report(Diagnostics::CONDITIONAL_UNTERMINATED, 1.240 + block.location, block.type); 1.241 + } 1.242 + break; 1.243 + } 1.244 + 1.245 + } while (skipping() || (token->type == '\n')); 1.246 + 1.247 + mPastFirstStatement = true; 1.248 +} 1.249 + 1.250 +void DirectiveParser::parseDirective(Token* token) 1.251 +{ 1.252 + assert(token->type == Token::PP_HASH); 1.253 + 1.254 + mTokenizer->lex(token); 1.255 + if (isEOD(token)) 1.256 + { 1.257 + // Empty Directive. 1.258 + return; 1.259 + } 1.260 + 1.261 + DirectiveType directive = getDirective(token); 1.262 + 1.263 + // While in an excluded conditional block/group, 1.264 + // we only parse conditional directives. 1.265 + if (skipping() && !isConditionalDirective(directive)) 1.266 + { 1.267 + skipUntilEOD(mTokenizer, token); 1.268 + return; 1.269 + } 1.270 + 1.271 + switch(directive) 1.272 + { 1.273 + case DIRECTIVE_NONE: 1.274 + mDiagnostics->report(Diagnostics::DIRECTIVE_INVALID_NAME, 1.275 + token->location, token->text); 1.276 + skipUntilEOD(mTokenizer, token); 1.277 + break; 1.278 + case DIRECTIVE_DEFINE: 1.279 + parseDefine(token); 1.280 + break; 1.281 + case DIRECTIVE_UNDEF: 1.282 + parseUndef(token); 1.283 + break; 1.284 + case DIRECTIVE_IF: 1.285 + parseIf(token); 1.286 + break; 1.287 + case DIRECTIVE_IFDEF: 1.288 + parseIfdef(token); 1.289 + break; 1.290 + case DIRECTIVE_IFNDEF: 1.291 + parseIfndef(token); 1.292 + break; 1.293 + case DIRECTIVE_ELSE: 1.294 + parseElse(token); 1.295 + break; 1.296 + case DIRECTIVE_ELIF: 1.297 + parseElif(token); 1.298 + break; 1.299 + case DIRECTIVE_ENDIF: 1.300 + parseEndif(token); 1.301 + break; 1.302 + case DIRECTIVE_ERROR: 1.303 + parseError(token); 1.304 + break; 1.305 + case DIRECTIVE_PRAGMA: 1.306 + parsePragma(token); 1.307 + break; 1.308 + case DIRECTIVE_EXTENSION: 1.309 + parseExtension(token); 1.310 + break; 1.311 + case DIRECTIVE_VERSION: 1.312 + parseVersion(token); 1.313 + break; 1.314 + case DIRECTIVE_LINE: 1.315 + parseLine(token); 1.316 + break; 1.317 + default: 1.318 + assert(false); 1.319 + break; 1.320 + } 1.321 + 1.322 + skipUntilEOD(mTokenizer, token); 1.323 + if (token->type == Token::LAST) 1.324 + { 1.325 + mDiagnostics->report(Diagnostics::EOF_IN_DIRECTIVE, 1.326 + token->location, token->text); 1.327 + } 1.328 +} 1.329 + 1.330 +void DirectiveParser::parseDefine(Token* token) 1.331 +{ 1.332 + assert(getDirective(token) == DIRECTIVE_DEFINE); 1.333 + 1.334 + mTokenizer->lex(token); 1.335 + if (token->type != Token::IDENTIFIER) 1.336 + { 1.337 + mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN, 1.338 + token->location, token->text); 1.339 + return; 1.340 + } 1.341 + if (isMacroPredefined(token->text, *mMacroSet)) 1.342 + { 1.343 + mDiagnostics->report(Diagnostics::MACRO_PREDEFINED_REDEFINED, 1.344 + token->location, token->text); 1.345 + return; 1.346 + } 1.347 + if (isMacroNameReserved(token->text)) 1.348 + { 1.349 + mDiagnostics->report(Diagnostics::MACRO_NAME_RESERVED, 1.350 + token->location, token->text); 1.351 + return; 1.352 + } 1.353 + 1.354 + Macro macro; 1.355 + macro.type = Macro::kTypeObj; 1.356 + macro.name = token->text; 1.357 + 1.358 + mTokenizer->lex(token); 1.359 + if (token->type == '(' && !token->hasLeadingSpace()) 1.360 + { 1.361 + // Function-like macro. Collect arguments. 1.362 + macro.type = Macro::kTypeFunc; 1.363 + do { 1.364 + mTokenizer->lex(token); 1.365 + if (token->type != Token::IDENTIFIER) 1.366 + break; 1.367 + macro.parameters.push_back(token->text); 1.368 + 1.369 + mTokenizer->lex(token); // Get ','. 1.370 + } while (token->type == ','); 1.371 + 1.372 + if (token->type != ')') 1.373 + { 1.374 + mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN, 1.375 + token->location, 1.376 + token->text); 1.377 + return; 1.378 + } 1.379 + mTokenizer->lex(token); // Get ')'. 1.380 + } 1.381 + 1.382 + while ((token->type != '\n') && (token->type != Token::LAST)) 1.383 + { 1.384 + // Reset the token location because it is unnecessary in replacement 1.385 + // list. Resetting it also allows us to reuse Token::equals() to 1.386 + // compare macros. 1.387 + token->location = SourceLocation(); 1.388 + macro.replacements.push_back(*token); 1.389 + mTokenizer->lex(token); 1.390 + } 1.391 + if (!macro.replacements.empty()) 1.392 + { 1.393 + // Whitespace preceding the replacement list is not considered part of 1.394 + // the replacement list for either form of macro. 1.395 + macro.replacements.front().setHasLeadingSpace(false); 1.396 + } 1.397 + 1.398 + // Check for macro redefinition. 1.399 + MacroSet::const_iterator iter = mMacroSet->find(macro.name); 1.400 + if (iter != mMacroSet->end() && !macro.equals(iter->second)) 1.401 + { 1.402 + mDiagnostics->report(Diagnostics::MACRO_REDEFINED, 1.403 + token->location, 1.404 + macro.name); 1.405 + return; 1.406 + } 1.407 + mMacroSet->insert(std::make_pair(macro.name, macro)); 1.408 +} 1.409 + 1.410 +void DirectiveParser::parseUndef(Token* token) 1.411 +{ 1.412 + assert(getDirective(token) == DIRECTIVE_UNDEF); 1.413 + 1.414 + mTokenizer->lex(token); 1.415 + if (token->type != Token::IDENTIFIER) 1.416 + { 1.417 + mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN, 1.418 + token->location, token->text); 1.419 + return; 1.420 + } 1.421 + 1.422 + MacroSet::iterator iter = mMacroSet->find(token->text); 1.423 + if (iter != mMacroSet->end()) 1.424 + { 1.425 + if (iter->second.predefined) 1.426 + { 1.427 + mDiagnostics->report(Diagnostics::MACRO_PREDEFINED_UNDEFINED, 1.428 + token->location, token->text); 1.429 + } 1.430 + else 1.431 + { 1.432 + mMacroSet->erase(iter); 1.433 + } 1.434 + } 1.435 + 1.436 + mTokenizer->lex(token); 1.437 +} 1.438 + 1.439 +void DirectiveParser::parseIf(Token* token) 1.440 +{ 1.441 + assert(getDirective(token) == DIRECTIVE_IF); 1.442 + parseConditionalIf(token); 1.443 +} 1.444 + 1.445 +void DirectiveParser::parseIfdef(Token* token) 1.446 +{ 1.447 + assert(getDirective(token) == DIRECTIVE_IFDEF); 1.448 + parseConditionalIf(token); 1.449 +} 1.450 + 1.451 +void DirectiveParser::parseIfndef(Token* token) 1.452 +{ 1.453 + assert(getDirective(token) == DIRECTIVE_IFNDEF); 1.454 + parseConditionalIf(token); 1.455 +} 1.456 + 1.457 +void DirectiveParser::parseElse(Token* token) 1.458 +{ 1.459 + assert(getDirective(token) == DIRECTIVE_ELSE); 1.460 + 1.461 + if (mConditionalStack.empty()) 1.462 + { 1.463 + mDiagnostics->report(Diagnostics::CONDITIONAL_ELSE_WITHOUT_IF, 1.464 + token->location, token->text); 1.465 + skipUntilEOD(mTokenizer, token); 1.466 + return; 1.467 + } 1.468 + 1.469 + ConditionalBlock& block = mConditionalStack.back(); 1.470 + if (block.skipBlock) 1.471 + { 1.472 + // No diagnostics. Just skip the whole line. 1.473 + skipUntilEOD(mTokenizer, token); 1.474 + return; 1.475 + } 1.476 + if (block.foundElseGroup) 1.477 + { 1.478 + mDiagnostics->report(Diagnostics::CONDITIONAL_ELSE_AFTER_ELSE, 1.479 + token->location, token->text); 1.480 + skipUntilEOD(mTokenizer, token); 1.481 + return; 1.482 + } 1.483 + 1.484 + block.foundElseGroup = true; 1.485 + block.skipGroup = block.foundValidGroup; 1.486 + block.foundValidGroup = true; 1.487 + 1.488 + // Warn if there are extra tokens after #else. 1.489 + mTokenizer->lex(token); 1.490 + if (!isEOD(token)) 1.491 + { 1.492 + mDiagnostics->report(Diagnostics::CONDITIONAL_UNEXPECTED_TOKEN, 1.493 + token->location, token->text); 1.494 + skipUntilEOD(mTokenizer, token); 1.495 + } 1.496 +} 1.497 + 1.498 +void DirectiveParser::parseElif(Token* token) 1.499 +{ 1.500 + assert(getDirective(token) == DIRECTIVE_ELIF); 1.501 + 1.502 + if (mConditionalStack.empty()) 1.503 + { 1.504 + mDiagnostics->report(Diagnostics::CONDITIONAL_ELIF_WITHOUT_IF, 1.505 + token->location, token->text); 1.506 + skipUntilEOD(mTokenizer, token); 1.507 + return; 1.508 + } 1.509 + 1.510 + ConditionalBlock& block = mConditionalStack.back(); 1.511 + if (block.skipBlock) 1.512 + { 1.513 + // No diagnostics. Just skip the whole line. 1.514 + skipUntilEOD(mTokenizer, token); 1.515 + return; 1.516 + } 1.517 + if (block.foundElseGroup) 1.518 + { 1.519 + mDiagnostics->report(Diagnostics::CONDITIONAL_ELIF_AFTER_ELSE, 1.520 + token->location, token->text); 1.521 + skipUntilEOD(mTokenizer, token); 1.522 + return; 1.523 + } 1.524 + if (block.foundValidGroup) 1.525 + { 1.526 + // Do not parse the expression. 1.527 + // Also be careful not to emit a diagnostic. 1.528 + block.skipGroup = true; 1.529 + skipUntilEOD(mTokenizer, token); 1.530 + return; 1.531 + } 1.532 + 1.533 + int expression = parseExpressionIf(token); 1.534 + block.skipGroup = expression == 0; 1.535 + block.foundValidGroup = expression != 0; 1.536 +} 1.537 + 1.538 +void DirectiveParser::parseEndif(Token* token) 1.539 +{ 1.540 + assert(getDirective(token) == DIRECTIVE_ENDIF); 1.541 + 1.542 + if (mConditionalStack.empty()) 1.543 + { 1.544 + mDiagnostics->report(Diagnostics::CONDITIONAL_ENDIF_WITHOUT_IF, 1.545 + token->location, token->text); 1.546 + skipUntilEOD(mTokenizer, token); 1.547 + return; 1.548 + } 1.549 + 1.550 + mConditionalStack.pop_back(); 1.551 + 1.552 + // Warn if there are tokens after #endif. 1.553 + mTokenizer->lex(token); 1.554 + if (!isEOD(token)) 1.555 + { 1.556 + mDiagnostics->report(Diagnostics::CONDITIONAL_UNEXPECTED_TOKEN, 1.557 + token->location, token->text); 1.558 + skipUntilEOD(mTokenizer, token); 1.559 + } 1.560 +} 1.561 + 1.562 +void DirectiveParser::parseError(Token* token) 1.563 +{ 1.564 + assert(getDirective(token) == DIRECTIVE_ERROR); 1.565 + 1.566 + std::ostringstream stream; 1.567 + mTokenizer->lex(token); 1.568 + while ((token->type != '\n') && (token->type != Token::LAST)) 1.569 + { 1.570 + stream << *token; 1.571 + mTokenizer->lex(token); 1.572 + } 1.573 + mDirectiveHandler->handleError(token->location, stream.str()); 1.574 +} 1.575 + 1.576 +// Parses pragma of form: #pragma name[(value)]. 1.577 +void DirectiveParser::parsePragma(Token* token) 1.578 +{ 1.579 + assert(getDirective(token) == DIRECTIVE_PRAGMA); 1.580 + 1.581 + enum State 1.582 + { 1.583 + PRAGMA_NAME, 1.584 + LEFT_PAREN, 1.585 + PRAGMA_VALUE, 1.586 + RIGHT_PAREN 1.587 + }; 1.588 + 1.589 + bool valid = true; 1.590 + std::string name, value; 1.591 + int state = PRAGMA_NAME; 1.592 + 1.593 + mTokenizer->lex(token); 1.594 + while ((token->type != '\n') && (token->type != Token::LAST)) 1.595 + { 1.596 + switch(state++) 1.597 + { 1.598 + case PRAGMA_NAME: 1.599 + name = token->text; 1.600 + valid = valid && (token->type == Token::IDENTIFIER); 1.601 + break; 1.602 + case LEFT_PAREN: 1.603 + valid = valid && (token->type == '('); 1.604 + break; 1.605 + case PRAGMA_VALUE: 1.606 + value = token->text; 1.607 + valid = valid && (token->type == Token::IDENTIFIER); 1.608 + break; 1.609 + case RIGHT_PAREN: 1.610 + valid = valid && (token->type == ')'); 1.611 + break; 1.612 + default: 1.613 + valid = false; 1.614 + break; 1.615 + } 1.616 + mTokenizer->lex(token); 1.617 + } 1.618 + 1.619 + valid = valid && ((state == PRAGMA_NAME) || // Empty pragma. 1.620 + (state == LEFT_PAREN) || // Without value. 1.621 + (state == RIGHT_PAREN + 1)); // With value. 1.622 + if (!valid) 1.623 + { 1.624 + mDiagnostics->report(Diagnostics::UNRECOGNIZED_PRAGMA, 1.625 + token->location, name); 1.626 + } 1.627 + else if (state > PRAGMA_NAME) // Do not notify for empty pragma. 1.628 + { 1.629 + mDirectiveHandler->handlePragma(token->location, name, value); 1.630 + } 1.631 +} 1.632 + 1.633 +void DirectiveParser::parseExtension(Token* token) 1.634 +{ 1.635 + assert(getDirective(token) == DIRECTIVE_EXTENSION); 1.636 + 1.637 + enum State 1.638 + { 1.639 + EXT_NAME, 1.640 + COLON, 1.641 + EXT_BEHAVIOR 1.642 + }; 1.643 + 1.644 + bool valid = true; 1.645 + std::string name, behavior; 1.646 + int state = EXT_NAME; 1.647 + 1.648 + mTokenizer->lex(token); 1.649 + while ((token->type != '\n') && (token->type != Token::LAST)) 1.650 + { 1.651 + switch (state++) 1.652 + { 1.653 + case EXT_NAME: 1.654 + if (valid && (token->type != Token::IDENTIFIER)) 1.655 + { 1.656 + mDiagnostics->report(Diagnostics::INVALID_EXTENSION_NAME, 1.657 + token->location, token->text); 1.658 + valid = false; 1.659 + } 1.660 + if (valid) name = token->text; 1.661 + break; 1.662 + case COLON: 1.663 + if (valid && (token->type != ':')) 1.664 + { 1.665 + mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN, 1.666 + token->location, token->text); 1.667 + valid = false; 1.668 + } 1.669 + break; 1.670 + case EXT_BEHAVIOR: 1.671 + if (valid && (token->type != Token::IDENTIFIER)) 1.672 + { 1.673 + mDiagnostics->report(Diagnostics::INVALID_EXTENSION_BEHAVIOR, 1.674 + token->location, token->text); 1.675 + valid = false; 1.676 + } 1.677 + if (valid) behavior = token->text; 1.678 + break; 1.679 + default: 1.680 + if (valid) 1.681 + { 1.682 + mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN, 1.683 + token->location, token->text); 1.684 + valid = false; 1.685 + } 1.686 + break; 1.687 + } 1.688 + mTokenizer->lex(token); 1.689 + } 1.690 + if (valid && (state != EXT_BEHAVIOR + 1)) 1.691 + { 1.692 + mDiagnostics->report(Diagnostics::INVALID_EXTENSION_DIRECTIVE, 1.693 + token->location, token->text); 1.694 + valid = false; 1.695 + } 1.696 + if (valid) 1.697 + mDirectiveHandler->handleExtension(token->location, name, behavior); 1.698 +} 1.699 + 1.700 +void DirectiveParser::parseVersion(Token* token) 1.701 +{ 1.702 + assert(getDirective(token) == DIRECTIVE_VERSION); 1.703 + 1.704 + if (mPastFirstStatement) 1.705 + { 1.706 + mDiagnostics->report(Diagnostics::VERSION_NOT_FIRST_STATEMENT, 1.707 + token->location, token->text); 1.708 + skipUntilEOD(mTokenizer, token); 1.709 + return; 1.710 + } 1.711 + 1.712 + enum State 1.713 + { 1.714 + VERSION_NUMBER 1.715 + }; 1.716 + 1.717 + bool valid = true; 1.718 + int version = 0; 1.719 + int state = VERSION_NUMBER; 1.720 + 1.721 + mTokenizer->lex(token); 1.722 + while ((token->type != '\n') && (token->type != Token::LAST)) 1.723 + { 1.724 + switch (state++) 1.725 + { 1.726 + case VERSION_NUMBER: 1.727 + if (valid && (token->type != Token::CONST_INT)) 1.728 + { 1.729 + mDiagnostics->report(Diagnostics::INVALID_VERSION_NUMBER, 1.730 + token->location, token->text); 1.731 + valid = false; 1.732 + } 1.733 + if (valid && !token->iValue(&version)) 1.734 + { 1.735 + mDiagnostics->report(Diagnostics::INTEGER_OVERFLOW, 1.736 + token->location, token->text); 1.737 + valid = false; 1.738 + } 1.739 + break; 1.740 + default: 1.741 + if (valid) 1.742 + { 1.743 + mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN, 1.744 + token->location, token->text); 1.745 + valid = false; 1.746 + } 1.747 + break; 1.748 + } 1.749 + mTokenizer->lex(token); 1.750 + } 1.751 + if (valid && (state != VERSION_NUMBER + 1)) 1.752 + { 1.753 + mDiagnostics->report(Diagnostics::INVALID_VERSION_DIRECTIVE, 1.754 + token->location, token->text); 1.755 + valid = false; 1.756 + } 1.757 + if (valid) 1.758 + mDirectiveHandler->handleVersion(token->location, version); 1.759 +} 1.760 + 1.761 +void DirectiveParser::parseLine(Token* token) 1.762 +{ 1.763 + assert(getDirective(token) == DIRECTIVE_LINE); 1.764 + 1.765 + enum State 1.766 + { 1.767 + LINE_NUMBER, 1.768 + FILE_NUMBER 1.769 + }; 1.770 + 1.771 + bool valid = true; 1.772 + int line = 0, file = 0; 1.773 + int state = LINE_NUMBER; 1.774 + 1.775 + MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics); 1.776 + macroExpander.lex(token); 1.777 + while ((token->type != '\n') && (token->type != Token::LAST)) 1.778 + { 1.779 + switch (state++) 1.780 + { 1.781 + case LINE_NUMBER: 1.782 + if (valid && (token->type != Token::CONST_INT)) 1.783 + { 1.784 + mDiagnostics->report(Diagnostics::INVALID_LINE_NUMBER, 1.785 + token->location, token->text); 1.786 + valid = false; 1.787 + } 1.788 + if (valid && !token->iValue(&line)) 1.789 + { 1.790 + mDiagnostics->report(Diagnostics::INTEGER_OVERFLOW, 1.791 + token->location, token->text); 1.792 + valid = false; 1.793 + } 1.794 + break; 1.795 + case FILE_NUMBER: 1.796 + if (valid && (token->type != Token::CONST_INT)) 1.797 + { 1.798 + mDiagnostics->report(Diagnostics::INVALID_FILE_NUMBER, 1.799 + token->location, token->text); 1.800 + valid = false; 1.801 + } 1.802 + if (valid && !token->iValue(&file)) 1.803 + { 1.804 + mDiagnostics->report(Diagnostics::INTEGER_OVERFLOW, 1.805 + token->location, token->text); 1.806 + valid = false; 1.807 + } 1.808 + break; 1.809 + default: 1.810 + if (valid) 1.811 + { 1.812 + mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN, 1.813 + token->location, token->text); 1.814 + valid = false; 1.815 + } 1.816 + break; 1.817 + } 1.818 + macroExpander.lex(token); 1.819 + } 1.820 + 1.821 + if (valid && (state != FILE_NUMBER) && (state != FILE_NUMBER + 1)) 1.822 + { 1.823 + mDiagnostics->report(Diagnostics::INVALID_LINE_DIRECTIVE, 1.824 + token->location, token->text); 1.825 + valid = false; 1.826 + } 1.827 + if (valid) 1.828 + { 1.829 + mTokenizer->setLineNumber(line); 1.830 + if (state == FILE_NUMBER + 1) mTokenizer->setFileNumber(file); 1.831 + } 1.832 +} 1.833 + 1.834 +bool DirectiveParser::skipping() const 1.835 +{ 1.836 + if (mConditionalStack.empty()) return false; 1.837 + 1.838 + const ConditionalBlock& block = mConditionalStack.back(); 1.839 + return block.skipBlock || block.skipGroup; 1.840 +} 1.841 + 1.842 +void DirectiveParser::parseConditionalIf(Token* token) 1.843 +{ 1.844 + ConditionalBlock block; 1.845 + block.type = token->text; 1.846 + block.location = token->location; 1.847 + 1.848 + if (skipping()) 1.849 + { 1.850 + // This conditional block is inside another conditional group 1.851 + // which is skipped. As a consequence this whole block is skipped. 1.852 + // Be careful not to parse the conditional expression that might 1.853 + // emit a diagnostic. 1.854 + skipUntilEOD(mTokenizer, token); 1.855 + block.skipBlock = true; 1.856 + } 1.857 + else 1.858 + { 1.859 + DirectiveType directive = getDirective(token); 1.860 + 1.861 + int expression = 0; 1.862 + switch (directive) 1.863 + { 1.864 + case DIRECTIVE_IF: 1.865 + expression = parseExpressionIf(token); 1.866 + break; 1.867 + case DIRECTIVE_IFDEF: 1.868 + expression = parseExpressionIfdef(token); 1.869 + break; 1.870 + case DIRECTIVE_IFNDEF: 1.871 + expression = parseExpressionIfdef(token) == 0 ? 1 : 0; 1.872 + break; 1.873 + default: 1.874 + assert(false); 1.875 + break; 1.876 + } 1.877 + block.skipGroup = expression == 0; 1.878 + block.foundValidGroup = expression != 0; 1.879 + } 1.880 + mConditionalStack.push_back(block); 1.881 +} 1.882 + 1.883 +int DirectiveParser::parseExpressionIf(Token* token) 1.884 +{ 1.885 + assert((getDirective(token) == DIRECTIVE_IF) || 1.886 + (getDirective(token) == DIRECTIVE_ELIF)); 1.887 + 1.888 + DefinedParser definedParser(mTokenizer, mMacroSet, mDiagnostics); 1.889 + MacroExpander macroExpander(&definedParser, mMacroSet, mDiagnostics); 1.890 + ExpressionParser expressionParser(¯oExpander, mDiagnostics); 1.891 + 1.892 + int expression = 0; 1.893 + macroExpander.lex(token); 1.894 + expressionParser.parse(token, &expression); 1.895 + 1.896 + // Warn if there are tokens after #if expression. 1.897 + if (!isEOD(token)) 1.898 + { 1.899 + mDiagnostics->report(Diagnostics::CONDITIONAL_UNEXPECTED_TOKEN, 1.900 + token->location, token->text); 1.901 + skipUntilEOD(mTokenizer, token); 1.902 + } 1.903 + 1.904 + return expression; 1.905 +} 1.906 + 1.907 +int DirectiveParser::parseExpressionIfdef(Token* token) 1.908 +{ 1.909 + assert((getDirective(token) == DIRECTIVE_IFDEF) || 1.910 + (getDirective(token) == DIRECTIVE_IFNDEF)); 1.911 + 1.912 + mTokenizer->lex(token); 1.913 + if (token->type != Token::IDENTIFIER) 1.914 + { 1.915 + mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN, 1.916 + token->location, token->text); 1.917 + skipUntilEOD(mTokenizer, token); 1.918 + return 0; 1.919 + } 1.920 + 1.921 + MacroSet::const_iterator iter = mMacroSet->find(token->text); 1.922 + int expression = iter != mMacroSet->end() ? 1 : 0; 1.923 + 1.924 + // Warn if there are tokens after #ifdef expression. 1.925 + mTokenizer->lex(token); 1.926 + if (!isEOD(token)) 1.927 + { 1.928 + mDiagnostics->report(Diagnostics::CONDITIONAL_UNEXPECTED_TOKEN, 1.929 + token->location, token->text); 1.930 + skipUntilEOD(mTokenizer, token); 1.931 + } 1.932 + return expression; 1.933 +} 1.934 + 1.935 +} // namespace pp