1 /*
2 // Copyright 2016 The SwiftShader Authors. All Rights Reserved.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15
16 This file contains the Yacc grammar for GLSL ES preprocessor expression.
17
18 IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_parser.sh,
19 WHICH GENERATES THE GLSL ES preprocessor expression parser.
20 */
21
22 %{
23 // Copyright 2016 The SwiftShader Authors. All Rights Reserved.
24 //
25 // Licensed under the Apache License, Version 2.0 (the "License");
26 // you may not use this file except in compliance with the License.
27 // You may obtain a copy of the License at
28 //
29 // http://www.apache.org/licenses/LICENSE-2.0
30 //
31 // Unless required by applicable law or agreed to in writing, software
32 // distributed under the License is distributed on an "AS IS" BASIS,
33 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
34 // See the License for the specific language governing permissions and
35 // limitations under the License.
36
37 // This file is auto-generated by generate_parser.sh. DO NOT EDIT!
38
39 #if defined(__GNUC__)
40 // Triggered by the auto-generated pplval variable.
41 #pragma GCC diagnostic ignored "-Wuninitialized"
42 #elif defined(_MSC_VER)
43 #pragma warning(disable: 4065 4701)
44 #endif
45
46 #include "ExpressionParser.h"
47
48 #include <cassert>
49 #include <sstream>
50
51 #include "Diagnostics.h"
52 #include "Lexer.h"
53 #include "Token.h"
54
55 #if defined(_MSC_VER)
56 typedef __int64 YYSTYPE;
57 #else
58 #include <stdint.h>
59 typedef intmax_t YYSTYPE;
60 #endif // _MSC_VER
61 #define YYSTYPE_IS_TRIVIAL 1
62 #define YYSTYPE_IS_DECLARED 1
63
64 namespace {
65 struct Context
66 {
67 pp::Diagnostics* diagnostics;
68 pp::Lexer* lexer;
69 pp::Token* token;
70 int* result;
71 int shortCircuited; // Don't produce errors when > 0
72 };
73 } // namespace
74 %}
75
76 %pure-parser
77 %name-prefix "pp"
78 %parse-param {Context *context}
79 %lex-param {Context *context}
80
81 %{
82 static int yylex(YYSTYPE* lvalp, Context* context);
83 static void yyerror(Context* context, const char* reason);
84 %}
85
86 %token TOK_CONST_INT
87 %left TOK_OP_OR
88 %left TOK_OP_AND
89 %left '|'
90 %left '^'
91 %left '&'
92 %left TOK_OP_EQ TOK_OP_NE
93 %left '<' '>' TOK_OP_LE TOK_OP_GE
94 %left TOK_OP_LEFT TOK_OP_RIGHT
95 %left '+' '-'
96 %left '*' '/' '%'
97 %right TOK_UNARY
98
99 %%
100
101 input
102 : expression {
103 *(context->result) = static_cast<int>($1);
104 YYACCEPT;
105 }
106 ;
107
108 expression
109 : TOK_CONST_INT
110 | expression TOK_OP_OR {
111 if ($1 != 0)
112 {
113 context->shortCircuited++;
114 }
115 } expression {
116 if ($1 != 0)
117 {
118 context->shortCircuited--;
119 $$ = 1;
120 }
121 else
122 {
123 $$ = $1 || $4;
124 }
125 }
126 | expression TOK_OP_AND {
127 if ($1 == 0)
128 {
129 context->shortCircuited++;
130 }
131 } expression {
132 if ($1 == 0)
133 {
134 context->shortCircuited--;
135 $$ = 0;
136 }
137 else
138 {
139 $$ = $1 && $4;
140 }
141 }
142 | expression '|' expression {
143 $$ = $1 | $3;
144 }
145 | expression '^' expression {
146 $$ = $1 ^ $3;
147 }
148 | expression '&' expression {
149 $$ = $1 & $3;
150 }
151 | expression TOK_OP_NE expression {
152 $$ = $1 != $3;
153 }
154 | expression TOK_OP_EQ expression {
155 $$ = $1 == $3;
156 }
157 | expression TOK_OP_GE expression {
158 $$ = $1 >= $3;
159 }
160 | expression TOK_OP_LE expression {
161 $$ = $1 <= $3;
162 }
163 | expression '>' expression {
164 $$ = $1 > $3;
165 }
166 | expression '<' expression {
167 $$ = $1 < $3;
168 }
169 | expression TOK_OP_RIGHT expression {
170 $$ = $1 >> $3;
171 }
172 | expression TOK_OP_LEFT expression {
173 $$ = $1 << $3;
174 }
175 | expression '-' expression {
176 $$ = $1 - $3;
177 }
178 | expression '+' expression {
179 $$ = $1 + $3;
180 }
181 | expression '%' expression {
182 if ($3 == 0)
183 {
184 if (!context->shortCircuited)
185 {
186 context->diagnostics->report(pp::Diagnostics::DIVISION_BY_ZERO,
187 context->token->location, "");
188 YYABORT;
189 }
190 else
191 {
192 $$ = 0;
193 }
194 }
195 else
196 {
197 $$ = $1 % $3;
198 }
199 }
200 | expression '/' expression {
201 if ($3 == 0)
202 {
203 if (!context->shortCircuited)
204 {
205 context->diagnostics->report(pp::Diagnostics::DIVISION_BY_ZERO,
206 context->token->location, "");
207 YYABORT;
208 }
209 else
210 {
211 $$ = 0;
212 }
213 }
214 else
215 {
216 $$ = $1 / $3;
217 }
218 }
219 | expression '*' expression {
220 $$ = $1 * $3;
221 }
222 | '!' expression %prec TOK_UNARY {
223 $$ = ! $2;
224 }
225 | '~' expression %prec TOK_UNARY {
226 $$ = ~ $2;
227 }
228 | '-' expression %prec TOK_UNARY {
229 $$ = - $2;
230 }
231 | '+' expression %prec TOK_UNARY {
232 $$ = + $2;
233 }
234 | '(' expression ')' {
235 $$ = $2;
236 }
237 ;
238
239 %%
240
241 int yylex(YYSTYPE* lvalp, Context* context)
242 {
243 int type = 0;
244
245 pp::Token* token = context->token;
246 switch (token->type)
247 {
248 case pp::Token::CONST_INT:
249 {
250 unsigned int val = 0;
251 if (!token->uValue(&val))
252 {
253 context->diagnostics->report(pp::Diagnostics::INTEGER_OVERFLOW,
254 token->location, token->text);
255 }
256 *lvalp = static_cast<YYSTYPE>(val);
257 type = TOK_CONST_INT;
258 break;
259 }
260 case pp::Token::IDENTIFIER:
261 if (!context->shortCircuited)
262 {
263 // Defined identifiers should have been expanded already.
264 // Unlike the C/C++ preprocessor, it does not default to 0.
265 // Use of such identifiers causes an error.
266 context->diagnostics->report(pp::Diagnostics::UNDEFINED_IDENTIFIER,
267 token->location, token->text);
268 }
269
270 *lvalp = 0;
271 type = TOK_CONST_INT;
272 break;
273 case pp::Token::OP_OR: type = TOK_OP_OR; break;
274 case pp::Token::OP_AND: type = TOK_OP_AND; break;
275 case pp::Token::OP_NE: type = TOK_OP_NE; break;
276 case pp::Token::OP_EQ: type = TOK_OP_EQ; break;
277 case pp::Token::OP_GE: type = TOK_OP_GE; break;
278 case pp::Token::OP_LE: type = TOK_OP_LE; break;
279 case pp::Token::OP_RIGHT: type = TOK_OP_RIGHT; break;
280 case pp::Token::OP_LEFT: type = TOK_OP_LEFT; break;
281 case '|': type = '|'; break;
282 case '^': type = '^'; break;
283 case '&': type = '&'; break;
284 case '>': type = '>'; break;
285 case '<': type = '<'; break;
286 case '-': type = '-'; break;
287 case '+': type = '+'; break;
288 case '%': type = '%'; break;
289 case '/': type = '/'; break;
290 case '*': type = '*'; break;
291 case '!': type = '!'; break;
292 case '~': type = '~'; break;
293 case '(': type = '('; break;
294 case ')': type = ')'; break;
295
296 default: break;
297 }
298
299 // Advance to the next token if the current one is valid.
300 if (type != 0) context->lexer->lex(token);
301
302 return type;
303 }
304
yyerror(Context * context,const char * reason)305 void yyerror(Context* context, const char* reason)
306 {
307 context->diagnostics->report(pp::Diagnostics::INVALID_EXPRESSION,
308 context->token->location,
309 reason);
310 }
311
312 namespace pp {
313
ExpressionParser(Lexer * lexer,Diagnostics * diagnostics)314 ExpressionParser::ExpressionParser(Lexer* lexer, Diagnostics* diagnostics) :
315 mLexer(lexer),
316 mDiagnostics(diagnostics)
317 {
318 }
319
parse(Token * token,int * result)320 bool ExpressionParser::parse(Token* token, int* result)
321 {
322 Context context;
323 context.diagnostics = mDiagnostics;
324 context.lexer = mLexer;
325 context.token = token;
326 context.result = result;
327 context.shortCircuited = 0;
328 int ret = yyparse(&context);
329 switch (ret)
330 {
331 case 0:
332 case 1:
333 break;
334
335 case 2:
336 mDiagnostics->report(Diagnostics::OUT_OF_MEMORY, token->location, "");
337 break;
338
339 default:
340 assert(false);
341 mDiagnostics->report(Diagnostics::INTERNAL_ERROR, token->location, "");
342 break;
343 }
344
345 return ret == 0;
346 }
347
348 } // namespace pp
349