blob: a98638a8df8c9a3e0e3f3e6c281ed6231826f1e1 [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 }
Olli Etuaho7f9a55f2016-10-03 14:32:08 +0100236 else if ($1 < 0)
237 {
238 // Logical shift left.
239 $$ = static_cast<YYSTYPE>(static_cast<UNSIGNED_TYPE>($1) << $3);
240 }
Jamie Madill461e3af2016-07-21 18:15:34 -0400241 else
242 {
243 $$ = $1 << $3;
244 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000245 }
246 | expression '-' expression {
Olli Etuaho7f9a55f2016-10-03 14:32:08 +0100247 $$ = gl::WrappingDiff<YYSTYPE>($1, $3);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000248 }
249 | expression '+' expression {
Olli Etuaho7f9a55f2016-10-03 14:32:08 +0100250 $$ = gl::WrappingSum<YYSTYPE>($1, $3);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000251 }
252 | expression '%' expression {
Olli Etuaho809ec542015-08-26 14:30:57 +0300253 if ($3 == 0)
254 {
Olli Etuaho3187a382015-09-09 12:00:12 +0300255 if (!context->isIgnoringErrors())
Olli Etuaho809ec542015-08-26 14:30:57 +0300256 {
257 std::ostringstream stream;
258 stream << $1 << " % " << $3;
259 std::string text = stream.str();
260 context->diagnostics->report(pp::Diagnostics::PP_DIVISION_BY_ZERO,
261 context->token->location,
262 text.c_str());
Olli Etuaho247374c2015-09-09 15:07:24 +0300263 *(context->valid) = false;
Olli Etuaho809ec542015-08-26 14:30:57 +0300264 }
Olli Etuaho3187a382015-09-09 12:00:12 +0300265 $$ = static_cast<YYSTYPE>(0);
Olli Etuaho809ec542015-08-26 14:30:57 +0300266 }
267 else
268 {
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000269 $$ = $1 % $3;
270 }
271 }
272 | expression '/' expression {
Olli Etuaho809ec542015-08-26 14:30:57 +0300273 if ($3 == 0)
274 {
Olli Etuaho3187a382015-09-09 12:00:12 +0300275 if (!context->isIgnoringErrors())
Olli Etuaho809ec542015-08-26 14:30:57 +0300276 {
277 std::ostringstream stream;
278 stream << $1 << " / " << $3;
279 std::string text = stream.str();
280 context->diagnostics->report(pp::Diagnostics::PP_DIVISION_BY_ZERO,
281 context->token->location,
282 text.c_str());
Olli Etuaho247374c2015-09-09 15:07:24 +0300283 *(context->valid) = false;
Olli Etuaho809ec542015-08-26 14:30:57 +0300284 }
Olli Etuaho3187a382015-09-09 12:00:12 +0300285 $$ = static_cast<YYSTYPE>(0);
Olli Etuaho809ec542015-08-26 14:30:57 +0300286 }
Olli Etuaho7f9a55f2016-10-03 14:32:08 +0100287 else if ($1 == std::numeric_limits<YYSTYPE>::min() && $3 == -1)
288 {
289 // Check for the special case where the minimum representable number is
290 // divided by -1. If left alone this leads to integer overflow in C++, which
291 // has undefined results.
292 $$ = std::numeric_limits<YYSTYPE>::max();
293 }
Olli Etuaho809ec542015-08-26 14:30:57 +0300294 else
295 {
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000296 $$ = $1 / $3;
297 }
298 }
299 | expression '*' expression {
Olli Etuaho7f9a55f2016-10-03 14:32:08 +0100300 $$ = gl::WrappingMul($1, $3);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000301 }
maxvujovic@gmail.come640ef82012-07-13 18:42:40 +0000302 | '!' expression %prec TOK_UNARY {
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000303 $$ = ! $2;
304 }
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 {
Olli Etuaho7f9a55f2016-10-03 14:32:08 +0100309 // Check for negation of minimum representable integer to prevent undefined signed int
310 // overflow.
311 if ($2 == std::numeric_limits<YYSTYPE>::min())
312 {
313 $$ = std::numeric_limits<YYSTYPE>::min();
314 }
315 else
316 {
317 $$ = -$2;
318 }
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000319 }
maxvujovic@gmail.come640ef82012-07-13 18:42:40 +0000320 | '+' expression %prec TOK_UNARY {
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000321 $$ = + $2;
322 }
323 | '(' expression ')' {
324 $$ = $2;
325 }
326;
327
328%%
329
Zhenyao Mod526f982014-05-13 14:51:19 -0700330int yylex(YYSTYPE *lvalp, Context *context)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000331{
Olli Etuaho3187a382015-09-09 12:00:12 +0300332 pp::Token *token = context->token;
Olli Etuaho247374c2015-09-09 15:07:24 +0300333 if (!context->parsePresetToken)
334 {
335 context->lexer->lex(token);
336 }
337 context->parsePresetToken = false;
Olli Etuaho3187a382015-09-09 12:00:12 +0300338
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000339 int type = 0;
340
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000341 switch (token->type)
342 {
Zhenyao Mod526f982014-05-13 14:51:19 -0700343 case pp::Token::CONST_INT: {
alokp@chromium.org2e818912012-06-29 21:26:03 +0000344 unsigned int val = 0;
Olli Etuaho247374c2015-09-09 15:07:24 +0300345 int testVal = 0;
346 if (!token->uValue(&val) || (!token->iValue(&testVal) &&
347 context->errorSettings.integerLiteralsMustFit32BitSignedRange))
alokp@chromium.org2e818912012-06-29 21:26:03 +0000348 {
Jamie Madillc9f140d2014-02-18 15:27:21 -0500349 context->diagnostics->report(pp::Diagnostics::PP_INTEGER_OVERFLOW,
alokp@chromium.org2e818912012-06-29 21:26:03 +0000350 token->location, token->text);
Olli Etuaho247374c2015-09-09 15:07:24 +0300351 *(context->valid) = false;
alokp@chromium.org2e818912012-06-29 21:26:03 +0000352 }
353 *lvalp = static_cast<YYSTYPE>(val);
maxvujovic@gmail.come640ef82012-07-13 18:42:40 +0000354 type = TOK_CONST_INT;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000355 break;
alokp@chromium.org2e818912012-06-29 21:26:03 +0000356 }
Olli Etuaho809ec542015-08-26 14:30:57 +0300357 case pp::Token::IDENTIFIER:
Olli Etuaho809ec542015-08-26 14:30:57 +0300358 *lvalp = static_cast<YYSTYPE>(-1);
359 type = TOK_IDENTIFIER;
360 break;
Zhenyao Mod526f982014-05-13 14:51:19 -0700361 case pp::Token::OP_OR:
362 type = TOK_OP_OR;
363 break;
364 case pp::Token::OP_AND:
365 type = TOK_OP_AND;
366 break;
367 case pp::Token::OP_NE:
368 type = TOK_OP_NE;
369 break;
370 case pp::Token::OP_EQ:
371 type = TOK_OP_EQ;
372 break;
373 case pp::Token::OP_GE:
374 type = TOK_OP_GE;
375 break;
376 case pp::Token::OP_LE:
377 type = TOK_OP_LE;
378 break;
379 case pp::Token::OP_RIGHT:
380 type = TOK_OP_RIGHT;
381 break;
382 case pp::Token::OP_LEFT:
383 type = TOK_OP_LEFT;
384 break;
385 case '|':
386 case '^':
387 case '&':
388 case '>':
389 case '<':
390 case '-':
391 case '+':
392 case '%':
393 case '/':
394 case '*':
395 case '!':
396 case '~':
397 case '(':
398 case ')':
399 type = token->type;
400 break;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000401
Zhenyao Mod526f982014-05-13 14:51:19 -0700402 default:
403 break;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000404 }
405
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000406 return type;
407}
408
Zhenyao Mod526f982014-05-13 14:51:19 -0700409void yyerror(Context *context, const char *reason)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000410{
Jamie Madillc9f140d2014-02-18 15:27:21 -0500411 context->diagnostics->report(pp::Diagnostics::PP_INVALID_EXPRESSION,
alokp@chromium.org2c958ee2012-05-17 20:35:42 +0000412 context->token->location,
413 reason);
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000414}
415
416namespace pp {
417
Zhenyao Mod526f982014-05-13 14:51:19 -0700418ExpressionParser::ExpressionParser(Lexer *lexer, Diagnostics *diagnostics)
419 : mLexer(lexer),
420 mDiagnostics(diagnostics)
alokp@chromium.org2c958ee2012-05-17 20:35:42 +0000421{
422}
423
Olli Etuaho247374c2015-09-09 15:07:24 +0300424bool ExpressionParser::parse(Token *token,
425 int *result,
426 bool parsePresetToken,
427 const ErrorSettings &errorSettings,
428 bool *valid)
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000429{
430 Context context;
alokp@chromium.org2c958ee2012-05-17 20:35:42 +0000431 context.diagnostics = mDiagnostics;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000432 context.lexer = mLexer;
433 context.token = token;
434 context.result = result;
Olli Etuaho809ec542015-08-26 14:30:57 +0300435 context.ignoreErrors = 0;
Olli Etuaho247374c2015-09-09 15:07:24 +0300436 context.parsePresetToken = parsePresetToken;
437 context.errorSettings = errorSettings;
438 context.valid = valid;
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000439 int ret = yyparse(&context);
440 switch (ret)
441 {
442 case 0:
443 case 1:
444 break;
445
446 case 2:
Jamie Madillc9f140d2014-02-18 15:27:21 -0500447 mDiagnostics->report(Diagnostics::PP_OUT_OF_MEMORY, token->location, "");
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000448 break;
449
450 default:
451 assert(false);
Jamie Madillc9f140d2014-02-18 15:27:21 -0500452 mDiagnostics->report(Diagnostics::PP_INTERNAL_ERROR, token->location, "");
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000453 break;
454 }
alokp@chromium.org2c958ee2012-05-17 20:35:42 +0000455
alokp@chromium.org04d7d222012-05-16 19:24:07 +0000456 return ret == 0;
457}
458
459} // namespace pp