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