]> sourceware.org Git - systemtap.git/blame - parse.cxx
Only run .plt tests on x86.
[systemtap.git] / parse.cxx
CommitLineData
2f1a1aea 1// recursive descent parser for systemtap scripts
1e6e9ec1 2// Copyright (C) 2005-2011 Red Hat Inc.
77a5c1f9 3// Copyright (C) 2006 Intel Corporation.
5811366a 4// Copyright (C) 2007 Bull S.A.S
69c68955
FCE
5//
6// This file is part of systemtap, and is free software. You can
7// redistribute it and/or modify it under the terms of the GNU General
8// Public License (GPL); either version 2, or (at your option) any
9// later version.
2f1a1aea 10
2b066ec1 11#include "config.h"
2f1a1aea
FCE
12#include "staptree.h"
13#include "parse.h"
177a8ead 14#include "session.h"
3f99432c
FCE
15#include "util.h"
16
2b066ec1 17#include <iostream>
eacb10ce 18
2b066ec1 19#include <fstream>
2f1a1aea 20#include <cctype>
9c0c0e46 21#include <cstdlib>
29e64872 22#include <cassert>
9c0c0e46
FCE
23#include <cerrno>
24#include <climits>
57b73400 25#include <sstream>
f74fb737 26#include <cstring>
3f99432c 27#include <cctype>
eacb10ce
FCE
28#include <iterator>
29
7a468d68
FCE
30extern "C" {
31#include <fnmatch.h>
32}
2f1a1aea
FCE
33
34using namespace std;
35
c18f07f8
JS
36
37class lexer
38{
39public:
c5be7511 40 bool ate_comment; // the most recent token followed a comment
c18f07f8
JS
41 token* scan (bool wildcard=false);
42 lexer (istream&, const string&, systemtap_session&);
43 void set_current_file (stapfile* f);
44
45private:
46 inline int input_get ();
47 inline int input_peek (unsigned n=0);
48 void input_put (const string&, const token*);
49 string input_name;
50 string input_contents;
51 const char *input_pointer; // index into input_contents
52 const char *input_end;
53 unsigned cursor_suspend_count;
54 unsigned cursor_suspend_line;
55 unsigned cursor_suspend_column;
56 unsigned cursor_line;
57 unsigned cursor_column;
58 systemtap_session& session;
59 stapfile* current_file;
60 static set<string> keywords;
61};
62
63
64class parser
65{
66public:
67 parser (systemtap_session& s, istream& i, bool p);
68 parser (systemtap_session& s, const string& n, bool p);
69 ~parser ();
70
71 stapfile* parse ();
72
73private:
74 typedef enum {
75 PP_NONE,
76 PP_KEEP_THEN,
77 PP_SKIP_THEN,
78 PP_KEEP_ELSE,
79 PP_SKIP_ELSE,
80 } pp_state_t;
81
82 systemtap_session& session;
83 string input_name;
84 istream* free_input;
85 lexer input;
86 bool privileged;
87 parse_context context;
88
89 // preprocessing subordinate
90 vector<pair<const token*, pp_state_t> > pp_state;
91 const token* scan_pp (bool wildcard=false);
92 const token* skip_pp ();
93
94 // scanning state
95 const token* last ();
96 const token* next (bool wildcard=false);
97 const token* peek (bool wildcard=false);
98
a07a2c28 99 const token* systemtap_v_seen;
c18f07f8
JS
100 const token* last_t; // the last value returned by peek() or next()
101 const token* next_t; // lookahead token
102
103 // expectations
104 const token* expect_known (token_type tt, string const & expected);
105 const token* expect_unknown (token_type tt, string & target);
106 const token* expect_unknown2 (token_type tt1, token_type tt2,
107 string & target);
108
109 // convenience forms
110 const token* expect_op (string const & expected);
111 const token* expect_kw (string const & expected);
112 const token* expect_number (int64_t & expected);
113 const token* expect_ident (string & target);
114 const token* expect_ident_or_keyword (string & target);
115 bool peek_op (string const & op);
116 bool peek_kw (string const & kw);
117
118 void print_error (const parse_error& pe);
119 unsigned num_errors;
120
121private: // nonterminals
122 void parse_probe (vector<probe*>&, vector<probe_alias*>&);
123 void parse_global (vector<vardecl*>&, vector<probe*>&);
124 void parse_functiondecl (vector<functiondecl*>&);
125 embeddedcode* parse_embeddedcode ();
126 probe_point* parse_probe_point ();
127 literal* parse_literal ();
128 block* parse_stmt_block ();
129 try_block* parse_try_block ();
130 statement* parse_statement ();
131 if_statement* parse_if_statement ();
132 for_loop* parse_for_loop ();
133 for_loop* parse_while_loop ();
134 foreach_loop* parse_foreach_loop ();
135 expr_statement* parse_expr_statement ();
136 return_statement* parse_return_statement ();
137 delete_statement* parse_delete_statement ();
138 next_statement* parse_next_statement ();
139 break_statement* parse_break_statement ();
140 continue_statement* parse_continue_statement ();
141 indexable* parse_indexable ();
142 const token *parse_hist_op_or_bare_name (hist_op *&hop, string &name);
143 target_symbol *parse_target_symbol (const token* t);
8cc799a5 144 expression* parse_entry_op (const token* t);
c18f07f8
JS
145 expression* parse_defined_op (const token* t);
146 expression* parse_expression ();
147 expression* parse_assignment ();
148 expression* parse_ternary ();
149 expression* parse_logical_or ();
150 expression* parse_logical_and ();
151 expression* parse_boolean_or ();
152 expression* parse_boolean_xor ();
153 expression* parse_boolean_and ();
154 expression* parse_array_in ();
155 expression* parse_comparison ();
156 expression* parse_shift ();
157 expression* parse_concatenation ();
158 expression* parse_additive ();
159 expression* parse_multiplicative ();
160 expression* parse_unary ();
161 expression* parse_crement ();
162 expression* parse_value ();
163 expression* parse_symbol ();
164
165 void parse_target_symbol_components (target_symbol* e);
166};
167
168
2f1a1aea
FCE
169// ------------------------------------------------------------------------
170
c18f07f8
JS
171stapfile*
172parse (systemtap_session& s, istream& i, bool pr)
173{
174 parser p (s, i, pr);
175 return p.parse ();
176}
177
178
179stapfile*
180parse (systemtap_session& s, const string& n, bool pr)
181{
182 parser p (s, n, pr);
183 return p.parse ();
184}
185
186// ------------------------------------------------------------------------
bb2e3076
FCE
187
188
177a8ead
FCE
189parser::parser (systemtap_session& s, istream& i, bool p):
190 session (s),
24cb178f 191 input_name ("<input>"), free_input (0),
213bee8f 192 input (i, input_name, s), privileged (p),
a07a2c28 193 context(con_unknown), systemtap_v_seen(0), last_t (0), next_t (0), num_errors (0)
2f1a1aea
FCE
194{ }
195
177a8ead
FCE
196parser::parser (systemtap_session& s, const string& fn, bool p):
197 session (s),
2f1a1aea 198 input_name (fn), free_input (new ifstream (input_name.c_str(), ios::in)),
213bee8f 199 input (* free_input, input_name, s), privileged (p),
a07a2c28 200 context(con_unknown), systemtap_v_seen(0), last_t (0), next_t (0), num_errors (0)
2f1a1aea
FCE
201{ }
202
203parser::~parser()
204{
205 if (free_input) delete free_input;
206}
207
d7f3e0c5
GH
208static string
209tt2str(token_type tt)
210{
211 switch (tt)
212 {
213 case tok_junk: return "junk";
214 case tok_identifier: return "identifier";
215 case tok_operator: return "operator";
216 case tok_string: return "string";
217 case tok_number: return "number";
218 case tok_embedded: return "embedded-code";
6e213f58 219 case tok_keyword: return "keyword";
d7f3e0c5
GH
220 }
221 return "unknown token";
222}
82919855 223
0323ed4d
WC
224ostream&
225operator << (ostream& o, const source_loc& loc)
226{
a704a23b 227 o << loc.file->name << ":"
0323ed4d
WC
228 << loc.line << ":"
229 << loc.column;
230
231 return o;
232}
233
56099f08
FCE
234ostream&
235operator << (ostream& o, const token& t)
236{
d7f3e0c5 237 o << tt2str(t.type);
56099f08 238
6e213f58 239 if (t.type != tok_embedded && t.type != tok_keyword) // XXX: other types?
56099f08 240 {
24cb178f
FCE
241 o << " '";
242 for (unsigned i=0; i<t.content.length(); i++)
243 {
244 char c = t.content[i];
245 o << (isprint (c) ? c : '?');
246 }
247 o << "'";
56099f08 248 }
56099f08 249
dff50e09 250 o << " at "
0323ed4d 251 << t.location;
56099f08
FCE
252
253 return o;
254}
255
256
dff50e09 257void
2f1a1aea
FCE
258parser::print_error (const parse_error &pe)
259{
1b1b4ceb 260 string align_parse_error (" ");
2677d2fb 261 cerr << _("parse error: ") << pe.what () << endl;
2f1a1aea 262
177a8ead
FCE
263 if (pe.tok)
264 {
2677d2fb 265 cerr << _("\tat: ") << *pe.tok << endl;
1b1b4ceb 266 session.print_error_source (cerr, align_parse_error, pe.tok);
177a8ead 267 }
2f1a1aea 268 else
177a8ead
FCE
269 {
270 const token* t = last_t;
271 if (t)
1b1b4ceb 272 {
2677d2fb 273 cerr << _("\tsaw: ") << *t << endl;
1b1b4ceb
RA
274 session.print_error_source (cerr, align_parse_error, t);
275 }
177a8ead 276 else
ce0f6648 277 cerr << _("\tsaw: ") << input_name << " EOF" << endl;
177a8ead 278 }
2f1a1aea
FCE
279
280 // XXX: make it possible to print the last input line,
281 // so as to line up an arrow with the specific error column
282
283 num_errors ++;
284}
285
286
dff50e09 287const token*
2f1a1aea
FCE
288parser::last ()
289{
290 return last_t;
291}
292
293
c434ec7e
FCE
294
295template <typename OPERAND>
296bool eval_comparison (const OPERAND& lhs, const token* op, const OPERAND& rhs)
297{
298 if (op->type == tok_operator && op->content == "<=")
299 { return lhs <= rhs; }
300 else if (op->type == tok_operator && op->content == ">=")
301 { return lhs >= rhs; }
302 else if (op->type == tok_operator && op->content == "<")
303 { return lhs < rhs; }
304 else if (op->type == tok_operator && op->content == ">")
305 { return lhs > rhs; }
306 else if (op->type == tok_operator && op->content == "==")
307 { return lhs == rhs; }
308 else if (op->type == tok_operator && op->content == "!=")
309 { return lhs != rhs; }
310 else
2677d2fb 311 throw parse_error (_("expected comparison operator"), op);
c434ec7e
FCE
312}
313
314
177a8ead
FCE
315// Here, we perform on-the-fly preprocessing.
316// The basic form is %( CONDITION %? THEN-TOKENS %: ELSE-TOKENS %)
44ce8ed5
FCE
317// where CONDITION is: kernel_v[r] COMPARISON-OP "version-string"
318// or: arch COMPARISON-OP "arch-string"
db135493 319// or: systemtap_v COMPARISON-OP "version-string"
561079c8 320// or: CONFIG_foo COMPARISON-OP "config-string"
717a457b 321// or: CONFIG_foo COMPARISON-OP number
4227f98d 322// or: CONFIG_foo COMPARISON-OP CONFIG_bar
5811366a
FCE
323// or: "string1" COMPARISON-OP "string2"
324// or: number1 COMPARISON-OP number2
44ce8ed5 325// The %: ELSE-TOKENS part is optional.
177a8ead
FCE
326//
327// e.g. %( kernel_v > "2.5" %? "foo" %: "baz" %)
c434ec7e 328// e.g. %( arch != "i?86" %? "foo" %: "baz" %)
561079c8 329// e.g. %( CONFIG_foo %? "foo" %: "baz" %)
177a8ead
FCE
330//
331// Up to an entire %( ... %) expression is processed by a single call
332// to this function. Tokens included by any nested conditions are
333// enqueued in a private vector.
334
335bool eval_pp_conditional (systemtap_session& s,
336 const token* l, const token* op, const token* r)
337{
44ce8ed5 338 if (l->type == tok_identifier && (l->content == "kernel_v" ||
db135493
FCE
339 l->content == "kernel_vr" ||
340 l->content == "systemtap_v"))
44ce8ed5 341 {
db135493 342 if (! (r->type == tok_string))
2677d2fb 343 throw parse_error (_("expected string literal"), r);
db135493 344
44ce8ed5 345 string target_kernel_vr = s.kernel_release;
197a4d62 346 string target_kernel_v = s.kernel_base_release;
db135493 347 string target;
dff50e09 348
db135493
FCE
349 if (l->content == "kernel_v") target = target_kernel_v;
350 else if (l->content == "kernel_vr") target = target_kernel_vr;
351 else if (l->content == "systemtap_v") target = s.compatible;
352 else assert (0);
7a468d68 353
7a468d68
FCE
354 string query = r->content;
355 bool rhs_wildcard = (strpbrk (query.c_str(), "*?[") != 0);
356
44ce8ed5
FCE
357 // collect acceptable strverscmp results.
358 int rvc_ok1, rvc_ok2;
7a468d68 359 bool wc_ok = false;
44ce8ed5
FCE
360 if (op->type == tok_operator && op->content == "<=")
361 { rvc_ok1 = -1; rvc_ok2 = 0; }
362 else if (op->type == tok_operator && op->content == ">=")
363 { rvc_ok1 = 1; rvc_ok2 = 0; }
364 else if (op->type == tok_operator && op->content == "<")
365 { rvc_ok1 = -1; rvc_ok2 = -1; }
366 else if (op->type == tok_operator && op->content == ">")
367 { rvc_ok1 = 1; rvc_ok2 = 1; }
368 else if (op->type == tok_operator && op->content == "==")
7a468d68 369 { rvc_ok1 = 0; rvc_ok2 = 0; wc_ok = true; }
44ce8ed5 370 else if (op->type == tok_operator && op->content == "!=")
7a468d68 371 { rvc_ok1 = -1; rvc_ok2 = 1; wc_ok = true; }
44ce8ed5 372 else
2677d2fb 373 throw parse_error (_("expected comparison operator"), op);
7a468d68
FCE
374
375 if ((!wc_ok) && rhs_wildcard)
2677d2fb 376 throw parse_error (_("wildcard not allowed with order comparison operators"), op);
7a468d68
FCE
377
378 if (rhs_wildcard)
379 {
380 int rvc_result = fnmatch (query.c_str(), target.c_str(),
381 FNM_NOESCAPE); // spooky
382 bool badness = (rvc_result == 0) ^ (op->content == "==");
383 return !badness;
384 }
385 else
386 {
387 int rvc_result = strverscmp (target.c_str(), query.c_str());
388 // normalize rvc_result
389 if (rvc_result < 0) rvc_result = -1;
390 if (rvc_result > 0) rvc_result = 1;
391 return (rvc_result == rvc_ok1 || rvc_result == rvc_ok2);
392 }
44ce8ed5
FCE
393 }
394 else if (l->type == tok_identifier && l->content == "arch")
395 {
396 string target_architecture = s.architecture;
397 if (! (r->type == tok_string))
2677d2fb 398 throw parse_error (_("expected string literal"), r);
44ce8ed5 399 string query_architecture = r->content;
dff50e09 400
7a468d68
FCE
401 int nomatch = fnmatch (query_architecture.c_str(),
402 target_architecture.c_str(),
403 FNM_NOESCAPE); // still spooky
404
561079c8
FCE
405 bool result;
406 if (op->type == tok_operator && op->content == "==")
407 result = !nomatch;
408 else if (op->type == tok_operator && op->content == "!=")
409 result = nomatch;
410 else
2677d2fb 411 throw parse_error (_("expected '==' or '!='"), op);
561079c8
FCE
412
413 return result;
414 }
60d98537 415 else if (l->type == tok_identifier && startswith(l->content, "CONFIG_"))
561079c8 416 {
717a457b
MW
417 if (r->type == tok_string)
418 {
419 string lhs = s.kernel_config[l->content]; // may be empty
420 string rhs = r->content;
561079c8 421
717a457b 422 int nomatch = fnmatch (rhs.c_str(), lhs.c_str(), FNM_NOESCAPE); // still spooky
561079c8 423
717a457b
MW
424 bool result;
425 if (op->type == tok_operator && op->content == "==")
426 result = !nomatch;
427 else if (op->type == tok_operator && op->content == "!=")
428 result = nomatch;
429 else
2677d2fb 430 throw parse_error (_("expected '==' or '!='"), op);
dff50e09 431
717a457b
MW
432 return result;
433 }
434 else if (r->type == tok_number)
435 {
436 const char* startp = s.kernel_config[l->content].c_str ();
437 char* endp = (char*) startp;
438 errno = 0;
439 int64_t lhs = (int64_t) strtoll (startp, & endp, 0);
440 if (errno == ERANGE || errno == EINVAL || *endp != '\0')
441 throw parse_error ("Config option value not a number", l);
442
443 int64_t rhs = lex_cast<int64_t>(r->content);
444 return eval_comparison (lhs, op, rhs);
445 }
4227f98d 446 else if (r->type == tok_identifier
60d98537 447 && startswith(r->content, "CONFIG_"))
4227f98d
MW
448 {
449 // First try to convert both to numbers,
450 // otherwise threat both as strings.
451 const char* startp = s.kernel_config[l->content].c_str ();
452 char* endp = (char*) startp;
453 errno = 0;
454 int64_t val = (int64_t) strtoll (startp, & endp, 0);
455 if (errno != ERANGE && errno != EINVAL && *endp == '\0')
456 {
457 int64_t lhs = val;
458 startp = s.kernel_config[r->content].c_str ();
459 endp = (char*) startp;
460 errno = 0;
461 int64_t rhs = (int64_t) strtoll (startp, & endp, 0);
462 if (errno != ERANGE && errno != EINVAL && *endp == '\0')
463 return eval_comparison (lhs, op, rhs);
464 }
465
466 string lhs = s.kernel_config[l->content];
467 string rhs = s.kernel_config[r->content];
468 return eval_comparison (lhs, op, rhs);
469 }
717a457b 470 else
ce0f6648 471 throw parse_error (_("expected string, number literal or other CONFIG_... as right side operand"), r);
dff50e09 472 }
c434ec7e 473 else if (l->type == tok_string && r->type == tok_string)
5811366a 474 {
c434ec7e
FCE
475 string lhs = l->content;
476 string rhs = r->content;
477 return eval_comparison (lhs, op, rhs);
478 // NB: no wildcarding option here
479 }
480 else if (l->type == tok_number && r->type == tok_number)
481 {
482 int64_t lhs = lex_cast<int64_t>(l->content);
483 int64_t rhs = lex_cast<int64_t>(r->content);
484 return eval_comparison (lhs, op, rhs);
7a468d68 485 // NB: no wildcarding option here
5811366a
FCE
486 }
487 else if (l->type == tok_string && r->type == tok_number
488 && op->type == tok_operator)
2677d2fb 489 throw parse_error (_("expected string literal as right value"), r);
5811366a
FCE
490 else if (l->type == tok_number && r->type == tok_string
491 && op->type == tok_operator)
2677d2fb 492 throw parse_error (_("expected number literal as right value"), r);
c434ec7e 493
177a8ead 494 else
2677d2fb
LB
495 throw parse_error (_("expected 'arch' or 'kernel_v' or 'kernel_vr' or 'CONFIG_...'\n"
496 " or comparison between strings or integers"), l);
177a8ead
FCE
497}
498
499
5811366a 500// Only tokens corresponding to the TRUE statement must be expanded
177a8ead 501const token*
3f847830 502parser::scan_pp (bool wildcard)
177a8ead
FCE
503{
504 while (true)
505 {
e92f2566
JS
506 pp_state_t pp = PP_NONE;
507 if (!pp_state.empty())
508 pp = pp_state.back().second;
509
510 const token* t = 0;
511 if (pp == PP_SKIP_THEN || pp == PP_SKIP_ELSE)
512 t = skip_pp ();
513 else
514 t = input.scan (wildcard);
515
516 if (t == 0) // EOF
177a8ead 517 {
e92f2566
JS
518 if (pp != PP_NONE)
519 {
520 t = pp_state.back().first;
521 pp_state.pop_back(); // so skip_some doesn't keep trying to close this
ce0f6648 522 //TRANSLATORS: 'conditional' meaning 'conditional preprocessing'
2677d2fb 523 throw parse_error (_("incomplete conditional at end of file"), t);
e92f2566 524 }
177a8ead
FCE
525 return t;
526 }
527
e92f2566
JS
528 // misplaced preprocessor "then"
529 if (t->type == tok_operator && t->content == "%?")
2677d2fb 530 throw parse_error (_("incomplete conditional - missing '%('"), t);
e92f2566
JS
531
532 // preprocessor "else"
533 if (t->type == tok_operator && t->content == "%:")
534 {
535 if (pp == PP_NONE)
2677d2fb 536 throw parse_error (_("incomplete conditional - missing '%('"), t);
e92f2566 537 if (pp == PP_KEEP_ELSE || pp == PP_SKIP_ELSE)
2677d2fb 538 throw parse_error (_("invalid conditional - duplicate '%:'"), t);
e92f2566
JS
539
540 pp_state.back().second = (pp == PP_KEEP_THEN) ?
541 PP_SKIP_ELSE : PP_KEEP_ELSE;
542 delete t;
543 continue;
544 }
545
546 // preprocessor close
547 if (t->type == tok_operator && t->content == "%)")
548 {
549 if (pp == PP_NONE)
2677d2fb 550 throw parse_error (_("incomplete conditional - missing '%('"), t);
e92f2566 551 delete pp_state.back().first;
a07a2c28 552 delete t; //this is the closing bracket
e92f2566
JS
553 pp_state.pop_back();
554 continue;
555 }
dff50e09 556
177a8ead
FCE
557 if (! (t->type == tok_operator && t->content == "%(")) // ordinary token
558 return t;
559
560 // We have a %( - it's time to throw a preprocessing party!
561
2d7881bf
PP
562 bool result = false;
563 bool and_result = true;
564 const token *n = NULL;
565 do {
566 const token *l, *op, *r;
e92f2566 567 l = input.scan (false);
2d7881bf
PP
568 op = input.scan (false);
569 r = input.scan (false);
570 if (l == 0 || op == 0 || r == 0)
2677d2fb 571 throw parse_error (_("incomplete condition after '%('"), t);
2d7881bf
PP
572 // NB: consider generalizing to consume all tokens until %?, and
573 // passing that as a vector to an evaluator.
574
575 // Do not evaluate the condition if we haven't expanded everything.
576 // This may occur when having several recursive conditionals.
577 and_result &= eval_pp_conditional (session, l, op, r);
a07a2c28
LB
578 if(l->content=="systemtap_v")
579 systemtap_v_seen=r;
580
581 else
582 delete r;
583
2d7881bf
PP
584 delete l;
585 delete op;
2d7881bf
PP
586 delete n;
587
588 n = input.scan ();
589 if (n && n->type == tok_operator && n->content == "&&")
590 continue;
591 result |= and_result;
592 and_result = true;
593 if (! (n && n->type == tok_operator && n->content == "||"))
594 break;
595 } while (true);
3f847830
FCE
596
597 /*
598 clog << "PP eval (" << *t << ") == " << result << endl;
599 */
600
e92f2566 601 const token *m = n;
177a8ead 602 if (! (m && m->type == tok_operator && m->content == "%?"))
2677d2fb 603 throw parse_error (_("expected '%?' marker for conditional"), t);
70c743d8 604 delete m; // "%?"
177a8ead 605
e92f2566
JS
606 pp = result ? PP_KEEP_THEN : PP_SKIP_THEN;
607 pp_state.push_back (make_pair (t, pp));
3f847830 608
e92f2566
JS
609 // Now loop around to look for a real token.
610 }
611}
3f847830 612
3f847830 613
e92f2566
JS
614// Skip over tokens and any errors, heeding
615// only nested preprocessor starts and ends.
616const token*
617parser::skip_pp ()
618{
619 const token* t = 0;
620 unsigned nesting = 0;
621 do
622 {
623 try
624 {
625 t = input.scan ();
177a8ead 626 }
e92f2566 627 catch (const parse_error &e)
70c743d8 628 {
e92f2566 629 continue;
70c743d8 630 }
e92f2566
JS
631 if (!t)
632 break;
633 if (t->type == tok_operator && t->content == "%(")
634 ++nesting;
635 else if (nesting && t->type == tok_operator && t->content == "%)")
636 --nesting;
637 else if (!nesting && t->type == tok_operator &&
638 (t->content == "%:" || t->content == "%?" || t->content == "%)"))
639 break;
640 delete t;
177a8ead 641 }
e92f2566
JS
642 while (true);
643 return t;
177a8ead
FCE
644}
645
646
2f1a1aea 647const token*
0c218afb 648parser::next (bool wildcard)
2f1a1aea
FCE
649{
650 if (! next_t)
0c218afb 651 next_t = scan_pp (wildcard);
2f1a1aea 652 if (! next_t)
2677d2fb 653 throw parse_error (_("unexpected end-of-file"));
2f1a1aea 654
2f1a1aea
FCE
655 last_t = next_t;
656 // advance by zeroing next_t
657 next_t = 0;
658 return last_t;
659}
660
661
662const token*
0c218afb 663parser::peek (bool wildcard)
2f1a1aea
FCE
664{
665 if (! next_t)
0c218afb 666 next_t = scan_pp (wildcard);
2f1a1aea
FCE
667
668 // don't advance by zeroing next_t
669 last_t = next_t;
670 return next_t;
671}
672
673
d7f3e0c5
GH
674static inline bool
675tok_is(token const * t, token_type tt, string const & expected)
676{
677 return t && t->type == tt && t->content == expected;
678}
679
680
dff50e09 681const token*
d7f3e0c5
GH
682parser::expect_known (token_type tt, string const & expected)
683{
684 const token *t = next();
57b73400 685 if (! (t && t->type == tt && t->content == expected))
ce0f6648 686 throw parse_error (_F("expected '%s'", expected.c_str()));
d7f3e0c5
GH
687 return t;
688}
689
690
dff50e09 691const token*
d7f3e0c5
GH
692parser::expect_unknown (token_type tt, string & target)
693{
694 const token *t = next();
695 if (!(t && t->type == tt))
2677d2fb 696 throw parse_error (_("expected ") + tt2str(tt));
d7f3e0c5
GH
697 target = t->content;
698 return t;
699}
700
701
dff50e09 702const token*
493ee224
DS
703parser::expect_unknown2 (token_type tt1, token_type tt2, string & target)
704{
705 const token *t = next();
706 if (!(t && (t->type == tt1 || t->type == tt2)))
707 throw parse_error ("expected " + tt2str(tt1) + " or " + tt2str(tt2));
708 target = t->content;
709 return t;
710}
711
712
dff50e09 713const token*
d7f3e0c5
GH
714parser::expect_op (std::string const & expected)
715{
716 return expect_known (tok_operator, expected);
717}
718
719
dff50e09 720const token*
d7f3e0c5
GH
721parser::expect_kw (std::string const & expected)
722{
f4fe2e93 723 return expect_known (tok_keyword, expected);
d7f3e0c5
GH
724}
725
dff50e09 726const token*
e38723d2 727parser::expect_number (int64_t & value)
57b73400 728{
e38723d2
MH
729 bool neg = false;
730 const token *t = next();
731 if (t->type == tok_operator && t->content == "-")
732 {
733 neg = true;
734 t = next ();
735 }
736 if (!(t && t->type == tok_number))
2677d2fb 737 throw parse_error (_("expected number"));
e38723d2
MH
738
739 const char* startp = t->content.c_str ();
740 char* endp = (char*) startp;
741
742 // NB: we allow controlled overflow from LLONG_MIN .. ULLONG_MAX
743 // Actually, this allows all the way from -ULLONG_MAX to ULLONG_MAX,
744 // since the lexer only gives us positive digit strings, but we'll
745 // limit it to LLONG_MIN when a '-' operator is fed into the literal.
746 errno = 0;
747 value = (int64_t) strtoull (startp, & endp, 0);
748 if (errno == ERANGE || errno == EINVAL || *endp != '\0'
749 || (neg && (unsigned long long) value > 9223372036854775808ULL)
750 || (unsigned long long) value > 18446744073709551615ULL
751 || value < -9223372036854775807LL-1)
2677d2fb 752 throw parse_error (_("number invalid or out of range"));
dff50e09 753
e38723d2
MH
754 if (neg)
755 value = -value;
756
757 return t;
57b73400
GH
758}
759
d7f3e0c5 760
dff50e09 761const token*
d7f3e0c5
GH
762parser::expect_ident (std::string & target)
763{
764 return expect_unknown (tok_identifier, target);
765}
766
767
dff50e09 768const token*
493ee224
DS
769parser::expect_ident_or_keyword (std::string & target)
770{
771 return expect_unknown2 (tok_identifier, tok_keyword, target);
772}
773
774
dff50e09 775bool
d7f3e0c5
GH
776parser::peek_op (std::string const & op)
777{
778 return tok_is (peek(), tok_operator, op);
779}
780
781
dff50e09 782bool
d7f3e0c5
GH
783parser::peek_kw (std::string const & kw)
784{
785 return tok_is (peek(), tok_identifier, kw);
786}
787
788
789
66c7d4c1 790lexer::lexer (istream& input, const string& in, systemtap_session& s):
c5be7511 791 ate_comment(false), input_name (in), input_pointer (0), input_end (0),
9300f661
JS
792 cursor_suspend_count(0), cursor_suspend_line (1), cursor_suspend_column (1),
793 cursor_line (1), cursor_column (1),
66c7d4c1 794 session(s), current_file (0)
eacb10ce 795{
66c7d4c1 796 getline(input, input_contents, '\0');
2203b032 797
66c7d4c1
JS
798 input_pointer = input_contents.data();
799 input_end = input_contents.data() + input_contents.size();
800
801 if (keywords.empty())
802 {
803 keywords.insert("probe");
804 keywords.insert("global");
805 keywords.insert("function");
806 keywords.insert("if");
807 keywords.insert("else");
808 keywords.insert("for");
809 keywords.insert("foreach");
810 keywords.insert("in");
811 keywords.insert("limit");
812 keywords.insert("return");
813 keywords.insert("delete");
814 keywords.insert("while");
815 keywords.insert("break");
816 keywords.insert("continue");
817 keywords.insert("next");
818 keywords.insert("string");
819 keywords.insert("long");
f4fe2e93
FCE
820 keywords.insert("try");
821 keywords.insert("catch");
66c7d4c1 822 }
eacb10ce 823}
2f1a1aea 824
66c7d4c1
JS
825set<string> lexer::keywords;
826
1b1b4ceb
RA
827void
828lexer::set_current_file (stapfile* f)
829{
830 current_file = f;
2203b032
JS
831 if (f)
832 {
833 f->file_contents = input_contents;
834 f->name = input_name;
835 }
1b1b4ceb 836}
bb2e3076
FCE
837
838int
839lexer::input_peek (unsigned n)
840{
66c7d4c1
JS
841 if (input_pointer + n >= input_end)
842 return -1; // EOF
843 return (unsigned char)*(input_pointer + n);
bb2e3076
FCE
844}
845
846
dff50e09 847int
2f1a1aea
FCE
848lexer::input_get ()
849{
66c7d4c1 850 int c = input_peek();
bb2e3076
FCE
851 if (c < 0) return c; // EOF
852
66c7d4c1
JS
853 ++input_pointer;
854
3f99432c 855 if (cursor_suspend_count)
9300f661
JS
856 {
857 // Track effect of input_put: preserve previous cursor/line_column
858 // until all of its characters are consumed.
859 if (--cursor_suspend_count == 0)
860 {
861 cursor_line = cursor_suspend_line;
862 cursor_column = cursor_suspend_column;
863 }
864 }
3f99432c 865 else
2f1a1aea 866 {
3f99432c
FCE
867 // update source cursor
868 if (c == '\n')
869 {
870 cursor_line ++;
871 cursor_column = 1;
872 }
873 else
874 cursor_column ++;
2f1a1aea 875 }
2f1a1aea 876
eacb10ce 877 // clog << "[" << (char)c << "]";
2f1a1aea
FCE
878 return c;
879}
880
881
3f99432c 882void
9300f661 883lexer::input_put (const string& chars, const token* t)
3f99432c 884{
66c7d4c1
JS
885 size_t pos = input_pointer - input_contents.data();
886 // clog << "[put:" << chars << " @" << pos << "]";
887 input_contents.insert (pos, chars);
eacb10ce 888 cursor_suspend_count += chars.size();
9300f661
JS
889 cursor_suspend_line = cursor_line;
890 cursor_suspend_column = cursor_column;
891 cursor_line = t->location.line;
892 cursor_column = t->location.column;
66c7d4c1
JS
893 input_pointer = input_contents.data() + pos;
894 input_end = input_contents.data() + input_contents.size();
3f99432c
FCE
895}
896
897
2f1a1aea 898token*
3f847830 899lexer::scan (bool wildcard)
2f1a1aea 900{
c5be7511 901 ate_comment = false; // reset for each new token
2f1a1aea 902 token* n = new token;
2203b032 903 n->location.file = current_file;
2f1a1aea 904
9300f661
JS
905skip:
906 bool suspended = (cursor_suspend_count > 0);
2f1a1aea
FCE
907 n->location.line = cursor_line;
908 n->location.column = cursor_column;
909
910 int c = input_get();
3f99432c 911 // clog << "{" << (char)c << (char)c2 << "}";
2f1a1aea
FCE
912 if (c < 0)
913 {
914 delete n;
915 return 0;
916 }
917
918 if (isspace (c))
919 goto skip;
920
66c7d4c1
JS
921 int c2 = input_peek ();
922
3f99432c
FCE
923 // Paste command line arguments as character streams into
924 // the beginning of a token. $1..$999 go through as raw
925 // characters; @1..@999 are quoted/escaped as strings.
926 // $# and @# expand to the number of arguments, similarly
927 // raw or quoted.
9300f661 928 if ((c == '$' || c == '@') && (c2 == '#'))
3f99432c 929 {
9300f661
JS
930 n->content.push_back (c);
931 n->content.push_back (c2);
3f99432c 932 input_get(); // swallow '#'
9300f661 933 if (suspended)
2677d2fb 934 throw parse_error (_("invalid nested substitution of command line arguments"), n);
9300f661
JS
935 size_t num_args = session.args.size ();
936 input_put ((c == '$') ? lex_cast (num_args) : lex_cast_qstring (num_args), n);
937 n->content.clear();
938 goto skip;
3f99432c 939 }
9300f661 940 else if ((c == '$' || c == '@') && (isdigit (c2)))
3f99432c 941 {
9300f661 942 n->content.push_back (c);
3f99432c
FCE
943 unsigned idx = 0;
944 do
945 {
946 input_get ();
947 idx = (idx * 10) + (c2 - '0');
9300f661 948 n->content.push_back (c2);
3f99432c
FCE
949 c2 = input_peek ();
950 } while (c2 > 0 &&
dff50e09 951 isdigit (c2) &&
3f99432c 952 idx <= session.args.size()); // prevent overflow
9300f661 953 if (suspended)
2677d2fb 954 throw parse_error (_("invalid nested substitution of command line arguments"), n);
3f99432c
FCE
955 if (idx == 0 ||
956 idx-1 >= session.args.size())
fc3f0ba7
FCE
957 throw parse_error (_F("command line argument index %lu out of range [1-%lu]",
958 (unsigned long) idx, (unsigned long) session.args.size()),
984ad50c 959 n);
9300f661
JS
960 const string& arg = session.args[idx-1];
961 input_put ((c == '$') ? arg : lex_cast_qstring (arg), n);
962 n->content.clear();
963 goto skip;
3f99432c
FCE
964 }
965
0c218afb
MH
966 else if (isalpha (c) || c == '$' || c == '@' || c == '_' ||
967 (wildcard && c == '*'))
2f1a1aea
FCE
968 {
969 n->type = tok_identifier;
970 n->content = (char) c;
0c218afb
MH
971 while (isalnum (c2) || c2 == '_' || c2 == '$' ||
972 (wildcard && c2 == '*'))
2f1a1aea 973 {
3f99432c
FCE
974 input_get ();
975 n->content.push_back (c2);
976 c2 = input_peek ();
6e213f58 977 }
213bee8f 978
66c7d4c1 979 if (keywords.count(n->content))
3f99432c 980 n->type = tok_keyword;
dff50e09 981
2f1a1aea
FCE
982 return n;
983 }
984
3a20432b 985 else if (isdigit (c)) // positive literal
2f1a1aea 986 {
2f1a1aea 987 n->type = tok_number;
9c0c0e46
FCE
988 n->content = (char) c;
989
66c7d4c1 990 while (isalnum (c2))
2f1a1aea 991 {
9c0c0e46
FCE
992 // NB: isalnum is very permissive. We rely on strtol, called in
993 // parser::parse_literal below, to confirm that the number string
994 // is correctly formatted and in range.
995
66c7d4c1
JS
996 input_get ();
997 n->content.push_back (c2);
998 c2 = input_peek ();
2f1a1aea
FCE
999 }
1000 return n;
1001 }
1002
1003 else if (c == '\"')
1004 {
1005 n->type = tok_string;
1006 while (1)
1007 {
1008 c = input_get ();
1009
3f99432c 1010 if (c < 0 || c == '\n')
2f1a1aea 1011 {
2677d2fb 1012 throw parse_error(_("Could not find matching closing quote"), n);
2f1a1aea
FCE
1013 }
1014 if (c == '\"') // closing double-quotes
1015 break;
3f99432c 1016 else if (c == '\\') // see also input_put
dff50e09 1017 {
7d46afb8
GH
1018 c = input_get ();
1019 switch (c)
1020 {
1021 case 'a':
1022 case 'b':
1023 case 't':
1024 case 'n':
1025 case 'v':
1026 case 'f':
1027 case 'r':
f03954fd 1028 case '0' ... '7': // NB: need only match the first digit
7d46afb8 1029 case '\\':
7d46afb8 1030 // Pass these escapes through to the string value
dff50e09 1031 // being parsed; it will be emitted into a C literal.
7d46afb8
GH
1032
1033 n->content.push_back('\\');
1034
3f99432c 1035 // fall through
7d46afb8 1036 default:
7d46afb8
GH
1037 n->content.push_back(c);
1038 break;
1039 }
2f1a1aea
FCE
1040 }
1041 else
1042 n->content.push_back(c);
1043 }
1044 return n;
1045 }
1046
1047 else if (ispunct (c))
1048 {
bb2e3076 1049 int c3 = input_peek (1);
2f1a1aea 1050
3a20432b
FCE
1051 // NB: if we were to recognize negative numeric literals here,
1052 // we'd introduce another grammar ambiguity:
1053 // 1-1 would be parsed as tok_number(1) and tok_number(-1)
1054 // instead of tok_number(1) tok_operator('-') tok_number(1)
1055
66c7d4c1 1056 if (c == '#') // shell comment
2f1a1aea
FCE
1057 {
1058 unsigned this_line = cursor_line;
bb2e3076
FCE
1059 do { c = input_get (); }
1060 while (c >= 0 && cursor_line == this_line);
c5be7511 1061 ate_comment = true;
2f1a1aea
FCE
1062 goto skip;
1063 }
66c7d4c1 1064 else if ((c == '/' && c2 == '/')) // C++ comment
63a7c90e
FCE
1065 {
1066 unsigned this_line = cursor_line;
bb2e3076
FCE
1067 do { c = input_get (); }
1068 while (c >= 0 && cursor_line == this_line);
c5be7511 1069 ate_comment = true;
63a7c90e
FCE
1070 goto skip;
1071 }
1072 else if (c == '/' && c2 == '*') // C comment
1073 {
66c7d4c1
JS
1074 (void) input_get (); // swallow '*' already in c2
1075 c = input_get ();
63a7c90e 1076 c2 = input_get ();
bb2e3076 1077 while (c2 >= 0)
63a7c90e 1078 {
66c7d4c1
JS
1079 if (c == '*' && c2 == '/')
1080 break;
63a7c90e
FCE
1081 c = c2;
1082 c2 = input_get ();
63a7c90e 1083 }
c5be7511 1084 ate_comment = true;
bb2e3076 1085 goto skip;
63a7c90e 1086 }
54dfabe9
FCE
1087 else if (c == '%' && c2 == '{') // embedded code
1088 {
1089 n->type = tok_embedded;
1090 (void) input_get (); // swallow '{' already in c2
66c7d4c1
JS
1091 c = input_get ();
1092 c2 = input_get ();
1093 while (c2 >= 0)
54dfabe9 1094 {
66c7d4c1
JS
1095 if (c == '%' && c2 == '}')
1096 return n;
54dfabe9 1097 n->content += c;
66c7d4c1
JS
1098 c = c2;
1099 c2 = input_get ();
54dfabe9 1100 }
72cdb9cd 1101
2677d2fb 1102 throw parse_error (_("Could not find matching '%}' to close embedded function block"), n);
54dfabe9 1103 }
2f1a1aea 1104
bb2e3076
FCE
1105 // We're committed to recognizing at least the first character
1106 // as an operator.
2f1a1aea 1107 n->type = tok_operator;
66c7d4c1 1108 n->content = c;
2f1a1aea 1109
bb2e3076 1110 // match all valid operators, in decreasing size order
66c7d4c1
JS
1111 if ((c == '<' && c2 == '<' && c3 == '<') ||
1112 (c == '<' && c2 == '<' && c3 == '=') ||
1113 (c == '>' && c2 == '>' && c3 == '='))
82919855 1114 {
66c7d4c1
JS
1115 n->content += c2;
1116 n->content += c3;
bb2e3076
FCE
1117 input_get (); input_get (); // swallow other two characters
1118 }
66c7d4c1
JS
1119 else if ((c == '=' && c2 == '=') ||
1120 (c == '!' && c2 == '=') ||
1121 (c == '<' && c2 == '=') ||
1122 (c == '>' && c2 == '=') ||
1123 (c == '+' && c2 == '=') ||
1124 (c == '-' && c2 == '=') ||
1125 (c == '*' && c2 == '=') ||
1126 (c == '/' && c2 == '=') ||
1127 (c == '%' && c2 == '=') ||
1128 (c == '&' && c2 == '=') ||
1129 (c == '^' && c2 == '=') ||
1130 (c == '|' && c2 == '=') ||
1131 (c == '.' && c2 == '=') ||
1132 (c == '&' && c2 == '&') ||
1133 (c == '|' && c2 == '|') ||
1134 (c == '+' && c2 == '+') ||
1135 (c == '-' && c2 == '-') ||
1136 (c == '-' && c2 == '>') ||
1137 (c == '<' && c2 == '<') ||
1138 (c == '>' && c2 == '>') ||
177a8ead 1139 // preprocessor tokens
66c7d4c1
JS
1140 (c == '%' && c2 == '(') ||
1141 (c == '%' && c2 == '?') ||
1142 (c == '%' && c2 == ':') ||
1143 (c == '%' && c2 == ')'))
bb2e3076 1144 {
66c7d4c1 1145 n->content += c2;
bb2e3076 1146 input_get (); // swallow other character
dff50e09 1147 }
2f1a1aea
FCE
1148
1149 return n;
1150 }
1151
1152 else
1153 {
1154 n->type = tok_junk;
1155 n->content = (char) c;
1156 return n;
1157 }
1158}
1159
1160
1161// ------------------------------------------------------------------------
1162
1163stapfile*
1164parser::parse ()
1165{
1166 stapfile* f = new stapfile;
1b1b4ceb 1167 input.set_current_file (f);
56099f08
FCE
1168
1169 bool empty = true;
1170
2f1a1aea
FCE
1171 while (1)
1172 {
1173 try
1174 {
a07a2c28 1175 systemtap_v_seen = 0;
2f1a1aea 1176 const token* t = peek ();
56099f08 1177 if (! t) // nice clean EOF
2f1a1aea
FCE
1178 break;
1179
56099f08 1180 empty = false;
6e213f58
DS
1181 if (t->type == tok_keyword && t->content == "probe")
1182 {
1183 context = con_probe;
1184 parse_probe (f->probes, f->aliases);
1185 }
1186 else if (t->type == tok_keyword && t->content == "global")
1187 {
1188 context = con_global;
4b5f3e45 1189 parse_global (f->globals, f->probes);
6e213f58
DS
1190 }
1191 else if (t->type == tok_keyword && t->content == "function")
1192 {
1193 context = con_function;
1194 parse_functiondecl (f->functions);
1195 }
54dfabe9 1196 else if (t->type == tok_embedded)
6e213f58
DS
1197 {
1198 context = con_embedded;
1199 f->embeds.push_back (parse_embeddedcode ());
1200 }
2f1a1aea 1201 else
6e213f58
DS
1202 {
1203 context = con_unknown;
2677d2fb 1204 throw parse_error (_("expected 'probe', 'global', 'function', or '%{'"));
6e213f58 1205 }
2f1a1aea
FCE
1206 }
1207 catch (parse_error& pe)
1208 {
1209 print_error (pe);
cd7116b8 1210 if (pe.skip_some) // for recovery
46954f1d
FCE
1211 // Quietly swallow all tokens until the next keyword we can start parsing from.
1212 while (1)
1213 try
1214 {
cd7116b8
FCE
1215 {
1216 const token* t = peek ();
1217 if (! t)
1218 break;
46954f1d
FCE
1219 if (t->type == tok_keyword && t->content == "probe") break;
1220 else if (t->type == tok_keyword && t->content == "global") break;
1221 else if (t->type == tok_keyword && t->content == "function") break;
1222 else if (t->type == tok_embedded) break;
1223 next(); // swallow it
cd7116b8 1224 }
46954f1d
FCE
1225 }
1226 catch (parse_error& pe2)
1227 {
1228 // parse error during recovery ... ugh
1229 print_error (pe2);
1230 }
177a8ead 1231 }
2f1a1aea
FCE
1232 }
1233
56099f08
FCE
1234 if (empty)
1235 {
46a1a151 1236 cerr << _F("Input file '%s' is empty or missing.", input_name.c_str()) << endl;
56099f08 1237 delete f;
2203b032 1238 f = 0;
56099f08
FCE
1239 }
1240 else if (num_errors > 0)
2f1a1aea 1241 {
cb9ae1fe 1242 cerr << _F(ngettext("%d parse error.", "%d parse errors.", num_errors), num_errors) << endl;
2f1a1aea 1243 delete f;
2203b032 1244 f = 0;
2f1a1aea 1245 }
dff50e09 1246
2203b032 1247 input.set_current_file(0);
2f1a1aea
FCE
1248 return f;
1249}
1250
1251
20c6c071 1252void
54dfabe9
FCE
1253parser::parse_probe (std::vector<probe *> & probe_ret,
1254 std::vector<probe_alias *> & alias_ret)
2f1a1aea 1255{
82919855 1256 const token* t0 = next ();
6e213f58 1257 if (! (t0->type == tok_keyword && t0->content == "probe"))
2677d2fb 1258 throw parse_error (_("expected 'probe'"));
82919855 1259
20c6c071
GH
1260 vector<probe_point *> aliases;
1261 vector<probe_point *> locations;
1262
1263 bool equals_ok = true;
82919855 1264
97266278
LG
1265 int epilogue_alias = 0;
1266
2f1a1aea
FCE
1267 while (1)
1268 {
b4ceace2 1269 probe_point * pp = parse_probe_point ();
dff50e09 1270
b4ceace2 1271 const token* t = peek ();
dff50e09 1272 if (equals_ok && t
b4ceace2
FCE
1273 && t->type == tok_operator && t->content == "=")
1274 {
1ad820e3 1275 if (pp->optional || pp->sufficient)
2677d2fb 1276 throw parse_error (_("probe point alias name cannot be optional nor sufficient"), pp->components.front()->tok);
b4ceace2
FCE
1277 aliases.push_back(pp);
1278 next ();
1279 continue;
1280 }
dff50e09 1281 else if (equals_ok && t
97266278
LG
1282 && t->type == tok_operator && t->content == "+=")
1283 {
1ad820e3 1284 if (pp->optional || pp->sufficient)
2677d2fb 1285 throw parse_error (_("probe point alias name cannot be optional nor sufficient"), pp->components.front()->tok);
97266278
LG
1286 aliases.push_back(pp);
1287 epilogue_alias = 1;
1288 next ();
1289 continue;
1290 }
b4ceace2
FCE
1291 else if (t && t->type == tok_operator && t->content == ",")
1292 {
1293 locations.push_back(pp);
1294 equals_ok = false;
1295 next ();
1296 continue;
1297 }
1298 else if (t && t->type == tok_operator && t->content == "{")
1299 {
1300 locations.push_back(pp);
1301 break;
1302 }
2f1a1aea 1303 else
2677d2fb 1304 throw parse_error (_("expected probe point specifier"));
2f1a1aea 1305 }
20c6c071 1306
20c6c071
GH
1307 if (aliases.empty())
1308 {
54dfabe9
FCE
1309 probe* p = new probe;
1310 p->tok = t0;
1311 p->locations = locations;
1312 p->body = parse_stmt_block ();
37ebca01 1313 p->privileged = privileged;
a07a2c28 1314 p->systemtap_v_conditional = systemtap_v_seen;
54dfabe9 1315 probe_ret.push_back (p);
20c6c071
GH
1316 }
1317 else
1318 {
54dfabe9 1319 probe_alias* p = new probe_alias (aliases);
97266278
LG
1320 if(epilogue_alias)
1321 p->epilogue_style = true;
1322 else
1323 p->epilogue_style = false;
54dfabe9
FCE
1324 p->tok = t0;
1325 p->locations = locations;
1326 p->body = parse_stmt_block ();
37ebca01 1327 p->privileged = privileged;
a07a2c28 1328 p->systemtap_v_conditional = systemtap_v_seen;
54dfabe9 1329 alias_ret.push_back (p);
20c6c071 1330 }
54dfabe9 1331}
20c6c071 1332
54dfabe9
FCE
1333
1334embeddedcode*
1335parser::parse_embeddedcode ()
1336{
1337 embeddedcode* e = new embeddedcode;
1338 const token* t = next ();
1339 if (t->type != tok_embedded)
2677d2fb 1340 throw parse_error (_("expected '%{'"));
24cb178f
FCE
1341
1342 if (! privileged)
2677d2fb 1343 throw parse_error (_("embedded code in unprivileged script"),
cd7116b8 1344 false /* don't skip tokens for parse resumption */);
54dfabe9
FCE
1345
1346 e->tok = t;
1347 e->code = t->content;
1348 return e;
2f1a1aea
FCE
1349}
1350
1351
1352block*
56099f08 1353parser::parse_stmt_block ()
2f1a1aea
FCE
1354{
1355 block* pb = new block;
1356
56099f08
FCE
1357 const token* t = next ();
1358 if (! (t->type == tok_operator && t->content == "{"))
2677d2fb 1359 throw parse_error (_("expected '{'"));
56099f08
FCE
1360
1361 pb->tok = t;
2b066ec1 1362
2f1a1aea
FCE
1363 while (1)
1364 {
46954f1d
FCE
1365 t = peek ();
1366 if (t && t->type == tok_operator && t->content == "}")
1367 {
1368 next ();
1369 break;
1370 }
1371 pb->statements.push_back (parse_statement ());
2f1a1aea
FCE
1372 }
1373
1374 return pb;
1375}
1376
1377
f4fe2e93
FCE
1378try_block*
1379parser::parse_try_block ()
1380{
1381 try_block* pb = new try_block;
1382
1383 pb->tok = expect_kw ("try");
1384 pb->try_block = parse_stmt_block();
1385 expect_kw ("catch");
1386
1387 const token* t = peek ();
1388 if (t->type == tok_operator && t->content == "(")
1389 {
1390 next (); // swallow the '('
1391
1392 t = next();
1393 if (! (t->type == tok_identifier))
2677d2fb 1394 throw parse_error (_("expected identifier"));
f4fe2e93
FCE
1395 symbol* sym = new symbol;
1396 sym->tok = t;
1397 sym->name = t->content;
1398 pb->catch_error_var = sym;
1399
1400 expect_op (")");
1401 }
1402 else
1403 pb->catch_error_var = 0;
1404
1405 pb->catch_block = parse_stmt_block();
1406
1407 return pb;
1408}
1409
1410
1411
2f1a1aea
FCE
1412statement*
1413parser::parse_statement ()
1414{
40b71c47 1415 statement *ret;
2f1a1aea
FCE
1416 const token* t = peek ();
1417 if (t && t->type == tok_operator && t->content == ";")
f946b10f 1418 return new null_statement (next ());
dff50e09 1419 else if (t && t->type == tok_operator && t->content == "{")
40b71c47 1420 return parse_stmt_block (); // Don't squash semicolons.
f4fe2e93
FCE
1421 else if (t && t->type == tok_keyword && t->content == "try")
1422 return parse_try_block (); // Don't squash semicolons.
6e213f58 1423 else if (t && t->type == tok_keyword && t->content == "if")
40b71c47 1424 return parse_if_statement (); // Don't squash semicolons.
6e213f58 1425 else if (t && t->type == tok_keyword && t->content == "for")
40b71c47 1426 return parse_for_loop (); // Don't squash semicolons.
6e213f58 1427 else if (t && t->type == tok_keyword && t->content == "foreach")
40b71c47
MW
1428 return parse_foreach_loop (); // Don't squash semicolons.
1429 else if (t && t->type == tok_keyword && t->content == "while")
1430 return parse_while_loop (); // Don't squash semicolons.
6e213f58 1431 else if (t && t->type == tok_keyword && t->content == "return")
40b71c47 1432 ret = parse_return_statement ();
6e213f58 1433 else if (t && t->type == tok_keyword && t->content == "delete")
40b71c47 1434 ret = parse_delete_statement ();
6e213f58 1435 else if (t && t->type == tok_keyword && t->content == "break")
40b71c47 1436 ret = parse_break_statement ();
6e213f58 1437 else if (t && t->type == tok_keyword && t->content == "continue")
40b71c47 1438 ret = parse_continue_statement ();
6e213f58 1439 else if (t && t->type == tok_keyword && t->content == "next")
40b71c47 1440 ret = parse_next_statement ();
2f1a1aea
FCE
1441 else if (t && (t->type == tok_operator || // expressions are flexible
1442 t->type == tok_identifier ||
1443 t->type == tok_number ||
7d902887
FCE
1444 t->type == tok_string ||
1445 t->type == tok_embedded ))
40b71c47 1446 ret = parse_expr_statement ();
54dfabe9 1447 // XXX: consider generally accepting tok_embedded here too
2f1a1aea 1448 else
2677d2fb 1449 throw parse_error (_("expected statement"));
40b71c47
MW
1450
1451 // Squash "empty" trailing colons after any "non-block-like" statement.
1452 t = peek ();
1453 if (t && t->type == tok_operator && t->content == ";")
1454 {
1455 next (); // Silently eat trailing ; after statement
1456 }
1457
1458 return ret;
2f1a1aea
FCE
1459}
1460
1461
56099f08 1462void
78f6bba6 1463parser::parse_global (vector <vardecl*>& globals, vector<probe*>&)
2f1a1aea 1464{
82919855 1465 const token* t0 = next ();
6e213f58 1466 if (! (t0->type == tok_keyword && t0->content == "global"))
2677d2fb 1467 throw parse_error (_("expected 'global'"));
82919855 1468
56099f08
FCE
1469 while (1)
1470 {
1471 const token* t = next ();
1472 if (! (t->type == tok_identifier))
2677d2fb 1473 throw parse_error (_("expected identifier"));
56099f08 1474
2b066ec1
FCE
1475 for (unsigned i=0; i<globals.size(); i++)
1476 if (globals[i]->name == t->content)
2677d2fb 1477 throw parse_error (_("duplicate global name"));
dff50e09 1478
24cb178f
FCE
1479 vardecl* d = new vardecl;
1480 d->name = t->content;
1481 d->tok = t;
a07a2c28 1482 d->systemtap_v_conditional = systemtap_v_seen;
24cb178f 1483 globals.push_back (d);
56099f08 1484
82919855 1485 t = peek ();
ef474d24 1486
74e6cc92
CM
1487 if(t && t->type == tok_operator && t->content == "%") //wrapping
1488 {
1489 d->wrap = true;
1490 next();
1491 t = peek();
1492 }
1493
ef474d24
JS
1494 if (t && t->type == tok_operator && t->content == "[") // array size
1495 {
1496 int64_t size;
1497 next ();
1498 expect_number(size);
1499 if (size <= 0 || size > 1000000) // arbitrary max
2677d2fb 1500 throw parse_error(_("array size out of range"));
ef474d24
JS
1501 d->maxsize = (int)size;
1502 expect_known(tok_operator, "]");
1503 t = peek ();
1504 }
1505
4b5f3e45 1506 if (t && t->type == tok_operator && t->content == "=") // initialization
ef474d24
JS
1507 {
1508 if (!d->compatible_arity(0))
2677d2fb 1509 throw parse_error(_("only scalar globals can be initialized"));
58701b78 1510 d->set_arity(0, t);
ef474d24
JS
1511 next ();
1512 d->init = parse_literal ();
1513 d->type = d->init->type;
1514 t = peek ();
1515 }
4b5f3e45 1516
c3799d72
AM
1517 if (t && t->type == tok_operator && t->content == ";") // termination
1518 next();
1519
4b5f3e45 1520 if (t && t->type == tok_operator && t->content == ",") // next global
82919855
FCE
1521 {
1522 next ();
1523 continue;
1524 }
56099f08 1525 else
82919855 1526 break;
56099f08
FCE
1527 }
1528}
1529
1530
24cb178f
FCE
1531void
1532parser::parse_functiondecl (std::vector<functiondecl*>& functions)
56099f08 1533{
82919855 1534 const token* t = next ();
6e213f58 1535 if (! (t->type == tok_keyword && t->content == "function"))
2677d2fb 1536 throw parse_error (_("expected 'function'"));
82919855 1537
56099f08 1538
82919855 1539 t = next ();
6e213f58
DS
1540 if (! (t->type == tok_identifier)
1541 && ! (t->type == tok_keyword
1542 && (t->content == "string" || t->content == "long")))
2677d2fb 1543 throw parse_error (_("expected identifier"));
24cb178f
FCE
1544
1545 for (unsigned i=0; i<functions.size(); i++)
1546 if (functions[i]->name == t->content)
2677d2fb 1547 throw parse_error (_("duplicate function name"));
24cb178f
FCE
1548
1549 functiondecl *fd = new functiondecl ();
56099f08
FCE
1550 fd->name = t->content;
1551 fd->tok = t;
1552
1553 t = next ();
6a505121
FCE
1554 if (t->type == tok_operator && t->content == ":")
1555 {
1556 t = next ();
6e213f58 1557 if (t->type == tok_keyword && t->content == "string")
6a505121 1558 fd->type = pe_string;
6e213f58 1559 else if (t->type == tok_keyword && t->content == "long")
6a505121 1560 fd->type = pe_long;
2677d2fb 1561 else throw parse_error (_("expected 'string' or 'long'"));
6a505121
FCE
1562
1563 t = next ();
1564 }
1565
56099f08 1566 if (! (t->type == tok_operator && t->content == "("))
2677d2fb 1567 throw parse_error (_("expected '('"));
56099f08
FCE
1568
1569 while (1)
1570 {
1571 t = next ();
1572
1573 // permit zero-argument fuctions
1574 if (t->type == tok_operator && t->content == ")")
1575 break;
1576 else if (! (t->type == tok_identifier))
2677d2fb 1577 throw parse_error (_("expected identifier"));
56099f08
FCE
1578 vardecl* vd = new vardecl;
1579 vd->name = t->content;
1580 vd->tok = t;
1581 fd->formal_args.push_back (vd);
a07a2c28 1582 fd->systemtap_v_conditional = systemtap_v_seen;
56099f08
FCE
1583
1584 t = next ();
6a505121
FCE
1585 if (t->type == tok_operator && t->content == ":")
1586 {
1587 t = next ();
6e213f58 1588 if (t->type == tok_keyword && t->content == "string")
6a505121 1589 vd->type = pe_string;
6e213f58 1590 else if (t->type == tok_keyword && t->content == "long")
6a505121 1591 vd->type = pe_long;
2677d2fb 1592 else throw parse_error (_("expected 'string' or 'long'"));
dff50e09 1593
6a505121
FCE
1594 t = next ();
1595 }
56099f08
FCE
1596 if (t->type == tok_operator && t->content == ")")
1597 break;
1598 if (t->type == tok_operator && t->content == ",")
1599 continue;
1600 else
2677d2fb 1601 throw parse_error (_("expected ',' or ')'"));
56099f08
FCE
1602 }
1603
54dfabe9
FCE
1604 t = peek ();
1605 if (t && t->type == tok_embedded)
1606 fd->body = parse_embeddedcode ();
1607 else
1608 fd->body = parse_stmt_block ();
24cb178f
FCE
1609
1610 functions.push_back (fd);
2f1a1aea
FCE
1611}
1612
1613
9c0c0e46
FCE
1614probe_point*
1615parser::parse_probe_point ()
2f1a1aea 1616{
9c0c0e46 1617 probe_point* pl = new probe_point;
2f1a1aea 1618
9c0c0e46 1619 while (1)
2f1a1aea 1620 {
0c218afb 1621 const token* t = next (true); // wildcard scanning here
6e213f58
DS
1622 if (! (t->type == tok_identifier
1623 // we must allow ".return" and ".function", which are keywords
0c218afb 1624 || t->type == tok_keyword))
2677d2fb 1625 throw parse_error (_("expected identifier or '*'"));
9c0c0e46 1626
9c0c0e46
FCE
1627
1628 probe_point::component* c = new probe_point::component;
1629 c->functor = t->content;
f1a0157a 1630 c->tok = t;
9c0c0e46 1631 pl->components.push_back (c);
6e3347a9 1632 // NB we may add c->arg soon
9c0c0e46
FCE
1633
1634 t = peek ();
a477f3f1 1635
6e3347a9 1636 // consume optional parameter
9c0c0e46
FCE
1637 if (t && t->type == tok_operator && t->content == "(")
1638 {
1639 next (); // consume "("
1640 c->arg = parse_literal ();
1641
1642 t = next ();
1643 if (! (t->type == tok_operator && t->content == ")"))
2677d2fb 1644 throw parse_error (_("expected ')'"));
9c0c0e46
FCE
1645
1646 t = peek ();
9c0c0e46 1647 }
9c0c0e46
FCE
1648
1649 if (t && t->type == tok_operator && t->content == ".")
6e3347a9
FCE
1650 {
1651 next ();
1652 continue;
1653 }
1654
f1a0157a 1655 // We only fall through here at the end of a probe point (past
6e3347a9
FCE
1656 // all the dotted/parametrized components).
1657
d898100a
FCE
1658 if (t && t->type == tok_operator &&
1659 (t->content == "?" || t->content == "!"))
6e3347a9
FCE
1660 {
1661 pl->optional = true;
d898100a
FCE
1662 if (t->content == "!") pl->sufficient = true;
1663 // NB: sufficient implies optional
6e3347a9
FCE
1664 next ();
1665 t = peek ();
1666 // fall through
cbbe8080
MH
1667 }
1668
1669 if (t && t->type == tok_keyword && t->content == "if")
1670 {
1671 next ();
1672 t = peek ();
75686668 1673 if (t && ! (t->type == tok_operator && t->content == "("))
2677d2fb 1674 throw parse_error (_("expected '('"));
cbbe8080
MH
1675 next ();
1676
1677 pl->condition = parse_expression ();
1678
1679 t = peek ();
75686668 1680 if (t && ! (t->type == tok_operator && t->content == ")"))
2677d2fb 1681 throw parse_error (_("expected ')'"));
cbbe8080
MH
1682 next ();
1683 t = peek ();
1684 // fall through
6e3347a9
FCE
1685 }
1686
dff50e09 1687 if (t && t->type == tok_operator
6e3347a9
FCE
1688 && (t->content == "{" || t->content == "," ||
1689 t->content == "=" || t->content == "+=" ))
1690 break;
dff50e09 1691
2677d2fb 1692 throw parse_error (_("expected one of '. , ( ? ! { = +='"));
2f1a1aea
FCE
1693 }
1694
1695 return pl;
1696}
1697
1698
1699literal*
1700parser::parse_literal ()
1701{
1702 const token* t = next ();
56099f08 1703 literal* l;
2f1a1aea 1704 if (t->type == tok_string)
c5be7511
JS
1705 {
1706 literal_string *ls = new literal_string (t->content);
1707
1708 // PR11208: check if the next token is also a string literal; auto-concatenate it
1709 // This is complicated to the extent that we need to skip intermediate whitespace.
1710 // XXX: but not comments
83d4d1a3
MW
1711 const token *n = peek();
1712 while (n != NULL && n->type == tok_string && !input.ate_comment)
1713 {
1714 ls->value.append(next()->content); // consume and append the token
1715 n = peek();
1716 }
c5be7511
JS
1717 l = ls;
1718 }
16e8f21f 1719 else
9c0c0e46 1720 {
16e8f21f
JS
1721 bool neg = false;
1722 if (t->type == tok_operator && t->content == "-")
1723 {
1724 neg = true;
1725 t = next ();
1726 }
1727
1728 if (t->type == tok_number)
1729 {
1730 const char* startp = t->content.c_str ();
1731 char* endp = (char*) startp;
1732
1733 // NB: we allow controlled overflow from LLONG_MIN .. ULLONG_MAX
1734 // Actually, this allows all the way from -ULLONG_MAX to ULLONG_MAX,
79e6d33f
JS
1735 // since the lexer only gives us positive digit strings, but we'll
1736 // limit it to LLONG_MIN when a '-' operator is fed into the literal.
16e8f21f
JS
1737 errno = 0;
1738 long long value = (long long) strtoull (startp, & endp, 0);
16e8f21f 1739 if (errno == ERANGE || errno == EINVAL || *endp != '\0'
79e6d33f 1740 || (neg && (unsigned long long) value > 9223372036854775808ULL)
16e8f21f
JS
1741 || (unsigned long long) value > 18446744073709551615ULL
1742 || value < -9223372036854775807LL-1)
2677d2fb 1743 throw parse_error (_("number invalid or out of range"));
16e8f21f 1744
79e6d33f
JS
1745 if (neg)
1746 value = -value;
1747
16e8f21f
JS
1748 l = new literal_number (value);
1749 }
1750 else
2677d2fb 1751 throw parse_error (_("expected literal string or number"));
9c0c0e46 1752 }
56099f08
FCE
1753
1754 l->tok = t;
1755 return l;
2f1a1aea
FCE
1756}
1757
1758
1759if_statement*
1760parser::parse_if_statement ()
1761{
1762 const token* t = next ();
6e213f58 1763 if (! (t->type == tok_keyword && t->content == "if"))
2677d2fb 1764 throw parse_error (_("expected 'if'"));
56099f08
FCE
1765 if_statement* s = new if_statement;
1766 s->tok = t;
1767
1768 t = next ();
2f1a1aea 1769 if (! (t->type == tok_operator && t->content == "("))
2677d2fb 1770 throw parse_error (_("expected '('"));
2f1a1aea 1771
2f1a1aea
FCE
1772 s->condition = parse_expression ();
1773
1774 t = next ();
1775 if (! (t->type == tok_operator && t->content == ")"))
2677d2fb 1776 throw parse_error (_("expected ')'"));
2f1a1aea
FCE
1777
1778 s->thenblock = parse_statement ();
1779
1780 t = peek ();
6e213f58 1781 if (t && t->type == tok_keyword && t->content == "else")
2f1a1aea
FCE
1782 {
1783 next ();
1784 s->elseblock = parse_statement ();
1785 }
ed10c639
FCE
1786 else
1787 s->elseblock = 0; // in case not otherwise initialized
2f1a1aea
FCE
1788
1789 return s;
1790}
1791
1792
69c68955
FCE
1793expr_statement*
1794parser::parse_expr_statement ()
1795{
1796 expr_statement *es = new expr_statement;
1797 const token* t = peek ();
1798 es->tok = t;
1799 es->value = parse_expression ();
1800 return es;
1801}
1802
1803
56099f08
FCE
1804return_statement*
1805parser::parse_return_statement ()
1806{
1807 const token* t = next ();
6e213f58 1808 if (! (t->type == tok_keyword && t->content == "return"))
2677d2fb 1809 throw parse_error (_("expected 'return'"));
6e213f58 1810 if (context != con_function)
2677d2fb 1811 throw parse_error (_("found 'return' not in function context"));
56099f08
FCE
1812 return_statement* s = new return_statement;
1813 s->tok = t;
1814 s->value = parse_expression ();
1815 return s;
1816}
1817
1818
1819delete_statement*
1820parser::parse_delete_statement ()
1821{
1822 const token* t = next ();
6e213f58 1823 if (! (t->type == tok_keyword && t->content == "delete"))
2677d2fb 1824 throw parse_error (_("expected 'delete'"));
56099f08
FCE
1825 delete_statement* s = new delete_statement;
1826 s->tok = t;
1827 s->value = parse_expression ();
1828 return s;
1829}
1830
1831
f3c26ea5
FCE
1832next_statement*
1833parser::parse_next_statement ()
1834{
1835 const token* t = next ();
6e213f58 1836 if (! (t->type == tok_keyword && t->content == "next"))
2677d2fb 1837 throw parse_error (_("expected 'next'"));
6e213f58 1838 if (context != con_probe)
2677d2fb 1839 throw parse_error (_("found 'next' not in probe context"));
f3c26ea5
FCE
1840 next_statement* s = new next_statement;
1841 s->tok = t;
1842 return s;
1843}
1844
1845
1846break_statement*
1847parser::parse_break_statement ()
1848{
1849 const token* t = next ();
6e213f58 1850 if (! (t->type == tok_keyword && t->content == "break"))
2677d2fb 1851 throw parse_error (_("expected 'break'"));
f3c26ea5
FCE
1852 break_statement* s = new break_statement;
1853 s->tok = t;
1854 return s;
1855}
1856
1857
1858continue_statement*
1859parser::parse_continue_statement ()
1860{
1861 const token* t = next ();
6e213f58 1862 if (! (t->type == tok_keyword && t->content == "continue"))
2677d2fb 1863 throw parse_error (_("expected 'continue'"));
f3c26ea5
FCE
1864 continue_statement* s = new continue_statement;
1865 s->tok = t;
1866 return s;
1867}
1868
1869
69c68955
FCE
1870for_loop*
1871parser::parse_for_loop ()
1872{
f3c26ea5 1873 const token* t = next ();
6e213f58 1874 if (! (t->type == tok_keyword && t->content == "for"))
2677d2fb 1875 throw parse_error (_("expected 'for'"));
f3c26ea5
FCE
1876 for_loop* s = new for_loop;
1877 s->tok = t;
1878
1879 t = next ();
1880 if (! (t->type == tok_operator && t->content == "("))
2677d2fb 1881 throw parse_error (_("expected '('"));
f3c26ea5
FCE
1882
1883 // initializer + ";"
1884 t = peek ();
1885 if (t && t->type == tok_operator && t->content == ";")
1886 {
cbfbbf69
FCE
1887 s->init = 0;
1888 next ();
f3c26ea5
FCE
1889 }
1890 else
1891 {
1892 s->init = parse_expr_statement ();
1893 t = next ();
1894 if (! (t->type == tok_operator && t->content == ";"))
2677d2fb 1895 throw parse_error (_("expected ';'"));
f3c26ea5
FCE
1896 }
1897
1898 // condition + ";"
1899 t = peek ();
1900 if (t && t->type == tok_operator && t->content == ";")
1901 {
1902 literal_number* l = new literal_number(1);
1903 s->cond = l;
1904 s->cond->tok = next ();
1905 }
1906 else
1907 {
1908 s->cond = parse_expression ();
1909 t = next ();
1910 if (! (t->type == tok_operator && t->content == ";"))
2677d2fb 1911 throw parse_error (_("expected ';'"));
f3c26ea5 1912 }
dff50e09 1913
f3c26ea5
FCE
1914 // increment + ")"
1915 t = peek ();
1916 if (t && t->type == tok_operator && t->content == ")")
1917 {
cbfbbf69
FCE
1918 s->incr = 0;
1919 next ();
f3c26ea5
FCE
1920 }
1921 else
1922 {
1923 s->incr = parse_expr_statement ();
1924 t = next ();
1925 if (! (t->type == tok_operator && t->content == ")"))
2677d2fb 1926 throw parse_error (_("expected ')'"));
f3c26ea5
FCE
1927 }
1928
1929 // block
1930 s->block = parse_statement ();
1931
1932 return s;
1933}
1934
1935
1936for_loop*
1937parser::parse_while_loop ()
1938{
1939 const token* t = next ();
6e213f58 1940 if (! (t->type == tok_keyword && t->content == "while"))
2677d2fb 1941 throw parse_error (_("expected 'while'"));
f3c26ea5
FCE
1942 for_loop* s = new for_loop;
1943 s->tok = t;
1944
1945 t = next ();
1946 if (! (t->type == tok_operator && t->content == "("))
2677d2fb 1947 throw parse_error (_("expected '('"));
f3c26ea5
FCE
1948
1949 // dummy init and incr fields
cbfbbf69
FCE
1950 s->init = 0;
1951 s->incr = 0;
f3c26ea5
FCE
1952
1953 // condition
1954 s->cond = parse_expression ();
1955
f3c26ea5
FCE
1956 t = next ();
1957 if (! (t->type == tok_operator && t->content == ")"))
2677d2fb 1958 throw parse_error (_("expected ')'"));
dff50e09 1959
f3c26ea5
FCE
1960 // block
1961 s->block = parse_statement ();
1962
1963 return s;
69c68955
FCE
1964}
1965
1966
1967foreach_loop*
1968parser::parse_foreach_loop ()
1969{
1970 const token* t = next ();
6e213f58 1971 if (! (t->type == tok_keyword && t->content == "foreach"))
2677d2fb 1972 throw parse_error (_("expected 'foreach'"));
69c68955
FCE
1973 foreach_loop* s = new foreach_loop;
1974 s->tok = t;
93484556 1975 s->sort_direction = 0;
c261711d 1976 s->value = NULL;
27f21e8c 1977 s->limit = NULL;
69c68955
FCE
1978
1979 t = next ();
1980 if (! (t->type == tok_operator && t->content == "("))
2677d2fb 1981 throw parse_error (_("expected '('"));
69c68955 1982
c261711d
JS
1983 symbol* lookahead_sym = NULL;
1984 int lookahead_sort = 0;
1985
1986 t = peek ();
1987 if (t && t->type == tok_identifier)
1988 {
1989 next ();
1990 lookahead_sym = new symbol;
1991 lookahead_sym->tok = t;
1992 lookahead_sym->name = t->content;
1993
1994 t = peek ();
1995 if (t && t->type == tok_operator &&
1996 (t->content == "+" || t->content == "-"))
1997 {
1998 next ();
1999 lookahead_sort = (t->content == "+") ? 1 : -1;
2000 }
2001
2002 t = peek ();
2003 if (t && t->type == tok_operator && t->content == "=")
2004 {
2005 next ();
2006 s->value = lookahead_sym;
2007 if (lookahead_sort)
2008 {
2009 s->sort_direction = lookahead_sort;
2010 s->sort_column = 0;
2011 }
2012 lookahead_sym = NULL;
2013 }
2014 }
2015
69c68955
FCE
2016 // see also parse_array_in
2017
2018 bool parenthesized = false;
2019 t = peek ();
c261711d 2020 if (!lookahead_sym && t && t->type == tok_operator && t->content == "[")
69c68955
FCE
2021 {
2022 next ();
2023 parenthesized = true;
2024 }
2025
c261711d
JS
2026 if (lookahead_sym)
2027 {
2028 s->indexes.push_back (lookahead_sym);
2029 if (lookahead_sort)
2030 {
2031 s->sort_direction = lookahead_sort;
2032 s->sort_column = 1;
2033 }
2034 lookahead_sym = NULL;
2035 }
2036 else while (1)
69c68955
FCE
2037 {
2038 t = next ();
2039 if (! (t->type == tok_identifier))
2677d2fb 2040 throw parse_error (_("expected identifier"));
69c68955
FCE
2041 symbol* sym = new symbol;
2042 sym->tok = t;
2043 sym->name = t->content;
2044 s->indexes.push_back (sym);
2045
93484556
FCE
2046 t = peek ();
2047 if (t && t->type == tok_operator &&
2048 (t->content == "+" || t->content == "-"))
2049 {
2050 if (s->sort_direction)
2677d2fb 2051 throw parse_error (_("multiple sort directives"));
93484556
FCE
2052 s->sort_direction = (t->content == "+") ? 1 : -1;
2053 s->sort_column = s->indexes.size();
2054 next();
2055 }
2056
69c68955
FCE
2057 if (parenthesized)
2058 {
93484556 2059 t = peek ();
69c68955
FCE
2060 if (t && t->type == tok_operator && t->content == ",")
2061 {
2062 next ();
2063 continue;
2064 }
2065 else if (t && t->type == tok_operator && t->content == "]")
2066 {
2067 next ();
2068 break;
2069 }
dff50e09 2070 else
2677d2fb 2071 throw parse_error (_("expected ',' or ']'"));
69c68955
FCE
2072 }
2073 else
2074 break; // expecting only one expression
2075 }
2076
2077 t = next ();
6e213f58 2078 if (! (t->type == tok_keyword && t->content == "in"))
2677d2fb 2079 throw parse_error (_("expected 'in'"));
dff50e09 2080
d02548c0 2081 s->base = parse_indexable();
69c68955 2082
93484556
FCE
2083 t = peek ();
2084 if (t && t->type == tok_operator &&
2085 (t->content == "+" || t->content == "-"))
2086 {
2087 if (s->sort_direction)
2677d2fb 2088 throw parse_error (_("multiple sort directives"));
93484556
FCE
2089 s->sort_direction = (t->content == "+") ? 1 : -1;
2090 s->sort_column = 0;
2091 next();
2092 }
2093
27f21e8c
DS
2094 t = peek ();
2095 if (tok_is(t, tok_keyword, "limit"))
2096 {
2097 next (); // get past the "limit"
2098 s->limit = parse_expression ();
2099 }
2100
69c68955
FCE
2101 t = next ();
2102 if (! (t->type == tok_operator && t->content == ")"))
2103 throw parse_error ("expected ')'");
2104
2105 s->block = parse_statement ();
2106 return s;
2107}
2108
2109
2f1a1aea
FCE
2110expression*
2111parser::parse_expression ()
2112{
2113 return parse_assignment ();
2114}
2115
2f1a1aea
FCE
2116
2117expression*
2118parser::parse_assignment ()
2119{
2120 expression* op1 = parse_ternary ();
2121
2122 const token* t = peek ();
82919855 2123 // right-associative operators
dff50e09 2124 if (t && t->type == tok_operator
2f1a1aea 2125 && (t->content == "=" ||
82919855 2126 t->content == "<<<" ||
2f1a1aea 2127 t->content == "+=" ||
bb2e3076
FCE
2128 t->content == "-=" ||
2129 t->content == "*=" ||
2130 t->content == "/=" ||
2131 t->content == "%=" ||
2132 t->content == "<<=" ||
2133 t->content == ">>=" ||
2134 t->content == "&=" ||
2135 t->content == "^=" ||
2136 t->content == "|=" ||
d5d7c2cc 2137 t->content == ".=" ||
dff50e09 2138 false))
2f1a1aea 2139 {
bb2e3076 2140 // NB: lvalueness is checked during elaboration / translation
2f1a1aea 2141 assignment* e = new assignment;
56099f08 2142 e->left = op1;
2f1a1aea 2143 e->op = t->content;
56099f08 2144 e->tok = t;
2f1a1aea 2145 next ();
82919855 2146 e->right = parse_expression ();
56099f08 2147 op1 = e;
2f1a1aea 2148 }
56099f08
FCE
2149
2150 return op1;
2f1a1aea
FCE
2151}
2152
2153
2154expression*
2155parser::parse_ternary ()
2156{
2157 expression* op1 = parse_logical_or ();
2158
2159 const token* t = peek ();
2160 if (t && t->type == tok_operator && t->content == "?")
2161 {
2f1a1aea 2162 ternary_expression* e = new ternary_expression;
56099f08 2163 e->tok = t;
2f1a1aea 2164 e->cond = op1;
56099f08
FCE
2165 next ();
2166 e->truevalue = parse_expression (); // XXX
2f1a1aea
FCE
2167
2168 t = next ();
2169 if (! (t->type == tok_operator && t->content == ":"))
2677d2fb 2170 throw parse_error (_("expected ':'"));
2f1a1aea 2171
56099f08 2172 e->falsevalue = parse_expression (); // XXX
2f1a1aea
FCE
2173 return e;
2174 }
2175 else
2176 return op1;
2177}
2178
2179
2180expression*
2181parser::parse_logical_or ()
2182{
2183 expression* op1 = parse_logical_and ();
dff50e09 2184
2f1a1aea 2185 const token* t = peek ();
56099f08 2186 while (t && t->type == tok_operator && t->content == "||")
2f1a1aea 2187 {
2f1a1aea 2188 logical_or_expr* e = new logical_or_expr;
56099f08
FCE
2189 e->tok = t;
2190 e->op = t->content;
2f1a1aea 2191 e->left = op1;
56099f08
FCE
2192 next ();
2193 e->right = parse_logical_and ();
2194 op1 = e;
2195 t = peek ();
2f1a1aea 2196 }
56099f08
FCE
2197
2198 return op1;
2f1a1aea
FCE
2199}
2200
2201
2202expression*
2203parser::parse_logical_and ()
2204{
bb2e3076 2205 expression* op1 = parse_boolean_or ();
2f1a1aea
FCE
2206
2207 const token* t = peek ();
56099f08 2208 while (t && t->type == tok_operator && t->content == "&&")
2f1a1aea 2209 {
2f1a1aea
FCE
2210 logical_and_expr *e = new logical_and_expr;
2211 e->left = op1;
56099f08
FCE
2212 e->op = t->content;
2213 e->tok = t;
2214 next ();
bb2e3076
FCE
2215 e->right = parse_boolean_or ();
2216 op1 = e;
2217 t = peek ();
2218 }
2219
2220 return op1;
2221}
2222
2223
2224expression*
2225parser::parse_boolean_or ()
2226{
2227 expression* op1 = parse_boolean_xor ();
2228
2229 const token* t = peek ();
2230 while (t && t->type == tok_operator && t->content == "|")
2231 {
2232 binary_expression* e = new binary_expression;
2233 e->left = op1;
2234 e->op = t->content;
2235 e->tok = t;
2236 next ();
2237 e->right = parse_boolean_xor ();
2238 op1 = e;
2239 t = peek ();
2240 }
2241
2242 return op1;
2243}
2244
2245
2246expression*
2247parser::parse_boolean_xor ()
2248{
2249 expression* op1 = parse_boolean_and ();
2250
2251 const token* t = peek ();
2252 while (t && t->type == tok_operator && t->content == "^")
2253 {
2254 binary_expression* e = new binary_expression;
2255 e->left = op1;
2256 e->op = t->content;
2257 e->tok = t;
2258 next ();
2259 e->right = parse_boolean_and ();
2260 op1 = e;
2261 t = peek ();
2262 }
2263
2264 return op1;
2265}
2266
2267
2268expression*
2269parser::parse_boolean_and ()
2270{
2271 expression* op1 = parse_array_in ();
2272
2273 const token* t = peek ();
2274 while (t && t->type == tok_operator && t->content == "&")
2275 {
2276 binary_expression* e = new binary_expression;
2277 e->left = op1;
2278 e->op = t->content;
2279 e->tok = t;
2280 next ();
56099f08
FCE
2281 e->right = parse_array_in ();
2282 op1 = e;
2283 t = peek ();
2f1a1aea 2284 }
56099f08
FCE
2285
2286 return op1;
2f1a1aea
FCE
2287}
2288
2289
2290expression*
2291parser::parse_array_in ()
2292{
ce10591c 2293 // This is a very tricky case. All these are legit expressions:
69c68955 2294 // "a in b" "a+0 in b" "[a,b] in c" "[c,(d+0)] in b"
ce10591c
FCE
2295 vector<expression*> indexes;
2296 bool parenthesized = false;
2f1a1aea
FCE
2297
2298 const token* t = peek ();
69c68955 2299 if (t && t->type == tok_operator && t->content == "[")
ce10591c
FCE
2300 {
2301 next ();
2302 parenthesized = true;
2303 }
2304
2305 while (1)
2306 {
2307 expression* op1 = parse_comparison ();
2308 indexes.push_back (op1);
2309
2310 if (parenthesized)
2311 {
2312 const token* t = peek ();
2313 if (t && t->type == tok_operator && t->content == ",")
2314 {
2315 next ();
2316 continue;
2317 }
69c68955 2318 else if (t && t->type == tok_operator && t->content == "]")
ce10591c
FCE
2319 {
2320 next ();
2321 break;
2322 }
dff50e09 2323 else
2677d2fb 2324 throw parse_error (_("expected ',' or ']'"));
ce10591c
FCE
2325 }
2326 else
2327 break; // expecting only one expression
2328 }
2329
2330 t = peek ();
6e213f58 2331 if (t && t->type == tok_keyword && t->content == "in")
2f1a1aea 2332 {
2f1a1aea 2333 array_in *e = new array_in;
56099f08 2334 e->tok = t;
ce10591c
FCE
2335 next (); // swallow "in"
2336
2337 arrayindex* a = new arrayindex;
2338 a->indexes = indexes;
d02548c0
GH
2339 a->base = parse_indexable();
2340 a->tok = a->base->get_tok();
ce10591c 2341 e->operand = a;
2f1a1aea
FCE
2342 return e;
2343 }
ce10591c
FCE
2344 else if (indexes.size() == 1) // no "in" - need one expression only
2345 return indexes[0];
2f1a1aea 2346 else
2677d2fb 2347 throw parse_error (_("unexpected comma-separated expression list"));
2f1a1aea
FCE
2348}
2349
2350
2351expression*
2352parser::parse_comparison ()
2353{
bb2e3076 2354 expression* op1 = parse_shift ();
2f1a1aea
FCE
2355
2356 const token* t = peek ();
dff50e09 2357 while (t && t->type == tok_operator
553d27a5
FCE
2358 && (t->content == ">" ||
2359 t->content == "<" ||
2360 t->content == "==" ||
2361 t->content == "!=" ||
2362 t->content == "<=" ||
bb2e3076 2363 t->content == ">="))
2f1a1aea
FCE
2364 {
2365 comparison* e = new comparison;
2366 e->left = op1;
2367 e->op = t->content;
56099f08 2368 e->tok = t;
2f1a1aea 2369 next ();
bb2e3076
FCE
2370 e->right = parse_shift ();
2371 op1 = e;
2372 t = peek ();
2373 }
2374
2375 return op1;
2376}
2377
2378
2379expression*
2380parser::parse_shift ()
2381{
2382 expression* op1 = parse_concatenation ();
2383
2384 const token* t = peek ();
dff50e09 2385 while (t && t->type == tok_operator &&
bb2e3076
FCE
2386 (t->content == "<<" || t->content == ">>"))
2387 {
2388 binary_expression* e = new binary_expression;
2389 e->left = op1;
2390 e->op = t->content;
2391 e->tok = t;
2392 next ();
56099f08
FCE
2393 e->right = parse_concatenation ();
2394 op1 = e;
2395 t = peek ();
2f1a1aea 2396 }
56099f08
FCE
2397
2398 return op1;
2f1a1aea
FCE
2399}
2400
2401
2402expression*
2403parser::parse_concatenation ()
2404{
2405 expression* op1 = parse_additive ();
2406
2407 const token* t = peek ();
2408 // XXX: the actual awk string-concatenation operator is *whitespace*.
2409 // I don't know how to easily to model that here.
56099f08 2410 while (t && t->type == tok_operator && t->content == ".")
2f1a1aea
FCE
2411 {
2412 concatenation* e = new concatenation;
2413 e->left = op1;
2414 e->op = t->content;
56099f08 2415 e->tok = t;
2f1a1aea 2416 next ();
56099f08
FCE
2417 e->right = parse_additive ();
2418 op1 = e;
2419 t = peek ();
2f1a1aea 2420 }
56099f08
FCE
2421
2422 return op1;
2f1a1aea
FCE
2423}
2424
2425
2426expression*
2427parser::parse_additive ()
2428{
2429 expression* op1 = parse_multiplicative ();
2430
2431 const token* t = peek ();
dff50e09 2432 while (t && t->type == tok_operator
2f1a1aea
FCE
2433 && (t->content == "+" || t->content == "-"))
2434 {
2435 binary_expression* e = new binary_expression;
2436 e->op = t->content;
2437 e->left = op1;
56099f08 2438 e->tok = t;
2f1a1aea 2439 next ();
56099f08
FCE
2440 e->right = parse_multiplicative ();
2441 op1 = e;
2442 t = peek ();
2f1a1aea 2443 }
56099f08
FCE
2444
2445 return op1;
2f1a1aea
FCE
2446}
2447
2448
2449expression*
2450parser::parse_multiplicative ()
2451{
2452 expression* op1 = parse_unary ();
2453
2454 const token* t = peek ();
dff50e09 2455 while (t && t->type == tok_operator
2f1a1aea
FCE
2456 && (t->content == "*" || t->content == "/" || t->content == "%"))
2457 {
2458 binary_expression* e = new binary_expression;
2459 e->op = t->content;
2460 e->left = op1;
56099f08 2461 e->tok = t;
2f1a1aea 2462 next ();
56099f08
FCE
2463 e->right = parse_unary ();
2464 op1 = e;
2465 t = peek ();
2f1a1aea 2466 }
56099f08
FCE
2467
2468 return op1;
2f1a1aea
FCE
2469}
2470
2471
2472expression*
2473parser::parse_unary ()
2474{
2475 const token* t = peek ();
dff50e09
FCE
2476 if (t && t->type == tok_operator
2477 && (t->content == "+" ||
2478 t->content == "-" ||
bb2e3076
FCE
2479 t->content == "!" ||
2480 t->content == "~" ||
2481 false))
2f1a1aea
FCE
2482 {
2483 unary_expression* e = new unary_expression;
2484 e->op = t->content;
56099f08 2485 e->tok = t;
2f1a1aea 2486 next ();
1cb79a72 2487 e->operand = parse_unary ();
2f1a1aea
FCE
2488 return e;
2489 }
2490 else
bb2e3076 2491 return parse_crement ();
2f1a1aea
FCE
2492}
2493
2494
2495expression*
2496parser::parse_crement () // as in "increment" / "decrement"
2497{
cbfbbf69
FCE
2498 // NB: Ideally, we'd parse only a symbol as an operand to the
2499 // *crement operators, instead of a general expression value. We'd
2500 // need more complex lookahead code to tell apart the postfix cases.
2501 // So we just punt, and leave it to pass-3 to signal errors on
2502 // cases like "4++".
2503
2f1a1aea 2504 const token* t = peek ();
dff50e09 2505 if (t && t->type == tok_operator
2f1a1aea
FCE
2506 && (t->content == "++" || t->content == "--"))
2507 {
2508 pre_crement* e = new pre_crement;
2509 e->op = t->content;
56099f08 2510 e->tok = t;
2f1a1aea
FCE
2511 next ();
2512 e->operand = parse_value ();
2513 return e;
2514 }
2515
2516 // post-crement or non-crement
2517 expression *op1 = parse_value ();
dff50e09 2518
2f1a1aea 2519 t = peek ();
dff50e09 2520 if (t && t->type == tok_operator
2f1a1aea
FCE
2521 && (t->content == "++" || t->content == "--"))
2522 {
2523 post_crement* e = new post_crement;
2524 e->op = t->content;
56099f08 2525 e->tok = t;
2f1a1aea
FCE
2526 next ();
2527 e->operand = op1;
2528 return e;
2529 }
2530 else
2531 return op1;
2532}
2533
2534
2535expression*
2536parser::parse_value ()
2537{
2538 const token* t = peek ();
2539 if (! t)
2677d2fb 2540 throw parse_error (_("expected value"));
2f1a1aea 2541
7d902887
FCE
2542 if (t->type == tok_embedded)
2543 {
2544 next ();
2545 if (! privileged)
2677d2fb 2546 throw parse_error (_("embedded expression code in unprivileged script"), false);
7d902887
FCE
2547
2548 embedded_expr *e = new embedded_expr;
2549 e->tok = t;
2550 e->code = t->content;
2551 return e;
2552 }
2553
2f1a1aea
FCE
2554 if (t->type == tok_operator && t->content == "(")
2555 {
2556 next ();
2557 expression* e = parse_expression ();
2558 t = next ();
2559 if (! (t->type == tok_operator && t->content == ")"))
2677d2fb 2560 throw parse_error (_("expected ')'"));
2f1a1aea
FCE
2561 return e;
2562 }
03c75a4a
JS
2563 else if (t->type == tok_operator && t->content == "&")
2564 {
2565 next ();
d48afc20 2566 return parse_target_symbol (t);
03c75a4a 2567 }
2f1a1aea
FCE
2568 else if (t->type == tok_identifier)
2569 return parse_symbol ();
2570 else
2571 return parse_literal ();
2572}
2573
2574
d02548c0
GH
2575const token *
2576parser::parse_hist_op_or_bare_name (hist_op *&hop, string &name)
2577{
2578 hop = NULL;
2579 const token* t = expect_ident (name);
2580 if (name == "@hist_linear" || name == "@hist_log")
2581 {
2582 hop = new hist_op;
2583 if (name == "@hist_linear")
2584 hop->htype = hist_linear;
2585 else if (name == "@hist_log")
2586 hop->htype = hist_log;
2587 hop->tok = t;
2588 expect_op("(");
2589 hop->stat = parse_expression ();
2590 int64_t tnum;
2591 if (hop->htype == hist_linear)
2592 {
2593 for (size_t i = 0; i < 3; ++i)
2594 {
2595 expect_op (",");
2596 expect_number (tnum);
2597 hop->params.push_back (tnum);
2598 }
2599 }
d02548c0
GH
2600 expect_op(")");
2601 }
2602 return t;
2603}
2604
2605
2606indexable*
2607parser::parse_indexable ()
2608{
2609 hist_op *hop = NULL;
2610 string name;
2611 const token *tok = parse_hist_op_or_bare_name(hop, name);
2612 if (hop)
2613 return hop;
2614 else
2615 {
2616 symbol* sym = new symbol;
2617 sym->name = name;
2618 sym->tok = tok;
2619 return sym;
2620 }
2621}
2622
2623
2624// var, indexable[index], func(parms), printf("...", ...), $var, $var->member, @stat_op(stat)
30263a73 2625expression* parser::parse_symbol ()
2f1a1aea 2626{
d02548c0
GH
2627 hist_op *hop = NULL;
2628 symbol *sym = NULL;
d7f3e0c5 2629 string name;
d02548c0
GH
2630 const token *t = parse_hist_op_or_bare_name(hop, name);
2631
2632 if (!hop)
0fefb486 2633 {
dff50e09 2634 // If we didn't get a hist_op, then we did get an identifier. We can
d02548c0
GH
2635 // now scrutinize this identifier for the various magic forms of identifier
2636 // (printf, @stat_op, and $var...)
2637
30263a73
FCE
2638 if (name == "@cast" || (name.size()>0 && name[0] == '$'))
2639 return parse_target_symbol (t);
9b5af295 2640
db135493
FCE
2641 // NB: PR11343: @defined() is not incompatible with earlier versions
2642 // of stap, so no need to check session.compatible for 1.2
30263a73
FCE
2643 if (name == "@defined")
2644 return parse_defined_op (t);
8cc799a5
JS
2645
2646 if (name == "@entry")
2647 return parse_entry_op (t);
2648
9b5af295 2649 else if (name.size() > 0 && name[0] == '@')
d7f3e0c5 2650 {
d02548c0
GH
2651 stat_op *sop = new stat_op;
2652 if (name == "@avg")
2653 sop->ctype = sc_average;
2654 else if (name == "@count")
2655 sop->ctype = sc_count;
2656 else if (name == "@sum")
2657 sop->ctype = sc_sum;
2658 else if (name == "@min")
2659 sop->ctype = sc_min;
2660 else if (name == "@max")
2661 sop->ctype = sc_max;
2662 else
2677d2fb 2663 throw parse_error(_("unknown statistic operator ") + name);
d02548c0
GH
2664 expect_op("(");
2665 sop->tok = t;
2666 sop->stat = parse_expression ();
2667 expect_op(")");
2668 return sop;
2669 }
dff50e09 2670
d5e178c1 2671 else if (print_format *fmt = print_format::create(t))
d02548c0 2672 {
d02548c0 2673 expect_op("(");
b15c465c
PP
2674 if ((name == "print" || name == "println" ||
2675 name == "sprint" || name == "sprintln") &&
3cb17058 2676 (peek_kw("@hist_linear") || peek_kw("@hist_log")))
a4636912
GH
2677 {
2678 // We have a special case where we recognize
2679 // print(@hist_foo(bar)) as a magic print-the-histogram
2680 // construct. This is sort of gross but it avoids
2681 // promoting histogram references to typeful
2682 // expressions.
dff50e09 2683
1bbeef03
GH
2684 hop = NULL;
2685 t = parse_hist_op_or_bare_name(hop, name);
2686 assert(hop);
dff50e09 2687
1bbeef03
GH
2688 // It is, sadly, possible that even while parsing a
2689 // hist_op, we *mis-guessed* and the user wishes to
2690 // print(@hist_op(foo)[bucket]), a scalar. In that case
2691 // we must parse the arrayindex and print an expression.
839325a1
JS
2692 //
2693 // XXX: This still fails if the arrayindex is part of a
2694 // larger expression. To really handle everything, we'd
2695 // need to push back all the hist tokens start over.
dff50e09 2696
1bbeef03
GH
2697 if (!peek_op ("["))
2698 fmt->hist = hop;
2699 else
2700 {
2701 // This is simplified version of the
2702 // multi-array-index parser below, because we can
2703 // only ever have one index on a histogram anyways.
2704 expect_op("[");
2705 struct arrayindex* ai = new arrayindex;
2706 ai->tok = t;
2707 ai->base = hop;
2708 ai->indexes.push_back (parse_expression ());
2709 expect_op("]");
2710 fmt->args.push_back(ai);
839325a1
JS
2711
2712 // Consume any subsequent arguments.
2713 while (!peek_op (")"))
2714 {
2715 expect_op(",");
2716 expression *e = parse_expression ();
2717 fmt->args.push_back(e);
2718 }
1bbeef03 2719 }
a4636912 2720 }
d7f3e0c5 2721 else
d02548c0 2722 {
3cb17058
JS
2723 int min_args = 0;
2724 if (fmt->print_with_format)
2725 {
2726 // Consume and convert a format string. Agreement between the
2727 // format string and the arguments is postponed to the
2728 // typechecking phase.
2729 string tmp;
2730 expect_unknown (tok_string, tmp);
2731 fmt->raw_components = tmp;
2732 fmt->components = print_format::string_to_components (tmp);
2733 }
2734 else if (fmt->print_with_delim)
2735 {
2736 // Consume a delimiter to separate arguments.
2737 fmt->delimiter.clear();
2738 fmt->delimiter.type = print_format::conv_literal;
2739 expect_unknown (tok_string, fmt->delimiter.literal_string);
2740 min_args = 2;
2741 }
2742 else
2743 {
2744 // If we are not printing with a format string, we must have
2745 // at least one argument (of any type).
2746 expression *e = parse_expression ();
2747 fmt->args.push_back(e);
2748 }
2749
2750 // Consume any subsequent arguments.
2751 while (min_args || !peek_op (")"))
2752 {
2753 expect_op(",");
2754 expression *e = parse_expression ();
2755 fmt->args.push_back(e);
2756 if (min_args)
2757 --min_args;
2758 }
d02548c0
GH
2759 }
2760 expect_op(")");
2761 return fmt;
2762 }
dff50e09 2763
d02548c0
GH
2764 else if (peek_op ("(")) // function call
2765 {
2766 next ();
2767 struct functioncall* f = new functioncall;
2768 f->tok = t;
2769 f->function = name;
2770 // Allow empty actual parameter list
2771 if (peek_op (")"))
2772 {
2773 next ();
2774 return f;
2775 }
2776 while (1)
2777 {
2778 f->args.push_back (parse_expression ());
2779 if (peek_op (")"))
2780 {
2781 next();
2782 break;
2783 }
2784 else if (peek_op (","))
2785 {
2786 next();
2787 continue;
2788 }
2789 else
2677d2fb 2790 throw parse_error (_("expected ',' or ')'"));
d02548c0
GH
2791 }
2792 return f;
2793 }
2794
2795 else
2796 {
2797 sym = new symbol;
2798 sym->name = name;
2799 sym->tok = t;
d7f3e0c5 2800 }
0fefb486 2801 }
dff50e09
FCE
2802
2803 // By now, either we had a hist_op in the first place, or else
d02548c0
GH
2804 // we had a plain word and it was converted to a symbol.
2805
70c743d8 2806 assert (!hop != !sym); // logical XOR
d02548c0
GH
2807
2808 // All that remains is to check for array indexing
2809
d7f3e0c5 2810 if (peek_op ("[")) // array
2f1a1aea
FCE
2811 {
2812 next ();
2813 struct arrayindex* ai = new arrayindex;
d02548c0
GH
2814 ai->tok = t;
2815
2816 if (hop)
2817 ai->base = hop;
2818 else
2819 ai->base = sym;
2820
2f1a1aea
FCE
2821 while (1)
2822 {
2823 ai->indexes.push_back (parse_expression ());
d7f3e0c5 2824 if (peek_op ("]"))
dff50e09
FCE
2825 {
2826 next();
2827 break;
d7f3e0c5
GH
2828 }
2829 else if (peek_op (","))
2830 {
2831 next();
2832 continue;
2833 }
2f1a1aea 2834 else
2677d2fb 2835 throw parse_error (_("expected ',' or ']'"));
2f1a1aea
FCE
2836 }
2837 return ai;
2838 }
d02548c0
GH
2839
2840 // If we got to here, we *should* have a symbol; if we have
2841 // a hist_op on its own, it doesn't count as an expression,
2842 // so we throw a parse error.
2843
2844 if (hop)
2677d2fb 2845 throw parse_error(_("base histogram operator where expression expected"), t);
dff50e09
FCE
2846
2847 return sym;
2f1a1aea 2848}
56099f08 2849
81931eab 2850
30263a73
FCE
2851// Parse a @cast or $var. Given head token has already been consumed.
2852target_symbol* parser::parse_target_symbol (const token* t)
2853{
d48afc20
JS
2854 bool addressof = false;
2855 if (t->type == tok_operator && t->content == "&")
2856 {
2857 addressof = true;
2858 t = next ();
2859 }
2860
30263a73
FCE
2861 if (t->type == tok_identifier && t->content == "@cast")
2862 {
2863 cast_op *cop = new cast_op;
2864 cop->tok = t;
277c21bc 2865 cop->name = t->content;
30263a73
FCE
2866 expect_op("(");
2867 cop->operand = parse_expression ();
2868 expect_op(",");
7f6b80bd 2869 expect_unknown(tok_string, cop->type_name);
30263a73
FCE
2870 if (peek_op (","))
2871 {
2872 next();
2873 expect_unknown(tok_string, cop->module);
2874 }
2875 expect_op(")");
2876 parse_target_symbol_components(cop);
d48afc20 2877 cop->addressof = addressof;
30263a73
FCE
2878 return cop;
2879 }
2880
2881 if (t->type == tok_identifier && t->content[0]=='$')
2882 {
2883 // target_symbol time
2884 target_symbol *tsym = new target_symbol;
2885 tsym->tok = t;
277c21bc 2886 tsym->name = t->content;
30263a73 2887 parse_target_symbol_components(tsym);
d48afc20 2888 tsym->addressof = addressof;
30263a73
FCE
2889 return tsym;
2890 }
2891
2677d2fb 2892 throw parse_error (_("expected @cast or $var"));
30263a73
FCE
2893}
2894
2895
2896// Parse a @defined(). Given head token has already been consumed.
2897expression* parser::parse_defined_op (const token* t)
2898{
2899 defined_op* dop = new defined_op;
2900 dop->tok = t;
2901 expect_op("(");
30263a73 2902 // no need for parse_hist_op... etc., as @defined takes only target_symbols as its operand.
d48afc20 2903 const token* tt = next ();
30263a73
FCE
2904 dop->operand = parse_target_symbol (tt);
2905 expect_op(")");
2906 return dop;
2907}
2908
2909
8cc799a5
JS
2910// Parse a @entry(). Given head token has already been consumed.
2911expression* parser::parse_entry_op (const token* t)
2912{
2913 entry_op* eop = new entry_op;
2914 eop->tok = t;
2915 expect_op("(");
2916 eop->operand = parse_expression ();
2917 expect_op(")");
2918 return eop;
2919}
2920
2921
30263a73 2922
81931eab
JS
2923void
2924parser::parse_target_symbol_components (target_symbol* e)
2925{
5f36109e
JS
2926 bool pprint = false;
2927
2928 // check for pretty-print in the form $foo$
277c21bc 2929 string &base = e->name;
5f36109e
JS
2930 size_t pprint_pos = base.find_last_not_of('$');
2931 if (0 < pprint_pos && pprint_pos < base.length() - 1)
2932 {
2933 string pprint_val = base.substr(pprint_pos + 1);
2934 base.erase(pprint_pos + 1);
2935 e->components.push_back (target_symbol::component(e->tok, pprint_val, true));
2936 pprint = true;
2937 }
2938
2939 while (!pprint)
81931eab 2940 {
81931eab
JS
2941 if (peek_op ("->"))
2942 {
c67847a0
JS
2943 const token* t = next();
2944 string member;
2945 expect_ident_or_keyword (member);
5f36109e
JS
2946
2947 // check for pretty-print in the form $foo->$ or $foo->bar$
2948 pprint_pos = member.find_last_not_of('$');
2949 string pprint_val;
2950 if (pprint_pos == string::npos || pprint_pos < member.length() - 1)
2951 {
2952 pprint_val = member.substr(pprint_pos + 1);
2953 member.erase(pprint_pos + 1);
2954 pprint = true;
2955 }
2956
2957 if (!member.empty())
2958 e->components.push_back (target_symbol::component(t, member));
2959 if (pprint)
2960 e->components.push_back (target_symbol::component(t, pprint_val, true));
81931eab
JS
2961 }
2962 else if (peek_op ("["))
2963 {
c67847a0 2964 const token* t = next();
6fda2dff
JS
2965 expression* index = parse_expression();
2966 literal_number* ln = dynamic_cast<literal_number*>(index);
2967 if (ln)
2968 e->components.push_back (target_symbol::component(t, ln->value));
2969 else
2970 e->components.push_back (target_symbol::component(t, index));
81931eab 2971 expect_op ("]");
81931eab
JS
2972 }
2973 else
2974 break;
2975 }
5f36109e
JS
2976
2977 if (!pprint)
2978 {
2979 // check for pretty-print in the form $foo $
2980 // i.e. as a separate token, esp. for $foo[i]$ and @cast(...)$
2981 const token* t = peek();
2982 if (t->type == tok_identifier &&
2983 t->content.find_first_not_of('$') == string::npos)
2984 {
2985 t = next();
2986 e->components.push_back (target_symbol::component(t, t->content, true));
2987 pprint = true;
2988 }
2989 }
2990
2991 if (pprint && (peek_op ("->") || peek_op("[")))
ce0f6648 2992 throw parse_error(_("-> and [ are not accepted for a pretty-printing variable"));
81931eab
JS
2993}
2994
73267b89 2995/* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
This page took 0.487147 seconds and 5 git commands to generate.