Edit

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

Branch :

  • Show log

    Commit

  • Author : James Darpinian
    Date : 2019-12-05 17:46:23
    Hash : d6053daa
    Message : Remove tabs from source files. WebKit's Subversion repo refuses to commit source files that contain tabs. Bug: angleproject:3439 Change-Id: I0a804bcfa0375a98e19945e20297c90d31106827 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1954410 Commit-Queue: James Darpinian <jdarpinian@chromium.org> Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>

  • src/compiler/preprocessor/preprocessor.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 scripts/run_code_generation.py
    WHICH GENERATES THE GLSL ES preprocessor expression parser.
    */
    
    %{
    // GENERATED FILE - DO NOT EDIT.
    // Generated by generate_parser.py from preprocessor.y
    //
    // Copyright 2019 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.
    //
    // preprocessor.y:
    //   Parser for the OpenGL shading language preprocessor.
    
    #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