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 
PreprocessorImplpp::PreprocessorImpl38 	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 
Preprocessor(Diagnostics * diagnostics,DirectiveHandler * directiveHandler)47 Preprocessor::Preprocessor(Diagnostics* diagnostics,
48                            DirectiveHandler* directiveHandler)
49 {
50 	mImpl = new PreprocessorImpl(diagnostics, directiveHandler);
51 }
52 
~Preprocessor()53 Preprocessor::~Preprocessor()
54 {
55 	delete mImpl;
56 }
57 
init(int count,const char * const string[],const int length[])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 
predefineMacro(const char * name,int value)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 
lex(Token * token)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