| // | |
| // 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 "Diagnostics.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(int 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 | |