Home | History | Annotate | Download | only in preprocessor
      1 // Copyright 2016 The SwiftShader Authors. All Rights Reserved.
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //    http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 #include "Preprocessor.h"
     16 
     17 #include <cassert>
     18 #include <sstream>
     19 
     20 #include "Diagnostics.h"
     21 #include "DirectiveParser.h"
     22 #include "Macro.h"
     23 #include "MacroExpander.h"
     24 #include "Token.h"
     25 #include "Tokenizer.h"
     26 
     27 namespace pp
     28 {
     29 
     30 struct PreprocessorImpl
     31 {
     32 	Diagnostics* diagnostics;
     33 	MacroSet macroSet;
     34 	Tokenizer tokenizer;
     35 	DirectiveParser directiveParser;
     36 	MacroExpander macroExpander;
     37 
     38 	PreprocessorImpl(Diagnostics* diag, DirectiveHandler* directiveHandler) :
     39 		diagnostics(diag),
     40 		tokenizer(diag),
     41 		directiveParser(&tokenizer, &macroSet, diag, directiveHandler),
     42 		macroExpander(&directiveParser, &macroSet, diag, false)
     43 	{
     44 	}
     45 };
     46 
     47 Preprocessor::Preprocessor(Diagnostics* diagnostics,
     48                            DirectiveHandler* directiveHandler)
     49 {
     50 	mImpl = new PreprocessorImpl(diagnostics, directiveHandler);
     51 }
     52 
     53 Preprocessor::~Preprocessor()
     54 {
     55 	delete mImpl;
     56 }
     57 
     58 bool Preprocessor::init(int count,
     59                         const char* const string[],
     60                         const int length[])
     61 {
     62 	static const int kGLSLVersion = 100;
     63 
     64 	// Add standard pre-defined macros.
     65 	predefineMacro("__LINE__", 0);
     66 	predefineMacro("__FILE__", 0);
     67 	predefineMacro("__VERSION__", kGLSLVersion);
     68 	predefineMacro("GL_ES", 1);
     69 
     70 	return mImpl->tokenizer.init(count, string, length);
     71 }
     72 
     73 void Preprocessor::predefineMacro(const char* name, int value)
     74 {
     75 	std::ostringstream stream;
     76 	stream << value;
     77 
     78 	Token token;
     79 	token.type = Token::CONST_INT;
     80 	token.text = stream.str();
     81 
     82 	Macro macro;
     83 	macro.predefined = true;
     84 	macro.type = Macro::kTypeObj;
     85 	macro.name = name;
     86 	macro.replacements.push_back(token);
     87 
     88 	mImpl->macroSet[name] = macro;
     89 }
     90 
     91 void Preprocessor::lex(Token* token)
     92 {
     93 	bool validToken = false;
     94 	while (!validToken)
     95 	{
     96 		mImpl->macroExpander.lex(token);
     97 		switch (token->type)
     98 		{
     99 		// We should not be returning internal preprocessing tokens.
    100 		// Convert preprocessing tokens to compiler tokens or report
    101 		// diagnostics.
    102 		case Token::PP_HASH:
    103 			assert(false);
    104 			break;
    105 		case Token::CONST_INT:
    106 		  {
    107 			int val = 0;
    108 			if (!token->iValue(&val))
    109 			{
    110 				// Do not mark the token as invalid.
    111 				// Just emit the diagnostic and reset value to 0.
    112 				mImpl->diagnostics->report(Diagnostics::INTEGER_OVERFLOW,
    113 				                           token->location, token->text);
    114 				token->text.assign("0");
    115 			}
    116 			validToken = true;
    117 			break;
    118 		  }
    119 		case Token::CONST_FLOAT:
    120 		  {
    121 			float val = 0;
    122 			if (!token->fValue(&val))
    123 			{
    124 				// Do not mark the token as invalid.
    125 				// Just emit the diagnostic and reset value to 0.0.
    126 				mImpl->diagnostics->report(Diagnostics::FLOAT_OVERFLOW,
    127 				                           token->location, token->text);
    128 				token->text.assign("0.0");
    129 			}
    130 			validToken = true;
    131 			break;
    132 		  }
    133 		case Token::PP_NUMBER:
    134 			mImpl->diagnostics->report(Diagnostics::INVALID_NUMBER,
    135 			                           token->location, token->text);
    136 			break;
    137 		case Token::PP_OTHER:
    138 			mImpl->diagnostics->report(Diagnostics::INVALID_CHARACTER,
    139 			                           token->location, token->text);
    140 			break;
    141 		default:
    142 			validToken = true;
    143 			break;
    144 		}
    145 	}
    146 }
    147 
    148 }  // namespace pp
    149 
    150