| // |
| // 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 "Preprocessor.h" |
| |
| #include <cassert> |
| #include <sstream> |
| |
| #include "DiagnosticsBase.h" |
| #include "DirectiveParser.h" |
| #include "Macro.h" |
| #include "MacroExpander.h" |
| #include "Token.h" |
| #include "Tokenizer.h" |
| |
| namespace pp |
| { |
| |
| struct PreprocessorImpl |
| { |
| Diagnostics* diagnostics; |
| MacroSet macroSet; |
| Tokenizer tokenizer; |
| DirectiveParser directiveParser; |
| MacroExpander macroExpander; |
| |
| PreprocessorImpl(Diagnostics* diag, |
| DirectiveHandler* directiveHandler) : |
| diagnostics(diag), |
| tokenizer(diag), |
| directiveParser(&tokenizer, ¯oSet, diag, directiveHandler), |
| macroExpander(&directiveParser, ¯oSet, diag) |
| { |
| } |
| }; |
| |
| Preprocessor::Preprocessor(Diagnostics* diagnostics, |
| DirectiveHandler* directiveHandler) |
| { |
| mImpl = new PreprocessorImpl(diagnostics, directiveHandler); |
| } |
| |
| Preprocessor::~Preprocessor() |
| { |
| delete mImpl; |
| } |
| |
| bool Preprocessor::init(size_t count, |
| const char* const string[], |
| const int length[]) |
| { |
| static const int kGLSLVersion = 100; |
| |
| // Add standard pre-defined macros. |
| predefineMacro("__LINE__", 0); |
| predefineMacro("__FILE__", 0); |
| predefineMacro("__VERSION__", kGLSLVersion); |
| predefineMacro("GL_ES", 1); |
| |
| return mImpl->tokenizer.init(count, string, length); |
| } |
| |
| void Preprocessor::predefineMacro(const char* name, int value) |
| { |
| std::ostringstream stream; |
| stream << value; |
| |
| Token token; |
| token.type = Token::CONST_INT; |
| token.text = stream.str(); |
| |
| Macro macro; |
| macro.predefined = true; |
| macro.type = Macro::kTypeObj; |
| macro.name = name; |
| macro.replacements.push_back(token); |
| |
| mImpl->macroSet[name] = macro; |
| } |
| |
| void Preprocessor::lex(Token* token) |
| { |
| bool validToken = false; |
| while (!validToken) |
| { |
| mImpl->macroExpander.lex(token); |
| switch (token->type) |
| { |
| // We should not be returning internal preprocessing tokens. |
| // Convert preprocessing tokens to compiler tokens or report |
| // diagnostics. |
| case Token::PP_HASH: |
| assert(false); |
| break; |
| case Token::CONST_INT: |
| { |
| int val = 0; |
| if (!token->iValue(&val)) |
| { |
| // Do not mark the token as invalid. |
| // Just emit the diagnostic and reset value to 0. |
| mImpl->diagnostics->report(Diagnostics::INTEGER_OVERFLOW, |
| token->location, token->text); |
| token->text.assign("0"); |
| } |
| validToken = true; |
| break; |
| } |
| case Token::CONST_FLOAT: |
| { |
| float val = 0; |
| if (!token->fValue(&val)) |
| { |
| // Do not mark the token as invalid. |
| // Just emit the diagnostic and reset value to 0.0. |
| mImpl->diagnostics->report(Diagnostics::FLOAT_OVERFLOW, |
| token->location, token->text); |
| token->text.assign("0.0"); |
| } |
| validToken = true; |
| break; |
| } |
| case Token::PP_NUMBER: |
| mImpl->diagnostics->report(Diagnostics::INVALID_NUMBER, |
| token->location, token->text); |
| break; |
| case Token::PP_OTHER: |
| mImpl->diagnostics->report(Diagnostics::INVALID_CHARACTER, |
| token->location, token->text); |
| break; |
| default: |
| validToken = true; |
| break; |
| } |
| } |
| } |
| |
| } // namespace pp |
| |