Edit

kc3-lang/angle/src/compiler/preprocessor/ExpressionParser.y

Branch :

  • Show log

    Commit

  • Author : Stuart Morgan
    Date : 2019-08-14 12:25:12
    Hash : 9d737966
    Message : Standardize copyright notices to project style For all "ANGLE Project" copyrights, standardize to the format specified by the style guide. Changes: - "Copyright (c)" and "Copyright(c)" changed to just "Copyright". - Removed the second half of date ranges ("Y1Y1-Y2Y2"->"Y1Y1"). - Fixed a small number of files that had no copyright date using the initial commit year from the version control history. - Fixed one instance of copyright being "The ANGLE Project" rather than "The ANGLE Project Authors" These changes are applied both to the copyright of source file, and where applicable to copyright statements that are generated by templates. BUG=angleproject:3811 Change-Id: I973dd65e4ef9deeba232d5be74c768256a0eb2e5 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1754397 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: Jamie Madill <jmadill@chromium.org>

  • src/compiler/preprocessor/ExpressionParser.y
  • /*
    //
    // Copyright 2012 The ANGLE Project Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style license that can be
    // found in the LICENSE file.
    //
    
    This file contains the Yacc grammar for GLSL ES preprocessor expression.
    
    IF YOU MODIFY THIS FILE YOU ALSO NEED TO RUN generate_parser.sh,
    WHICH GENERATES THE GLSL ES preprocessor expression parser.
    */
    
    %{
    //
    // Copyright 2012 The ANGLE Project Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style license that can be
    // found in the LICENSE file.
    //
    
    // This file is auto-generated by generate_parser.sh. DO NOT EDIT!
    
    #if defined(__GNUC__)
    // Triggered by the auto-generated pplval variable.
    #if !defined(__clang__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))
    #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
    #else
    #pragma GCC diagnostic ignored "-Wuninitialized"
    #endif
    #elif defined(_MSC_VER)
    #pragma warning(disable: 4065 4244 4701 4702)
    #endif
    #if defined(__clang__)
    #pragma clang diagnostic ignored "-Wunreachable-code"
    #endif
    
    #include "ExpressionParser.h"
    
    #if defined(_MSC_VER)
    #include <malloc.h>
    #else
    #include <stdlib.h>
    #endif
    
    #include <cassert>
    #include <sstream>
    #include <stdint.h>
    
    #include "DiagnosticsBase.h"
    #include "Lexer.h"
    #include "Token.h"
    #include "common/mathutil.h"
    
    typedef int32_t YYSTYPE;
    typedef uint32_t UNSIGNED_TYPE;
    
    #define YYENABLE_NLS 0
    #define YYLTYPE_IS_TRIVIAL 1
    #define YYSTYPE_IS_TRIVIAL 1
    #define YYSTYPE_IS_DECLARED 1
    
    namespace {
    struct Context
    {
        angle::pp::Diagnostics *diagnostics;
        angle::pp::Lexer *lexer;
        angle::pp::Token *token;
        int* result;
        bool parsePresetToken;
    
        angle::pp::ExpressionParser::ErrorSettings errorSettings;
        bool *valid;
    
        void startIgnoreErrors() { ++ignoreErrors; }
        void endIgnoreErrors() { --ignoreErrors; }
    
        bool isIgnoringErrors() { return ignoreErrors > 0; }
    
        int ignoreErrors;
    };
    }  // namespace
    %}
    
    %pure-parser
    %name-prefix "pp"
    %parse-param {Context *context}
    %lex-param {Context *context}
    
    %{
    static int yylex(YYSTYPE* lvalp, Context* context);
    static void yyerror(Context* context, const char* reason);
    %}
    
    %token TOK_CONST_INT
    %token TOK_IDENTIFIER
    %left TOK_OP_OR
    %left TOK_OP_AND
    %left '|'
    %left '^'
    %left '&'
    %left TOK_OP_EQ TOK_OP_NE
    %left '<' '>' TOK_OP_LE TOK_OP_GE
    %left TOK_OP_LEFT TOK_OP_RIGHT
    %left '+' '-'
    %left '*' '/' '%'
    %right TOK_UNARY
    
    %%
    
    input
        : expression {
            *(context->result) = static_cast<int>($1);
            YYACCEPT;
        }
    ;
    
    expression
        : TOK_CONST_INT
        | TOK_IDENTIFIER {
            if (!context->isIgnoringErrors())
            {
                // This rule should be applied right after the token is lexed, so we can
                // refer to context->token in the error message.
                context->diagnostics->report(context->errorSettings.unexpectedIdentifier,
                                             context->token->location, context->token->text);
                *(context->valid) = false;
            }
            $$ = $1;
        }
        | expression TOK_OP_OR {
            if ($1 != 0)
            {
                // Ignore errors in the short-circuited part of the expression.
                // ESSL3.00 section 3.4:
                // If an operand is not evaluated, the presence of undefined identifiers
                // in the operand will not cause an error.
                // Unevaluated division by zero should not cause an error either.
                context->startIgnoreErrors();
            }
        } expression {
            if ($1 != 0)
            {
                context->endIgnoreErrors();
                $$ = static_cast<YYSTYPE>(1);
            }
            else
            {
                $$ = $1 || $4;
            }
        }
        | expression TOK_OP_AND {
            if ($1 == 0)
            {
                // Ignore errors in the short-circuited part of the expression.
                // ESSL3.00 section 3.4:
                // If an operand is not evaluated, the presence of undefined identifiers
                // in the operand will not cause an error.
                // Unevaluated division by zero should not cause an error either.
                context->startIgnoreErrors();
            }
        } expression {
            if ($1 == 0)
            {
                context->endIgnoreErrors();
                $$ = static_cast<YYSTYPE>(0);
            }
            else
            {
                $$ = $1 && $4;
            }
        }
        | expression '|' expression {
            $$ = $1 | $3;
        }
        | expression '^' expression {
            $$ = $1 ^ $3;
        }
        | expression '&' expression {
            $$ = $1 & $3;
        }
        | expression TOK_OP_NE expression {
            $$ = $1 != $3;
        }
        | expression TOK_OP_EQ expression {
            $$ = $1 == $3;
        }
        | expression TOK_OP_GE expression {
            $$ = $1 >= $3;
        }
        | expression TOK_OP_LE expression {
            $$ = $1 <= $3;
        }
        | expression '>' expression {
            $$ = $1 > $3;
        }
        | expression '<' expression {
            $$ = $1 < $3;
        }
        | expression TOK_OP_RIGHT expression {
            if ($3 < 0 || $3 > 31)
            {
                if (!context->isIgnoringErrors())
                {
                    std::ostringstream stream;
                    stream << $1 << " >> " << $3;
                    std::string text = stream.str();
                    context->diagnostics->report(angle::pp::Diagnostics::PP_UNDEFINED_SHIFT,
                                                 context->token->location,
                                                 text.c_str());
                    *(context->valid) = false;
                }
                $$ = static_cast<YYSTYPE>(0);
            }
            else if ($1 < 0)
            {
                // Logical shift right.
                $$ = static_cast<YYSTYPE>(static_cast<UNSIGNED_TYPE>($1) >> $3);
            }
            else
            {
                $$ = $1 >> $3;
            }
        }
        | expression TOK_OP_LEFT expression {
            if ($3 < 0 || $3 > 31)
            {
                if (!context->isIgnoringErrors())
                {
                    std::ostringstream stream;
                    stream << $1 << " << " << $3;
                    std::string text = stream.str();
                    context->diagnostics->report(angle::pp::Diagnostics::PP_UNDEFINED_SHIFT,
                                                 context->token->location,
                                                 text.c_str());
                    *(context->valid) = false;
                }
                $$ = static_cast<YYSTYPE>(0);
            }
            else
            {
                // Logical shift left. Casting to unsigned is needed to ensure there's no signed integer
                // overflow, which some tools treat as an error.
                $$ = static_cast<YYSTYPE>(static_cast<UNSIGNED_TYPE>($1) << $3);
            }
        }
        | expression '-' expression {
            $$ = gl::WrappingDiff<YYSTYPE>($1, $3);
        }
        | expression '+' expression {
            $$ = gl::WrappingSum<YYSTYPE>($1, $3);
        }
        | expression '%' expression {
            if ($3 == 0)
            {
                if (!context->isIgnoringErrors())
                {
                    std::ostringstream stream;
                    stream << $1 << " % " << $3;
                    std::string text = stream.str();
                    context->diagnostics->report(angle::pp::Diagnostics::PP_DIVISION_BY_ZERO,
                                                 context->token->location,
                                                 text.c_str());
                    *(context->valid) = false;
                }
                $$ = static_cast<YYSTYPE>(0);
            }
            else if (($1 == std::numeric_limits<YYSTYPE>::min()) && ($3 == -1))
            {
                // Check for the special case where the minimum representable number is
                // divided by -1. If left alone this has undefined results.
                $$ = 0;
            }
            else
            {
                $$ = $1 % $3;
            }
        }
        | expression '/' expression {
            if ($3 == 0)
            {
                if (!context->isIgnoringErrors())
                {
                    std::ostringstream stream;
                    stream << $1 << " / " << $3;
                    std::string text = stream.str();
                    context->diagnostics->report(angle::pp::Diagnostics::PP_DIVISION_BY_ZERO,
                                                context->token->location,
                                                text.c_str());
                    *(context->valid) = false;
                }
                $$ = static_cast<YYSTYPE>(0);
            }
            else if (($1 == std::numeric_limits<YYSTYPE>::min()) && ($3 == -1))
            {
                // Check for the special case where the minimum representable number is
                // divided by -1. If left alone this leads to integer overflow in C++, which
                // has undefined results.
                $$ = std::numeric_limits<YYSTYPE>::max();
            }
            else
            {
                $$ = $1 / $3;
            }
        }
        | expression '*' expression {
            $$ = gl::WrappingMul($1, $3);
        }
        | '!' expression %prec TOK_UNARY {
            $$ = ! $2;
        }
        | '~' expression %prec TOK_UNARY {
            $$ = ~ $2;
        }
        | '-' expression %prec TOK_UNARY {
            // Check for negation of minimum representable integer to prevent undefined signed int
            // overflow.
            if ($2 == std::numeric_limits<YYSTYPE>::min())
            {
                $$ = std::numeric_limits<YYSTYPE>::min();
            }
            else
            {
                $$ = -$2;
            }
        }
        | '+' expression %prec TOK_UNARY {
            $$ = + $2;
        }
        | '(' expression ')' {
            $$ = $2;
        }
    ;
    
    %%
    
    int yylex(YYSTYPE *lvalp, Context *context)
    {
        angle::pp::Token *token = context->token;
        if (!context->parsePresetToken)
        {
            context->lexer->lex(token);
        }
        context->parsePresetToken = false;
    
        int type = 0;
    
        switch (token->type)
        {
          case angle::pp::Token::CONST_INT: {
            unsigned int val = 0;
            int testVal = 0;
            if (!token->uValue(&val) || (!token->iValue(&testVal) &&
                                         context->errorSettings.integerLiteralsMustFit32BitSignedRange))
            {
                context->diagnostics->report(angle::pp::Diagnostics::PP_INTEGER_OVERFLOW,
                                             token->location, token->text);
                *(context->valid) = false;
            }
            *lvalp = static_cast<YYSTYPE>(val);
            type = TOK_CONST_INT;
            break;
          }
          case angle::pp::Token::IDENTIFIER:
            *lvalp = static_cast<YYSTYPE>(-1);
            type = TOK_IDENTIFIER;
            break;
          case angle::pp::Token::OP_OR:
            type = TOK_OP_OR;
            break;
          case angle::pp::Token::OP_AND:
            type = TOK_OP_AND;
            break;
          case angle::pp::Token::OP_NE:
            type = TOK_OP_NE;
            break;
          case angle::pp::Token::OP_EQ:
            type = TOK_OP_EQ;
            break;
          case angle::pp::Token::OP_GE:
            type = TOK_OP_GE;
            break;
          case angle::pp::Token::OP_LE:
            type = TOK_OP_LE;
            break;
          case angle::pp::Token::OP_RIGHT:
            type = TOK_OP_RIGHT;
            break;
          case angle::pp::Token::OP_LEFT:
            type = TOK_OP_LEFT;
            break;
          case '|':
          case '^':
          case '&':
          case '>':
          case '<':
          case '-':
          case '+':
          case '%':
          case '/':
          case '*':
          case '!':
          case '~':
          case '(':
          case ')':
            type = token->type;
            break;
    
          default:
            break;
        }
    
        return type;
    }
    
    void yyerror(Context *context, const char *reason)
    {
        context->diagnostics->report(angle::pp::Diagnostics::PP_INVALID_EXPRESSION,
                                     context->token->location,
                                     reason);
    }
    
    namespace angle {
    
    namespace pp {
    
    ExpressionParser::ExpressionParser(Lexer *lexer, Diagnostics *diagnostics)
        : mLexer(lexer),
          mDiagnostics(diagnostics)
    {
    }
    
    bool ExpressionParser::parse(Token *token,
                                 int *result,
                                 bool parsePresetToken,
                                 const ErrorSettings &errorSettings,
                                 bool *valid)
    {
        Context context;
        context.diagnostics = mDiagnostics;
        context.lexer = mLexer;
        context.token = token;
        context.result = result;
        context.ignoreErrors = 0;
        context.parsePresetToken = parsePresetToken;
        context.errorSettings    = errorSettings;
        context.valid            = valid;
        int ret = yyparse(&context);
        switch (ret)
        {
          case 0:
          case 1:
            break;
    
          case 2:
            mDiagnostics->report(Diagnostics::PP_OUT_OF_MEMORY, token->location, "");
            break;
    
          default:
            assert(false);
            mDiagnostics->report(Diagnostics::PP_INTERNAL_ERROR, token->location, "");
            break;
        }
    
        return ret == 0;
    }
    
    }  // namespace pp
    
    }  // namespace angle