Apply the Apache 2.0 license.

Change-Id: I4a7aeefedcd2d891093520d5a10ebefadcddb5be
Reviewed-on: https://swiftshader-review.googlesource.com/5320
Reviewed-by: Nicolas Capens <capn@google.com>
Tested-by: Nicolas Capens <capn@google.com>
diff --git a/src/OpenGL/compiler/preprocessor/DirectiveParser.cpp b/src/OpenGL/compiler/preprocessor/DirectiveParser.cpp
index 8e6dcbd..ec77c21 100644
--- a/src/OpenGL/compiler/preprocessor/DirectiveParser.cpp
+++ b/src/OpenGL/compiler/preprocessor/DirectiveParser.cpp
@@ -1,891 +1,899 @@
-//

-// Copyright (c) 2011 The ANGLE Project Authors. All rights reserved.

-// Use of this source code is governed by a BSD-style license that can be

-// found in the LICENSE file.

-//

-

-#include "DirectiveParser.h"

-

-#include <cassert>

-#include <cstdlib>

-#include <sstream>

-

-#include "Diagnostics.h"

-#include "DirectiveHandler.h"

-#include "ExpressionParser.h"

-#include "MacroExpander.h"

-#include "Token.h"

-#include "Tokenizer.h"

-

-namespace {

-enum DirectiveType

-{

-    DIRECTIVE_NONE,

-    DIRECTIVE_DEFINE,

-    DIRECTIVE_UNDEF,

-    DIRECTIVE_IF,

-    DIRECTIVE_IFDEF,

-    DIRECTIVE_IFNDEF,

-    DIRECTIVE_ELSE,

-    DIRECTIVE_ELIF,

-    DIRECTIVE_ENDIF,

-    DIRECTIVE_ERROR,

-    DIRECTIVE_PRAGMA,

-    DIRECTIVE_EXTENSION,

-    DIRECTIVE_VERSION,

-    DIRECTIVE_LINE

-};

-}  // namespace

-

-static DirectiveType getDirective(const pp::Token* token)

-{

-    static const std::string kDirectiveDefine("define");

-    static const std::string kDirectiveUndef("undef");

-    static const std::string kDirectiveIf("if");

-    static const std::string kDirectiveIfdef("ifdef");

-    static const std::string kDirectiveIfndef("ifndef");

-    static const std::string kDirectiveElse("else");

-    static const std::string kDirectiveElif("elif");

-    static const std::string kDirectiveEndif("endif");

-    static const std::string kDirectiveError("error");

-    static const std::string kDirectivePragma("pragma");

-    static const std::string kDirectiveExtension("extension");

-    static const std::string kDirectiveVersion("version");

-    static const std::string kDirectiveLine("line");

-

-    if (token->type != pp::Token::IDENTIFIER)

-        return DIRECTIVE_NONE;

-

-    if (token->text == kDirectiveDefine)

-        return DIRECTIVE_DEFINE;

-    else if (token->text == kDirectiveUndef)

-        return DIRECTIVE_UNDEF;

-    else if (token->text == kDirectiveIf)

-        return DIRECTIVE_IF;

-    else if (token->text == kDirectiveIfdef)

-        return DIRECTIVE_IFDEF;

-    else if (token->text == kDirectiveIfndef)

-        return DIRECTIVE_IFNDEF;

-    else if (token->text == kDirectiveElse)

-        return DIRECTIVE_ELSE;

-    else if (token->text == kDirectiveElif)

-        return DIRECTIVE_ELIF;

-    else if (token->text == kDirectiveEndif)

-        return DIRECTIVE_ENDIF;

-    else if (token->text == kDirectiveError)

-        return DIRECTIVE_ERROR;

-    else if (token->text == kDirectivePragma)

-        return DIRECTIVE_PRAGMA;

-    else if (token->text == kDirectiveExtension)

-        return DIRECTIVE_EXTENSION;

-    else if (token->text == kDirectiveVersion)

-        return DIRECTIVE_VERSION;

-    else if (token->text == kDirectiveLine)

-        return DIRECTIVE_LINE;

-

-    return DIRECTIVE_NONE;

-}

-

-static bool isConditionalDirective(DirectiveType directive)

-{

-    switch (directive)

-    {

-      case DIRECTIVE_IF:

-      case DIRECTIVE_IFDEF:

-      case DIRECTIVE_IFNDEF:

-      case DIRECTIVE_ELSE:

-      case DIRECTIVE_ELIF:

-      case DIRECTIVE_ENDIF:

-        return true;

-      default:

-        return false;

-    }

-}

-

-// Returns true if the token represents End Of Directive.

-static bool isEOD(const pp::Token* token)

-{

-    return (token->type == '\n') || (token->type == pp::Token::LAST);

-}

-

-static void skipUntilEOD(pp::Lexer* lexer, pp::Token* token)

-{

-    while(!isEOD(token))

-    {

-        lexer->lex(token);

-    }

-}

-

-static bool isMacroNameReserved(const std::string& name)

-{

-    // Names prefixed with "GL_" are reserved.

-    if (name.substr(0, 3) == "GL_")

-        return true;

-

-    // Names containing two consecutive underscores are reserved.

-    if (name.find("__") != std::string::npos)

-        return true;

-

-    return false;

-}

-

-static bool isMacroPredefined(const std::string& name,

-                              const pp::MacroSet& macroSet)

-{

-    pp::MacroSet::const_iterator iter = macroSet.find(name);

-    return iter != macroSet.end() ? iter->second.predefined : false;

-}

-

-namespace pp

