• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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