xref: /aosp_15_r20/external/angle/src/compiler/preprocessor/preprocessor.y (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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