-{

-

-DirectiveParser::DirectiveParser(Tokenizer* tokenizer,

-                                 MacroSet* macroSet,

-                                 Diagnostics* diagnostics,

-                                 DirectiveHandler* directiveHandler) :

-    mPastFirstStatement(false),

-    mTokenizer(tokenizer),

-    mMacroSet(macroSet),

-    mDiagnostics(diagnostics),

-    mDirectiveHandler(directiveHandler)

-{

-}

-

-void DirectiveParser::lex(Token* token)

-{

-    do

-    {

-        mTokenizer->lex(token);

-

-        if (token->type == Token::PP_HASH)

-        {

-            parseDirective(token);

-            mPastFirstStatement = true;

-        }

-

-        if (token->type == Token::LAST)

-        {

-            if (!mConditionalStack.empty())

-            {

-                const ConditionalBlock& block = mConditionalStack.back();

-                mDiagnostics->report(Diagnostics::CONDITIONAL_UNTERMINATED,

-                                     block.location, block.type);

-            }

-            break;

-        }

-

-    } while (skipping() || (token->type == '\n'));

-

-    mPastFirstStatement = true;

-}

-

-void DirectiveParser::parseDirective(Token* token)

-{

-    assert(token->type == Token::PP_HASH);

-

-    mTokenizer->lex(token);

-    if (isEOD(token))

-    {

-        // Empty Directive.

-        return;

-    }

-

-    DirectiveType directive = getDirective(token);

-

-    // While in an excluded conditional block/group,

-    // we only parse conditional directives.

-    if (skipping() && !isConditionalDirective(directive))

-    {

-        skipUntilEOD(mTokenizer, token);

-        return;

-    }

-

-    switch(directive)

-    {

-      case DIRECTIVE_NONE:

-        mDiagnostics->report(Diagnostics::DIRECTIVE_INVALID_NAME,

-                             token->location, token->text);

-        skipUntilEOD(mTokenizer, token);

-        break;

-      case DIRECTIVE_DEFINE:

-        parseDefine(token);

-        break;

-      case DIRECTIVE_UNDEF:

-        parseUndef(token);

-        break;

-      case DIRECTIVE_IF:

-        parseIf(token);

-        break;

-      case DIRECTIVE_IFDEF:

-        parseIfdef(token);

-        break;

-      case DIRECTIVE_IFNDEF:

-        parseIfndef(token);

-        break;

-      case DIRECTIVE_ELSE:

-        parseElse(token);

-        break;

-      case DIRECTIVE_ELIF:

-        parseElif(token);

-        break;

-      case DIRECTIVE_ENDIF:

-        parseEndif(token);

-        break;

-      case DIRECTIVE_ERROR:

-        parseError(token);

-        break;

-      case DIRECTIVE_PRAGMA:

-        parsePragma(token);

-        break;

-      case DIRECTIVE_EXTENSION:

-        parseExtension(token);

-        break;

-      case DIRECTIVE_VERSION:

-        parseVersion(token);

-        break;

-      case DIRECTIVE_LINE:

-        parseLine(token);

-        break;

-      default:

-        assert(false);

-        break;

-    }

-

-    skipUntilEOD(mTokenizer, token);

-    if (token->type == Token::LAST)

-    {

-        mDiagnostics->report(Diagnostics::EOF_IN_DIRECTIVE,

-                             token->location, token->text);

-    }

-}

-

-void DirectiveParser::parseDefine(Token* token)

-{

-    assert(getDirective(token) == DIRECTIVE_DEFINE);

-

-    mTokenizer->lex(token);

-    if (token->type != Token::IDENTIFIER)

-    {

-        mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,

-                             token->location, token->text);

-        return;

-    }

-    if (isMacroPredefined(token->text, *mMacroSet))

-    {

-        mDiagnostics->report(Diagnostics::MACRO_PREDEFINED_REDEFINED,

-                             token->location, token->text);

-        return;

-    }

-    if (isMacroNameReserved(token->text))

-    {

-        mDiagnostics->report(Diagnostics::MACRO_NAME_RESERVED,

-                             token->location, token->text);

-        return;

-    }

-

-    Macro macro;

-    macro.type = Macro::kTypeObj;

-    macro.name = token->text;

-

-    mTokenizer->lex(token);

-    if (token->type == '(' && !token->hasLeadingSpace())

-    {

-        // Function-like macro. Collect arguments.

-        macro.type = Macro::kTypeFunc;

-        do {

-            mTokenizer->lex(token);

-            if (token->type != Token::IDENTIFIER)

-                break;

-

-            if (std::find(macro.parameters.begin(), macro.parameters.end(), token->text) != macro.parameters.end())

-            {

-                mDiagnostics->report(Diagnostics::MACRO_DUPLICATE_PARAMETER_NAMES,

-                                     token->location, token->text);

-                return;

-            }

-

-            macro.parameters.push_back(token->text);

-

-            mTokenizer->lex(token);  // Get ','.

-        } while (token->type == ',');

-

-        if (token->type != ')')

-        {

-            mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,

-                                 token->location,

-                                 token->text);

-            return;

-        }

-        mTokenizer->lex(token);  // Get ')'.

-    }

-

-    while ((token->type != '\n') && (token->type != Token::LAST))

-    {

-        // Reset the token location because it is unnecessary in replacement

-        // list. Resetting it also allows us to reuse Token::equals() to

-        // compare macros.

-        token->location = SourceLocation();

-        macro.replacements.push_back(*token);

-        mTokenizer->lex(token);

-    }

-    if (!macro.replacements.empty())

-    {

-        // Whitespace preceding the replacement list is not considered part of

-        // the replacement list for either form of macro.

-        macro.replacements.front().setHasLeadingSpace(false);

-    }

-

-    // Check for macro redefinition.

-    MacroSet::const_iterator iter = mMacroSet->find(macro.name);

-    if (iter != mMacroSet->end() && !macro.equals(iter->second))

-    {

-        mDiagnostics->report(Diagnostics::MACRO_REDEFINED,

-                             token->location,

-                             macro.name);

-        return;

-    }

-    mMacroSet->insert(std::make_pair(macro.name, macro));

-}

-

-void DirectiveParser::parseUndef(Token* token)

-{

-    assert(getDirective(token) == DIRECTIVE_UNDEF);

-

-    mTokenizer->lex(token);

-    if (token->type != Token::IDENTIFIER)

-    {

-        mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,

-                             token->location, token->text);

-        return;

-    }

-

-    MacroSet::iterator iter = mMacroSet->find(token->text);

-    if (iter != mMacroSet->end())

-    {

-        if (iter->second.predefined)

-        {

-            mDiagnostics->report(Diagnostics::MACRO_PREDEFINED_UNDEFINED,

-                                 token->location, token->text);

-        }

-        else

-        {

-            mMacroSet->erase(iter);

-        }

-    }

-

-    mTokenizer->lex(token);

-}

-

-void DirectiveParser::parseIf(Token* token)

-{

-    assert(getDirective(token) == DIRECTIVE_IF);

-    parseConditionalIf(token);

-}

-

-void DirectiveParser::parseIfdef(Token* token)

-{

-    assert(getDirective(token) == DIRECTIVE_IFDEF);

-    parseConditionalIf(token);

-}

-

-void DirectiveParser::parseIfndef(Token* token)

-{

-    assert(getDirective(token) == DIRECTIVE_IFNDEF);

-    parseConditionalIf(token);

-}

-

-void DirectiveParser::parseElse(Token* token)

-{

-    assert(getDirective(token) == DIRECTIVE_ELSE);

-

-    if (mConditionalStack.empty())

-    {

-        mDiagnostics->report(Diagnostics::CONDITIONAL_ELSE_WITHOUT_IF,

-                             token->location, token->text);

-        skipUntilEOD(mTokenizer, token);

-        return;

-    }

-

-    ConditionalBlock& block = mConditionalStack.back();

-    if (block.skipBlock)

-    {

-        // No diagnostics. Just skip the whole line.

-        skipUntilEOD(mTokenizer, token);

-        return;

-    }

-    if (block.foundElseGroup)

-    {

-        mDiagnostics->report(Diagnostics::CONDITIONAL_ELSE_AFTER_ELSE,

-                             token->location, token->text);

-        skipUntilEOD(mTokenizer, token);

-        return;

-    }

-

-    block.foundElseGroup = true;

-    block.skipGroup = block.foundValidGroup;

-    block.foundValidGroup = true;

-

-    // Check if there are extra tokens after #else.

-    mTokenizer->lex(token);

-    if (!isEOD(token))

-    {

-        mDiagnostics->report(Diagnostics::CONDITIONAL_UNEXPECTED_TOKEN,

-                             token->location, token->text);

-        skipUntilEOD(mTokenizer, token);

-    }

-}

