Home | History | Annotate | Download | only in preprocessor
      1 /*
      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 
      8 This file contains the Yacc grammar for GLSL ES preprocessor expression.
      9 
     10 IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_parser.sh,
     11 WHICH 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__)
     24 // Triggered by the auto-generated pplval variable.
     25 #if !defined(__clang__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))
     26 #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
     27 #else
     28 #pragma GCC diagnostic ignored "-Wuninitialized"
     29 #endif
     30 #elif defined(_MSC_VER)
     31 #pragma warning(disable: 4065 4701)
     32 #endif
     33 
     34 #include "ExpressionParser.h"
     35 
     36 #if defined(_MSC_VER)
     37 #include <malloc.h>
     38 #else
     39 #include <stdlib.h>
     40 #endif
     41 
     42 #include <cassert>
     43 #include <sstream>
     44 
     45 #include "DiagnosticsBase.h"
     46 #include "Lexer.h"
     47 #include "Token.h"
     48 
     49 #if defined(_MSC_VER)
     50 typedef __int64 YYSTYPE;
     51 #else
     52 #include <stdint.h>
     53 typedef intmax_t YYSTYPE;
     54 #endif  // _MSC_VER
     55 #define YYENABLE_NLS 0
     56 #define YYLTYPE_IS_TRIVIAL 1
     57 #define YYSTYPE_IS_TRIVIAL 1
     58 #define YYSTYPE_IS_DECLARED 1
     59 
     60 namespace {
     61 struct Context
     62 {
     63     pp::Diagnostics* diagnostics;
     64     pp::Lexer* lexer;
     65     pp::Token* token;
     66     int* result;
     67 };
     68 }  // namespace
     69 %}
     70 
     71 %pure-parser
     72 %name-prefix="pp"
     73 %parse-param {Context *context}
     74 %lex-param {Context *context}
     75 
     76 %{
     77 static int yylex(YYSTYPE* lvalp, Context* context);
     78 static void yyerror(Context* context, const char* reason);
     79 %}
     80 
     81 %token TOK_CONST_INT
     82 %left TOK_OP_OR
     83 %left TOK_OP_AND
     84 %left '|'
     85 %left '^'
     86 %left '&'
     87 %left TOK_OP_EQ TOK_OP_NE
     88 %left '<' '>' TOK_OP_LE TOK_OP_GE
     89 %left TOK_OP_LEFT TOK_OP_RIGHT
     90 %left '+' '-'
     91 %left '*' '/' '%'
     92 %right TOK_UNARY
     93 
     94 %%
     95 
     96 input
     97     : expression {
     98         *(context->result) = static_cast<int>($1);
     99         YYACCEPT;
    100     }
    101 ;
    102 
    103 expression
    104     : TOK_CONST_INT
    105     | expression TOK_OP_OR expression {
    106         $$ = $1 || $3;
    107     }
    108     | expression TOK_OP_AND expression {
    109         $$ = $1 && $3;
    110     }
    111     | expression '|' expression {
    112         $$ = $1 | $3;
    113     }
    114     | expression '^' expression {
    115         $$ = $1 ^ $3;
    116     }
    117     | expression '&' expression {
    118         $$ = $1 & $3;
    119     }
    120     | expression TOK_OP_NE expression {
    121         $$ = $1 != $3;
    122     }
    123     | expression TOK_OP_EQ expression {
    124         $$ = $1 == $3;
    125     }
    126     | expression TOK_OP_GE expression {
    127         $$ = $1 >= $3;
    128     }
    129     | expression TOK_OP_LE expression {
    130         $$ = $1 <= $3;
    131     }
    132     | expression '>' expression {
    133         $$ = $1 > $3;
    134     }
    135     | expression '<' expression {
    136         $$ = $1 < $3;
    137     }
    138     | expression TOK_OP_RIGHT expression {
    139         $$ = $1 >> $3;
    140     }
    141     | expression TOK_OP_LEFT expression {
    142         $$ = $1 << $3;
    143     }
    144     | expression '-' expression {
    145         $$ = $1 - $3;
    146     }
    147     | expression '+' expression {
    148         $$ = $1 + $3;
    149     }
    150     | expression '%' expression {
    151         if ($3 == 0) {
    152             std::ostringstream stream;
    153             stream << $1 << " % " << $3;
    154             std::string text = stream.str();
    155             context->diagnostics->report(pp::Diagnostics::PP_DIVISION_BY_ZERO,
    156                                          context->token->location,
    157                                          text.c_str());
    158             YYABORT;
    159         } else {
    160             $$ = $1 % $3;
    161         }
    162     }
    163     | expression '/' expression {
    164         if ($3 == 0) {
    165             std::ostringstream stream;
    166             stream << $1 << " / " << $3;
    167             std::string text = stream.str();
    168             context->diagnostics->report(pp::Diagnostics::PP_DIVISION_BY_ZERO,
    169                                          context->token->location,
    170                                          text.c_str());
    171             YYABORT;
    172         } else {
    173             $$ = $1 / $3;
    174         }
    175     }
    176     | expression '*' expression {
    177         $$ = $1 * $3;
    178     }
    179     | '!' expression %prec TOK_UNARY {
    180         $$ = ! $2;
    181     }
    182     | '~' expression %prec TOK_UNARY {
    183         $$ = ~ $2;
    184     }
    185     | '-' expression %prec TOK_UNARY {
    186         $$ = - $2;
    187     }
    188     | '+' expression %prec TOK_UNARY {
    189         $$ = + $2;
    190     }
    191     | '(' expression ')' {
    192         $$ = $2;
    193     }
    194 ;
    195 
    196 %%
    197 
    198 int yylex(YYSTYPE *lvalp, Context *context)
    199 {
    200     int type = 0;
    201 
    202     pp::Token *token = context->token;
    203     switch (token->type)
    204     {
    205       case pp::Token::CONST_INT: {
    206         unsigned int val = 0;
    207         if (!token->uValue(&val))
    208         {
    209             context->diagnostics->report(pp::Diagnostics::PP_INTEGER_OVERFLOW,
    210                                          token->location, token->text);
    211         }
    212         *lvalp = static_cast<YYSTYPE>(val);
    213         type = TOK_CONST_INT;
    214         break;
    215       }
    216       case pp::Token::OP_OR:
    217         type = TOK_OP_OR;
    218         break;
    219       case pp::Token::OP_AND:
    220         type = TOK_OP_AND;
    221         break;
    222       case pp::Token::OP_NE:
    223         type = TOK_OP_NE;
    224         break;
    225       case pp::Token::OP_EQ:
    226         type = TOK_OP_EQ;
    227         break;
    228       case pp::Token::OP_GE:
    229         type = TOK_OP_GE;
    230         break;
    231       case pp::Token::OP_LE:
    232         type = TOK_OP_LE;
    233         break;
    234       case pp::Token::OP_RIGHT:
    235         type = TOK_OP_RIGHT;
    236         break;
    237       case pp::Token::OP_LEFT:
    238         type = TOK_OP_LEFT;
    239         break;
    240       case '|':
    241       case '^':
    242       case '&':
    243       case '>':
    244       case '<':
    245       case '-':
    246       case '+':
    247       case '%':
    248       case '/':
    249       case '*':
    250       case '!':
    251       case '~':
    252       case '(':
    253       case ')':
    254         type = token->type;
    255         break;
    256 
    257       default:
    258         break;
    259     }
    260 
    261     // Advance to the next token if the current one is valid.
    262     if (type != 0)
    263         context->lexer->lex(token);
    264 
    265     return type;
    266 }
    267 
    268 void yyerror(Context *context, const char *reason)
    269 {
    270     context->diagnostics->report(pp::Diagnostics::PP_INVALID_EXPRESSION,
    271                                  context->token->location,
    272                                  reason);
    273 }
    274 
    275 namespace pp {
    276 
    277 ExpressionParser::ExpressionParser(Lexer *lexer, Diagnostics *diagnostics)
    278     : mLexer(lexer),
    279       mDiagnostics(diagnostics)
    280 {
    281 }
    282 
    283 bool ExpressionParser::parse(Token *token, int *result)
    284 {
    285     Context context;
    286     context.diagnostics = mDiagnostics;
    287     context.lexer = mLexer;
    288     context.token = token;
    289     context.result = result;
    290     int ret = yyparse(&context);
    291     switch (ret)
    292     {
    293       case 0:
    294       case 1:
    295         break;
    296 
    297       case 2:
    298         mDiagnostics->report(Diagnostics::PP_OUT_OF_MEMORY, token->location, "");
    299         break;
    300 
    301       default:
    302         assert(false);
    303         mDiagnostics->report(Diagnostics::PP_INTERNAL_ERROR, token->location, "");
    304         break;
    305     }
    306 
    307     return ret == 0;
    308 }
    309 
    310 }  // namespace pp
    311