/* // // Copyright (c) 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 (c) 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 4701) #endif #include "ExpressionParser.h" #if defined(_MSC_VER) #include #else #include #endif #include #include #include "DiagnosticsBase.h" #include "Lexer.h" #include "Token.h" #if defined(_MSC_VER) typedef __int64 YYSTYPE; #else #include typedef intmax_t YYSTYPE; #endif // _MSC_VER #define YYENABLE_NLS 0 #define YYLTYPE_IS_TRIVIAL 1 #define YYSTYPE_IS_TRIVIAL 1 #define YYSTYPE_IS_DECLARED 1 namespace { struct Context { pp::Diagnostics* diagnostics; pp::Lexer* lexer; pp::Token* token; int* result; }; } // 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 %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($1); YYACCEPT; } ; expression : TOK_CONST_INT | expression TOK_OP_OR expression { $$ = $1 || $3; } | expression TOK_OP_AND expression { $$ = $1 && $3; } | 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 { $$ = $1 >> $3; } | expression TOK_OP_LEFT expression { $$ = $1 << $3; } | expression '-' expression { $$ = $1 - $3; } | expression '+' expression { $$ = $1 + $3; } | expression '%' expression { if ($3 == 0) { std::ostringstream stream; stream << $1 << " % " << $3; std::string text = stream.str(); context->diagnostics->report(pp::Diagnostics::PP_DIVISION_BY_ZERO, context->token->location, text.c_str()); YYABORT; } else { $$ = $1 % $3; } } | expression '/' expression { if ($3 == 0) { std::ostringstream stream; stream << $1 << " / " << $3; std::string text = stream.str(); context->diagnostics->report(pp::Diagnostics::PP_DIVISION_BY_ZERO, context->token->location, text.c_str()); YYABORT; } else { $$ = $1 / $3; } } | expression '*' expression { $$ = $1 * $3; } | '!' expression %prec TOK_UNARY { $$ = ! $2; } | '~' expression %prec TOK_UNARY { $$ = ~ $2; } | '-' expression %prec TOK_UNARY { $$ = - $2; } | '+' expression %prec TOK_UNARY { $$ = + $2; } | '(' expression ')' { $$ = $2; } ; %% int yylex(YYSTYPE *lvalp, Context *context) { int type = 0; pp::Token *token = context->token; switch (token->type) { case pp::Token::CONST_INT: { unsigned int val = 0; if (!token->uValue(&val)) { context->diagnostics->report(pp::Diagnostics::PP_INTEGER_OVERFLOW, token->location, token->text); } *lvalp = static_cast(val); type = TOK_CONST_INT; break; } case pp::Token::OP_OR: type = TOK_OP_OR; break; case pp::Token::OP_AND: type = TOK_OP_AND; break; case pp::Token::OP_NE: type = TOK_OP_NE; break; case pp::Token::OP_EQ: type = TOK_OP_EQ; break; case pp::Token::OP_GE: type = TOK_OP_GE; break; case pp::Token::OP_LE: type = TOK_OP_LE; break; case pp::Token::OP_RIGHT: type = TOK_OP_RIGHT; break; case 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; } // Advance to the next token if the current one is valid. if (type != 0) context->lexer->lex(token); return type; } void yyerror(Context *context, const char *reason) { context->diagnostics->report(pp::Diagnostics::PP_INVALID_EXPRESSION, context->token->location, reason); } namespace pp { ExpressionParser::ExpressionParser(Lexer *lexer, Diagnostics *diagnostics) : mLexer(lexer), mDiagnostics(diagnostics) { } bool ExpressionParser::parse(Token *token, int *result) { Context context; context.diagnostics = mDiagnostics; context.lexer = mLexer; context.token = token; context.result = result; 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