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