-

-void DirectiveParser::parseElif(Token* token)

-{

-    assert(getDirective(token) == DIRECTIVE_ELIF);

-

-    if (mConditionalStack.empty())

-    {

-        mDiagnostics->report(Diagnostics::CONDITIONAL_ELIF_WITHOUT_IF,

-                             token->location, token->text);

-        skipUntilEOD(mTokenizer, token);

-        return;

-    }

-

-    ConditionalBlock& block = mConditionalStack.back();

-    if (block.skipBlock)

-    {

-        // No diagnostics. Just skip the whole line.

-        skipUntilEOD(mTokenizer, token);

-        return;

-    }

-    if (block.foundElseGroup)

-    {

-        mDiagnostics->report(Diagnostics::CONDITIONAL_ELIF_AFTER_ELSE,

-                             token->location, token->text);

-        skipUntilEOD(mTokenizer, token);

-        return;

-    }

-    if (block.foundValidGroup)

-    {

-        // Do not parse the expression.

-        // Also be careful not to emit a diagnostic.

-        block.skipGroup = true;

-        skipUntilEOD(mTokenizer, token);

-        return;

-    }

-

-    int expression = parseExpressionIf(token);

-    block.skipGroup = expression == 0;

-    block.foundValidGroup = expression != 0;

-}

-

-void DirectiveParser::parseEndif(Token* token)

-{

-    assert(getDirective(token) == DIRECTIVE_ENDIF);

-

-    if (mConditionalStack.empty())

-    {

-        mDiagnostics->report(Diagnostics::CONDITIONAL_ENDIF_WITHOUT_IF,

-                             token->location, token->text);

-        skipUntilEOD(mTokenizer, token);

-        return;

-    }

-

-    mConditionalStack.pop_back();

-

-    // Check if there are tokens after #endif.

-    mTokenizer->lex(token);

-    if (!isEOD(token))

-    {

-        mDiagnostics->report(Diagnostics::CONDITIONAL_UNEXPECTED_TOKEN,

-                             token->location, token->text);

-        skipUntilEOD(mTokenizer, token);

-    }

-}

-

-void DirectiveParser::parseError(Token* token)

-{

-    assert(getDirective(token) == DIRECTIVE_ERROR);

-

-    std::ostringstream stream;

-    mTokenizer->lex(token);

-    while ((token->type != '\n') && (token->type != Token::LAST))

-    {

-        stream << *token;

-        mTokenizer->lex(token);

-    }

-    mDirectiveHandler->handleError(token->location, stream.str());

-}

-

-// Parses pragma of form: #pragma name[(value)].

-void DirectiveParser::parsePragma(Token* token)

-{

-    assert(getDirective(token) == DIRECTIVE_PRAGMA);

-

-    enum State

-    {

-        PRAGMA_NAME,

-        LEFT_PAREN,

-        PRAGMA_VALUE,

-        RIGHT_PAREN

-    };

-

-    bool valid = true;

-    std::string name, value;

-    int state = PRAGMA_NAME;

-

-    mTokenizer->lex(token);

-    while ((token->type != '\n') && (token->type != Token::LAST))

-    {

-        switch(state++)

-        {

-          case PRAGMA_NAME:

-            name = token->text;

-            valid = valid && (token->type == Token::IDENTIFIER);

-            break;

-          case LEFT_PAREN:

-            valid = valid && (token->type == '(');

-            break;

-          case PRAGMA_VALUE:

-            value = token->text;

-            valid = valid && (token->type == Token::IDENTIFIER);

-            break;

-          case RIGHT_PAREN:

-            valid = valid && (token->type == ')');

-            break;

-          default:

-            valid = false;

-            break;

-        }

-        mTokenizer->lex(token);

-    }

-

-    valid = valid && ((state == PRAGMA_NAME) ||     // Empty pragma.

-                      (state == LEFT_PAREN) ||      // Without value.

-                      (state == RIGHT_PAREN + 1));  // With value.

-    if (!valid)

-    {

-        mDiagnostics->report(Diagnostics::UNRECOGNIZED_PRAGMA,

-                             token->location, name);

-    }

-    else if (state > PRAGMA_NAME)  // Do not notify for empty pragma.

-    {

-        mDirectiveHandler->handlePragma(token->location, name, value);

-    }

-}

-

-void DirectiveParser::parseExtension(Token* token)

-{

-    assert(getDirective(token) == DIRECTIVE_EXTENSION);

-

-    enum State

-    {

-        EXT_NAME,

-        COLON,

-        EXT_BEHAVIOR

-    };

-

-    bool valid = true;

-    std::string name, behavior;

-    int state = EXT_NAME;

-

-    mTokenizer->lex(token);

-    while ((token->type != '\n') && (token->type != Token::LAST))

-    {

-        switch (state++)

-        {

-          case EXT_NAME:

-            if (valid && (token->type != Token::IDENTIFIER))

-            {

-                mDiagnostics->report(Diagnostics::INVALID_EXTENSION_NAME,

-                                     token->location, token->text);

-                valid = false;

-            }

-            if (valid) name = token->text;

-            break;

-          case COLON:

-            if (valid && (token->type != ':'))

-            {

-                mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,

-                                     token->location, token->text);

-                valid = false;

-            }

-            break;

-          case EXT_BEHAVIOR:

-            if (valid && (token->type != Token::IDENTIFIER))

-            {

-                mDiagnostics->report(Diagnostics::INVALID_EXTENSION_BEHAVIOR,

-                                     token->location, token->text);

-                valid = false;

-            }

-            if (valid) behavior = token->text;

-            break;

-          default:

-            if (valid)

-            {

-                mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,

-                                     token->location, token->text);

-                valid = false;

-            }

-            break;

-        }

-        mTokenizer->lex(token);

-    }

-    if (valid && (state != EXT_BEHAVIOR + 1))

-    {

-        mDiagnostics->report(Diagnostics::INVALID_EXTENSION_DIRECTIVE,

-                             token->location, token->text);

-        valid = false;

-    }

-    if (valid)

-        mDirectiveHandler->handleExtension(token->location, name, behavior);

-}

-

-void DirectiveParser::parseVersion(Token* token)

