michael@0: // michael@0: // Copyright (c) 2011 The ANGLE Project Authors. All rights reserved. michael@0: // Use of this source code is governed by a BSD-style license that can be michael@0: // found in the LICENSE file. michael@0: // michael@0: michael@0: #include "Preprocessor.h" michael@0: michael@0: #include michael@0: #include michael@0: michael@0: #include "DiagnosticsBase.h" michael@0: #include "DirectiveParser.h" michael@0: #include "Macro.h" michael@0: #include "MacroExpander.h" michael@0: #include "Token.h" michael@0: #include "Tokenizer.h" michael@0: michael@0: namespace pp michael@0: { michael@0: michael@0: struct PreprocessorImpl michael@0: { michael@0: Diagnostics* diagnostics; michael@0: MacroSet macroSet; michael@0: Tokenizer tokenizer; michael@0: DirectiveParser directiveParser; michael@0: MacroExpander macroExpander; michael@0: michael@0: PreprocessorImpl(Diagnostics* diag, michael@0: DirectiveHandler* directiveHandler) : michael@0: diagnostics(diag), michael@0: tokenizer(diag), michael@0: directiveParser(&tokenizer, ¯oSet, diag, directiveHandler), michael@0: macroExpander(&directiveParser, ¯oSet, diag) michael@0: { michael@0: } michael@0: }; michael@0: michael@0: Preprocessor::Preprocessor(Diagnostics* diagnostics, michael@0: DirectiveHandler* directiveHandler) michael@0: { michael@0: mImpl = new PreprocessorImpl(diagnostics, directiveHandler); michael@0: } michael@0: michael@0: Preprocessor::~Preprocessor() michael@0: { michael@0: delete mImpl; michael@0: } michael@0: michael@0: bool Preprocessor::init(size_t count, michael@0: const char* const string[], michael@0: const int length[]) michael@0: { michael@0: static const int kGLSLVersion = 100; michael@0: michael@0: // Add standard pre-defined macros. michael@0: predefineMacro("__LINE__", 0); michael@0: predefineMacro("__FILE__", 0); michael@0: predefineMacro("__VERSION__", kGLSLVersion); michael@0: predefineMacro("GL_ES", 1); michael@0: michael@0: return mImpl->tokenizer.init(count, string, length); michael@0: } michael@0: michael@0: void Preprocessor::predefineMacro(const char* name, int value) michael@0: { michael@0: std::ostringstream stream; michael@0: stream << value; michael@0: michael@0: Token token; michael@0: token.type = Token::CONST_INT; michael@0: token.text = stream.str(); michael@0: michael@0: Macro macro; michael@0: macro.predefined = true; michael@0: macro.type = Macro::kTypeObj; michael@0: macro.name = name; michael@0: macro.replacements.push_back(token); michael@0: michael@0: mImpl->macroSet[name] = macro; michael@0: } michael@0: michael@0: void Preprocessor::lex(Token* token) michael@0: { michael@0: bool validToken = false; michael@0: while (!validToken) michael@0: { michael@0: mImpl->macroExpander.lex(token); michael@0: switch (token->type) michael@0: { michael@0: // We should not be returning internal preprocessing tokens. michael@0: // Convert preprocessing tokens to compiler tokens or report michael@0: // diagnostics. michael@0: case Token::PP_HASH: michael@0: assert(false); michael@0: break; michael@0: case Token::CONST_INT: michael@0: { michael@0: int val = 0; michael@0: if (!token->iValue(&val)) michael@0: { michael@0: // Do not mark the token as invalid. michael@0: // Just emit the diagnostic and reset value to 0. michael@0: mImpl->diagnostics->report(Diagnostics::INTEGER_OVERFLOW, michael@0: token->location, token->text); michael@0: token->text.assign("0"); michael@0: } michael@0: validToken = true; michael@0: break; michael@0: } michael@0: case Token::CONST_FLOAT: michael@0: { michael@0: float val = 0; michael@0: if (!token->fValue(&val)) michael@0: { michael@0: // Do not mark the token as invalid. michael@0: // Just emit the diagnostic and reset value to 0.0. michael@0: mImpl->diagnostics->report(Diagnostics::FLOAT_OVERFLOW, michael@0: token->location, token->text); michael@0: token->text.assign("0.0"); michael@0: } michael@0: validToken = true; michael@0: break; michael@0: } michael@0: case Token::PP_NUMBER: michael@0: mImpl->diagnostics->report(Diagnostics::INVALID_NUMBER, michael@0: token->location, token->text); michael@0: break; michael@0: case Token::PP_OTHER: michael@0: mImpl->diagnostics->report(Diagnostics::INVALID_CHARACTER, michael@0: token->location, token->text); michael@0: break; michael@0: default: michael@0: validToken = true; michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: michael@0: } // namespace pp michael@0: