Home | History | Annotate | Download | only in preprocessor
      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 
     88     void startIgnoreErrors() { ++ignoreErrors; }
     89     void endIgnoreErrors() { --ignoreErrors; }
     90 
     91     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 
    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 
    438 ExpressionParser::ExpressionParser(Lexer *lexer, Diagnostics *diagnostics)
    439     : mLexer(lexer),
    440       mDiagnostics(diagnostics)
    441 {
    442 }
    443 
    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