/* Copyright (C) 2021-2024 Free Software Foundation, Inc. Contributed by Oracle. This file is part of GNU Binutils. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ // To rebuild QLParser.tab.cc and QLParser.tab.hh, use bison 3.6 or newer: // cd gprofng/src && bison QLParser.yy // For "api.parser.class" %require "3.0" %language "C++" %code top { #include #include #include } %code requires { #include "QLParser.h" #include "DbeSession.h" #include "Expression.h" #include "Table.h" #include "i18n.h" } %code { namespace QL { static QL::Parser::symbol_type yylex (QL::Result &result); static Expression * processName (std::string str) { const char *name = str.c_str(); int propID = dbeSession->getPropIdByName (name); if (propID != PROP_NONE) return new Expression (Expression::OP_NAME, new Expression (Expression::OP_NUM, (uint64_t) propID)); // If a name is not statically known try user defined objects Expression *expr = dbeSession->findObjDefByName (name); if (expr != NULL) return expr->copy(); throw Parser::syntax_error ("Name not found"); } } } %defines %define api.namespace {QL} // in Bison 3.3, use %define api.parser.class {Parser} instead parser_class_name %define parser_class_name {Parser} %define api.token.constructor %define api.value.type variant // Later: api.value.automove %define api.token.prefix {L_} %define parse.assert %param {QL::Result &result} %start S %token LPAR "(" RPAR ")" HASPROP FILEIOVFD %token YYEOF 0 %token NUM FNAME JGROUP JPARENT QSTR %token NAME %nonassoc IN SOME ORDR %left COMMA "," %right QWE "?" COLON ":" %left AND "&&" OR "|" EQV NEQV BITAND BITOR BITXOR "^" %nonassoc EQ "=" NE "!=" LT "<" GT ">" LE "<=" GE ">=" %left LS "<<" RS ">>" ADD "+" MINUS "-" MUL "*" DIV "/" REM "%" %right DEG NOT "!" BITNOT "~" %type exp term // %destructor { delete $$; } ; %% S: /* empty */ { result.out = new Expression (Expression::OP_NUM, (uint64_t) 1); } | exp { result.out = $1; } exp: exp DEG exp { $$ = new Expression (Expression::OP_DEG, $1, $3); } /* dead? */ | exp MUL exp { $$ = new Expression (Expression::OP_MUL, $1, $3); } | exp DIV exp { $$ = new Expression (Expression::OP_DIV, $1, $3); } | exp REM exp { $$ = new Expression (Expression::OP_REM, $1, $3); } | exp ADD exp { $$ = new Expression (Expression::OP_ADD, $1, $3); } | exp MINUS exp { $$ = new Expression (Expression::OP_MINUS, $1, $3); } | exp LS exp { $$ = new Expression (Expression::OP_LS, $1, $3); } | exp RS exp { $$ = new Expression (Expression::OP_RS, $1, $3); } | exp LT exp { $$ = new Expression (Expression::OP_LT, $1, $3); } | exp LE exp { $$ = new Expression (Expression::OP_LE, $1, $3); } | exp GT exp { $$ = new Expression (Expression::OP_GT, $1, $3); } | exp GE exp { $$ = new Expression (Expression::OP_GE, $1, $3); } | exp EQ exp { $$ = new Expression (Expression::OP_EQ, $1, $3); } | exp NE exp { $$ = new Expression (Expression::OP_NE, $1, $3); } | exp BITAND exp { $$ = new Expression (Expression::OP_BITAND, $1, $3); } | exp BITXOR exp { $$ = new Expression (Expression::OP_BITXOR, $1, $3); } | exp BITOR exp { $$ = new Expression (Expression::OP_BITOR, $1, $3); } | exp AND exp { $$ = new Expression (Expression::OP_AND, $1, $3); } | exp OR exp { $$ = new Expression (Expression::OP_OR, $1, $3); } | exp NEQV exp { $$ = new Expression (Expression::OP_NEQV, $1, $3); } /* dead? */ | exp EQV exp { $$ = new Expression (Expression::OP_EQV, $1, $3); } /* dead? */ | exp QWE exp COLON exp { $$ = new Expression (Expression::OP_QWE, $1, new Expression (Expression::OP_COLON, $3, $5)); } | exp COMMA exp { $$ = new Expression (Expression::OP_COMMA, $1, $3); } | exp IN exp { $$ = new Expression (Expression::OP_IN, $1, $3); } | exp SOME IN exp { $$ = new Expression (Expression::OP_SOMEIN, $1, $4); } | exp ORDR IN exp { $$ = new Expression (Expression::OP_ORDRIN, $1, $4); } | term { $$ = $1; } term: MINUS term { $$ = new Expression (Expression::OP_MINUS, new Expression (Expression::OP_NUM, (uint64_t) 0), $2); } | NOT term { $$ = new Expression (Expression::OP_NOT, $2); } | BITNOT term { $$ = new Expression (Expression::OP_BITNOT, $2); } | LPAR exp RPAR { $$ = $2; } | FNAME LPAR QSTR RPAR { $$ = new Expression (Expression::OP_FUNC, new Expression (Expression::OP_NUM, $1), new Expression (Expression::OP_NUM, $3)); } | HASPROP LPAR NAME RPAR { $$ = new Expression (Expression::OP_HASPROP, new Expression (Expression::OP_NUM, processName($3))); } | JGROUP LPAR QSTR RPAR { $$ = new Expression (Expression::OP_JAVA, new Expression (Expression::OP_NUM, $1), new Expression (Expression::OP_NUM, $3)); } | JPARENT LPAR QSTR RPAR { $$ = new Expression (Expression::OP_JAVA, new Expression (Expression::OP_NUM, $1), new Expression (Expression::OP_NUM, $3)); } | FILEIOVFD LPAR QSTR RPAR { $$ = new Expression (Expression::OP_FILE, new Expression (Expression::OP_NUM, (uint64_t) 0), new Expression (Expression::OP_NUM, $3)); } | NUM { $$ = new Expression (Expression::OP_NUM, $1); } | NAME { $$ = processName($1); } %% namespace QL { static Parser::symbol_type unget_ret (std::istream &in, char c, Parser::symbol_type tok) { in.putback (c); return tok; } static Parser::symbol_type yylex (QL::Result &result) { int base = 0; int c; do c = result.in.get (); while (result.in && (c == ' ' || c == '\t')); if (!result.in) return Parser::make_YYEOF (); switch (c) { case '\0': case '\n': return Parser::make_YYEOF (); case '(': return Parser::make_LPAR () ; case ')': return Parser::make_RPAR (); case ',': return Parser::make_COMMA (); case '%': return Parser::make_REM (); case '/': return Parser::make_DIV (); case '*': return Parser::make_MUL (); case '-': return Parser::make_MINUS (); case '+': return Parser::make_ADD (); case '~': return Parser::make_BITNOT (); case '^': return Parser::make_BITXOR (); case '?': return Parser::make_QWE (); case ':': return Parser::make_COLON (); case '|': c = result.in.get (); if (c == '|') return Parser::make_OR (); else return unget_ret (result.in, c, Parser::make_BITOR ()); case '&': c = result.in.get (); if (c == '&') return Parser::make_AND (); else return unget_ret (result.in, c, Parser::make_BITAND ()); case '!': c = result.in.get (); if (c == '=') return Parser::make_NE (); else return unget_ret (result.in, c, Parser::make_NOT ()); case '=': c = result.in.get (); if (c == '=') return Parser::make_EQ (); else throw Parser::syntax_error ("Syntax error after ="); case '<': c = result.in.get (); if (c == '=') return Parser::make_LE (); else if (c == '<') return Parser::make_LS (); else return unget_ret (result.in, c, Parser::make_LT ()); case '>': c = result.in.get (); if (c == '=') return Parser::make_GE (); else if (c == '>') return Parser::make_RS (); else return unget_ret (result.in, c, Parser::make_GT ()); case '"': { int maxsz = 16; char *str = (char *) malloc (maxsz); char *ptr = str; for (;;) { c = result.in.get (); if (!result.in) { free (str); throw Parser::syntax_error ("Unclosed \""); } switch (c) { case '"': *ptr = (char)0; // XXX omazur: need new string type return Parser::make_QSTR ((uint64_t) str); case 0: case '\n': free (str); throw Parser::syntax_error ("Multiline strings are not supported"); default: if (ptr - str >= maxsz) { size_t len = ptr - str; maxsz = maxsz > 8192 ? maxsz + 8192 : maxsz * 2; char *new_s = (char *) realloc (str, maxsz); str = new_s; ptr = str + len; } *ptr++ = c; } } } default: if (c == '0') { base = 8; c = result.in.get (); if ( c == 'x' ) { base = 16; c = result.in.get (); } } else if (c >= '1' && c <='9') base = 10; if (base) { uint64_t lval = 0; for (;;) { int digit = -1; switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': digit = c - '0'; break; case '8': case '9': if (base > 8) digit = c - '0'; break; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': if (base == 16) digit = c - 'a' + 10; break; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': if (base == 16) digit = c - 'A' + 10; break; } if (digit == -1) { result.in.putback (c); break; } lval = lval * base + digit; c = result.in.get (); } return Parser::make_NUM (lval); } if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) { char name[32]; // omazur XXX: accept any length name[0] = (char)c; for (size_t i = 1; i < sizeof (name); i++) { c = result.in.get (); if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || (c == '_')) name[i] = c; else { name[i] = (char)0; result.in.putback (c); break; } } if (strcasecmp (name, NTXT ("IN")) == 0) return Parser::make_IN (); else if (strcasecmp (name, NTXT ("SOME")) == 0) return Parser::make_SOME (); else if (strcasecmp (name, NTXT ("ORDERED")) == 0) return Parser::make_ORDR (); else if (strcasecmp (name, NTXT ("TRUE")) == 0) return Parser::make_NUM ((uint64_t) 1); else if (strcasecmp (name, NTXT ("FALSE")) == 0) return Parser::make_NUM ((uint64_t) 0); else if (strcasecmp (name, NTXT ("FNAME")) == 0) return Parser::make_FNAME (Expression::FUNC_FNAME); else if (strcasecmp (name, NTXT ("HAS_PROP")) == 0) return Parser::make_HASPROP (); else if (strcasecmp (name, NTXT ("JGROUP")) == 0) return Parser::make_JGROUP (Expression::JAVA_JGROUP); else if (strcasecmp (name, NTXT ("JPARENT")) == 0 ) return Parser::make_JPARENT (Expression::JAVA_JPARENT); else if (strcasecmp (name, NTXT ("DNAME")) == 0) return Parser::make_FNAME (Expression::FUNC_DNAME); else if (strcasecmp (name, NTXT ("FILEIOVFD")) == 0 ) return Parser::make_FILEIOVFD (); std::string nm = std::string (name); return Parser::make_NAME (nm); } throw Parser::syntax_error ("Syntax error"); } } void Parser::error (const std::string &) { // do nothing for now } }