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 #pragma GCC diagnostic ignored "-Wuninitialized"
     42 #elif defined(_MSC_VER)
     43 #pragma warning(disable: 4065 4701)
     44 #endif
     45 
     46 #include "ExpressionParser.h"
     47 
     48 #include <cassert>
     49 #include <sstream>
     50 
     51 #include "Diagnostics.h"
     52 #include "Lexer.h"
     53 #include "Token.h"
     54 
     55 #if defined(_MSC_VER)
     56 typedef __int64 YYSTYPE;
     57 #else
     58 #include <stdint.h>
     59 typedef intmax_t YYSTYPE;
     60 #endif  // _MSC_VER
     61 #define YYSTYPE_IS_TRIVIAL 1
     62 #define YYSTYPE_IS_DECLARED 1
     63 
     64 namespace {
     65 struct Context
     66 {
     67     pp::Diagnostics* diagnostics;
     68     pp::Lexer* lexer;
     69     pp::Token* token;
     70     int* result;
     71     int shortCircuited;   // Don't produce errors when > 0
     72 };
     73 }  // namespace
     74 %}
     75 
     76 %pure-parser
     77 %name-prefix "pp"
     78 %parse-param {Context *context}
     79 %lex-param {Context *context}
     80 
     81 %{
     82 static int yylex(YYSTYPE* lvalp, Context* context);
     83 static void yyerror(Context* context, const char* reason);
     84 %}
     85 
     86 %token TOK_CONST_INT
     87 %left TOK_OP_OR
     88 %left TOK_OP_AND
     89 %left '|'
     90 %left '^'
     91 %left '&'
     92 %left TOK_OP_EQ TOK_OP_NE
     93 %left '<' '>' TOK_OP_LE TOK_OP_GE
     94 %left TOK_OP_LEFT TOK_OP_RIGHT
     95 %left '+' '-'
     96 %left '*' '/' '%'
     97 %right TOK_UNARY
     98 
     99 %%
    100 
    101 input
    102     : expression {
    103         *(context->result) = static_cast<int>($1);
    104         YYACCEPT;
    105     }
    106 ;
    107 
    108 expression
    109     : TOK_CONST_INT
    110     | expression TOK_OP_OR {
    111         if ($1 != 0)
    112         {
    113             context->shortCircuited++;
    114         }
    115     } expression {
    116         if ($1 != 0)
    117         {
    118             context->shortCircuited--;
    119             $$ = 1;
    120         }
    121         else
    122         {
    123             $$ = $1 || $4;
    124         }
    125     }
    126     | expression TOK_OP_AND {
    127         if ($1 == 0)
    128         {
    129             context->shortCircuited++;
    130         }
    131     } expression {
    132         if ($1 == 0)
    133         {
    134             context->shortCircuited--;
    135             $$ = 0;
    136         }
    137         else
    138         {
    139             $$ = $1 && $4;
    140         }
    141     }
    142     | expression '|' expression {
    143         $$ = $1 | $3;
    144     }
    145     | expression '^' expression {
    146         $$ = $1 ^ $3;
    147     }
    148     | expression '&' expression {
    149         $$ = $1 & $3;
    150     }
    151     | expression TOK_OP_NE expression {
    152         $$ = $1 != $3;
    153     }
    154     | expression TOK_OP_EQ expression {
    155         $$ = $1 == $3;
    156     }
    157     | expression TOK_OP_GE expression {
    158         $$ = $1 >= $3;
    159     }
    160     | expression TOK_OP_LE expression {
    161         $$ = $1 <= $3;
    162     }
    163     | expression '>' expression {
    164         $$ = $1 > $3;
    165     }
    166     | expression '<' expression {
    167         $$ = $1 < $3;
    168     }
    169     | expression TOK_OP_RIGHT expression {
    170         $$ = $1 >> $3;
    171     }
    172     | expression TOK_OP_LEFT expression {
    173         $$ = $1 << $3;
    174     }
    175     | expression '-' expression {
    176         $$ = $1 - $3;
    177     }
    178     | expression '+' expression {
    179         $$ = $1 + $3;
    180     }
    181     | expression '%' expression {
    182         if ($3 == 0)
    183         {
    184             if (!context->shortCircuited)
    185             {
    186                 context->diagnostics->report(pp::Diagnostics::DIVISION_BY_ZERO,
    187                                              context->token->location, "");
    188                 YYABORT;
    189             }
    190             else
    191             {
    192                 $$ = 0;
    193             }
    194         }
    195         else
    196         {
    197             $$ = $1 % $3;
    198         }
    199     }
    200     | expression '/' expression {
    201         if ($3 == 0)
    202         {
    203             if (!context->shortCircuited)
    204             {
    205                 context->diagnostics->report(pp::Diagnostics::DIVISION_BY_ZERO,
    206                                              context->token->location, "");
    207                 YYABORT;
    208             }
    209             else
    210             {
    211                 $$ = 0;
    212             }
    213         }
    214         else
    215         {
    216             $$ = $1 / $3;
    217         }
    218     }
    219     | expression '*' expression {
    220         $$ = $1 * $3;
    221     }
    222     | '!' expression %prec TOK_UNARY {
    223         $$ = ! $2;
    224     }
    225     | '~' expression %prec TOK_UNARY {
    226         $$ = ~ $2;
    227     }
    228     | '-' expression %prec TOK_UNARY {
    229         $$ = - $2;
    230     }
    231     | '+' expression %prec TOK_UNARY {
    232         $$ = + $2;
    233     }
    234     | '(' expression ')' {
    235         $$ = $2;
    236     }
    237 ;
    238 
    239 %%
    240 
    241 int yylex(YYSTYPE* lvalp, Context* context)
    242 {
    243     int type = 0;
    244 
    245     pp::Token* token = context->token;
    246     switch (token->type)
    247     {
    248       case pp::Token::CONST_INT:
    249       {
    250         unsigned int val = 0;
    251         if (!token->uValue(&val))
    252         {
    253             context->diagnostics->report(pp::Diagnostics::INTEGER_OVERFLOW,
    254                                          token->location, token->text);
    255         }
    256         *lvalp = static_cast<YYSTYPE>(val);
    257         type = TOK_CONST_INT;
    258         break;
    259       }
    260       case pp::Token::IDENTIFIER:
    261         if (!context->shortCircuited)
    262         {
    263             // Defined identifiers should have been expanded already.
    264             // Unlike the C/C++ preprocessor, it does not default to 0.
    265             // Use of such identifiers causes an error.
    266             context->diagnostics->report(pp::Diagnostics::UNDEFINED_IDENTIFIER,
    267                                          token->location, token->text);
    268         }
    269 
    270         *lvalp = 0;
    271         type = TOK_CONST_INT;
    272         break;
    273       case pp::Token::OP_OR: type = TOK_OP_OR; break;
    274       case pp::Token::OP_AND: type = TOK_OP_AND; break;
    275       case pp::Token::OP_NE: type = TOK_OP_NE; break;
    276       case pp::Token::OP_EQ: type = TOK_OP_EQ; break;
    277       case pp::Token::OP_GE: type = TOK_OP_GE; break;
    278       case pp::Token::OP_LE: type = TOK_OP_LE; break;
    279       case pp::Token::OP_RIGHT: type = TOK_OP_RIGHT; break;
    280       case pp::Token::OP_LEFT: type = TOK_OP_LEFT; break;
    281       case '|': type = '|'; break;
    282       case '^': type = '^'; break;
    283       case '&': type = '&'; break;
    284       case '>': type = '>'; break;
    285       case '<': type = '<'; break;
    286       case '-': type = '-'; break;
    287       case '+': type = '+'; break;
    288       case '%': type = '%'; break;
    289       case '/': type = '/'; break;
    290       case '*': type = '*'; break;
    291       case '!': type = '!'; break;
    292       case '~': type = '~'; break;
    293       case '(': type = '('; break;
    294       case ')': type = ')'; break;
    295 
    296       default: break;
    297     }
    298 
    299     // Advance to the next token if the current one is valid.
    300     if (type != 0) context->lexer->lex(token);
    301 
    302     return type;
    303 }
    304 
    305 void yyerror(Context* context, const char* reason)
    306 {
    307     context->diagnostics->report(pp::Diagnostics::INVALID_EXPRESSION,
    308                                  context->token->location,
    309                                  reason);
    310 }
    311 
    312 namespace pp {
    313 
    314 ExpressionParser::ExpressionParser(Lexer* lexer, Diagnostics* diagnostics) :
    315     mLexer(lexer),
    316     mDiagnostics(diagnostics)
    317 {
    318 }
    319 
    320 bool ExpressionParser::parse(Token* token, int* result)
    321 {
    322     Context context;
    323     context.diagnostics = mDiagnostics;
    324     context.lexer = mLexer;
    325     context.token = token;
    326     context.result = result;
    327     context.shortCircuited = 0;
    328     int ret = yyparse(&context);
    329     switch (ret)
    330     {
    331       case 0:
    332       case 1:
    333         break;
    334 
    335       case 2:
    336         mDiagnostics->report(Diagnostics::OUT_OF_MEMORY, token->location, "");
    337         break;
    338 
    339       default:
    340         assert(false);
    341         mDiagnostics->report(Diagnostics::INTERNAL_ERROR, token->location, "");
    342         break;
    343     }
    344 
    345     return ret == 0;
    346 }
    347 
    348 }  // namespace pp
    349