blob: 68d7cc3958cc4c8f5caad9867b5579ae12fdb6a2 [file] [log] [blame]
alokp@chromium.org04d7d222012-05-16 19:24:07 +00001/*
2//
3// Copyright (c) 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
8This file contains the Yacc grammar for GLSL ES preprocessor expression.
9
10IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_parser.sh,
11WHICH GENERATES THE GLSL ES preprocessor expression parser.
12*/
13
14%{
15//
16// Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
17// Use of this source code is governed by a BSD-style license that can be
18// found in the LICENSE file.
19//
20
21// This file is auto-generated by generate_parser.sh. DO NOT EDIT!
22
23#if defined(__GNUC__)
maxvujovic@gmail.comc6b3b3c2012-06-27 22:49:39 +000024// Triggered by the auto-generated pplval variable.
shannon.woods@transgaming.comeb68fd02013-02-28 23:20:01 +000025#if !defined(__clang__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))
daniel@transgaming.comb3077d02013-01-11 04:12:09 +000026#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
shannon.woods@transgaming.comeb68fd02013-02-28 23:20:01 +000027#else
28#pragma GCC diagnostic ignored "-Wuninitialized"
shannon.woods@transgaming.come36fddf2013-01-25 21:57:50 +000029#endif
alokp@chromium.org04d7d222012-05-16 19:24:07 +000030#elif defined(_MSC_VER)
Minmin Gong794e0002015-04-07 18:31:54 -070031#pragma warning(disable: 4065 4244 4701 4702)
alokp@chromium.org04d7d222012-05-16 19:24:07 +000032#endif
33
34#include "ExpressionParser.h"
35
Jamie Madilla738f082013-11-01 17:45:04 -040036#if defined(_MSC_VER)
Jamie Madilld7f21352013-10-30 17:53:15 -040037#include <malloc.h>
Jamie Madilla738f082013-11-01 17:45:04 -040038#else
39#include <stdlib.h>
40#endif
41
alokp@chromium.org04d7d222012-05-16 19:24:07 +000042#include <cassert>
43#include <sstream>
Olli Etuaho7f9a55f2016-10-03 14:32:08 +010044#include <stdint.h>
alokp@chromium.org04d7d222012-05-16 19:24:07 +000045
daniel@transgaming.comb3077d02013-01-11 04:12:09 +000046#include "DiagnosticsBase.h"
alokp@chromium.org04d7d222012-05-16 19:24:07 +000047#include "Lexer.h"
48#include "Token.h"
Olli Etuaho7f9a55f2016-10-03 14:32:08 +010049#include "common/mathutil.h"
alokp@chromium.org04d7d222012-05-16 19:24:07 +000050
Olli Etuaho7f9a55f2016-10-03 14:32:08 +010051typedef int32_t YYSTYPE;
52typedef uint32_t UNSIGNED_TYPE;
Olli Etuaho3187a382015-09-09 12:00:12 +030053
daniel@transgaming.comb3077d02013-01-11 04:12:09 +000054#define YYENABLE_NLS 0
55#define YYLTYPE_IS_TRIVIAL 1
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000056#define YYSTYPE_IS_TRIVIAL 1
57#define YYSTYPE_IS_DECLARED 1
58
alokp@chromium.org04d7d222012-05-16 19:24:07 +000059namespace {
60struct Context
61{
alokp@chromium.org2c958ee2012-05-17 20:35:42 +000062 pp::Diagnostics* diagnostics;
alokp@chromium.org04d7d222012-05-16 19:24:07 +000063 pp::Lexer* lexer;
64 pp::Token* token;
65 int* result;
Olli Etuaho247374c2015-09-09 15:07:24 +030066 bool parsePresetToken;
67
68 pp::ExpressionParser::ErrorSettings errorSettings;
69 bool *valid;
Olli Etuaho809ec542015-08-26 14:30:57 +030070
71 void startIgnoreErrors() { ++ignoreErrors; }
72 void endIgnoreErrors() { --ignoreErrors; }
73
74 bool isIgnoringErrors() { return ignoreErrors > 0; }
75
76 int ignoreErrors;
alokp@chromium.org04d7d222012-05-16 19:24:07 +000077};
78} // namespace
79%}
80
maxvujovic@gmail.come640ef82012-07-13 18:42:40 +000081%pure-parser
Jamie Madill185de882014-12-22 15:17:52 -050082%name-prefix "pp"
alokp@chromium.org04d7d222012-05-16 19:24:07 +000083%parse-param {Context *context}
84%lex-param {Context *context}
85
86%{
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +000087static int yylex(YYSTYPE* lvalp, Context* context);
alokp@chromium.org04d7d222012-05-16 19:24:07 +000088static void yyerror(Context* context, const char* reason);
89%}
90
maxvujovic@gmail.come640ef82012-07-13 18:42:40 +000091%token TOK_CONST_INT
Olli Etuaho809ec542015-08-26 14:30:57 +030092%token TOK_IDENTIFIER
maxvujovic@gmail.come640ef82012-07-13 18:42:40 +000093%left TOK_OP_OR
94%left TOK_OP_AND
alokp@chromium.org04d7d222012-05-16 19:24:07 +000095%left '|'
96%left '^'
97%left '&'
maxvujovic@gmail.come640ef82012-07-13 18:42:40 +000098%left TOK_OP_EQ TOK_OP_NE
99%left '<' '>' TOK_OP_LE TOK_OP_GE
100%left TOK_OP_LEFT TOK_OP_RIGHT
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000101%left '+' '-'
102%left '*' '/' '%'
maxvujovic@gmail.come640ef82012-07-13 18:42:40 +0000103%right TOK_UNARY
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000104
105%%
106
107input
108 : expression {
alokp@chromium.orgd39ec4c2012-06-26 04:37:55 +0000109 *(context->result) = static_cast<int>($1);
Olli Etuaho3187a382015-09-09 12:00:12 +0300110 YYACCEPT;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000111 }
112;
113
114expression
maxvujovic@gmail.come640ef82012-07-13 18:42:40 +0000115 : TOK_CONST_INT
Olli Etuaho809ec542015-08-26 14:30:57 +0300116 | TOK_IDENTIFIER {
117 if (!context->isIgnoringErrors())
118 {
Olli Etuaho3187a382015-09-09 12:00:12 +0300119 // This rule should be applied right after the token is lexed, so we can
120 // refer to context->token in the error message.
Olli Etuaho247374c2015-09-09 15:07:24 +0300121 context->diagnostics->report(context->errorSettings.unexpectedIdentifier,
Olli Etuaho3187a382015-09-09 12:00:12 +0300122 context->token->location, context->token->text);
Olli Etuaho247374c2015-09-09 15:07:24 +0300123 *(context->valid) = false;
Olli Etuaho809ec542015-08-26 14:30:57 +0300124 }
Olli Etuaho3187a382015-09-09 12:00:12 +0300125 $$ = $1;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000126 }
Olli Etuaho809ec542015-08-26 14:30:57 +0300127 | expression TOK_OP_OR {
128 if ($1 != 0)
129 {
130 // Ignore errors in the short-circuited part of the expression.
131 // ESSL3.00 section 3.4:
132 // If an operand is not evaluated, the presence of undefined identifiers
133 // in the operand will not cause an error.
134 // Unevaluated division by zero should not cause an error either.
135 context->startIgnoreErrors();
136 }
137 } expression {
138 if ($1 != 0)
139 {
140 context->endIgnoreErrors();
141 $$ = static_cast<YYSTYPE>(1);
142 }
143 else
144 {
145 $$ = $1 || $4;
146 }
147 }
148 | expression TOK_OP_AND {
149 if ($1 == 0)
150 {
151 // Ignore errors in the short-circuited part of the expression.
152 // ESSL3.00 section 3.4:
153 // If an operand is not evaluated, the presence of undefined identifiers
154 // in the operand will not cause an error.
155 // Unevaluated division by zero should not cause an error either.
156 context->startIgnoreErrors();
157 }
158 } expression {
159 if ($1 == 0)
160 {
161 context->endIgnoreErrors();
162 $$ = static_cast<YYSTYPE>(0);
163 }
164 else
165 {
166 $$ = $1 && $4;
167 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000168 }
169 | expression '|' expression {
170 $$ = $1 | $3;
171 }
172 | expression '^' expression {
173 $$ = $1 ^ $3;
174 }
175 | expression '&' expression {
176 $$ = $1 & $3;
177 }
maxvujovic@gmail.come640ef82012-07-13 18:42:40 +0000178 | expression TOK_OP_NE expression {
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000179 $$ = $1 != $3;
180 }
maxvujovic@gmail.come640ef82012-07-13 18:42:40 +0000181 | expression TOK_OP_EQ expression {
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000182 $$ = $1 == $3;
183 }
maxvujovic@gmail.come640ef82012-07-13 18:42:40 +0000184 | expression TOK_OP_GE expression {
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000185 $$ = $1 >= $3;
186 }
maxvujovic@gmail.come640ef82012-07-13 18:42:40 +0000187 | expression TOK_OP_LE expression {
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000188 $$ = $1 <= $3;
189 }
190 | expression '>' expression {
191 $$ = $1 > $3;
192 }
193 | expression '<' expression {
194 $$ = $1 < $3;
195 }
maxvujovic@gmail.come640ef82012-07-13 18:42:40 +0000196 | expression TOK_OP_RIGHT expression {
Olli Etuaho7f9a55f2016-10-03 14:32:08 +0100197 if ($3 < 0 || $3 > 31)
Jamie Madill461e3af2016-07-21 18:15:34 -0400198 {
199 if (!context->isIgnoringErrors())
200 {
201 std::ostringstream stream;
202 stream << $1 << " >> " << $3;
203 std::string text = stream.str();
204 context->diagnostics->report(pp::Diagnostics::PP_UNDEFINED_SHIFT,
205 context->token->location,
206 text.c_str());
207 *(context->valid) = false;
208 }
209 $$ = static_cast<YYSTYPE>(0);
210 }
Olli Etuaho7f9a55f2016-10-03 14:32:08 +0100211 else if ($1 < 0)
212 {
213 // Logical shift right.
214 $$ = static_cast<YYSTYPE>(static_cast<UNSIGNED_TYPE>($1) >> $3);
215 }
Jamie Madill461e3af2016-07-21 18:15:34 -0400216 else
217 {
218 $$ = $1 >> $3;
219 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000220 }
maxvujovic@gmail.come640ef82012-07-13 18:42:40 +0000221 | expression TOK_OP_LEFT expression {
Olli Etuaho7f9a55f2016-10-03 14:32:08 +0100222 if ($3 < 0 || $3 > 31)
Jamie Madill461e3af2016-07-21 18:15:34 -0400223 {
224 if (!context->isIgnoringErrors())
225 {
226 std::ostringstream stream;
227 stream << $1 << " << " << $3;
228 std::string text = stream.str();
229 context->diagnostics->report(pp::Diagnostics::PP_UNDEFINED_SHIFT,
230 context->token->location,
231 text.c_str());
232 *(context->valid) = false;
233 }
234 $$ = static_cast<YYSTYPE>(0);
235 }
236 else
237 {
Olli Etuahoa3d384a2017-10-06 16:12:50 +0300238 // Logical shift left. Casting to unsigned is needed to ensure there's no signed integer
239 // overflow, which some tools treat as an error.
240 $$ = static_cast<YYSTYPE>(static_cast<UNSIGNED_TYPE>($1) << $3);
Jamie Madill461e3af2016-07-21 18:15:34 -0400241 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000242 }
243 | expression '-' expression {
Olli Etuaho7f9a55f2016-10-03 14:32:08 +0100244 $$ = gl::WrappingDiff<YYSTYPE>($1, $3);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000245 }
246 | expression '+' expression {
Olli Etuaho7f9a55f2016-10-03 14:32:08 +0100247 $$ = gl::WrappingSum<YYSTYPE>($1, $3);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000248 }
249 | expression '%' expression {
Olli Etuaho809ec542015-08-26 14:30:57 +0300250 if ($3 == 0)
251 {
Olli Etuaho3187a382015-09-09 12:00:12 +0300252 if (!context->isIgnoringErrors())
Olli Etuaho809ec542015-08-26 14:30:57 +0300253 {
254 std::ostringstream stream;
255 stream << $1 << " % " << $3;
256 std::string text = stream.str();
257 context->diagnostics->report(pp::Diagnostics::PP_DIVISION_BY_ZERO,
258 context->token->location,
259 text.c_str());
Olli Etuaho247374c2015-09-09 15:07:24 +0300260 *(context->valid) = false;
Olli Etuaho809ec542015-08-26 14:30:57 +0300261 }
Olli Etuaho3187a382015-09-09 12:00:12 +0300262 $$ = static_cast<YYSTYPE>(0);
Olli Etuaho809ec542015-08-26 14:30:57 +0300263 }
Olli Etuahod1d1dff2016-11-03 14:56:14 +0000264 else if (($1 == std::numeric_limits<YYSTYPE>::min()) && ($3 == -1))
265 {
266 // Check for the special case where the minimum representable number is
267 // divided by -1. If left alone this has undefined results.
268 $$ = 0;
269 }
Olli Etuaho809ec542015-08-26 14:30:57 +0300270 else
271 {
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000272 $$ = $1 % $3;
273 }
274 }
275 | expression '/' expression {
Olli Etuaho809ec542015-08-26 14:30:57 +0300276 if ($3 == 0)
277 {
Olli Etuaho3187a382015-09-09 12:00:12 +0300278 if (!context->isIgnoringErrors())
Olli Etuaho809ec542015-08-26 14:30:57 +0300279 {
280 std::ostringstream stream;
281 stream << $1 << " / " << $3;
282 std::string text = stream.str();
283 context->diagnostics->report(pp::Diagnostics::PP_DIVISION_BY_ZERO,
284 context->token->location,
285 text.c_str());
Olli Etuaho247374c2015-09-09 15:07:24 +0300286 *(context->valid) = false;
Olli Etuaho809ec542015-08-26 14:30:57 +0300287 }
Olli Etuaho3187a382015-09-09 12:00:12 +0300288 $$ = static_cast<YYSTYPE>(0);
Olli Etuaho809ec542015-08-26 14:30:57 +0300289 }
Olli Etuahod1d1dff2016-11-03 14:56:14 +0000290 else if (($1 == std::numeric_limits<YYSTYPE>::min()) && ($3 == -1))
Olli Etuaho7f9a55f2016-10-03 14:32:08 +0100291 {
292 // Check for the special case where the minimum representable number is
293 // divided by -1. If left alone this leads to integer overflow in C++, which
294 // has undefined results.
295 $$ = std::numeric_limits<YYSTYPE>::max();
296 }
Olli Etuaho809ec542015-08-26 14:30:57 +0300297 else
298 {
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000299 $$ = $1 / $3;
300 }
301 }
302 | expression '*' expression {
Olli Etuaho7f9a55f2016-10-03 14:32:08 +0100303 $$ = gl::WrappingMul($1, $3);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000304 }
maxvujovic@gmail.come640ef82012-07-13 18:42:40 +0000305 | '!' expression %prec TOK_UNARY {
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000306 $$ = ! $2;
307 }
maxvujovic@gmail.come640ef82012-07-13 18:42:40 +0000308 | '~' expression %prec TOK_UNARY {
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000309 $$ = ~ $2;
310 }
maxvujovic@gmail.come640ef82012-07-13 18:42:40 +0000311 | '-' expression %prec TOK_UNARY {
Olli Etuaho7f9a55f2016-10-03 14:32:08 +0100312 // Check for negation of minimum representable integer to prevent undefined signed int
313 // overflow.
314 if ($2 == std::numeric_limits<YYSTYPE>::min())
315 {
316 $$ = std::numeric_limits<YYSTYPE>::min();
317 }
318 else
319 {
320 $$ = -$2;
321 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000322 }
maxvujovic@gmail.come640ef82012-07-13 18:42:40 +0000323 | '+' expression %prec TOK_UNARY {
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000324 $$ = + $2;
325 }
326 | '(' expression ')' {
327 $$ = $2;
328 }
329;
330
331%%
332
Zhenyao Mod526f982014-05-13 14:51:19 -0700333int yylex(YYSTYPE *lvalp, Context *context)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000334{
Olli Etuaho3187a382015-09-09 12:00:12 +0300335 pp::Token *token = context->token;
Olli Etuaho247374c2015-09-09 15:07:24 +0300336 if (!context->parsePresetToken)
337 {
338 context->lexer->lex(token);
339 }
340 context->parsePresetToken = false;
Olli Etuaho3187a382015-09-09 12:00:12 +0300341
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000342 int type = 0;
343
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000344 switch (token->type)
345 {
Zhenyao Mod526f982014-05-13 14:51:19 -0700346 case pp::Token::CONST_INT: {
alokp@chromium.org2e818912012-06-29 21:26:03 +0000347 unsigned int val = 0;
Olli Etuaho247374c2015-09-09 15:07:24 +0300348 int testVal = 0;
349 if (!token->uValue(&val) || (!token->iValue(&testVal) &&
350 context->errorSettings.integerLiteralsMustFit32BitSignedRange))
alokp@chromium.org2e818912012-06-29 21:26:03 +0000351 {
Jamie Madillc9f140d2014-02-18 15:27:21 -0500352 context->diagnostics->report(pp::Diagnostics::PP_INTEGER_OVERFLOW,
alokp@chromium.org2e818912012-06-29 21:26:03 +0000353 token->location, token->text);
Olli Etuaho247374c2015-09-09 15:07:24 +0300354 *(context->valid) = false;
alokp@chromium.org2e818912012-06-29 21:26:03 +0000355 }
356 *lvalp = static_cast<YYSTYPE>(val);
maxvujovic@gmail.come640ef82012-07-13 18:42:40 +0000357 type = TOK_CONST_INT;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000358 break;
alokp@chromium.org2e818912012-06-29 21:26:03 +0000359 }
Olli Etuaho809ec542015-08-26 14:30:57 +0300360 case pp::Token::IDENTIFIER:
Olli Etuaho809ec542015-08-26 14:30:57 +0300361 *lvalp = static_cast<YYSTYPE>(-1);
362 type = TOK_IDENTIFIER;
363 break;
Zhenyao Mod526f982014-05-13 14:51:19 -0700364 case pp::Token::OP_OR:
365 type = TOK_OP_OR;
366 break;
367 case pp::Token::OP_AND:
368 type = TOK_OP_AND;
369 break;
370 case pp::Token::OP_NE:
371 type = TOK_OP_NE;
372 break;
373 case pp::Token::OP_EQ:
374 type = TOK_OP_EQ;
375 break;
376 case pp::Token::OP_GE:
377 type = TOK_OP_GE;
378 break;
379 case pp::Token::OP_LE:
380 type = TOK_OP_LE;
381 break;
382 case pp::Token::OP_RIGHT:
383 type = TOK_OP_RIGHT;
384 break;
385 case pp::Token::OP_LEFT:
386 type = TOK_OP_LEFT;
387 break;
388 case '|':
389 case '^':
390 case '&':
391 case '>':
392 case '<':
393 case '-':
394 case '+':
395 case '%':
396 case '/':
397 case '*':
398 case '!':
399 case '~':
400 case '(':
401 case ')':
402 type = token->type;
403 break;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000404
Zhenyao Mod526f982014-05-13 14:51:19 -0700405 default:
406 break;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000407 }
408
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000409 return type;
410}
411
Zhenyao Mod526f982014-05-13 14:51:19 -0700412void yyerror(Context *context, const char *reason)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000413{
Jamie Madillc9f140d2014-02-18 15:27:21 -0500414 context->diagnostics->report(pp::Diagnostics::PP_INVALID_EXPRESSION,
alokp@chromium.org2c958ee2012-05-17 20:35:42 +0000415 context->token->location,
416 reason);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000417}
418
419namespace pp {
420
Zhenyao Mod526f982014-05-13 14:51:19 -0700421ExpressionParser::ExpressionParser(Lexer *lexer, Diagnostics *diagnostics)
422 : mLexer(lexer),
423 mDiagnostics(diagnostics)
alokp@chromium.org2c958ee2012-05-17 20:35:42 +0000424{
425}
426
Olli Etuaho247374c2015-09-09 15:07:24 +0300427bool ExpressionParser::parse(Token *token,
428 int *result,
429 bool parsePresetToken,
430 const ErrorSettings &errorSettings,
431 bool *valid)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000432{
433 Context context;
alokp@chromium.org2c958ee2012-05-17 20:35:42 +0000434 context.diagnostics = mDiagnostics;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000435 context.lexer = mLexer;
436 context.token = token;
437 context.result = result;
Olli Etuaho809ec542015-08-26 14:30:57 +0300438 context.ignoreErrors = 0;
Olli Etuaho247374c2015-09-09 15:07:24 +0300439 context.parsePresetToken = parsePresetToken;
440 context.errorSettings = errorSettings;
441 context.valid = valid;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000442 int ret = yyparse(&context);
443 switch (ret)
444 {
445 case 0:
446 case 1:
447 break;
448
449 case 2:
Jamie Madillc9f140d2014-02-18 15:27:21 -0500450 mDiagnostics->report(Diagnostics::PP_OUT_OF_MEMORY, token->location, "");
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000451 break;
452
453 default:
454 assert(false);
Jamie Madillc9f140d2014-02-18 15:27:21 -0500455 mDiagnostics->report(Diagnostics::PP_INTERNAL_ERROR, token->location, "");
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000456 break;
457 }
alokp@chromium.org2c958ee2012-05-17 20:35:42 +0000458
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000459 return ret == 0;
460}
461
462} // namespace pp