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