-{

-    assert(getDirective(token) == DIRECTIVE_VERSION);

-

-    if (mPastFirstStatement)

-    {

-        mDiagnostics->report(Diagnostics::VERSION_NOT_FIRST_STATEMENT,

-                             token->location, token->text);

-        skipUntilEOD(mTokenizer, token);

-        return;

-    }

-

-    enum State

-    {

-        VERSION_NUMBER,

-        VERSION_PROFILE,

-        VERSION_ENDLINE

-    };

-

-    bool valid = true;

-    int version = 0;

-    int state = VERSION_NUMBER;

-

-    mTokenizer->lex(token);

-    while (valid && (token->type != '\n') && (token->type != Token::LAST))

-    {

-        switch (state)

-        {

-          case VERSION_NUMBER:

-            if (token->type != Token::CONST_INT)

-            {

-                mDiagnostics->report(Diagnostics::INVALID_VERSION_NUMBER,

-                                     token->location, token->text);

-                valid = false;

-            }

-            if (valid && !token->iValue(&version))

-            {

-                mDiagnostics->report(Diagnostics::INTEGER_OVERFLOW,

-                                     token->location, token->text);

-                valid = false;

-            }

-            if (valid)

-            {

-                state = (version < 300) ? VERSION_ENDLINE : VERSION_PROFILE;

-            }

-            break;

-          case VERSION_PROFILE:

-            if (token->type != Token::IDENTIFIER || token->text != "es")

-            {

-                mDiagnostics->report(Diagnostics::INVALID_VERSION_DIRECTIVE,

-                                     token->location, token->text);

-                valid = false;

-            }

-            state = VERSION_ENDLINE;

-            break;

-          default:

-            mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,

-                                 token->location, token->text);

-            valid = false;

-            break;

-        }

-

-        mTokenizer->lex(token);

-    }

-

-    if (valid && (state != VERSION_ENDLINE))

-    {

-        mDiagnostics->report(Diagnostics::INVALID_VERSION_DIRECTIVE,

-                             token->location, token->text);

-        valid = false;

-    }

-

-    if (valid)

-    {

-        mDirectiveHandler->handleVersion(token->location, version);

-    }

-}

-

-void DirectiveParser::parseLine(Token* token)

-{

-    assert(getDirective(token) == DIRECTIVE_LINE);

-

-    enum State

-    {

-        LINE_NUMBER,

-        FILE_NUMBER

-    };

-

-    bool valid = true;

-    int line = 0, file = 0;

-    int state = LINE_NUMBER;

-

-    MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics, false);

-    macroExpander.lex(token);

-    while ((token->type != '\n') && (token->type != Token::LAST))

-    {

-        switch (state++)

-        {

-          case LINE_NUMBER:

-            if (valid && (token->type != Token::CONST_INT))

-            {

-                mDiagnostics->report(Diagnostics::INVALID_LINE_NUMBER,

-                                     token->location, token->text);

-                valid = false;

-            }

-            if (valid && !token->iValue(&line))

-            {

-                mDiagnostics->report(Diagnostics::INTEGER_OVERFLOW,

-                                     token->location, token->text);

-                valid = false;

-            }

-            break;

-          case FILE_NUMBER:

-            if (valid && (token->type != Token::CONST_INT))

-            {

-                mDiagnostics->report(Diagnostics::INVALID_FILE_NUMBER,

-                                     token->location, token->text);

-                valid = false;

-            }

-            if (valid && !token->iValue(&file))

-            {

-                mDiagnostics->report(Diagnostics::INTEGER_OVERFLOW,

-                                     token->location, token->text);

-                valid = false;

-            }

-            break;

-          default:

-            if (valid)

-            {

-                mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,

-                                     token->location, token->text);

-                valid = false;

-            }

-            break;

-        }

-        macroExpander.lex(token);

-    }

-

-    if (valid && (state != FILE_NUMBER) && (state != FILE_NUMBER + 1))

-    {

-        mDiagnostics->report(Diagnostics::INVALID_LINE_DIRECTIVE,

-                             token->location, token->text);

-        valid = false;

-    }

-    if (valid)

-    {

-        mTokenizer->setLineNumber(line);

-        if (state == FILE_NUMBER + 1) mTokenizer->setFileNumber(file);

-    }

-}

-

-bool DirectiveParser::skipping() const

-{

-    if (mConditionalStack.empty()) return false;

-

-    const ConditionalBlock& block = mConditionalStack.back();

-    return block.skipBlock || block.skipGroup;

-}

-

-void DirectiveParser::parseConditionalIf(Token* token)

-{

-    ConditionalBlock block;

-    block.type = token->text;

-    block.location = token->location;

-

-    if (skipping())

-    {

-        // This conditional block is inside another conditional group

-        // which is skipped. As a consequence this whole block is skipped.

-        // Be careful not to parse the conditional expression that might

-        // emit a diagnostic.

-        skipUntilEOD(mTokenizer, token);

-        block.skipBlock = true;

-    }

-    else

-    {

-        DirectiveType directive = getDirective(token);

-

-        int expression = 0;

-        switch (directive)

-        {

-          case DIRECTIVE_IF:

-            expression = parseExpressionIf(token);

-            break;

-          case DIRECTIVE_IFDEF:

-            expression = parseExpressionIfdef(token);

-            break;

-          case DIRECTIVE_IFNDEF:

-            expression = parseExpressionIfdef(token) == 0 ? 1 : 0;

-            break;

-          default:

-            assert(false);

-            break;

-        }

-        block.skipGroup = expression == 0;

-        block.foundValidGroup = expression != 0;

-    }

-    mConditionalStack.push_back(block);

-}

-

-int DirectiveParser::parseExpressionIf(Token* token)

-{

-    assert((getDirective(token) == DIRECTIVE_IF) ||

-           (getDirective(token) == DIRECTIVE_ELIF));

-

-    MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics, true);

-    ExpressionParser expressionParser(&macroExpander, mDiagnostics);

-

-    int expression = 0;

-    macroExpander.lex(token);

-    expressionParser.parse(token, &expression);

-

-    // Check if there are tokens after #if expression.

-    if (!isEOD(token))

-    {

-        mDiagnostics->report(Diagnostics::CONDITIONAL_UNEXPECTED_TOKEN,

-                             token->location, token->text);

-        skipUntilEOD(mTokenizer, token);

-    }

-

-    return expression;

-}

-

-int DirectiveParser::parseExpressionIfdef(Token* token)

-{

-    assert((getDirective(token) == DIRECTIVE_IFDEF) ||

-           (getDirective(token) == DIRECTIVE_IFNDEF));

-

-    mTokenizer->lex(token);

-    if (token->type != Token::IDENTIFIER)

-    {

-        mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,

-                             token->location, token->text);

-        skipUntilEOD(mTokenizer, token);

-        return 0;

-    }

-

-    MacroSet::const_iterator iter = mMacroSet->find(token->text);

-    int expression = iter != mMacroSet->end() ? 1 : 0;

-

-    // Check if there are tokens after #ifdef expression.

