| /* Copyright (C) 2021 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 <stdio.h> |
| #include <string.h> |
| #include <string> |
| } |
| %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 <uint64_t> NUM FNAME JGROUP JPARENT QSTR |
| %token <std::string> 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 <Expression *> exp term |
| |
| // %destructor { delete $$; } <Expression *>; |
| |
| %% |
| |
| 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 |
| } |
| } |
| |