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