-    mTokenizer->lex(token);

-    if (!isEOD(token))

-    {

-        mDiagnostics->report(Diagnostics::CONDITIONAL_UNEXPECTED_TOKEN,

-                             token->location, token->text);

-        skipUntilEOD(mTokenizer, token);

-    }

-    return expression;

-}

-

-}  // namespace pp

+// Copyright 2016 The SwiftShader Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "DirectiveParser.h"
+
+#include <cassert>
+#include <cstdlib>
+#include <sstream>
+
+#include "Diagnostics.h"
+#include "DirectiveHandler.h"
+#include "ExpressionParser.h"
+#include "MacroExpander.h"
+#include "Token.h"
+#include "Tokenizer.h"
+
+namespace {
+enum DirectiveType
+{
+	DIRECTIVE_NONE,
+	DIRECTIVE_DEFINE,
+	DIRECTIVE_UNDEF,
+	DIRECTIVE_IF,
+	DIRECTIVE_IFDEF,
+	DIRECTIVE_IFNDEF,
+	DIRECTIVE_ELSE,
+	DIRECTIVE_ELIF,
+	DIRECTIVE_ENDIF,
+	DIRECTIVE_ERROR,
+	DIRECTIVE_PRAGMA,
+	DIRECTIVE_EXTENSION,
+	DIRECTIVE_VERSION,
+	DIRECTIVE_LINE
+};
+}  // namespace
+
+static DirectiveType getDirective(const pp::Token* token)
+{
+	static const std::string kDirectiveDefine("define");
+	static const std::string kDirectiveUndef("undef");
+	static const std::string kDirectiveIf("if");
+	static const std::string kDirectiveIfdef("ifdef");
+	static const std::string kDirectiveIfndef("ifndef");
+	static const std::string kDirectiveElse("else");
+	static const std::string kDirectiveElif("elif");
+	static const std::string kDirectiveEndif("endif");
+	static const std::string kDirectiveError("error");
+	static const std::string kDirectivePragma("pragma");
+	static const std::string kDirectiveExtension("extension");
+	static const std::string kDirectiveVersion("version");
+	static const std::string kDirectiveLine("line");
+
+	if (token->type != pp::Token::IDENTIFIER)
+		return DIRECTIVE_NONE;
+
+	if (token->text == kDirectiveDefine)
+		return DIRECTIVE_DEFINE;
+	else if (token->text == kDirectiveUndef)
+		return DIRECTIVE_UNDEF;
+	else if (token->text == kDirectiveIf)
+		return DIRECTIVE_IF;
+	else if (token->text == kDirectiveIfdef)
+		return DIRECTIVE_IFDEF;
+	else if (token->text == kDirectiveIfndef)
+		return DIRECTIVE_IFNDEF;
+	else if (token->text == kDirectiveElse)
+		return DIRECTIVE_ELSE;
+	else if (token->text == kDirectiveElif)
+		return DIRECTIVE_ELIF;
+	else if (token->text == kDirectiveEndif)
+		return DIRECTIVE_ENDIF;
+	else if (token->text == kDirectiveError)
+		return DIRECTIVE_ERROR;
+	else if (token->text == kDirectivePragma)
+		return DIRECTIVE_PRAGMA;
+	else if (token->text == kDirectiveExtension)
+		return DIRECTIVE_EXTENSION;
+	else if (token->text == kDirectiveVersion)
+		return DIRECTIVE_VERSION;
+	else if (token->text == kDirectiveLine)
+		return DIRECTIVE_LINE;
+
+	return DIRECTIVE_NONE;
+}
+
+static bool isConditionalDirective(DirectiveType directive)
+{
+	switch (directive)
+	{
+	case DIRECTIVE_IF:
+	case DIRECTIVE_IFDEF:
+	case DIRECTIVE_IFNDEF:
+	case DIRECTIVE_ELSE:
+	case DIRECTIVE_ELIF:
+	case DIRECTIVE_ENDIF:
+		return true;
+	default:
+		return false;
+	}
+}
+
+// Returns true if the token represents End Of Directive.
+static bool isEOD(const pp::Token* token)
+{
+	return (token->type == '\n') || (token->type == pp::Token::LAST);
+}
+
+static void skipUntilEOD(pp::Lexer* lexer, pp::Token* token)
+{
+	while(!isEOD(token))
+	{
+		lexer->lex(token);
+	}
+}
+
+static bool isMacroNameReserved(const std::string& name)
+{
+	// Names prefixed with "GL_" are reserved.
+	if (name.substr(0, 3) == "GL_")
+		return true;
+
+	// Names containing two consecutive underscores are reserved.
+	if (name.find("__") != std::string::npos)
+		return true;
+
+	return false;
+}
+
+static bool isMacroPredefined(const std::string& name,
+                              const pp::MacroSet& macroSet)
+{
+	pp::MacroSet::const_iterator iter = macroSet.find(name);
+	return iter != macroSet.end() ? iter->second.predefined : false;
+}
+
+namespace pp
+{
+
+DirectiveParser::DirectiveParser(Tokenizer* tokenizer,
+                                 MacroSet* macroSet,
+                                 Diagnostics* diagnostics,
+                                 DirectiveHandler* directiveHandler) :
+	mPastFirstStatement(false),
+	mTokenizer(tokenizer),
+	mMacroSet(macroSet),
+	mDiagnostics(diagnostics),
+	mDirectiveHandler(directiveHandler)
+{
+}
+
+void DirectiveParser::lex(Token* token)
+{
+	do
+	{
+		mTokenizer->lex(token);
+
+		if (token->type == Token::PP_HASH)
+		{
+			parseDirective(token);
+			mPastFirstStatement = true;
+		}
+
+		if (token->type == Token::LAST)
+		{
+			if (!mConditionalStack.empty())
+			{
+				const ConditionalBlock& block = mConditionalStack.back();
+				mDiagnostics->report(Diagnostics::CONDITIONAL_UNTERMINATED,
+				                     block.location, block.type);
+			}
+			break;
+		}
+
+	} while (skipping() || (token->type == '\n'));
+
+	mPastFirstStatement = true;
+}
+
+void DirectiveParser::parseDirective(Token* token)
+{
+	assert(token->type == Token::PP_HASH);
+
+	mTokenizer->lex(token);
+	if (isEOD(token))
+	{
+		// Empty Directive.
+		return;
+	}
+
+	DirectiveType directive = getDirective(token);
+
+	// While in an excluded conditional block/group,
+	// we only parse conditional directives.
+	if (skipping() && !isConditionalDirective(directive))
+	{
+		skipUntilEOD(mTokenizer, token);
+		return;
+	}
+
+	switch(directive)
+	{
+	case DIRECTIVE_NONE:
+		mDiagnostics->report(Diagnostics::DIRECTIVE_INVALID_NAME,
+		                     token->location, token->text);
+		skipUntilEOD(mTokenizer, token);
+		break;
+	case DIRECTIVE_DEFINE:
+		parseDefine(token);
+		break;
+	case DIRECTIVE_UNDEF:
+		parseUndef(token);
+		break;
+	case DIRECTIVE_IF:
+		parseIf(token);
+		break;
+	case DIRECTIVE_IFDEF:
+		parseIfdef(token);
+		break;
+	case DIRECTIVE_IFNDEF:
+		parseIfndef(token);
+		break;
+	case DIRECTIVE_ELSE:
+		parseElse(token);
+		break;
+	case DIRECTIVE_ELIF:
+		parseElif(token);
+		break;
+	case DIRECTIVE_ENDIF:
+		parseEndif(token);
+		break;
+	case DIRECTIVE_ERROR:
+		parseError(token);
+		break;
+	case DIRECTIVE_PRAGMA:
+		parsePragma(token);
+		break;
+	case DIRECTIVE_EXTENSION:
+		parseExtension(token);
+		break;
+	case DIRECTIVE_VERSION:
+		parseVersion(token);
+		break;
+	case DIRECTIVE_LINE:
+		parseLine(token);
+		break;
+	default:
+		assert(false);
+		break;
+	}
+
+	skipUntilEOD(mTokenizer, token);
+	if (token->type == Token::LAST)
+	{
+		mDiagnostics->report(Diagnostics::EOF_IN_DIRECTIVE,
+		                     token->location, token->text);
+	}
+}
+
+void DirectiveParser::parseDefine(Token* token)
+{
+	assert(getDirective(token) == DIRECTIVE_DEFINE);
+
+	mTokenizer->lex(token);
+	if (token->type != Token::IDENTIFIER)
+	{
+		mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
+		                     token->location, token->text);
+		return;
+	}
+	if (isMacroPredefined(token->text, *mMacroSet))
+	{
+		mDiagnostics->report(Diagnostics::MACRO_PREDEFINED_REDEFINED,
+		                     token->location, token->text);
+		return;
+	}
+	if (isMacroNameReserved(token->text))
+	{
+		mDiagnostics->report(Diagnostics::MACRO_NAME_RESERVED,
+		                     token->location, token->text);
+		return;
+	}
+
+	Macro macro;
+	macro.type = Macro::kTypeObj;
+	macro.name = token->text;
+
+	mTokenizer->lex(token);
+	if (token->type == '(' && !token->hasLeadingSpace())
+	{
+		// Function-like macro. Collect arguments.
+		macro.type = Macro::kTypeFunc;
+		do {
+			mTokenizer->lex(token);
+			if (token->type != Token::IDENTIFIER)
+				break;
+
+			if (std::find(macro.parameters.begin(), macro.parameters.end(), token->text) != macro.parameters.end())
+			{
+				mDiagnostics->report(Diagnostics::MACRO_DUPLICATE_PARAMETER_NAMES,
+				                     token->location, token->text);
+				return;
+			}
+
+			macro.parameters.push_back(token->text);
+
+			mTokenizer->lex(token);  // Get ','.
+		} while (token->type == ',');
+
+		if (token->type != ')')
+		{
+			mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
+			                     token->location,
+			                     token->text);
+			return;
+		}
+		mTokenizer->lex(token);  // Get ')'.
+	}
+
+	while ((token->type != '\n') && (token->type != Token::LAST))
+	{
+		// Reset the token location because it is unnecessary in replacement
+		// list. Resetting it also allows us to reuse Token::equals() to
+		// compare macros.
+		token->location = SourceLocation();
+		macro.replacements.push_back(*token);
+		mTokenizer->lex(token);
+	}
+	if (!macro.replacements.empty())
+	{
+		// Whitespace preceding the replacement list is not considered part of
+		// the replacement list for either form of macro.
+		macro.replacements.front().setHasLeadingSpace(false);
+	}
+
+	// Check for macro redefinition.
+	MacroSet::const_iterator iter = mMacroSet->find(macro.name);
+	if (iter != mMacroSet->end() && !macro.equals(iter->second))
+	{
+		mDiagnostics->report(Diagnostics::MACRO_REDEFINED,
+		                     token->location,
+		                     macro.name);
+		return;
+	}
+	mMacroSet->insert(std::make_pair(macro.name, macro));
+}
+
+void DirectiveParser::parseUndef(Token* token)
+{
+	assert(getDirective(token) == DIRECTIVE_UNDEF);
+
+	mTokenizer->lex(token);
+	if (token->type != Token::IDENTIFIER)
+	{
+		mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
+		                     token->location, token->text);
+		return;
+	}
+
+	MacroSet::iterator iter = mMacroSet->find(token->text);
+	if (iter != mMacroSet->end())
+	{
+		if (iter->second.predefined)
+		{
+			mDiagnostics->report(Diagnostics::MACRO_PREDEFINED_UNDEFINED,
+			                     token->location, token->text);
+		}
+		else
+		{
+			mMacroSet->erase(iter);
+		}
+	}
+
+	mTokenizer->lex(token);
+}
+
+void DirectiveParser::parseIf(Token* token)
+{
+	assert(getDirective(token) == DIRECTIVE_IF);
+	parseConditionalIf(token);
+}
+
+void DirectiveParser::parseIfdef(Token* token)
+{
+	assert(getDirective(token) == DIRECTIVE_IFDEF);
+	parseConditionalIf(token);
+}
+
+void DirectiveParser::parseIfndef(Token* token)
+{
+	assert(getDirective(token) == DIRECTIVE_IFNDEF);
+	parseConditionalIf(token);
+}
+
+void DirectiveParser::parseElse(Token* token)
+{
+	assert(getDirective(token) == DIRECTIVE_ELSE);
+
+	if (mConditionalStack.empty())
+	{
+		mDiagnostics->report(Diagnostics::CONDITIONAL_ELSE_WITHOUT_IF,
+		                     token->location, token->text);
+		skipUntilEOD(mTokenizer, token);
+		return;
+	}
+
+	ConditionalBlock& block = mConditionalStack.back();
+	if (block.skipBlock)
+	{
+		// No diagnostics. Just skip the whole line.
+		skipUntilEOD(mTokenizer, token);
+		return;
+	}
+	if (block.foundElseGroup)
+	{
+		mDiagnostics->report(Diagnostics::CONDITIONAL_ELSE_AFTER_ELSE,
+		                     token->location, token->text);
+		skipUntilEOD(mTokenizer, token);
+		return;
+	}
+
+	block.foundElseGroup = true;
+	block.skipGroup = block.foundValidGroup;
+	block.foundValidGroup = true;
+
+	// Check if there are extra tokens after #else.
+	mTokenizer->lex(token);
+	if (!isEOD(token))
+	{
+		mDiagnostics->report(Diagnostics::CONDITIONAL_UNEXPECTED_TOKEN,
+		                     token->location, token->text);
+		skipUntilEOD(mTokenizer, token);
+	}
+}
+
+void DirectiveParser::parseElif(Token* token)
+{
+	assert(getDirective(token) == DIRECTIVE_ELIF);
+
+	if (mConditionalStack.empty())
+	{
+		mDiagnostics->report(Diagnostics::CONDITIONAL_ELIF_WITHOUT_IF,
+		                     token->location, token->text);
+		skipUntilEOD(mTokenizer, token);
+		return;
+	}
+
+	ConditionalBlock& block = mConditionalStack.back();
+	if (block.skipBlock)
+	{
+		// No diagnostics. Just skip the whole line.
+		skipUntilEOD(mTokenizer, token);
+		return;
+	}
+	if (block.foundElseGroup)
+	{
+		mDiagnostics->report(Diagnostics::CONDITIONAL_ELIF_AFTER_ELSE,
+		                     token->location, token->text);
+		skipUntilEOD(mTokenizer, token);
+		return;
+	}
+	if (block.foundValidGroup)
+	{
+		// Do not parse the expression.
+		// Also be careful not to emit a diagnostic.
+		block.skipGroup = true;
+		skipUntilEOD(mTokenizer, token);
+		return;
+	}
+
+	int expression = parseExpressionIf(token);
+	block.skipGroup = expression == 0;
+	block.foundValidGroup = expression != 0;
+}
+
+void DirectiveParser::parseEndif(Token* token)
+{
+	assert(getDirective(token) == DIRECTIVE_ENDIF);
+
+	if (mConditionalStack.empty())
+	{
+		mDiagnostics->report(Diagnostics::CONDITIONAL_ENDIF_WITHOUT_IF,
+		                     token->location, token->text);
+		skipUntilEOD(mTokenizer, token);
+		return;
+	}
+
+	mConditionalStack.pop_back();
+
+	// Check if there are tokens after #endif.
+	mTokenizer->lex(token);
+	if (!isEOD(token))
+	{
+		mDiagnostics->report(Diagnostics::CONDITIONAL_UNEXPECTED_TOKEN,
+		                     token->location, token->text);
+		skipUntilEOD(mTokenizer, token);
+	}
+}
+
+void DirectiveParser::parseError(Token* token)
+{
+	assert(getDirective(token) == DIRECTIVE_ERROR);
+
+	std::ostringstream stream;
+	mTokenizer->lex(token);
+	while ((token->type != '\n') && (token->type != Token::LAST))
+	{
+		stream << *token;
+		mTokenizer->lex(token);
+	}
+	mDirectiveHandler->handleError(token->location, stream.str());
+}
+
+// Parses pragma of form: #pragma name[(value)].
+void DirectiveParser::parsePragma(Token* token)
+{
+	assert(getDirective(token) == DIRECTIVE_PRAGMA);
+
+	enum State
+	{
+		PRAGMA_NAME,
+		LEFT_PAREN,
+		PRAGMA_VALUE,
+		RIGHT_PAREN
+	};
+
+	bool valid = true;
+	std::string name, value;
+	int state = PRAGMA_NAME;
+
+	mTokenizer->lex(token);
+	while ((token->type != '\n') && (token->type != Token::LAST))
+	{
+		switch(state++)
+		{
+		case PRAGMA_NAME:
+			name = token->text;
+			valid = valid && (token->type == Token::IDENTIFIER);
+			break;
+		case LEFT_PAREN:
+			valid = valid && (token->type == '(');
+			break;
+		case PRAGMA_VALUE:
+			value = token->text;
+			valid = valid && (token->type == Token::IDENTIFIER);
+			break;
+		case RIGHT_PAREN:
+			valid = valid && (token->type == ')');
+			break;
+		default:
+			valid = false;
+			break;
+		}
+		mTokenizer->lex(token);
+	}
+
+	valid = valid && ((state == PRAGMA_NAME) ||     // Empty pragma.
+	                  (state == LEFT_PAREN) ||      // Without value.
+	                  (state == RIGHT_PAREN + 1));  // With value.
+	if (!valid)
+	{
+		mDiagnostics->report(Diagnostics::UNRECOGNIZED_PRAGMA,
+		                     token->location, name);
+	}
+	else if (state > PRAGMA_NAME)  // Do not notify for empty pragma.
+	{
+		mDirectiveHandler->handlePragma(token->location, name, value);
+	}
+}
+
+void DirectiveParser::parseExtension(Token* token)
+{
+	assert(getDirective(token) == DIRECTIVE_EXTENSION);
+
+	enum State
+	{
+		EXT_NAME,
+		COLON,
+		EXT_BEHAVIOR
+	};
+
+	bool valid = true;
+	std::string name, behavior;
+	int state = EXT_NAME;
+
+	mTokenizer->lex(token);
+	while ((token->type != '\n') && (token->type != Token::LAST))
+	{
+		switch (state++)
+		{
+		case EXT_NAME:
+			if (valid && (token->type != Token::IDENTIFIER))
+			{
+				mDiagnostics->report(Diagnostics::INVALID_EXTENSION_NAME,
+				                     token->location, token->text);
+				valid = false;
+			}
+			if (valid) name = token->text;
+			break;
+		case COLON:
+			if (valid && (token->type != ':'))
+			{
+				mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
+				                     token->location, token->text);
+				valid = false;
+			}
+			break;
+		case EXT_BEHAVIOR:
+			if (valid && (token->type != Token::IDENTIFIER))
+			{
+				mDiagnostics->report(Diagnostics::INVALID_EXTENSION_BEHAVIOR,
+				                     token->location, token->text);
+				valid = false;
+			}
+			if (valid) behavior = token->text;
+			break;
+		default:
+			if (valid)
+			{
+				mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
+				                     token->location, token->text);
+				valid = false;
+			}
+			break;
+		}
+		mTokenizer->lex(token);
+	}
+	if (valid && (state != EXT_BEHAVIOR + 1))
+	{
+		mDiagnostics->report(Diagnostics::INVALID_EXTENSION_DIRECTIVE,
+		                     token->location, token->text);
+		valid = false;
+	}
+	if (valid)
+		mDirectiveHandler->handleExtension(token->location, name, behavior);
+}
+
+void DirectiveParser::parseVersion(Token* token)
+{
+	assert(getDirective(token) == DIRECTIVE_VERSION);
+
+	if (mPastFirstStatement)
+	{
+		mDiagnostics->report(Diagnostics::VERSION_NOT_FIRST_STATEMENT,
+		                     token->location, token->text);
+		skipUntilEOD(mTokenizer, token);
+		return;
+	}
+
+	enum State
+	{
+		VERSION_NUMBER,
+		VERSION_PROFILE,
+		VERSION_ENDLINE
+	};
+
+	bool valid = true;
+	int version = 0;
+	int state = VERSION_NUMBER;
+
+	mTokenizer->lex(token);
+	while (valid && (token->type != '\n') && (token->type != Token::LAST))
+	{
+		switch (state)
+		{
+		case VERSION_NUMBER:
+			if (token->type != Token::CONST_INT)
+			{
+				mDiagnostics->report(Diagnostics::INVALID_VERSION_NUMBER,
+				                     token->location, token->text);
+				valid = false;
+			}
+			if (valid && !token->iValue(&version))
+			{
+				mDiagnostics->report(Diagnostics::INTEGER_OVERFLOW,
+				                     token->location, token->text);
+				valid = false;
+			}
+			if (valid)
+			{
+				state = (version < 300) ? VERSION_ENDLINE : VERSION_PROFILE;
+			}
+			break;
+		case VERSION_PROFILE:
+			if (token->type != Token::IDENTIFIER || token->text != "es")
+			{
+				mDiagnostics->report(Diagnostics::INVALID_VERSION_DIRECTIVE,
+				                     token->location, token->text);
+				valid = false;
+			}
+			state = VERSION_ENDLINE;
+			break;
+		default:
+			mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
+			                     token->location, token->text);
+			valid = false;
+			break;
+		}
+
+		mTokenizer->lex(token);
+	}
+
+	if (valid && (state != VERSION_ENDLINE))
+	{
+		mDiagnostics->report(Diagnostics::INVALID_VERSION_DIRECTIVE,
+		                     token->location, token->text);
+		valid = false;
+	}
+
+	if (valid)
+	{
+		mDirectiveHandler->handleVersion(token->location, version);
+	}
+}
+
+void DirectiveParser::parseLine(Token* token)
+{
+	assert(getDirective(token) == DIRECTIVE_LINE);
+
+	enum State
+	{
+		LINE_NUMBER,
+		FILE_NUMBER
+	};
+
+	bool valid = true;
+	int line = 0, file = 0;
+	int state = LINE_NUMBER;
+
+	MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics, false);
+	macroExpander.lex(token);
+	while ((token->type != '\n') && (token->type != Token::LAST))
+	{
+		switch (state++)
+		{
+		case LINE_NUMBER:
+			if (valid && (token->type != Token::CONST_INT))
+			{
+				mDiagnostics->report(Diagnostics::INVALID_LINE_NUMBER,
+				                     token->location, token->text);
+				valid = false;
+			}
+			if (valid && !token->iValue(&line))
+			{
+				mDiagnostics->report(Diagnostics::INTEGER_OVERFLOW,
+				                     token->location, token->text);
+				valid = false;
+			}
+			break;
+		case FILE_NUMBER:
+			if (valid && (token->type != Token::CONST_INT))
+			{
+				mDiagnostics->report(Diagnostics::INVALID_FILE_NUMBER,
+				                     token->location, token->text);
+				valid = false;
+			}
+			if (valid && !token->iValue(&file))
+			{
+				mDiagnostics->report(Diagnostics::INTEGER_OVERFLOW,
+				                     token->location, token->text);
+				valid = false;
+			}
+			break;
+		default:
+			if (valid)
+			{
+				mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
+				                     token->location, token->text);
+				valid = false;
+			}
+			break;
+		}
+		macroExpander.lex(token);
+	}
+
+	if (valid && (state != FILE_NUMBER) && (state != FILE_NUMBER + 1))
+	{
+		mDiagnostics->report(Diagnostics::INVALID_LINE_DIRECTIVE,
+		                     token->location, token->text);
+		valid = false;
+	}
+	if (valid)
+	{
+		mTokenizer->setLineNumber(line);
+		if (state == FILE_NUMBER + 1) mTokenizer->setFileNumber(file);
+	}
+}
+
+bool DirectiveParser::skipping() const
+{
+	if (mConditionalStack.empty()) return false;
+
+	const ConditionalBlock& block = mConditionalStack.back();
+	return block.skipBlock || block.skipGroup;
+}
+
+void DirectiveParser::parseConditionalIf(Token* token)
+{
+	ConditionalBlock block;
+	block.type = token->text;
+	block.location = token->location;
+
+	if (skipping())
+	{
+		// This conditional block is inside another conditional group
+		// which is skipped. As a consequence this whole block is skipped.
+		// Be careful not to parse the conditional expression that might
+		// emit a diagnostic.
+		skipUntilEOD(mTokenizer, token);
+		block.skipBlock = true;
+	}
+	else
+	{
+		DirectiveType directive = getDirective(token);
+
+		int expression = 0;
+		switch (directive)
+		{
+		case DIRECTIVE_IF:
+			expression = parseExpressionIf(token);
+			break;
+		case DIRECTIVE_IFDEF:
+			expression = parseExpressionIfdef(token);
+			break;
+		case DIRECTIVE_IFNDEF:
+			expression = parseExpressionIfdef(token) == 0 ? 1 : 0;
+			break;
+		default:
+			assert(false);
+			break;
+		}
+		block.skipGroup = expression == 0;
+		block.foundValidGroup = expression != 0;
+	}
+	mConditionalStack.push_back(block);
+}
+
+int DirectiveParser::parseExpressionIf(Token* token)
+{
+	assert((getDirective(token) == DIRECTIVE_IF) ||
+	       (getDirective(token) == DIRECTIVE_ELIF));
+
+	MacroExpander macroExpander(mTokenizer, mMacroSet, mDiagnostics, true);
+	ExpressionParser expressionParser(&macroExpander, mDiagnostics);
+
+	int expression = 0;
+	macroExpander.lex(token);
+	expressionParser.parse(token, &expression);
+
+	// Check if there are tokens after #if expression.
+	if (!isEOD(token))
+	{
+		mDiagnostics->report(Diagnostics::CONDITIONAL_UNEXPECTED_TOKEN,
+		                     token->location, token->text);
+		skipUntilEOD(mTokenizer, token);
+	}
+
+	return expression;
+}
+
+int DirectiveParser::parseExpressionIfdef(Token* token)
+{
+	assert((getDirective(token) == DIRECTIVE_IFDEF) ||
+		   (getDirective(token) == DIRECTIVE_IFNDEF));
+
+	mTokenizer->lex(token);
+	if (token->type != Token::IDENTIFIER)
+	{
+		mDiagnostics->report(Diagnostics::UNEXPECTED_TOKEN,
+		                     token->location, token->text);
+		skipUntilEOD(mTokenizer, token);
+		return 0;
+	}
+
+	MacroSet::const_iterator iter = mMacroSet->find(token->text);
+	int expression = iter != mMacroSet->end() ? 1 : 0;
+
+	// Check if there are tokens after #ifdef expression.
+	mTokenizer->lex(token);
+	if (!isEOD(token))
+	{
+		mDiagnostics->report(Diagnostics::CONDITIONAL_UNEXPECTED_TOKEN,
+		                     token->location, token->text);
+		skipUntilEOD(mTokenizer, token);
+	}
+	return expression;
+}
+
+}  // namespace pp