gfx/angle/src/compiler/preprocessor/DirectiveParser.cpp

changeset 0
6474c204b198
     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(&macroExpander, 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

mercurial