1/* Copyright (C) 2021 Free Software Foundation, Inc. 2 Contributed by Oracle. 3 4 This file is part of GNU Binutils. 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3, or (at your option) 9 any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program; if not, write to the Free Software 18 Foundation, 51 Franklin Street - Fifth Floor, Boston, 19 MA 02110-1301, USA. */ 20 21// To rebuild QLParser.tab.cc and QLParser.tab.hh, use bison 3.6 or newer: 22// cd gprofng/src && bison QLParser.yy 23 24// For "api.parser.class" 25%require "3.0" 26%language "C++" 27 28%code top { 29#include <stdio.h> 30#include <string.h> 31#include <string> 32} 33%code requires { 34#include "QLParser.h" 35#include "DbeSession.h" 36#include "Expression.h" 37#include "Table.h" 38#include "i18n.h" 39} 40 41%code 42{ 43namespace QL 44{ 45 static QL::Parser::symbol_type yylex (QL::Result &result); 46 47 static Expression * 48 processName (std::string str) 49 { 50 const char *name = str.c_str(); 51 int propID = dbeSession->getPropIdByName (name); 52 if (propID != PROP_NONE) 53 return new Expression (Expression::OP_NAME, 54 new Expression (Expression::OP_NUM, (uint64_t) propID)); 55 56 // If a name is not statically known try user defined objects 57 Expression *expr = dbeSession->findObjDefByName (name); 58 if (expr != NULL) 59 return expr->copy(); 60 61 throw Parser::syntax_error ("Name not found"); 62 } 63} 64} 65 66%defines 67%define api.namespace {QL} 68// in Bison 3.3, use %define api.parser.class {Parser} instead parser_class_name 69%define parser_class_name {Parser} 70%define api.token.constructor 71%define api.value.type variant 72// Later: api.value.automove 73%define api.token.prefix {L_} 74%define parse.assert 75%param {QL::Result &result} 76 77%start S 78 79%token LPAR "(" 80 RPAR ")" 81 HASPROP 82 FILEIOVFD 83 84%token YYEOF 0 85%token <uint64_t> NUM FNAME JGROUP JPARENT QSTR 86%token <std::string> NAME 87 88%nonassoc IN SOME ORDR 89%left COMMA "," 90%right QWE "?" 91 COLON ":" 92%left AND "&&" 93 OR "|" 94 EQV NEQV 95 BITAND BITOR 96 BITXOR "^" 97%nonassoc EQ "=" 98 NE "!=" 99 LT "<" 100 GT ">" 101 LE "<=" 102 GE ">=" 103%left LS "<<" 104 RS ">>" 105 ADD "+" 106 MINUS "-" 107 MUL "*" 108 DIV "/" 109 REM "%" 110%right DEG 111 NOT "!" 112 BITNOT "~" 113 114%type <Expression *> exp term 115 116// %destructor { delete $$; } <Expression *>; 117 118%% 119 120S: /* empty */ { result.out = new Expression (Expression::OP_NUM, (uint64_t) 1); } 121| exp { result.out = $1; } 122 123exp: exp DEG exp { $$ = new Expression (Expression::OP_DEG, $1, $3); } /* dead? */ 124 | exp MUL exp { $$ = new Expression (Expression::OP_MUL, $1, $3); } 125 | exp DIV exp { $$ = new Expression (Expression::OP_DIV, $1, $3); } 126 | exp REM exp { $$ = new Expression (Expression::OP_REM, $1, $3); } 127 | exp ADD exp { $$ = new Expression (Expression::OP_ADD, $1, $3); } 128 | exp MINUS exp { $$ = new Expression (Expression::OP_MINUS, $1, $3); } 129 | exp LS exp { $$ = new Expression (Expression::OP_LS, $1, $3); } 130 | exp RS exp { $$ = new Expression (Expression::OP_RS, $1, $3); } 131 | exp LT exp { $$ = new Expression (Expression::OP_LT, $1, $3); } 132 | exp LE exp { $$ = new Expression (Expression::OP_LE, $1, $3); } 133 | exp GT exp { $$ = new Expression (Expression::OP_GT, $1, $3); } 134 | exp GE exp { $$ = new Expression (Expression::OP_GE, $1, $3); } 135 | exp EQ exp { $$ = new Expression (Expression::OP_EQ, $1, $3); } 136 | exp NE exp { $$ = new Expression (Expression::OP_NE, $1, $3); } 137 | exp BITAND exp { $$ = new Expression (Expression::OP_BITAND, $1, $3); } 138 | exp BITXOR exp { $$ = new Expression (Expression::OP_BITXOR, $1, $3); } 139 | exp BITOR exp { $$ = new Expression (Expression::OP_BITOR, $1, $3); } 140 | exp AND exp { $$ = new Expression (Expression::OP_AND, $1, $3); } 141 | exp OR exp { $$ = new Expression (Expression::OP_OR, $1, $3); } 142 | exp NEQV exp { $$ = new Expression (Expression::OP_NEQV, $1, $3); } /* dead? */ 143 | exp EQV exp { $$ = new Expression (Expression::OP_EQV, $1, $3); } /* dead? */ 144 | exp QWE exp COLON exp 145 { 146 $$ = new Expression (Expression::OP_QWE, $1, 147 new Expression (Expression::OP_COLON, $3, $5)); 148 } 149 | exp COMMA exp { $$ = new Expression (Expression::OP_COMMA, $1, $3); } 150 | exp IN exp { $$ = new Expression (Expression::OP_IN, $1, $3); } 151 | exp SOME IN exp { $$ = new Expression (Expression::OP_SOMEIN, $1, $4); } 152 | exp ORDR IN exp { $$ = new Expression (Expression::OP_ORDRIN, $1, $4); } 153 | term { $$ = $1; } 154 155term: MINUS term 156 { 157 $$ = new Expression (Expression::OP_MINUS, 158 new Expression (Expression::OP_NUM, (uint64_t) 0), $2); 159 } 160 | NOT term { $$ = new Expression (Expression::OP_NOT, $2); } 161 | BITNOT term { $$ = new Expression (Expression::OP_BITNOT, $2); } 162 | LPAR exp RPAR { $$ = $2; } 163 | FNAME LPAR QSTR RPAR 164 { 165 $$ = new Expression (Expression::OP_FUNC, 166 new Expression (Expression::OP_NUM, $1), 167 new Expression (Expression::OP_NUM, $3)); 168 } 169 | HASPROP LPAR NAME RPAR 170 { 171 $$ = new Expression (Expression::OP_HASPROP, 172 new Expression (Expression::OP_NUM, processName($3))); 173 } 174 | JGROUP LPAR QSTR RPAR 175 { 176 $$ = new Expression (Expression::OP_JAVA, 177 new Expression (Expression::OP_NUM, $1), 178 new Expression (Expression::OP_NUM, $3)); 179 } 180 | JPARENT LPAR QSTR RPAR 181 { 182 $$ = new Expression (Expression::OP_JAVA, 183 new Expression (Expression::OP_NUM, $1), 184 new Expression (Expression::OP_NUM, $3)); 185 } 186 | FILEIOVFD LPAR QSTR RPAR 187 { 188 $$ = new Expression (Expression::OP_FILE, 189 new Expression (Expression::OP_NUM, (uint64_t) 0), 190 new Expression (Expression::OP_NUM, $3)); 191 } 192 | NUM { $$ = new Expression (Expression::OP_NUM, $1); } 193 | NAME { $$ = processName($1); } 194 195%% 196 197namespace QL 198{ 199 static Parser::symbol_type 200 unget_ret (std::istream &in, char c, Parser::symbol_type tok) 201 { 202 in.putback (c); 203 return tok; 204 } 205 206 static Parser::symbol_type 207 yylex (QL::Result &result) 208 { 209 int base = 0; 210 int c; 211 212 do 213 c = result.in.get (); 214 while (result.in && (c == ' ' || c == '\t')); 215 if (!result.in) 216 return Parser::make_YYEOF (); 217 218 switch (c) 219 { 220 case '\0': 221 case '\n': return Parser::make_YYEOF (); 222 case '(': return Parser::make_LPAR () ; 223 case ')': return Parser::make_RPAR (); 224 case ',': return Parser::make_COMMA (); 225 case '%': return Parser::make_REM (); 226 case '/': return Parser::make_DIV (); 227 case '*': return Parser::make_MUL (); 228 case '-': return Parser::make_MINUS (); 229 case '+': return Parser::make_ADD (); 230 case '~': return Parser::make_BITNOT (); 231 case '^': return Parser::make_BITXOR (); 232 case '?': return Parser::make_QWE (); 233 case ':': return Parser::make_COLON (); 234 case '|': 235 c = result.in.get (); 236 if (c == '|') 237 return Parser::make_OR (); 238 else 239 return unget_ret (result.in, c, Parser::make_BITOR ()); 240 case '&': 241 c = result.in.get (); 242 if (c == '&') 243 return Parser::make_AND (); 244 else 245 return unget_ret (result.in, c, Parser::make_BITAND ()); 246 case '!': 247 c = result.in.get (); 248 if (c == '=') 249 return Parser::make_NE (); 250 else 251 return unget_ret (result.in, c, Parser::make_NOT ()); 252 case '=': 253 c = result.in.get (); 254 if (c == '=') 255 return Parser::make_EQ (); 256 else 257 throw Parser::syntax_error ("Syntax error after ="); 258 case '<': 259 c = result.in.get (); 260 if (c == '=') 261 return Parser::make_LE (); 262 else if (c == '<') 263 return Parser::make_LS (); 264 else 265 return unget_ret (result.in, c, Parser::make_LT ()); 266 case '>': 267 c = result.in.get (); 268 if (c == '=') 269 return Parser::make_GE (); 270 else if (c == '>') 271 return Parser::make_RS (); 272 else 273 return unget_ret (result.in, c, Parser::make_GT ()); 274 case '"': 275 { 276 int maxsz = 16; 277 char *str = (char *) malloc (maxsz); 278 char *ptr = str; 279 280 for (;;) 281 { 282 c = result.in.get (); 283 if (!result.in) 284 { 285 free (str); 286 throw Parser::syntax_error ("Unclosed \""); 287 } 288 289 switch (c) 290 { 291 case '"': 292 *ptr = (char)0; 293 // XXX omazur: need new string type 294 return Parser::make_QSTR ((uint64_t) str); 295 case 0: 296 case '\n': 297 free (str); 298 throw Parser::syntax_error ("Multiline strings are not supported"); 299 default: 300 if (ptr - str >= maxsz) 301 { 302 size_t len = ptr - str; 303 maxsz = maxsz > 8192 ? maxsz + 8192 : maxsz * 2; 304 char *new_s = (char *) realloc (str, maxsz); 305 str = new_s; 306 ptr = str + len; 307 } 308 *ptr++ = c; 309 } 310 } 311 } 312 default: 313 if (c == '0') 314 { 315 base = 8; 316 c = result.in.get (); 317 if ( c == 'x' ) 318 { 319 base = 16; 320 c = result.in.get (); 321 } 322 } 323 else if (c >= '1' && c <='9') 324 base = 10; 325 326 if (base) 327 { 328 uint64_t lval = 0; 329 for (;;) 330 { 331 int digit = -1; 332 switch (c) 333 { 334 case '0': case '1': case '2': case '3': 335 case '4': case '5': case '6': case '7': 336 digit = c - '0'; 337 break; 338 case '8': case '9': 339 if (base > 8) 340 digit = c - '0'; 341 break; 342 case 'a': case 'b': case 'c': 343 case 'd': case 'e': case 'f': 344 if (base == 16) 345 digit = c - 'a' + 10; 346 break; 347 case 'A': case 'B': case 'C': 348 case 'D': case 'E': case 'F': 349 if (base == 16) 350 digit = c - 'A' + 10; 351 break; 352 } 353 if (digit == -1) 354 { 355 result.in.putback (c); 356 break; 357 } 358 lval = lval * base + digit; 359 c = result.in.get (); 360 } 361 return Parser::make_NUM (lval); 362 } 363 364 if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) 365 { 366 char name[32]; // omazur XXX: accept any length 367 name[0] = (char)c; 368 for (size_t i = 1; i < sizeof (name); i++) 369 { 370 c = result.in.get (); 371 if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || 372 (c >= '0' && c <= '9') || (c == '_')) 373 name[i] = c; 374 else 375 { 376 name[i] = (char)0; 377 result.in.putback (c); 378 break; 379 } 380 } 381 382 if (strcasecmp (name, NTXT ("IN")) == 0) 383 return Parser::make_IN (); 384 else if (strcasecmp (name, NTXT ("SOME")) == 0) 385 return Parser::make_SOME (); 386 else if (strcasecmp (name, NTXT ("ORDERED")) == 0) 387 return Parser::make_ORDR (); 388 else if (strcasecmp (name, NTXT ("TRUE")) == 0) 389 return Parser::make_NUM ((uint64_t) 1); 390 else if (strcasecmp (name, NTXT ("FALSE")) == 0) 391 return Parser::make_NUM ((uint64_t) 0); 392 else if (strcasecmp (name, NTXT ("FNAME")) == 0) 393 return Parser::make_FNAME (Expression::FUNC_FNAME); 394 else if (strcasecmp (name, NTXT ("HAS_PROP")) == 0) 395 return Parser::make_HASPROP (); 396 else if (strcasecmp (name, NTXT ("JGROUP")) == 0) 397 return Parser::make_JGROUP (Expression::JAVA_JGROUP); 398 else if (strcasecmp (name, NTXT ("JPARENT")) == 0 ) 399 return Parser::make_JPARENT (Expression::JAVA_JPARENT); 400 else if (strcasecmp (name, NTXT ("DNAME")) == 0) 401 return Parser::make_FNAME (Expression::FUNC_DNAME); 402 else if (strcasecmp (name, NTXT ("FILEIOVFD")) == 0 ) 403 return Parser::make_FILEIOVFD (); 404 405 std::string nm = std::string (name); 406 return Parser::make_NAME (nm); 407 } 408 409 throw Parser::syntax_error ("Syntax error"); 410 } 411 } 412 void 413 Parser::error (const std::string &) 414 { 415 // do nothing for now 416 } 417} 418 419