1 // 2 // Copyright (c) 2011 The ANGLE Project Authors. All rights reserved. 3 // Use of this source code is governed by a BSD-style license that can be 4 // found in the LICENSE file. 5 // 6 7 #include "Preprocessor.h" 8 9 #include <cassert> 10 #include <sstream> 11 12 #include "DiagnosticsBase.h" 13 #include "DirectiveParser.h" 14 #include "Macro.h" 15 #include "MacroExpander.h" 16 #include "Token.h" 17 #include "Tokenizer.h" 18 19 namespace pp 20 { 21 22 struct PreprocessorImpl 23 { 24 Diagnostics* diagnostics; 25 MacroSet macroSet; 26 Tokenizer tokenizer; 27 DirectiveParser directiveParser; 28 MacroExpander macroExpander; 29 30 PreprocessorImpl(Diagnostics* diag, 31 DirectiveHandler* directiveHandler) : 32 diagnostics(diag), 33 tokenizer(diag), 34 directiveParser(&tokenizer, ¯oSet, diag, directiveHandler), 35 macroExpander(&directiveParser, ¯oSet, diag) 36 { 37 } 38 }; 39 40 Preprocessor::Preprocessor(Diagnostics* diagnostics, 41 DirectiveHandler* directiveHandler) 42 { 43 mImpl = new PreprocessorImpl(diagnostics, directiveHandler); 44 } 45 46 Preprocessor::~Preprocessor() 47 { 48 delete mImpl; 49 } 50 51 bool Preprocessor::init(size_t count, 52 const char* const string[], 53 const int length[]) 54 { 55 static const int kGLSLVersion = 100; 56 57 // Add standard pre-defined macros. 58 predefineMacro("__LINE__", 0); 59 predefineMacro("__FILE__", 0); 60 predefineMacro("__VERSION__", kGLSLVersion); 61 predefineMacro("GL_ES", 1); 62 63 return mImpl->tokenizer.init(count, string, length); 64 } 65 66 void Preprocessor::predefineMacro(const char* name, int value) 67 { 68 std::ostringstream stream; 69 stream << value; 70 71 Token token; 72 token.type = Token::CONST_INT; 73 token.text = stream.str(); 74 75 Macro macro; 76 macro.predefined = true; 77 macro.type = Macro::kTypeObj; 78 macro.name = name; 79 macro.replacements.push_back(token); 80 81 mImpl->macroSet[name] = macro; 82 } 83 84 void Preprocessor::lex(Token* token) 85 { 86 bool validToken = false; 87 while (!validToken) 88 { 89 mImpl->macroExpander.lex(token); 90 switch (token->type) 91 { 92 // We should not be returning internal preprocessing tokens. 93 // Convert preprocessing tokens to compiler tokens or report 94 // diagnostics. 95 case Token::PP_HASH: 96 assert(false); 97 break; 98 case Token::CONST_INT: 99 { 100 int val = 0; 101 if (!token->iValue(&val)) 102 { 103 // Do not mark the token as invalid. 104 // Just emit the diagnostic and reset value to 0. 105 mImpl->diagnostics->report(Diagnostics::INTEGER_OVERFLOW, 106 token->location, token->text); 107 token->text.assign("0"); 108 } 109 validToken = true; 110 break; 111 } 112 case Token::CONST_FLOAT: 113 { 114 float val = 0; 115 if (!token->fValue(&val)) 116 { 117 // Do not mark the token as invalid. 118 // Just emit the diagnostic and reset value to 0.0. 119 mImpl->diagnostics->report(Diagnostics::FLOAT_OVERFLOW, 120 token->location, token->text); 121 token->text.assign("0.0"); 122 } 123 validToken = true; 124 break; 125 } 126 case Token::PP_NUMBER: 127 mImpl->diagnostics->report(Diagnostics::INVALID_NUMBER, 128 token->location, token->text); 129 break; 130 case Token::PP_OTHER: 131 mImpl->diagnostics->report(Diagnostics::INVALID_CHARACTER, 132 token->location, token->text); 133 break; 134 default: 135 validToken = true; 136 break; 137 } 138 } 139 } 140 141 } // namespace pp 142 143