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 #if !defined(__clang__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))
42 #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
43 #else
44 #pragma GCC diagnostic ignored "-Wuninitialized"
45 #endif
46 #elif defined(_MSC_VER)
47 #pragma warning(disable: 4065 4244 4701 4702)
48 #endif
49
50 #include "ExpressionParser.h"
51
52 #if defined(_MSC_VER)
53 #include <malloc.h>
54 #else
55 #include <stdlib.h>
56 #endif
57
58 #include <limits>
59 #include <cassert>
60 #include <sstream>
61 #include <stdint.h>
62
63 #include "DiagnosticsBase.h"
64 #include "Lexer.h"
65 #include "Token.h"
66 #include "../../common/debug.h"
67
68 typedef int32_t YYSTYPE;
69 typedef uint32_t UNSIGNED_TYPE;
70
71 #define YYENABLE_NLS 0
72 #define YYLTYPE_IS_TRIVIAL 1
73 #define YYSTYPE_IS_TRIVIAL 1
74 #define YYSTYPE_IS_DECLARED 1
75
76 namespace {
77 struct Context
78 {
79 pp::Diagnostics* diagnostics;
80 pp::Lexer* lexer;
81 pp::Token* token;
82 int* result;
83 bool parsePresetToken;
84
85 pp::ExpressionParser::ErrorSettings errorSettings;
86 bool *valid;
87
startIgnoreErrorsContext88 void startIgnoreErrors() { ++ignoreErrors; }
endIgnoreErrorsContext89 void endIgnoreErrors() { --ignoreErrors; }
90
isIgnoringErrorsContext91 bool isIgnoringErrors() { return ignoreErrors > 0; }
92
93 int ignoreErrors;
94 };
95 } // namespace
96 %}
97
98 %pure-parser
99 %name-prefix "pp"
100 %parse-param {Context *context}
101 %lex-param {Context *context}
102
103 %{
104 static int yylex(YYSTYPE* lvalp, Context* context);
105 static void yyerror(Context* context, const char* reason);
106 %}
107
108 %token TOK_CONST_INT
109 %token TOK_IDENTIFIER
110 %left TOK_OP_OR
111 %left TOK_OP_AND
112 %left '|'
113 %left '^'
114 %left '&'
115 %left TOK_OP_EQ TOK_OP_NE
116 %left '<' '>' TOK_OP_LE TOK_OP_GE
117 %left TOK_OP_LEFT TOK_OP_RIGHT
118 %left '+' '-'
119 %left '*' '/' '%'
120 %right TOK_UNARY
121
122 %%
123
124 input
125 : expression {
126 *(context->result) = static_cast<int>($1);
127 YYACCEPT;
128 }
129 ;
130
131 expression
132 : TOK_CONST_INT
133 | TOK_IDENTIFIER {
134 if (!context->isIgnoringErrors())
135 {
136 // This rule should be applied right after the token is lexed, so we can
137 // refer to context->token in the error message.
138 context->diagnostics->report(context->errorSettings.unexpectedIdentifier,
139 context->token->location, context->token->text);
140 *(context->valid) = false;
141 }
142 $$ = $1;
143 }
144 | expression TOK_OP_OR {
145 if ($1 != 0)
146 {
147 // Ignore errors in the short-circuited part of the expression.
148 // ESSL3.00 section 3.4:
149 // If an operand is not evaluated, the presence of undefined identifiers
150 // in the operand will not cause an error.
151 // Unevaluated division by zero should not cause an error either.
152 context->startIgnoreErrors();
153 }
154 } expression {
155 if ($1 != 0)
156 {
157 context->endIgnoreErrors();
158 $$ = static_cast<YYSTYPE>(1);
159 }
160 else
161 {
162 $$ = $1 || $4;
163 }
164 }
165 | expression TOK_OP_AND {
166 if ($1 == 0)
167 {
168 // Ignore errors in the short-circuited part of the expression.
169 // ESSL3.00 section 3.4:
170 // If an operand is not evaluated, the presence of undefined identifiers
171 // in the operand will not cause an error.
172 // Unevaluated division by zero should not cause an error either.
173 context->startIgnoreErrors();
174 }
175 } expression {
176 if ($1 == 0)
177 {
178 context->endIgnoreErrors();
179 $$ = static_cast<YYSTYPE>(0);
180 }
181 else
182 {
183 $$ = $1 && $4;
184 }
185 }
186 | expression '|' expression {
187 $$ = $1 | $3;
188 }
189 | expression '^' expression {
190 $$ = $1 ^ $3;
191 }
192 | expression '&' expression {
193 $$ = $1 & $3;
194 }
195 | expression TOK_OP_NE expression {
196 $$ = $1 != $3;
197 }
198 | expression TOK_OP_EQ expression {
199 $$ = $1 == $3;
200 }
201 | expression TOK_OP_GE expression {
202 $$ = $1 >= $3;
203 }
204 | expression TOK_OP_LE expression {
205 $$ = $1 <= $3;
206 }
207 | expression '>' expression {
208 $$ = $1 > $3;
209 }
210 | expression '<' expression {
211 $$ = $1 < $3;
212 }
213 | expression TOK_OP_RIGHT expression {
214 if ($3 < 0 || $3 > 31)
215 {
216 if (!context->isIgnoringErrors())
217 {
218 std::ostringstream stream;
219 stream << $1 << " >> " << $3;
220 std::string text = stream.str();
221 context->diagnostics->report(pp::Diagnostics::PP_UNDEFINED_SHIFT,
222 context->token->location,
223 text.c_str());
224 *(context->valid) = false;
225 }
226 $$ = static_cast<YYSTYPE>(0);
227 }
228 else if ($1 < 0)
229 {
230 // Logical shift right.
231 $$ = static_cast<YYSTYPE>(static_cast<UNSIGNED_TYPE>($1) >> $3);
232 }
233 else
234 {
235 $$ = $1 >> $3;
236 }
237 }
238 | expression TOK_OP_LEFT expression {
239 if ($3 < 0 || $3 > 31)
240 {
241 if (!context->isIgnoringErrors())
242 {
243 std::ostringstream stream;
244 stream << $1 << " << " << $3;
245 std::string text = stream.str();
246 context->diagnostics->report(pp::Diagnostics::PP_UNDEFINED_SHIFT,
247 context->token->location,
248 text.c_str());
249 *(context->valid) = false;
250 }
251 $$ = static_cast<YYSTYPE>(0);
252 }
253 else
254 {
255 // Logical shift left. Casting to unsigned is needed to ensure there's no signed integer
256 // overflow, which some tools treat as an error.
257 $$ = static_cast<YYSTYPE>(static_cast<UNSIGNED_TYPE>($1) << $3);
258 }
259 }
260 | expression '-' expression {
261 $$ = $1 - $3;
262 }
263 | expression '+' expression {
264 $$ = $1 + $3;
265 }
266 | expression '%' expression {
267 if ($3 == 0)
268 {
269 if (!context->isIgnoringErrors())
270 {
271 std::ostringstream stream;
272 stream << $1 << " % " << $3;
273 std::string text = stream.str();
274 context->diagnostics->report(pp::Diagnostics::PP_DIVISION_BY_ZERO,
275 context->token->location,
276 text.c_str());
277 *(context->valid) = false;
278 }
279 $$ = static_cast<YYSTYPE>(0);
280 }
281 else if (($1 == std::numeric_limits<YYSTYPE>::min()) && ($3 == -1))
282 {
283 // Check for the special case where the minimum representable number is
284 // divided by -1. If left alone this has undefined results.
285 $$ = 0;
286 }
287 else
288 {
289 $$ = $1 % $3;
290 }
291 }
292 | expression '/' expression {
293 if ($3 == 0)
294 {
295 if (!context->isIgnoringErrors())
296 {
297 std::ostringstream stream;
298 stream << $1 << " / " << $3;
299 std::string text = stream.str();
300 context->diagnostics->report(pp::Diagnostics::PP_DIVISION_BY_ZERO,
301 context->token->location,
302 text.c_str());
303 *(context->valid) = false;
304 }
305 $$ = static_cast<YYSTYPE>(0);
306 }
307 else if (($1 == std::numeric_limits<YYSTYPE>::min()) && ($3 == -1))
308 {
309 // Check for the special case where the minimum representable number is
310 // divided by -1. If left alone this leads to integer overflow in C++, which
311 // has undefined results.
312 $$ = std::numeric_limits<YYSTYPE>::max();
313 }
314 else
315 {
316 $$ = $1 / $3;
317 }
318 }
319 | expression '*' expression {
320 $$ = $1 * $3;
321 }
322 | '!' expression %prec TOK_UNARY {
323 $$ = ! $2;
324 }
325 | '~' expression %prec TOK_UNARY {
326 $$ = ~ $2;
327 }
328 | '-' expression %prec TOK_UNARY {
329 // Check for negation of minimum representable integer to prevent undefined signed int
330 // overflow.
331 if ($2 == std::numeric_limits<YYSTYPE>::min())
332 {
333 $$ = std::numeric_limits<YYSTYPE>::min();
334 }
335 else
336 {
337 $$ = -$2;
338 }
339 }
340 | '+' expression %prec TOK_UNARY {
341 $$ = + $2;
342 }
343 | '(' expression ')' {
344 $$ = $2;
345 }
346 ;
347
348 %%
349
350 int yylex(YYSTYPE *lvalp, Context *context)
351 {
352 pp::Token *token = context->token;
353 if (!context->parsePresetToken)
354 {
355 context->lexer->lex(token);
356 }
357 context->parsePresetToken = false;
358
359 int type = 0;
360
361 switch (token->type)
362 {
363 case pp::Token::CONST_INT: {
364 unsigned int val = 0;
365 int testVal = 0;
366 if (!token->uValue(&val) || (!token->iValue(&testVal) &&
367 context->errorSettings.integerLiteralsMustFit32BitSignedRange))
368 {
369 context->diagnostics->report(pp::Diagnostics::PP_INTEGER_OVERFLOW,
370 token->location, token->text);
371 *(context->valid) = false;
372 }
373 *lvalp = static_cast<YYSTYPE>(val);
374 type = TOK_CONST_INT;
375 break;
376 }
377 case pp::Token::IDENTIFIER:
378 *lvalp = static_cast<YYSTYPE>(-1);
379 type = TOK_IDENTIFIER;
380 break;
381 case pp::Token::OP_OR:
382 type = TOK_OP_OR;
383 break;
384 case pp::Token::OP_AND:
385 type = TOK_OP_AND;
386 break;
387 case pp::Token::OP_NE:
388 type = TOK_OP_NE;
389 break;
390 case pp::Token::OP_EQ:
391 type = TOK_OP_EQ;
392 break;
393 case pp::Token::OP_GE:
394 type = TOK_OP_GE;
395 break;
396 case pp::Token::OP_LE:
397 type = TOK_OP_LE;
398 break;
399 case pp::Token::OP_RIGHT:
400 type = TOK_OP_RIGHT;
401 break;
402 case pp::Token::OP_LEFT:
403 type = TOK_OP_LEFT;
404 break;
405 case '|':
406 case '^':
407 case '&':
408 case '>':
409 case '<':
410 case '-':
411 case '+':
412 case '%':
413 case '/':
414 case '*':
415 case '!':
416 case '~':
417 case '(':
418 case ')':
419 type = token->type;
420 break;
421
422 default:
423 break;
424 }
425
426 return type;
427 }
428
yyerror(Context * context,const char * reason)429 void yyerror(Context *context, const char *reason)
430 {
431 context->diagnostics->report(pp::Diagnostics::PP_INVALID_EXPRESSION,
432 context->token->location,
433 reason);
434 }
435
436 namespace pp {
437
ExpressionParser(Lexer * lexer,Diagnostics * diagnostics)438 ExpressionParser::ExpressionParser(Lexer *lexer, Diagnostics *diagnostics)
439 : mLexer(lexer),
440 mDiagnostics(diagnostics)
441 {
442 }
443
parse(Token * token,int * result,bool parsePresetToken,const ErrorSettings & errorSettings,bool * valid)444 bool ExpressionParser::parse(Token *token,
445 int *result,
446 bool parsePresetToken,
447 const ErrorSettings &errorSettings,
448 bool *valid)
449 {
450 Context context;
451 context.diagnostics = mDiagnostics;
452 context.lexer = mLexer;
453 context.token = token;
454 context.result = result;
455 context.ignoreErrors = 0;
456 context.parsePresetToken = parsePresetToken;
457 context.errorSettings = errorSettings;
458 context.valid = valid;
459 int ret = yyparse(&context);
460 switch (ret)
461 {
462 case 0:
463 case 1:
464 break;
465
466 case 2:
467 mDiagnostics->report(Diagnostics::PP_OUT_OF_MEMORY, token->location, "");
468 break;
469
470 default:
471 assert(false);
472 mDiagnostics->report(Diagnostics::PP_INTERNAL_ERROR, token->location, "");
473 break;
474 }
475
476 return ret == 0;
477 }
478
479 } // namespace pp
480