Branch data Line data Source code
1 : : // recursive descent parser for systemtap scripts
2 : : // Copyright (C) 2005-2013 Red Hat Inc.
3 : : // Copyright (C) 2006 Intel Corporation.
4 : : // Copyright (C) 2007 Bull S.A.S
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.
10 : :
11 : : #include "config.h"
12 : : #include "staptree.h"
13 : : #include "parse.h"
14 : : #include "session.h"
15 : : #include "util.h"
16 : :
17 : : #include <iostream>
18 : :
19 : : #include <fstream>
20 : : #include <cctype>
21 : : #include <cstdlib>
22 : : #include <cassert>
23 : : #include <cerrno>
24 : : #include <climits>
25 : : #include <sstream>
26 : : #include <cstring>
27 : : #include <cctype>
28 : : #include <iterator>
29 : :
30 : : extern "C" {
31 : : #include <fnmatch.h>
32 : : }
33 : :
34 : : using namespace std;
35 : :
36 : :
37 [ + - ]: 191819 : class lexer
38 : : {
39 : : public:
40 : : bool ate_comment; // current token follows a comment
41 : : bool ate_whitespace; // the most recent token followed whitespace
42 : : bool saw_tokens; // the lexer found tokens (before preprocessing occurred)
43 : :
44 : : token* scan ();
45 : : lexer (istream&, const string&, systemtap_session&);
46 : : void set_current_file (stapfile* f);
47 : :
48 : : static set<string> keywords;
49 : : static set<string> atwords;
50 : : private:
51 : : inline int input_get ();
52 : : inline int input_peek (unsigned n=0);
53 : : void input_put (const string&, const token*);
54 : : string input_name;
55 : : string input_contents;
56 : : const char *input_pointer; // index into input_contents
57 : : const char *input_end;
58 : : unsigned cursor_suspend_count;
59 : : unsigned cursor_suspend_line;
60 : : unsigned cursor_suspend_column;
61 : : unsigned cursor_line;
62 : : unsigned cursor_column;
63 : : systemtap_session& session;
64 : : stapfile* current_file;
65 : : };
66 : :
67 : :
68 : : class parser
69 : : {
70 : : public:
71 : : parser (systemtap_session& s, const string& n, istream& i, bool p);
72 : : ~parser ();
73 : :
74 : : stapfile* parse ();
75 : : stapfile* parse_library_macros ();
76 : :
77 : : private:
78 : : typedef enum {
79 : : PP_NONE,
80 : : PP_KEEP_THEN,
81 : : PP_SKIP_THEN,
82 : : PP_KEEP_ELSE,
83 : : PP_SKIP_ELSE,
84 : : } pp_state_t;
85 : :
86 : : struct pp1_activation;
87 : :
88 [ - + ]: 1887180 : struct pp_macrodecl : public macrodecl {
89 : : pp1_activation* parent_act; // used for param bindings
90 : 2779156 : virtual bool is_closure() { return parent_act != 0; }
91 : 943590 : pp_macrodecl () : macrodecl(), parent_act(0) { }
92 : : };
93 : :
94 : : systemtap_session& session;
95 : : string input_name;
96 : : lexer input;
97 : : bool privileged;
98 : : parse_context context;
99 : :
100 : : // preprocessing subordinate, first pass (macros)
101 : : struct pp1_activation {
102 : : const token* tok;
103 : : unsigned cursor; // position within macro body
104 : : map<string, pp_macrodecl*> params;
105 : :
106 : : macrodecl* curr_macro;
107 : :
108 : 1915243 : pp1_activation (const token tok, macrodecl* curr_macro)
109 [ + - ]: 1915243 : : tok(new token(tok)), cursor(0), curr_macro(curr_macro) { }
110 : : ~pp1_activation ();
111 : : };
112 : :
113 : : map<string, macrodecl*> pp1_namespace;
114 : : vector<pp1_activation*> pp1_state;
115 : : const token* next_pp1 ();
116 : : const token* scan_pp1 ();
117 : : const token* slurp_pp1_param (vector<const token*>& param);
118 : : const token* slurp_pp1_body (vector<const token*>& body);
119 : :
120 : : // preprocessing subordinate, final pass (conditionals)
121 : : vector<pair<const token*, pp_state_t> > pp_state;
122 : : const token* scan_pp ();
123 : : const token* skip_pp ();
124 : :
125 : : // scanning state
126 : : const token* next ();
127 : : const token* peek ();
128 : :
129 : : // Advance past and throw away current token after peek () or next ().
130 : : void swallow ();
131 : :
132 : : const token* systemtap_v_seen;
133 : : const token* last_t; // the last value returned by peek() or next()
134 : : const token* next_t; // lookahead token
135 : :
136 : : // expectations, these swallow the token
137 : : void expect_known (token_type tt, string const & expected);
138 : : void expect_unknown (token_type tt, string & target);
139 : : void expect_unknown2 (token_type tt1, token_type tt2, string & target);
140 : :
141 : : // convenience forms, these also swallow the token
142 : : void expect_op (string const & expected);
143 : : void expect_kw (string const & expected);
144 : : void expect_number (int64_t & expected);
145 : : void expect_ident_or_keyword (string & target);
146 : :
147 : : // convenience forms, which return true or false, these don't swallow token
148 : : bool peek_op (string const & op);
149 : : bool peek_kw (string const & kw);
150 : :
151 : : // convenience forms, which return the token
152 : : const token* expect_kw_token (string const & expected);
153 : : const token* expect_ident_or_atword (string & target);
154 : :
155 : : void print_error (const parse_error& pe);
156 : : unsigned num_errors;
157 : :
158 : : private: // nonterminals
159 : : void parse_probe (vector<probe*>&, vector<probe_alias*>&);
160 : : void parse_global (vector<vardecl*>&, vector<probe*>&);
161 : : void parse_functiondecl (vector<functiondecl*>&);
162 : : embeddedcode* parse_embeddedcode ();
163 : : probe_point* parse_probe_point ();
164 : : literal_string* consume_string_literals (const token*);
165 : : literal_string* parse_literal_string ();
166 : : literal* parse_literal ();
167 : : block* parse_stmt_block ();
168 : : try_block* parse_try_block ();
169 : : statement* parse_statement ();
170 : : if_statement* parse_if_statement ();
171 : : for_loop* parse_for_loop ();
172 : : for_loop* parse_while_loop ();
173 : : foreach_loop* parse_foreach_loop ();
174 : : expr_statement* parse_expr_statement ();
175 : : return_statement* parse_return_statement ();
176 : : delete_statement* parse_delete_statement ();
177 : : next_statement* parse_next_statement ();
178 : : break_statement* parse_break_statement ();
179 : : continue_statement* parse_continue_statement ();
180 : : indexable* parse_indexable ();
181 : : const token *parse_hist_op_or_bare_name (hist_op *&hop, string &name);
182 : : target_symbol *parse_target_symbol (const token* t);
183 : : expression* parse_entry_op (const token* t);
184 : : expression* parse_defined_op (const token* t);
185 : : expression* parse_perf_op (const token* t);
186 : : expression* parse_expression ();
187 : : expression* parse_assignment ();
188 : : expression* parse_ternary ();
189 : : expression* parse_logical_or ();
190 : : expression* parse_logical_and ();
191 : : expression* parse_boolean_or ();
192 : : expression* parse_boolean_xor ();
193 : : expression* parse_boolean_and ();
194 : : expression* parse_array_in ();
195 : : expression* parse_comparison_or_regex_query ();
196 : : expression* parse_shift ();
197 : : expression* parse_concatenation ();
198 : : expression* parse_additive ();
199 : : expression* parse_multiplicative ();
200 : : expression* parse_unary ();
201 : : expression* parse_crement ();
202 : : expression* parse_value ();
203 : : expression* parse_symbol ();
204 : :
205 : : void parse_target_symbol_components (target_symbol* e);
206 : : };
207 : :
208 : :
209 : : // ------------------------------------------------------------------------
210 : :
211 : : stapfile*
212 : 540 : parse (systemtap_session& s, istream& i, bool pr)
213 : : {
214 [ + - ][ + - ]: 540 : parser p (s, "<input>", i, pr);
[ + - ]
215 [ + - ][ + - ]: 540 : return p.parse ();
216 : : }
217 : :
218 : :
219 : : stapfile*
220 : 186972 : parse (systemtap_session& s, const string& name, bool pr)
221 : : {
222 [ + - ][ + - ]: 186972 : ifstream i(name.c_str(), ios::in);
223 [ + - ][ + + ]: 186972 : if (i.fail())
224 : : {
225 [ + - ]: 1 : cerr << (file_exists(name)
226 : 0 : ? _F("Input file '%s' can't be opened for reading.", name.c_str())
227 [ - + ][ # # ]: 2 : : _F("Input file '%s' is missing.", name.c_str()))
[ # # ][ + - ]
[ + - ][ + - ]
[ + - ]
228 [ + - ]: 1 : << endl;
229 : 1 : return 0;
230 : : }
231 : :
232 [ + - ]: 186971 : parser p (s, name, i, pr);
233 [ + - ][ + - ]: 186972 : return p.parse ();
[ + - ]
234 : : }
235 : :
236 : : stapfile*
237 : 4308 : parse_library_macros (systemtap_session& s, const string& name)
238 : : {
239 [ + - ][ + - ]: 4308 : ifstream i(name.c_str(), ios::in);
240 [ + - ][ - + ]: 4308 : if (i.fail())
241 : : {
242 [ # # ]: 0 : cerr << (file_exists(name)
243 : 0 : ? _F("Input file '%s' can't be opened for reading.", name.c_str())
244 [ # # ][ # # ]: 0 : : _F("Input file '%s' is missing.", name.c_str()))
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
245 [ # # ]: 0 : << endl;
246 : 0 : return 0;
247 : : }
248 : :
249 [ + - ]: 4308 : parser p (s, name, i, false); // TODOXX pr is ...? should path be full??
250 [ + - ][ + - ]: 4308 : return p.parse_library_macros ();
[ + - ]
251 : : }
252 : :
253 : : // ------------------------------------------------------------------------
254 : :
255 : :
256 : 191819 : parser::parser (systemtap_session& s, const string &n, istream& i, bool p):
257 : : session (s), input_name (n), input (i, input_name, s), privileged (p),
258 [ + - ][ + - ]: 191819 : context(con_unknown), systemtap_v_seen(0), last_t (0), next_t (0), num_errors (0)
[ + - ][ + - ]
259 : : {
260 : 191819 : }
261 : :
262 : 959095 : parser::~parser()
263 : : {
264 [ + - ][ + - ]: 191819 : }
[ + - ][ + - ]
265 : :
266 : : static string
267 : 59564 : tt2str(token_type tt)
268 : : {
269 [ + + + + : 59564 : switch (tt)
+ + + - ]
270 : : {
271 [ + - ]: 6 : case tok_junk: return "junk";
272 [ + - ]: 36344 : case tok_identifier: return "identifier";
273 [ + - ]: 6423 : case tok_operator: return "operator";
274 [ + - ]: 20 : case tok_string: return "string";
275 [ + - ]: 24 : case tok_number: return "number";
276 [ + - ]: 4 : case tok_embedded: return "embedded-code";
277 [ + - ]: 16743 : case tok_keyword: return "keyword";
278 : : }
279 [ # # ]: 59564 : return "unknown token";
280 : : }
281 : :
282 : : ostream&
283 : 93286 : operator << (ostream& o, const source_loc& loc)
284 : : {
285 : 93286 : o << loc.file->name << ":"
286 : 93286 : << loc.line << ":"
287 : 93286 : << loc.column;
288 : :
289 : 93286 : return o;
290 : : }
291 : :
292 : : ostream&
293 : 59561 : operator << (ostream& o, const token& t)
294 : : {
295 [ + - ]: 59561 : o << tt2str(t.type);
296 : :
297 [ + + ][ + + ]: 59561 : if (t.type != tok_embedded && t.type != tok_keyword) // XXX: other types?
298 : : {
299 : 42814 : o << " '";
300 [ + + ]: 290845 : for (unsigned i=0; i<t.content.length(); i++)
301 : : {
302 : 248031 : char c = t.content[i];
303 [ + - ]: 248031 : o << (isprint (c) ? c : '?');
304 : : }
305 : 42814 : o << "'";
306 : : }
307 : :
308 : 59561 : o << " at "
309 : 59561 : << t.location;
310 : :
311 : 59561 : return o;
312 : : }
313 : :
314 : :
315 : : void
316 : 141 : parser::print_error (const parse_error &pe)
317 : : {
318 [ + - ]: 141 : string align_parse_error (" ");
319 : :
320 [ + + ]: 141 : const token *tok = pe.tok ? pe.tok : last_t;
321 : :
322 : : // print either pe.what() or a deferred error from the lexer
323 : 141 : bool found_junk = false;
324 [ + + ][ + + ]: 141 : if (tok && tok->type == tok_junk && tok->msg != "")
[ + - ][ + - ]
[ + + ]
325 : : {
326 : 6 : found_junk = true;
327 [ + - ][ + - ]: 6 : cerr << _("parse error: ") << tok->msg << endl;
[ + - ]
328 : : }
329 : : else
330 : : {
331 [ + - ][ + - ]: 135 : cerr << _("parse error: ") << pe.what() << endl;
[ + - ]
332 : : }
333 : :
334 : : // NB: It makes sense for lexer errors to always override parser
335 : : // errors, since the original obvious scheme was for the lexer to
336 : : // throw an exception before the token reached the parser.
337 : :
338 [ + + ][ + + ]: 141 : if (pe.tok || found_junk)
339 : : {
340 [ + - ][ + - ]: 47 : cerr << _("\tat: ") << *tok << endl;
[ + - ]
341 [ + - ]: 47 : session.print_error_source (cerr, align_parse_error, tok);
342 : : }
343 [ + + ]: 94 : else if (tok) // "expected" type error
344 : : {
345 [ + - ][ + - ]: 88 : cerr << _("\tsaw: ") << *tok << endl;
[ + - ]
346 [ + - ]: 88 : session.print_error_source (cerr, align_parse_error, tok);
347 : : }
348 : : else
349 : : {
350 [ + - ][ + - ]: 6 : cerr << _("\tsaw: ") << input_name << " EOF" << endl;
[ + - ][ + - ]
351 : : }
352 : :
353 : : // print chained macro invocations
354 [ + + ][ + + ]: 144 : while (tok && tok->chain) {
[ + + ]
355 : 3 : tok = tok->chain;
356 [ + - ][ + - ]: 3 : cerr << _("\tin expansion of macro: ") << *tok << endl;
[ + - ]
357 [ + - ]: 3 : session.print_error_source (cerr, align_parse_error, tok);
358 : : }
359 : :
360 [ + - ]: 141 : num_errors ++;
361 : 141 : }
362 : :
363 : :
364 : :
365 : :
366 : : template <typename OPERAND>
367 : 82016 : bool eval_comparison (const OPERAND& lhs, const token* op, const OPERAND& rhs)
368 : : {
369 [ + - ][ - + ]: 82016 : if (op->type == tok_operator && op->content == "<=")
[ - + ][ + - ]
[ - + ][ - + ]
370 : 0 : { return lhs <= rhs; }
371 [ + - ][ - + ]: 82016 : else if (op->type == tok_operator && op->content == ">=")
[ - + ][ + - ]
[ + + ][ + + ]
372 : 79770 : { return lhs >= rhs; }
373 [ + - ][ + + ]: 2246 : else if (op->type == tok_operator && op->content == "<")
[ + + ][ + - ]
[ + + ][ + + ]
374 : 13 : { return lhs < rhs; }
375 [ + - ][ - + ]: 2233 : else if (op->type == tok_operator && op->content == ">")
[ - + ][ + - ]
[ + + ][ + + ]
376 : 24 : { return lhs > rhs; }
377 [ + - ][ + + ]: 2209 : else if (op->type == tok_operator && op->content == "==")
[ + + ][ + - ]
[ + + ][ + + ]
378 : 2193 : { return lhs == rhs; }
379 [ + - ][ + - ]: 16 : else if (op->type == tok_operator && op->content == "!=")
[ + - ][ + - ]
[ + - ][ + - ]
380 : 16 : { return lhs != rhs; }
381 : : else
382 [ # # ][ # # ]: 82016 : throw parse_error (_("expected comparison operator"), op);
[ # # ][ # # ]
383 : : }
384 : :
385 : :
386 : : // Here, we perform on-the-fly preprocessing in two passes.
387 : :
388 : : // First pass - macro declaration and expansion.
389 : : //
390 : : // The basic form of a declaration is @define SIGNATURE %( BODY %)
391 : : // where SIGNATURE is of the form macro_name (a, b, c, ...)
392 : : // and BODY can obtain the parameter contents as @a, @b, @c, ....
393 : : // Note that parameterless macros can also be declared.
394 : : //
395 : : // Macro definitions may not be nested.
396 : : // A macro is available textually after it has been defined.
397 : : //
398 : : // The basic form of a macro invocation
399 : : // for a parameterless macro is @macro_name,
400 : : // for a macro with parameters is @macro_name(param_1, param_2, ...).
401 : : //
402 : : // TODOXXX NB: this means that a parameterless macro @foo called as
403 : : // @foo(a, b, c) leaves its 'parameters' alone, rather than consuming
404 : : // them to result in a "too many parameters error".
405 : : //
406 : : // Invocations of unknown macros are left unexpanded, to allow
407 : : // the continued use of constructs such as @cast, @var, etc.
408 : :
409 : 3774360 : macrodecl::~macrodecl ()
410 : : {
411 [ + - ][ + - ]: 943590 : delete tok;
412 [ + - ][ + - ]: 8677100 : for (vector<const token*>::iterator it = body.begin();
[ + - ][ + + ]
413 [ + - ]: 4338550 : it != body.end(); it++)
414 [ + - ][ + - ]: 3394960 : delete *it;
415 [ + - ][ + - ]: 943590 : }
[ - + ]
416 : :
417 : 3830486 : parser::pp1_activation::~pp1_activation ()
418 : : {
419 [ + - ][ + - ]: 1915243 : delete tok;
420 [ + - ][ + + ]: 1915243 : if (curr_macro->is_closure()) return; // body is shared with an earlier declaration
421 [ + - ][ + + ]: 5433334 : for (map<string, pp_macrodecl*>::iterator it = params.begin();
422 [ + - ]: 2716667 : it != params.end(); it++)
423 [ + - ][ + - ]: 943590 : delete it->second;
[ + - ]
424 : 1915243 : }
425 : :
426 : : // Grab a token from the current input source (main file or macro body):
427 : : const token*
428 : 275820886 : parser::next_pp1 ()
429 : : {
430 [ + + ]: 275820886 : if (pp1_state.empty())
431 : 254414512 : return input.scan ();
432 : :
433 : : // otherwise, we're inside a macro
434 : 21406374 : pp1_activation* act = pp1_state.back();
435 : 21406374 : unsigned& cursor = act->cursor;
436 [ + + ]: 21406374 : if (cursor < act->curr_macro->body.size())
437 : : {
438 [ + - ]: 19491134 : token* t = new token(*act->curr_macro->body[cursor]);
439 : 19491134 : t->chain = act->tok; // mark chained token
440 : 19491134 : cursor++;
441 : 19491134 : return t;
442 : : }
443 : : else
444 : 275820886 : return 0; // reached end of macro body
445 : : }
446 : :
447 : : const token*
448 : 269748149 : parser::scan_pp1 ()
449 : : {
450 : 269748140 : while (true)
451 : : {
452 : 269748149 : const token* t = next_pp1 ();
453 [ + + ]: 269748149 : if (t == 0) // EOF or end of macro body
454 : : {
455 [ + + ]: 2111502 : if (pp1_state.empty()) // actual EOF
456 : 196263 : return 0;
457 : :
458 : : // Exit macro and loop around to look for the next token.
459 : 1915239 : pp1_activation* act = pp1_state.back();
460 [ + - ]: 1915239 : pp1_state.pop_back(); delete act;
461 : 1915239 : continue;
462 : : }
463 : :
464 : : // macro definition
465 [ + + ][ + + ]: 267636647 : if (t->type == tok_operator && t->content == "@define")
[ + + ]
466 : : {
467 [ + - ][ - + ]: 12955 : if (!pp1_state.empty())
468 [ # # ][ # # ]: 0 : throw parse_error (_("'@define' forbidden inside macro body"), t);
469 [ + - ][ + - ]: 12955 : delete t;
470 : :
471 : : // handle macro definition
472 : : // (1) consume macro signature
473 [ + - ]: 12955 : t = input.scan();
474 [ + + ][ - + ]: 12955 : if (! (t && t->type == tok_identifier))
475 [ + - ][ + - ]: 1 : throw parse_error (_("expected identifier"), t);
476 [ + - ]: 12954 : string name = t->content;
477 : :
478 : : // check for redefinition of existing macro
479 [ + - ][ + - ]: 12954 : if (pp1_namespace.find(name) != pp1_namespace.end())
[ - + ]
480 : : // TODOXXX use a slightly different chaining hack to also point to
481 : : // pp1_namespace[name]->tok, the site of the original definition?
482 [ # # ][ # # ]: 0 : throw parse_error (_F("attempt to redefine macro '@%s' in the same file", name.c_str ()), t);
[ # # ]
483 : : // TODOXXX this is only really necessary if we want to leave open the possibility of statically-scoped semantics in the future...?
484 : :
485 : : // XXX this cascades into further parse errors as the
486 : : // parser tries to parse the remaining definition...
487 [ + - ][ + + ]: 12954 : if (name == "define")
488 [ + - ][ + - ]: 1 : throw parse_error (_("attempt to redefine '@define'"), t);
489 [ + - ][ + - ]: 12953 : if (input.atwords.count("@" + name))
[ + - ][ + + ]
490 [ + - ][ + - ]: 2 : session.print_warning (_F("macro redefines built-in operator '@%s'", name.c_str()), t);
[ + - ][ + - ]
491 : :
492 [ + - ][ + - ]: 12953 : macrodecl* decl = (pp1_namespace[name] = new macrodecl);
[ + - ]
493 : 12953 : decl->tok = t;
494 : :
495 : : // determine if the macro takes parameters
496 : 12953 : bool saw_params = false;
497 [ + - ]: 12953 : t = input.scan();
498 [ + + ][ + - ]: 12953 : if (t && t->type == tok_operator && t->content == "(")
[ + - ][ + + ]
[ + + ]
499 : : {
500 : 6479 : saw_params = true;
501 : 2154 : do
502 : : {
503 [ + - ][ + - ]: 8633 : delete t;
504 : :
505 [ + - ]: 8633 : t = input.scan ();
506 [ + - ][ - + ]: 8633 : if (! (t && t->type == tok_identifier))
507 [ # # ][ # # ]: 0 : throw parse_error(_("expected identifier"), t);
508 [ + - ]: 8633 : decl->formal_args.push_back(t->content);
509 [ + - ][ + - ]: 8633 : delete t;
510 : :
511 [ + - ]: 8633 : t = input.scan ();
512 [ + - ][ + - ]: 8633 : if (t && t->type == tok_operator && t->content == ",")
[ + - ][ + + ]
[ + + ]
513 : : {
514 : 2154 : continue;
515 : : }
516 [ + - ][ + - ]: 6479 : else if (t && t->type == tok_operator && t->content == ")")
[ + - ][ + - ]
[ + - ]
517 : : {
518 [ + - ][ + - ]: 6479 : delete t;
519 [ + - ]: 6479 : t = input.scan();
520 : 6479 : break;
521 : : }
522 : : else
523 : : {
524 [ # # ][ # # ]: 6479 : throw parse_error (_("expected ',' or ')'"), t);
525 : : }
526 : : }
527 : : while (true);
528 : : }
529 : :
530 : : // (2) identify & consume macro body
531 [ + + ][ + - ]: 12953 : if (! (t && t->type == tok_operator && t->content == "%("))
[ + - ][ - + ]
[ + + ]
532 : : {
533 [ - + ]: 1 : if (saw_params)
534 [ # # ][ # # ]: 0 : throw parse_error (_("expected '%('"), t);
535 : : else
536 [ + - ][ + - ]: 1 : throw parse_error (_("expected '%(' or '('"), t);
537 : : }
538 [ + - ][ + - ]: 12952 : delete t;
539 : :
540 [ + - ]: 12952 : t = slurp_pp1_body (decl->body);
541 [ + + ]: 12952 : if (!t)
542 [ + - ][ + - ]: 2 : throw parse_error (_("incomplete macro definition - missing '%)'"), decl->tok);
543 [ + - ][ + - ]: 12950 : delete t;
544 : :
545 : : // Now loop around to look for a real token.
546 [ + - ]: 12955 : continue;
547 : : }
548 : :
549 : : // (potential) macro invocation
550 [ + + ][ + + ]: 267623692 : if (t->type == tok_operator && t->content[0] == '@')
[ + + ]
551 : : {
552 [ + - ]: 3601015 : string name = t->content.substr(1); // strip initial '@'
553 : :
554 : : // check if name refers to a real parameter or macro
555 : : macrodecl* decl;
556 [ + - ][ + + ]: 3601015 : pp1_activation* act = pp1_state.empty() ? 0 : pp1_state.back();
[ + - ]
557 [ + + ][ + - ]: 3601015 : if (act && act->params.find(name) != act->params.end())
[ + - ][ + + ]
[ + + ][ + + ]
[ + + # #
# # ]
558 [ + - ]: 1389578 : decl = act->params[name];
559 [ + + ]: 6188377 : else if (!(act && act->curr_macro->context == ctx_library)
[ + + + + ]
[ + + ]
560 [ + - ][ + - ]: 3976940 : && pp1_namespace.find(name) != pp1_namespace.end())
[ + + ][ + + ]
[ # # # # ]
561 [ + - ]: 66807 : decl = pp1_namespace[name];
562 [ + + ]: 2144630 : else if (session.library_macros.find(name)
563 [ + - ][ + - ]: 2144630 : != session.library_macros.end())
564 [ + - ]: 458858 : decl = session.library_macros[name];
565 : : else // this is an ordinary @operator
566 : 1685772 : return t;
567 : :
568 : : // handle macro invocation
569 [ + - ][ + - ]: 1915243 : pp1_activation *new_act = new pp1_activation(*t, decl);
[ + - ][ + - ]
570 : 1915243 : unsigned num_params = decl->formal_args.size();
571 : :
572 : : // (1a) restore parameter invocation closure
573 [ + + ][ + - ]: 1915243 : if (num_params == 0 && decl->is_closure())
[ + + ][ + + ]
574 : : {
575 : : // NB: decl->parent_act is always safe since the
576 : : // parameter decl (if any) comes from an activation
577 : : // record which deeper in the stack than new_act.
578 : :
579 : : // decl is a macro parameter which must be evaluated in
580 : : // the context of the original point of invocation:
581 [ + - ]: 142166 : new_act->params = ((pp_macrodecl*)decl)->parent_act->params;
582 : 142166 : goto expand;
583 : : }
584 : :
585 : : // (1b) consume macro parameters (if any)
586 [ + + ]: 1773077 : if (num_params == 0)
587 : 1275420 : goto expand;
588 : :
589 : : // for simplicity, we do not allow macro constructs here
590 : : // -- if we did, we'd have to recursively call scan_pp1()
591 [ + - ]: 497657 : t = next_pp1 ();
592 [ + - ][ + - ]: 497657 : if (! (t && t->type == tok_operator && t->content == "("))
[ + - ][ + + ]
[ + + ]
593 : : {
594 [ + - ][ + - ]: 1 : delete new_act;
595 : 1 : throw parse_error (_F(ngettext
596 : : ("expected '(' in invocation of macro '@%s'"
597 : : " taking %d parameter",
598 : : "expected '(' in invocation of macro '@%s'"
599 : : " taking %d parameters",
600 [ + - ][ + - ]: 2 : num_params), name.c_str(), num_params), t);
[ + - ]
601 : : }
602 : :
603 : : // XXX perhaps parse/count the full number of params,
604 : : // so we can say "expected x, found y params" on error?
605 [ + + ]: 1441243 : for (unsigned i = 0; i < num_params; i++)
606 : : {
607 [ + - ][ + - ]: 943590 : delete t;
608 : :
609 : : // create parameter closure
610 [ + - ]: 943590 : string param_name = decl->formal_args[i];
611 [ + - ]: 943590 : pp_macrodecl* p = (new_act->params[param_name]
612 [ + - ][ + - ]: 943590 : = new pp_macrodecl);
613 [ + - ][ + - ]: 943590 : p->tok = new token(*new_act->tok);
614 : 943590 : p->parent_act = act;
615 : : // NB: *new_act->tok points to invocation, act is NULL at top level
616 : :
617 [ + - ]: 943590 : t = slurp_pp1_param (p->body);
618 : :
619 : : // check correct usage of ',' or ')'
620 [ + + ]: 943590 : if (t == 0) // hit unexpected EOF or end of macro
621 : : {
622 : : // XXX could we pop the stack and continue parsing
623 : : // the invocation, allowing macros to construct new
624 : : // invocations in piecemeal fashion??
625 [ + - ][ + - ]: 2 : const token* orig_t = new token(*new_act->tok);
626 [ + - ][ + - ]: 2 : delete new_act;
627 [ + - ][ + - ]: 2 : throw parse_error (_("could not find end of macro invocation"), orig_t);
628 : : }
629 [ + - ][ + - ]: 943588 : if (t->type == tok_operator && t->content == ",")
[ + + ][ + + ]
630 : : {
631 [ + + ]: 445935 : if (i + 1 == num_params)
632 : : {
633 [ + - ][ + - ]: 1 : delete new_act;
634 [ + - ][ + - ]: 1 : throw parse_error (_F("too many parameters for macro '@%s' (expected %d)", name.c_str(), num_params), t);
[ + - ]
635 : : }
636 : : }
637 [ + - ][ + - ]: 497653 : else if (t->type == tok_operator && t->content == ")")
[ + - ][ + - ]
638 : : {
639 [ - + ]: 497653 : if (i + 1 != num_params)
640 : : {
641 [ # # ][ # # ]: 0 : delete new_act;
642 [ # # ][ # # ]: 0 : throw parse_error (_F("too few parameters for macro '@%s' (expected %d)", name.c_str(), num_params), t);
[ # # ]
643 : : }
644 : : }
645 : : else
646 : : {
647 : : // XXX this is, incidentally, impossible
648 [ # # ][ # # ]: 0 : delete new_act;
649 [ # # ][ # # ]: 0 : throw parse_error(_("expected ',' or ')' after macro parameter"), t);
650 : : }
651 [ + - ]: 943590 : }
652 : :
653 [ + - ][ + - ]: 497653 : delete t;
654 : :
655 : : // (2) set up macro expansion
656 : : expand:
657 [ + - ]: 1915239 : pp1_state.push_back (new_act);
658 : :
659 : : // Now loop around to look for a real token.
660 [ + - ][ + + ]: 3601015 : continue;
661 : : }
662 : :
663 : : // Otherwise, we have an ordinary token.
664 : 264022677 : return t;
665 : : }
666 : : }
667 : :
668 : : // Consume a single macro invocation's parameters, heeding nested ( )
669 : : // brackets and stopping on an unbalanced ')' or an unbracketed ','
670 : : // (and returning the final separator token).
671 : : const token*
672 : 943590 : parser::slurp_pp1_param (vector<const token*>& param)
673 : : {
674 : 943590 : const token* t = 0;
675 : 943590 : unsigned nesting = 0;
676 : 3394960 : do
677 : : {
678 [ + - ]: 4338550 : t = next_pp1 ();
679 : :
680 [ + + ]: 4338550 : if (!t)
681 : 2 : break;
682 [ + + ][ + - ]: 4338548 : if (t->type == tok_operator && t->content == "(")
[ + + ][ + + ]
683 : 217555 : ++nesting;
684 [ + + ][ + + ]: 4120993 : else if (nesting && t->type == tok_operator && t->content == ")")
[ + - ][ + + ]
[ + + ]
685 : 217555 : --nesting;
686 [ + + ][ + + ]: 6503633 : else if (!nesting && t->type == tok_operator
[ + + ][ + + ]
[ + + ]
687 [ + - ][ + - ]: 2600195 : && (t->content == ")" || t->content == ","))
688 : 943588 : break;
689 [ + - ]: 3394960 : param.push_back(t);
690 : : }
691 : : while (true);
692 : 943590 : return t; // report ")" or "," or NULL
693 : : }
694 : :
695 : :
696 : : // Consume a macro declaration's body, heeding nested %( %) brackets.
697 : : const token*
698 : 12952 : parser::slurp_pp1_body (vector<const token*>& body)
699 : : {
700 : 12952 : const token* t = 0;
701 : 12952 : unsigned nesting = 0;
702 : 1223578 : do
703 : : {
704 [ + - ]: 1236530 : t = next_pp1 ();
705 : :
706 [ + + ]: 1236530 : if (!t)
707 : 2 : break;
708 [ + + ][ + - ]: 1236528 : if (t->type == tok_operator && t->content == "%(")
[ + + ][ + + ]
709 : 2 : ++nesting;
710 [ + + ][ + + ]: 1236526 : else if (nesting && t->type == tok_operator && t->content == "%)")
[ + - ][ + + ]
[ + + ]
711 : 2 : --nesting;
712 [ + + ][ + + ]: 1236524 : else if (!nesting && t->type == tok_operator && t->content == "%)")
[ + - ][ + + ]
[ + + ]
713 : 12950 : break;
714 [ + - ]: 1223578 : body.push_back(t);
715 : : }
716 : : while (true);
717 : 12952 : return t; // report final "%)" or NULL
718 : : }
719 : :
720 : : // Used for parsing .stpm files.
721 : : stapfile*
722 : 4308 : parser::parse_library_macros ()
723 : : {
724 [ + - ]: 4308 : stapfile* f = new stapfile;
725 : 4308 : input.set_current_file (f);
726 : :
727 : : try
728 : : {
729 [ + - ]: 4308 : const token* t = scan_pp1 ();
730 : :
731 : : // Currently we only take objection to macro invocations if they
732 : : // produce a non-whitespace token after being expanded.
733 : :
734 : : // XXX should we prevent macro invocations even if they expand to empty??
735 : :
736 [ - + ]: 4308 : if (t != 0)
737 [ # # ][ # # ]: 0 : throw parse_error (_F("library macro file '%s' contains non-@define construct", input_name.c_str()), t);
[ # # ]
738 : :
739 : : // We need to first check whether *any* of the macros are duplicates,
740 : : // then commit to including the entire file in the global namespace
741 : : // (or not). Yuck.
742 [ + - ][ + + ]: 17232 : for (map<string, macrodecl*>::iterator it = pp1_namespace.begin();
743 [ + - ]: 8616 : it != pp1_namespace.end(); it++)
744 : : {
745 [ + - ][ + - ]: 4308 : string name = it->first;
746 : :
747 [ + - ][ + - ]: 4308 : if (session.library_macros.find(name) != session.library_macros.end())
[ - + ]
748 : : {
749 : : // XXX ugly hack simulates chaining
750 [ # # ][ # # ]: 0 : parse_error* er1 = new parse_error (_F("duplicate definition of library macro '%s'", name.c_str()), it->second->tok);
[ # # ][ # # ]
[ # # ][ # # ]
751 [ # # ][ # # ]: 0 : parse_error* er2 = new parse_error (_("location of original definition was"), session.library_macros[name]->tok);
[ # # ][ # # ]
[ # # ]
752 [ # # ]: 0 : print_error (*er1);
753 [ # # ]: 0 : print_error (*er2);
754 [ # # ][ # # ]: 0 : delete er1; delete er2;
755 : :
756 [ # # ][ # # ]: 0 : delete f;
757 : 4308 : return 0;
758 : : }
759 [ + - ][ + - ]: 4308 : }
760 : :
761 : : }
762 [ # # ]: : catch (const parse_error& pe)
763 : : {
764 [ # # ]: : print_error (pe);
765 [ # # # # ]: : delete f;
766 : : return 0;
767 : : }
768 : :
769 : : // If no errors, include the entire file. Note how this is outside
770 : : // of the try-catch block -- no errors possible.
771 [ + - ][ + + ]: 17232 : for (map<string, macrodecl*>::iterator it = pp1_namespace.begin();
772 [ + - ]: 8616 : it != pp1_namespace.end(); it++)
773 : : {
774 [ + - ][ + - ]: 4308 : string name = it->first;
775 : :
776 [ + - ][ + - ]: 4308 : session.library_macros[name] = it->second;
777 [ + - ]: 4308 : session.library_macros[name]->context = ctx_library;
778 : : // TODOXXX be sure declaration is retained and not deleted
779 [ + - ]: 4308 : }
780 : :
781 : 4308 : return f;
782 : : }
783 : :
784 : : // Second pass - preprocessor conditional expansion.
785 : : //
786 : : // The basic form is %( CONDITION %? THEN-TOKENS %: ELSE-TOKENS %)
787 : : // where CONDITION is: kernel_v[r] COMPARISON-OP "version-string"
788 : : // or: arch COMPARISON-OP "arch-string"
789 : : // or: systemtap_v COMPARISON-OP "version-string"
790 : : // or: systemtap_privilege COMPARISON-OP "privilege-string"
791 : : // or: CONFIG_foo COMPARISON-OP "config-string"
792 : : // or: CONFIG_foo COMPARISON-OP number
793 : : // or: CONFIG_foo COMPARISON-OP CONFIG_bar
794 : : // or: "string1" COMPARISON-OP "string2"
795 : : // or: number1 COMPARISON-OP number2
796 : : // The %: ELSE-TOKENS part is optional.
797 : : //
798 : : // e.g. %( kernel_v > "2.5" %? "foo" %: "baz" %)
799 : : // e.g. %( arch != "i?86" %? "foo" %: "baz" %)
800 : : // e.g. %( CONFIG_foo %? "foo" %: "baz" %)
801 : : //
802 : : // Up to an entire %( ... %) expression is processed by a single call
803 : : // to this function. Tokens included by any nested conditions are
804 : : // enqueued in a private vector.
805 : :
806 : 295568 : bool eval_pp_conditional (systemtap_session& s,
807 : : const token* l, const token* op, const token* r)
808 : : {
809 [ + + ][ + + : 634094 : if (l->type == tok_identifier && (l->content == "kernel_v" ||
+ + + + ]
[ + + ]
810 : 170349 : l->content == "kernel_vr" ||
811 : 168177 : l->content == "systemtap_v"))
812 : : {
813 [ + + ]: 153107 : if (! (r->type == tok_string))
814 [ + - ][ + - ]: 1 : throw parse_error (_("expected string literal"), r);
815 : :
816 [ + - ]: 153106 : string target_kernel_vr = s.kernel_release;
817 [ + - ]: 153106 : string target_kernel_v = s.kernel_base_release;
818 [ + - ]: 153106 : string target;
819 : :
820 [ + - ][ + + ]: 153106 : if (l->content == "kernel_v") target = target_kernel_v;
[ + - ]
821 [ + - ][ + + ]: 103428 : else if (l->content == "kernel_vr") target = target_kernel_vr;
[ + - ]
822 [ + - ][ + - ]: 101256 : else if (l->content == "systemtap_v") target = s.compatible;
[ + - ]
823 : 0 : else assert (0);
824 : :
825 [ + - ]: 153106 : string query = r->content;
826 [ + - ]: 153106 : bool rhs_wildcard = (strpbrk (query.c_str(), "*?[") != 0);
827 : :
828 : : // collect acceptable strverscmp results.
829 : : int rvc_ok1, rvc_ok2;
830 : 153106 : bool wc_ok = false;
831 [ + - ][ + - ]: 153106 : if (op->type == tok_operator && op->content == "<=")
[ + + ][ + + ]
832 : 96950 : { rvc_ok1 = -1; rvc_ok2 = 0; }
833 [ + - ][ + - ]: 56156 : else if (op->type == tok_operator && op->content == ">=")
[ + + ][ + + ]
834 : 36640 : { rvc_ok1 = 1; rvc_ok2 = 0; }
835 [ + - ][ + - ]: 19516 : else if (op->type == tok_operator && op->content == "<")
[ + + ][ + + ]
836 : 15146 : { rvc_ok1 = -1; rvc_ok2 = -1; }
837 [ + - ][ + - ]: 4370 : else if (op->type == tok_operator && op->content == ">")
[ + + ][ + + ]
838 : 2195 : { rvc_ok1 = 1; rvc_ok2 = 1; }
839 [ + - ][ + - ]: 2175 : else if (op->type == tok_operator && op->content == "==")
[ + + ][ + + ]
840 : 2164 : { rvc_ok1 = 0; rvc_ok2 = 0; wc_ok = true; }
841 [ + - ][ + - ]: 11 : else if (op->type == tok_operator && op->content == "!=")
[ + + ][ + + ]
842 : 10 : { rvc_ok1 = -1; rvc_ok2 = 1; wc_ok = true; }
843 : : else
844 [ + - ][ + - ]: 1 : throw parse_error (_("expected comparison operator"), op);
845 : :
846 [ + + ][ - + ]: 153105 : if ((!wc_ok) && rhs_wildcard)
847 [ # # ][ # # ]: 0 : throw parse_error (_("wildcard not allowed with order comparison operators"), op);
848 : :
849 [ + + ]: 153105 : if (rhs_wildcard)
850 : : {
851 : : int rvc_result = fnmatch (query.c_str(), target.c_str(),
852 [ + - ][ + - ]: 8 : FNM_NOESCAPE); // spooky
[ + - ]
853 [ + - ]: 8 : bool badness = (rvc_result == 0) ^ (op->content == "==");
854 : 8 : return !badness;
855 : : }
856 : : else
857 : : {
858 [ + - ][ + - ]: 153097 : int rvc_result = strverscmp (target.c_str(), query.c_str());
859 : : // normalize rvc_result
860 [ + + ]: 153097 : if (rvc_result < 0) rvc_result = -1;
861 [ + + ]: 153097 : if (rvc_result > 0) rvc_result = 1;
862 [ + + ][ + + ]: 153097 : return (rvc_result == rvc_ok1 || rvc_result == rvc_ok2);
863 [ + - ][ + - ]: 153107 : }
[ + - ][ + - ]
864 : : }
865 [ + + ][ + + ]: 142461 : else if (l->type == tok_identifier && l->content == "systemtap_privilege")
[ + + ]
866 : : {
867 : : string target_privilege =
868 : : /* XXX perhaps include a "guru" state */
869 [ + - ]: 2145 : pr_contains(s.privilege, pr_stapdev) ? "stapdev"
870 [ + - ]: 151 : : pr_contains(s.privilege, pr_stapsys) ? "stapsys"
871 [ + - ]: 93 : : pr_contains(s.privilege, pr_stapusr) ? "stapusr"
872 [ + + ][ + + ]: 2389 : : "none"; /* should be impossible -- s.privilege always one of above */
[ + - ][ + - ]
873 [ + - ][ - + ]: 2145 : assert(target_privilege != "none");
874 : :
875 [ - + ]: 2145 : if (! (r->type == tok_string))
876 [ # # ][ # # ]: 0 : throw parse_error (_("expected string literal"), r);
877 [ + - ]: 2145 : string query_privilege = r->content;
878 : :
879 [ + - ]: 2145 : bool nomatch = (target_privilege != query_privilege);
880 : :
881 : : bool result;
882 [ + - ][ + - ]: 2145 : if (op->type == tok_operator && op->content == "==")
[ + + ][ + + ]
883 : 1 : result = !nomatch;
884 [ + - ][ + - ]: 2144 : else if (op->type == tok_operator && op->content == "!=")
[ + - ][ + - ]
885 : 2144 : result = nomatch;
886 : : else
887 [ # # ][ # # ]: 0 : throw parse_error (_("expected '==' or '!='"), op);
888 : : /* XXX perhaps allow <= >= and similar comparisons */
889 : :
890 [ + - ][ + - ]: 2145 : return result;
891 : : }
892 [ + + ][ + + ]: 140316 : else if (l->type == tok_identifier && l->content == "arch")
[ + + ]
893 : : {
894 [ + - ]: 34507 : string target_architecture = s.architecture;
895 [ + + ]: 34507 : if (! (r->type == tok_string))
896 [ + - ][ + - ]: 1 : throw parse_error (_("expected string literal"), r);
897 [ + - ]: 34506 : string query_architecture = r->content;
898 : :
899 : : int nomatch = fnmatch (query_architecture.c_str(),
900 : : target_architecture.c_str(),
901 [ + - ][ + - ]: 34506 : FNM_NOESCAPE); // still spooky
[ + - ]
902 : :
903 : : bool result;
904 [ + - ][ + - ]: 34506 : if (op->type == tok_operator && op->content == "==")
[ + + ][ + + ]
905 : 8650 : result = !nomatch;
906 [ + - ][ + - ]: 25856 : else if (op->type == tok_operator && op->content == "!=")
[ + + ][ + + ]
907 : 25855 : result = nomatch;
908 : : else
909 [ + - ][ + - ]: 1 : throw parse_error (_("expected '==' or '!='"), op);
910 : :
911 [ + - ][ + - ]: 34507 : return result;
912 : : }
913 [ + + ][ + + ]: 105809 : else if (l->type == tok_identifier && startswith(l->content, "CONFIG_"))
[ + + ]
914 : : {
915 [ + + ]: 30267 : if (r->type == tok_string)
916 : : {
917 [ + - ][ + - ]: 23787 : string lhs = s.kernel_config[l->content]; // may be empty
918 [ + - ]: 23787 : string rhs = r->content;
919 : :
920 [ + - ][ + - ]: 23787 : int nomatch = fnmatch (rhs.c_str(), lhs.c_str(), FNM_NOESCAPE); // still spooky
[ + - ]
921 : :
922 : : bool result;
923 [ + - ][ + - ]: 23787 : if (op->type == tok_operator && op->content == "==")
[ + + ][ + + ]
924 : 23779 : result = !nomatch;
925 [ + - ][ + - ]: 8 : else if (op->type == tok_operator && op->content == "!=")
[ + - ][ + - ]
926 : 8 : result = nomatch;
927 : : else
928 [ # # ][ # # ]: 0 : throw parse_error (_("expected '==' or '!='"), op);
929 : :
930 [ + - ][ + - ]: 23787 : return result;
931 : : }
932 [ + + ]: 6480 : else if (r->type == tok_number)
933 : : {
934 [ + - ][ + - ]: 8 : const char* startp = s.kernel_config[l->content].c_str ();
935 : 8 : char* endp = (char*) startp;
936 : 8 : errno = 0;
937 : 8 : int64_t lhs = (int64_t) strtoll (startp, & endp, 0);
938 [ + - ][ + - ]: 8 : if (errno == ERANGE || errno == EINVAL || *endp != '\0')
[ - + ]
939 [ # # ][ # # ]: 0 : throw parse_error ("Config option value not a number", l);
940 : :
941 [ + - ]: 8 : int64_t rhs = lex_cast<int64_t>(r->content);
942 [ + - ]: 8 : return eval_comparison (lhs, op, rhs);
943 : : }
944 [ + - + - ]: 12944 : else if (r->type == tok_identifier
[ + - ]
945 : 6472 : && startswith(r->content, "CONFIG_"))
946 : : {
947 : : // First try to convert both to numbers,
948 : : // otherwise threat both as strings.
949 [ + - ][ + - ]: 6472 : const char* startp = s.kernel_config[l->content].c_str ();
950 : 6472 : char* endp = (char*) startp;
951 : 6472 : errno = 0;
952 : 6472 : int64_t val = (int64_t) strtoll (startp, & endp, 0);
953 [ + - ][ + - ]: 6472 : if (errno != ERANGE && errno != EINVAL && *endp == '\0')
[ + + ]
954 : : {
955 : 6470 : int64_t lhs = val;
956 [ + - ][ + - ]: 6470 : startp = s.kernel_config[r->content].c_str ();
957 : 6470 : endp = (char*) startp;
958 : 6470 : errno = 0;
959 : 6470 : int64_t rhs = (int64_t) strtoll (startp, & endp, 0);
960 [ + - ][ + - ]: 6470 : if (errno != ERANGE && errno != EINVAL && *endp == '\0')
[ + + ]
961 [ + - ]: 6470 : return eval_comparison (lhs, op, rhs);
962 : : }
963 : :
964 [ + - ][ + - ]: 4 : string lhs = s.kernel_config[l->content];
965 [ + - ][ + - ]: 4 : string rhs = s.kernel_config[r->content];
966 [ + - ][ + - ]: 6472 : return eval_comparison (lhs, op, rhs);
[ + - ]
967 : : }
968 : : else
969 [ # # ][ # # ]: 0 : throw parse_error (_("expected string, number literal or other CONFIG_... as right side operand"), r);
970 : : }
971 [ + + ][ + + ]: 75542 : else if (l->type == tok_string && r->type == tok_string)
972 : : {
973 [ + - ]: 8 : string lhs = l->content;
974 [ + - ]: 8 : string rhs = r->content;
975 [ + - ][ + - ]: 8 : return eval_comparison (lhs, op, rhs);
[ + - ]
976 : : // NB: no wildcarding option here
977 : : }
978 [ + + ][ + + ]: 75534 : else if (l->type == tok_number && r->type == tok_number)
979 : : {
980 [ + - ]: 75528 : int64_t lhs = lex_cast<int64_t>(l->content);
981 [ + - ]: 75528 : int64_t rhs = lex_cast<int64_t>(r->content);
982 [ + - ]: 75528 : return eval_comparison (lhs, op, rhs);
983 : : // NB: no wildcarding option here
984 : : }
985 [ + + ][ + - ]: 6 : else if (l->type == tok_string && r->type == tok_number
[ + - ]
986 : : && op->type == tok_operator)
987 [ + - ][ + - ]: 1 : throw parse_error (_("expected string literal as right value"), r);
988 [ + + ][ + - ]: 5 : else if (l->type == tok_number && r->type == tok_string
[ + - ]
989 : : && op->type == tok_operator)
990 [ + - ][ + - ]: 1 : throw parse_error (_("expected number literal as right value"), r);
991 : :
992 : : else
993 : 4 : throw parse_error (_("expected 'arch' or 'kernel_v' or 'kernel_vr' or 'CONFIG_...'\n"
994 [ + - ][ + - ]: 295562 : " or comparison between strings or integers"), l);
995 : : }
996 : :
997 : :
998 : : // Only tokens corresponding to the TRUE statement must be expanded
999 : : const token*
1000 : 260812752 : parser::scan_pp ()
1001 : : {
1002 : 260812710 : while (true)
1003 : : {
1004 : 260812752 : pp_state_t pp = PP_NONE;
1005 [ + + ]: 260812752 : if (!pp_state.empty())
1006 : 2094058 : pp = pp_state.back().second;
1007 : :
1008 : 260812752 : const token* t = 0;
1009 [ + + ][ + + ]: 260812752 : if (pp == PP_SKIP_THEN || pp == PP_SKIP_ELSE)
1010 : 221870 : t = skip_pp ();
1011 : : else
1012 : 260590882 : t = scan_pp1 ();
1013 : :
1014 [ + + ]: 260812743 : if (t == 0) // EOF
1015 : : {
1016 [ + + ]: 191954 : if (pp != PP_NONE)
1017 : : {
1018 : 3 : t = pp_state.back().first;
1019 : 3 : pp_state.pop_back(); // so skip_some doesn't keep trying to close this
1020 : : //TRANSLATORS: 'conditional' meaning 'conditional preprocessing'
1021 [ + - ][ + - ]: 3 : throw parse_error (_("incomplete conditional at end of file"), t);
1022 : : }
1023 : 191951 : return t;
1024 : : }
1025 : :
1026 : : // misplaced preprocessor "then"
1027 [ + + ][ + + ]: 260620789 : if (t->type == tok_operator && t->content == "%?")
[ + + ]
1028 [ + - ][ + - ]: 9 : throw parse_error (_("incomplete conditional - missing '%('"), t);
1029 : :
1030 : : // preprocessor "else"
1031 [ + + ][ + + ]: 260620780 : if (t->type == tok_operator && t->content == "%:")
[ + + ]
1032 : : {
1033 [ - + ]: 64814 : if (pp == PP_NONE)
1034 [ # # ][ # # ]: 0 : throw parse_error (_("incomplete conditional - missing '%('"), t);
1035 [ + - ][ - + ]: 64814 : if (pp == PP_KEEP_ELSE || pp == PP_SKIP_ELSE)
1036 [ # # ][ # # ]: 0 : throw parse_error (_("invalid conditional - duplicate '%:'"), t);
1037 : : // XXX: here and elsewhere, error cascades might be avoided
1038 : : // by dropping tokens until we reach the closing %)
1039 : :
1040 : 64814 : pp_state.back().second = (pp == PP_KEEP_THEN) ?
1041 [ + + ]: 64814 : PP_SKIP_ELSE : PP_KEEP_ELSE;
1042 [ + - ]: 64814 : delete t;
1043 : 64814 : continue;
1044 : : }
1045 : :
1046 : : // preprocessor close
1047 [ + + ][ + + ]: 260555966 : if (t->type == tok_operator && t->content == "%)")
[ + + ]
1048 : : {
1049 [ + + ]: 280436 : if (pp == PP_NONE)
1050 [ + - ][ + - ]: 9 : throw parse_error (_("incomplete conditional - missing '%('"), t);
1051 [ + - ]: 280427 : delete pp_state.back().first;
1052 [ + - ]: 280427 : delete t; //this is the closing bracket
1053 : 280427 : pp_state.pop_back();
1054 : 280427 : continue;
1055 : : }
1056 : :
1057 [ + + ][ + + ]: 260275530 : if (! (t->type == tok_operator && t->content == "%(")) // ordinary token
[ + + ]
1058 : 259995088 : return t;
1059 : :
1060 : : // We have a %( - it's time to throw a preprocessing party!
1061 : :
1062 : 280442 : bool result = false;
1063 : 280442 : bool and_result = true;
1064 : 280442 : const token *n = NULL;
1065 : 15127 : do {
1066 : : const token *l, *op, *r;
1067 : 295569 : l = scan_pp1 ();
1068 : 295569 : op = scan_pp1 ();
1069 : 295569 : r = scan_pp1 ();
1070 [ + - ][ + - ]: 295569 : if (l == 0 || op == 0 || r == 0)
[ + + ]
1071 [ + - ][ + - ]: 1 : throw parse_error (_("incomplete condition after '%('"), t);
1072 : : // NB: consider generalizing to consume all tokens until %?, and
1073 : : // passing that as a vector to an evaluator.
1074 : :
1075 : : // Do not evaluate the condition if we haven't expanded everything.
1076 : : // This may occur when having several recursive conditionals.
1077 : 295568 : and_result &= eval_pp_conditional (session, l, op, r);
1078 [ + + ]: 295558 : if(l->content=="systemtap_v")
1079 : 101256 : systemtap_v_seen=r;
1080 : :
1081 : : else
1082 [ + - ]: 194302 : delete r;
1083 : :
1084 [ + - ]: 295558 : delete l;
1085 [ + - ]: 295558 : delete op;
1086 [ + + ]: 295558 : delete n;
1087 : :
1088 : 295558 : n = scan_pp1 ();
1089 [ + - ][ + - ]: 295558 : if (n && n->type == tok_operator && n->content == "&&")
[ + + ][ + + ]
1090 : 12957 : continue;
1091 : 282601 : result |= and_result;
1092 : 282601 : and_result = true;
1093 [ + - ][ + - ]: 282601 : if (! (n && n->type == tok_operator && n->content == "||"))
[ + + ][ + + ]
1094 : 280431 : break;
1095 : : } while (true);
1096 : :
1097 : : /*
1098 : : clog << "PP eval (" << *t << ") == " << result << endl;
1099 : : */
1100 : :
1101 : 280431 : const token *m = n;
1102 [ + - ][ + - ]: 280431 : if (! (m && m->type == tok_operator && m->content == "%?"))
[ + + ][ + + ]
1103 [ + - ][ + - ]: 1 : throw parse_error (_("expected '%?' marker for conditional"), t);
1104 [ + - ]: 280430 : delete m; // "%?"
1105 : :
1106 [ + + ]: 280430 : pp = result ? PP_KEEP_THEN : PP_SKIP_THEN;
1107 [ + - ]: 280430 : pp_state.push_back (make_pair (t, pp));
1108 : :
1109 : : // Now loop around to look for a real token.
1110 : : }
1111 : : }
1112 : :
1113 : :
1114 : : // Skip over tokens and any errors, heeding
1115 : : // only nested preprocessor starts and ends.
1116 : : const token*
1117 : 221870 : parser::skip_pp ()
1118 : : {
1119 : 221870 : const token* t = 0;
1120 : 221870 : unsigned nesting = 0;
1121 : 3905396 : do
1122 : : {
1123 : : try
1124 : : {
1125 [ + - ]: 4127266 : t = scan_pp1 ();
1126 : : }
1127 : : catch (const parse_error &e)
1128 : : {
1129 : : continue;
1130 : : }
1131 [ - + ]: 4127266 : if (!t)
1132 : 0 : break;
1133 [ + + ][ + + ]: 4127266 : if (t->type == tok_operator && t->content == "%(")
[ + + ]
1134 : 4523 : ++nesting;
1135 [ + + ][ + + ]: 4122743 : else if (nesting && t->type == tok_operator && t->content == "%)")
[ + + ][ + + ]
1136 : 4523 : --nesting;
1137 [ + + ][ + + : 10548888 : else if (!nesting && t->type == tok_operator &&
+ + + + +
+ ][ + + ]
1138 : 6430668 : (t->content == "%:" || t->content == "%?" || t->content == "%)"))
1139 : 221870 : break;
1140 [ + - ]: 3905396 : delete t;
1141 : : }
1142 : : while (true);
1143 [ # # ]: 221870 : return t;
1144 : : }
1145 : :
1146 : :
1147 : : const token*
1148 : 190421513 : parser::next ()
1149 : : {
1150 [ + + ]: 190421513 : if (! next_t)
1151 : 61024859 : next_t = scan_pp ();
1152 [ - + ]: 190421511 : if (! next_t)
1153 [ # # ][ # # ]: 0 : throw parse_error (_("unexpected end-of-file"));
1154 : :
1155 : 190421511 : last_t = next_t;
1156 : : // advance by zeroing next_t
1157 : 190421511 : next_t = 0;
1158 : 190421511 : return last_t;
1159 : : }
1160 : :
1161 : :
1162 : : const token*
1163 : 1521915152 : parser::peek ()
1164 : : {
1165 [ + + ]: 1521915152 : if (! next_t)
1166 : 199162222 : next_t = scan_pp ();
1167 : :
1168 : : // don't advance by zeroing next_t
1169 : 1521915112 : last_t = next_t;
1170 : 1521915112 : return next_t;
1171 : : }
1172 : :
1173 : :
1174 : : void
1175 : 112553105 : parser::swallow ()
1176 : : {
1177 : : // can only swallow something last peeked or nexted token.
1178 [ - + ]: 112553105 : assert (last_t != 0);
1179 [ + - ]: 112553105 : delete last_t;
1180 : : // advance by zeroing next_t
1181 : 112553105 : last_t = next_t = 0;
1182 : 112553105 : }
1183 : :
1184 : :
1185 : : static inline bool
1186 : 123380100 : tok_is(token const * t, token_type tt, string const & expected)
1187 : : {
1188 [ + - ][ + + ]: 123380100 : return t && t->type == tt && t->content == expected;
[ + + ]
1189 : : }
1190 : :
1191 : :
1192 : : void
1193 : 13934579 : parser::expect_known (token_type tt, string const & expected)
1194 : : {
1195 : 13934579 : const token *t = next();
1196 [ + - ][ + + ]: 13934579 : if (! (t && t->type == tt && t->content == expected))
[ + + ][ + + ]
1197 [ + - ][ + - ]: 3 : throw parse_error (_F("expected '%s'", expected.c_str()));
[ + - ]
1198 : 13934576 : swallow (); // We are done with it, content was copied.
1199 : 13934576 : }
1200 : :
1201 : :
1202 : : void
1203 : 3495070 : parser::expect_unknown (token_type tt, string & target)
1204 : : {
1205 : 3495070 : const token *t = next();
1206 [ + - ][ + + ]: 3495070 : if (!(t && t->type == tt))
1207 [ + - ][ + - ]: 2 : throw parse_error (_("expected ") + tt2str(tt));
[ + - ]
1208 : 3495068 : target = t->content;
1209 : 3495068 : swallow (); // We are done with it, content was copied.
1210 : 3495068 : }
1211 : :
1212 : :
1213 : : void
1214 : 3701179 : parser::expect_unknown2 (token_type tt1, token_type tt2, string & target)
1215 : : {
1216 : 3701179 : const token *t = next();
1217 [ + - ][ + + ]: 3701179 : if (!(t && (t->type == tt1 || t->type == tt2)))
[ - + ]
1218 [ # # ][ # # ]: 0 : throw parse_error (_F("expected %s or %s", tt2str(tt1).c_str(), tt2str(tt2).c_str()));
[ # # ][ # # ]
[ # # ][ # # ]
1219 : 3701179 : target = t->content;
1220 : 3701179 : swallow (); // We are done with it, content was copied.
1221 : 3701179 : }
1222 : :
1223 : :
1224 : : void
1225 : 13895658 : parser::expect_op (std::string const & expected)
1226 : : {
1227 : 13895658 : expect_known (tok_operator, expected);
1228 : 13895655 : }
1229 : :
1230 : :
1231 : : void
1232 : 15133 : parser::expect_kw (std::string const & expected)
1233 : : {
1234 : 15133 : expect_known (tok_keyword, expected);
1235 : 15133 : }
1236 : :
1237 : : const token*
1238 : 15133 : parser::expect_kw_token (std::string const & expected)
1239 : : {
1240 : 15133 : const token *t = next();
1241 [ + - ][ + - ]: 15133 : if (! (t && t->type == tok_keyword && t->content == expected))
[ - + ][ - + ]
1242 [ # # ][ # # ]: 0 : throw parse_error (_F("expected '%s'", expected.c_str()));
[ # # ]
1243 : 15133 : return t;
1244 : : }
1245 : :
1246 : : void
1247 : 23958 : parser::expect_number (int64_t & value)
1248 : : {
1249 : 23958 : bool neg = false;
1250 [ + - ]: 23958 : const token *t = next();
1251 [ + + ][ + - ]: 23958 : if (t->type == tok_operator && t->content == "-")
[ + - ][ + + ]
1252 : : {
1253 : 12 : neg = true;
1254 [ + - ]: 12 : swallow ();
1255 [ + - ]: 12 : t = next ();
1256 : : }
1257 [ + - ][ - + ]: 23958 : if (!(t && t->type == tok_number))
1258 [ # # ][ # # ]: 0 : throw parse_error (_("expected number"));
1259 : :
1260 [ + - ]: 23958 : const char* startp = t->content.c_str ();
1261 : 23958 : char* endp = (char*) startp;
1262 : :
1263 : : // NB: we allow controlled overflow from LLONG_MIN .. ULLONG_MAX
1264 : : // Actually, this allows all the way from -ULLONG_MAX to ULLONG_MAX,
1265 : : // since the lexer only gives us positive digit strings, but we'll
1266 : : // limit it to LLONG_MIN when a '-' operator is fed into the literal.
1267 : 23958 : errno = 0;
1268 : 23958 : value = (int64_t) strtoull (startp, & endp, 0);
1269 [ + - ][ + - ]: 23958 : if (errno == ERANGE || errno == EINVAL || *endp != '\0'
[ + - ][ + + ]
[ - + ]
1270 : : || (neg && (unsigned long long) value > 9223372036854775808ULL)
1271 : : || (unsigned long long) value > 18446744073709551615ULL
1272 : : || value < -9223372036854775807LL-1)
1273 [ # # ][ # # ]: 0 : throw parse_error (_("number invalid or out of range"));
1274 : :
1275 [ + + ]: 23958 : if (neg)
1276 : 12 : value = -value;
1277 : :
1278 [ + - ]: 23958 : swallow (); // We are done with it, content was parsed and copied into value.
1279 : 23958 : }
1280 : :
1281 : :
1282 : : const token*
1283 : 50626767 : parser::expect_ident_or_atword (std::string & target)
1284 : : {
1285 : 50626767 : const token *t = next();
1286 : :
1287 : : // accept identifiers and operators beginning in '@':
1288 [ + - ][ + + ]: 52066761 : if (!t || (t->type != tok_identifier
[ + - + + ]
[ + + ]
1289 : 1439994 : && (t->type != tok_operator || t->content[0] != '@')))
1290 : : // XXX currently this is only called from parse_hist_op_or_bare_name(),
1291 : : // so the message is accurate, but keep an eye out in the future:
1292 [ + - ][ + - ]: 1 : throw parse_error (_F("expected %s or statistical operation", tt2str(tok_identifier).c_str()));
[ + - ][ + - ]
1293 : :
1294 : 50626766 : target = t->content;
1295 : 50626766 : return t;
1296 : : }
1297 : :
1298 : :
1299 : : void
1300 : 3701179 : parser::expect_ident_or_keyword (std::string & target)
1301 : : {
1302 : 3701179 : expect_unknown2 (tok_identifier, tok_keyword, target);
1303 : 3701179 : }
1304 : :
1305 : :
1306 : : bool
1307 : 123362535 : parser::peek_op (std::string const & op)
1308 : : {
1309 : 123362535 : return tok_is (peek(), tok_operator, op);
1310 : : }
1311 : :
1312 : :
1313 : : bool
1314 : 0 : parser::peek_kw (std::string const & kw)
1315 : : {
1316 : 0 : return tok_is (peek(), tok_identifier, kw);
1317 : : }
1318 : :
1319 : :
1320 : :
1321 : 191819 : lexer::lexer (istream& input, const string& in, systemtap_session& s):
1322 : : ate_comment(false), ate_whitespace(false), saw_tokens(false),
1323 : : input_name (in), input_pointer (0), input_end (0), cursor_suspend_count(0),
1324 : : cursor_suspend_line (1), cursor_suspend_column (1), cursor_line (1),
1325 [ + - ]: 191819 : cursor_column (1), session(s), current_file (0)
1326 : : {
1327 [ + - ]: 191819 : getline(input, input_contents, '\0');
1328 : :
1329 [ + - ]: 191819 : input_pointer = input_contents.data();
1330 [ + - ][ + - ]: 191819 : input_end = input_contents.data() + input_contents.size();
1331 : :
1332 [ + - ][ + + ]: 191819 : if (keywords.empty())
1333 : : {
1334 : : // NB: adding new keywords is highly disruptive to the language,
1335 : : // in particular to existing scripts that could be suddenly
1336 : : // broken. If done at all, it has to be s.compatible-sensitive,
1337 : : // and broadly advertised.
1338 [ + - ][ + - ]: 2154 : keywords.insert("probe");
[ + - ]
1339 [ + - ][ + - ]: 2154 : keywords.insert("global");
[ + - ]
1340 [ + - ][ + - ]: 2154 : keywords.insert("function");
[ + - ]
1341 [ + - ][ + - ]: 2154 : keywords.insert("if");
[ + - ]
1342 [ + - ][ + - ]: 2154 : keywords.insert("else");
[ + - ]
1343 [ + - ][ + - ]: 2154 : keywords.insert("for");
[ + - ]
1344 [ + - ][ + - ]: 2154 : keywords.insert("foreach");
[ + - ]
1345 [ + - ][ + - ]: 2154 : keywords.insert("in");
[ + - ]
1346 [ + - ][ + - ]: 2154 : keywords.insert("limit");
[ + - ]
1347 [ + - ][ + - ]: 2154 : keywords.insert("return");
[ + - ]
1348 [ + - ][ + - ]: 2154 : keywords.insert("delete");
[ + - ]
1349 [ + - ][ + - ]: 2154 : keywords.insert("while");
[ + - ]
1350 [ + - ][ + - ]: 2154 : keywords.insert("break");
[ + - ]
1351 [ + - ][ + - ]: 2154 : keywords.insert("continue");
[ + - ]
1352 [ + - ][ + - ]: 2154 : keywords.insert("next");
[ + - ]
1353 [ + - ][ + - ]: 2154 : keywords.insert("string");
[ + - ]
1354 [ + - ][ + - ]: 2154 : keywords.insert("long");
[ + - ]
1355 [ + - ][ + - ]: 2154 : keywords.insert("try");
[ + - ]
1356 [ + - ][ + - ]: 2154 : keywords.insert("catch");
[ + - ]
1357 : : }
1358 : :
1359 [ + - ][ + + ]: 191819 : if (atwords.empty())
1360 : : {
1361 : : // NB: adding new @words is mildly disruptive to existing
1362 : : // scripts that define macros with the same name, but not
1363 : : // really. The user will merely receive a warning that they are
1364 : : // redefining an existing operator.
1365 [ + - ][ + - ]: 2154 : atwords.insert("@cast");
[ + - ]
1366 [ + - ][ + - ]: 2154 : atwords.insert("@defined");
[ + - ]
1367 [ + - ][ + - ]: 2154 : atwords.insert("@entry");
[ + - ]
1368 [ + - ][ + - ]: 2154 : atwords.insert("@var");
[ + - ]
1369 [ + - ][ + - ]: 2154 : atwords.insert("@avg");
[ + - ]
1370 [ + - ][ + - ]: 2154 : atwords.insert("@count");
[ + - ]
1371 [ + - ][ + - ]: 2154 : atwords.insert("@sum");
[ + - ]
1372 [ + - ][ + - ]: 2154 : atwords.insert("@min");
[ + - ]
1373 [ + - ][ + - ]: 2154 : atwords.insert("@max");
[ + - ]
1374 [ + - ][ + - ]: 2154 : atwords.insert("@hist_linear");
[ + - ]
1375 [ + - ][ + - ]: 2154 : atwords.insert("@hist_log");
[ + - ]
1376 : : }
1377 : 191819 : }
1378 : :
1379 : 2414 : set<string> lexer::keywords;
1380 : 2414 : set<string> lexer::atwords;
1381 : :
1382 : : void
1383 : 379330 : lexer::set_current_file (stapfile* f)
1384 : : {
1385 : 379330 : current_file = f;
1386 [ + + ]: 379330 : if (f)
1387 : : {
1388 : 191819 : f->file_contents = input_contents;
1389 : 191819 : f->name = input_name;
1390 : : }
1391 : 379330 : }
1392 : :
1393 : : int
1394 : 3485294005 : lexer::input_peek (unsigned n)
1395 : : {
1396 [ + + ]: 3485294005 : if (input_pointer + n >= input_end)
1397 : 308101 : return -1; // EOF
1398 : 3485294005 : return (unsigned char)*(input_pointer + n);
1399 : : }
1400 : :
1401 : :
1402 : : int
1403 : 2504841823 : lexer::input_get ()
1404 : : {
1405 : 2504841823 : int c = input_peek();
1406 [ + + ]: 2504841823 : if (c < 0) return c; // EOF
1407 : :
1408 : 2504645552 : ++input_pointer;
1409 : :
1410 [ + + ]: 2504645552 : if (cursor_suspend_count)
1411 : : {
1412 : : // Track effect of input_put: preserve previous cursor/line_column
1413 : : // until all of its characters are consumed.
1414 [ + + ]: 89972 : if (--cursor_suspend_count == 0)
1415 : : {
1416 : 80830 : cursor_line = cursor_suspend_line;
1417 : 80830 : cursor_column = cursor_suspend_column;
1418 : : }
1419 : : }
1420 : : else
1421 : : {
1422 : : // update source cursor
1423 [ + + ]: 2504555580 : if (c == '\n')
1424 : : {
1425 : 84036061 : cursor_line ++;
1426 : 84036061 : cursor_column = 1;
1427 : : }
1428 : : else
1429 : 2420519519 : cursor_column ++;
1430 : : }
1431 : :
1432 : : // clog << "[" << (char)c << "]";
1433 : 2504841823 : return c;
1434 : : }
1435 : :
1436 : :
1437 : : void
1438 : 80830 : lexer::input_put (const string& chars, const token* t)
1439 : : {
1440 : 80830 : size_t pos = input_pointer - input_contents.data();
1441 : : // clog << "[put:" << chars << " @" << pos << "]";
1442 : 80830 : input_contents.insert (pos, chars);
1443 : 80830 : cursor_suspend_count += chars.size();
1444 : 80830 : cursor_suspend_line = cursor_line;
1445 : 80830 : cursor_suspend_column = cursor_column;
1446 : 80830 : cursor_line = t->location.line;
1447 : 80830 : cursor_column = t->location.column;
1448 : 80830 : input_pointer = input_contents.data() + pos;
1449 : 80830 : input_end = input_contents.data() + input_contents.size();
1450 : 80830 : }
1451 : :
1452 : :
1453 : : token*
1454 : 254464165 : lexer::scan ()
1455 : : {
1456 : 254464165 : ate_comment = false; // reset for each new token
1457 : 254464165 : ate_whitespace = false; // reset for each new token
1458 : :
1459 : : // XXX be very sure to restore old_saw_tokens if we return without a token:
1460 : 254464165 : bool old_saw_tokens = saw_tokens;
1461 : 254464165 : saw_tokens = true;
1462 : :
1463 [ + - ]: 254464165 : token* n = new token;
1464 : 254464165 : n->location.file = current_file;
1465 : 254464165 : n->chain = NULL; // important safety dance
1466 : :
1467 : : skip:
1468 : 503504655 : bool suspended = (cursor_suspend_count > 0);
1469 : 503504655 : n->location.line = cursor_line;
1470 : 503504655 : n->location.column = cursor_column;
1471 : :
1472 : 503504655 : int c = input_get();
1473 : : // clog << "{" << (char)c << (char)c2 << "}";
1474 [ + + ]: 503504655 : if (c < 0)
1475 : : {
1476 [ + - ]: 196268 : delete n;
1477 : 196268 : saw_tokens = old_saw_tokens;
1478 : 196268 : return 0;
1479 : : }
1480 : :
1481 [ + + ]: 503308387 : if (isspace (c))
1482 : : {
1483 : 235328902 : ate_whitespace = true;
1484 : 235328902 : goto skip;
1485 : : }
1486 : :
1487 : 267979485 : int c2 = input_peek ();
1488 : :
1489 : : // Paste command line arguments as character streams into
1490 : : // the beginning of a token. $1..$999 go through as raw
1491 : : // characters; @1..@999 are quoted/escaped as strings.
1492 : : // $# and @# expand to the number of arguments, similarly
1493 : : // raw or quoted.
1494 [ + + ][ + + ]: 267979485 : if ((c == '$' || c == '@') && (c2 == '#'))
[ + + ]
1495 : : {
1496 [ + - ]: 79821 : n->content.push_back (c);
1497 [ + - ]: 79821 : n->content.push_back (c2);
1498 : 79821 : input_get(); // swallow '#'
1499 [ - + ]: 79821 : if (suspended)
1500 : : {
1501 [ # # ][ # # ]: 0 : n->make_junk(_("invalid nested substitution of command line arguments"));
[ # # ]
1502 : 0 : return n;
1503 : : }
1504 : 79821 : size_t num_args = session.args.size ();
1505 [ + + ][ + - ]: 79821 : input_put ((c == '$') ? lex_cast (num_args) : lex_cast_qstring (num_args), n);
[ + - ][ + - ]
[ + - ]
1506 [ + - ]: 79821 : n->content.clear();
1507 : : goto skip;
1508 : : }
1509 [ + + ][ + + ]: 267899664 : else if ((c == '$' || c == '@') && (isdigit (c2)))
[ + + ]
1510 : : {
1511 : 69824 : n->content.push_back (c);
1512 : 69824 : unsigned idx = 0;
1513 [ + + ]: 121403 : do
[ + + + + ]
[ + + ]
1514 : : {
1515 : 71814 : input_get ();
1516 : 71814 : idx = (idx * 10) + (c2 - '0');
1517 : 71814 : n->content.push_back (c2);
1518 : 71814 : c2 = input_peek ();
1519 : : } while (c2 > 0 &&
1520 : 71811 : isdigit (c2) &&
1521 : 49589 : idx <= session.args.size()); // prevent overflow
1522 [ + + ]: 69824 : if (suspended)
1523 : : {
1524 [ + - ][ + - ]: 2 : n->make_junk(_("invalid nested substitution of command line arguments"));
[ + - ]
1525 : 2 : return n;
1526 : : }
1527 [ + + + + ]: 139643 : if (idx == 0 ||
[ + + ]
1528 : 69821 : idx-1 >= session.args.size())
1529 : : {
1530 : 68813 : n->make_junk(_F("command line argument index %lu out of range [1-%lu]",
1531 [ + - ]: 68813 : (unsigned long) idx, (unsigned long) session.args.size()));
1532 : 68813 : return n;
1533 : : }
1534 : 1009 : const string& arg = session.args[idx-1];
1535 [ + + ][ + - ]: 1009 : input_put ((c == '$') ? arg : lex_cast_qstring (arg), n);
1536 : 1009 : n->content.clear();
1537 : 1009 : goto skip;
1538 : : }
1539 : :
1540 [ + + ][ + + ]: 267829840 : else if (isalpha (c) || c == '$' || c == '@' || c == '_')
[ + + ][ + + ]
1541 : : {
1542 : 98065200 : n->type = tok_identifier;
1543 : 98065200 : n->content = (char) c;
1544 [ + + ][ + + ]: 661469831 : while (isalnum (c2) || c2 == '_' || c2 == '$')
[ + + ][ + + ]
1545 : : {
1546 : 563404631 : input_get ();
1547 : 563404631 : n->content.push_back (c2);
1548 : 563404631 : c2 = input_peek ();
1549 : : }
1550 : :
1551 [ + + ]: 98065200 : if (keywords.count(n->content))
1552 : 23140781 : n->type = tok_keyword;
1553 [ + + ]: 74924419 : else if (n->content[0] == '@')
1554 : : // makes it easier to detect illegal use of @words:
1555 : 1487635 : n->type = tok_operator;
1556 : :
1557 : 98065200 : return n;
1558 : : }
1559 : :
1560 [ + + ]: 169764640 : else if (isdigit (c)) // positive literal
1561 : : {
1562 : 8394350 : n->type = tok_number;
1563 : 8394350 : n->content = (char) c;
1564 : :
1565 [ + + ]: 12347428 : while (isalnum (c2))
1566 : : {
1567 : : // NB: isalnum is very permissive. We rely on strtol, called in
1568 : : // parser::parse_literal below, to confirm that the number string
1569 : : // is correctly formatted and in range.
1570 : :
1571 : 3953078 : input_get ();
1572 : 3953078 : n->content.push_back (c2);
1573 : 3953078 : c2 = input_peek ();
1574 : : }
1575 : 8394350 : return n;
1576 : : }
1577 : :
1578 [ + + ]: 161370290 : else if (c == '\"')
1579 : : {
1580 : 16327116 : n->type = tok_string;
1581 : 180372462 : while (1)
1582 : : {
1583 : 196699578 : c = input_get ();
1584 : :
1585 [ + - ][ - + ]: 196699578 : if (c < 0 || c == '\n')
1586 : : {
1587 [ # # ][ # # ]: 0 : n->make_junk(_("Could not find matching closing quote"));
[ # # ]
1588 : 0 : return n;
1589 : : }
1590 [ + + ]: 196699578 : if (c == '\"') // closing double-quotes
1591 : 16327116 : break;
1592 [ + + ]: 180372462 : else if (c == '\\') // see also input_put
1593 : : {
1594 : 48859 : c = input_get ();
1595 [ + + ]: 48859 : switch (c)
1596 : : {
1597 : : case 'a':
1598 : : case 'b':
1599 : : case 't':
1600 : : case 'n':
1601 : : case 'v':
1602 : : case 'f':
1603 : : case 'r':
1604 : : case '0' ... '7': // NB: need only match the first digit
1605 : : case '\\':
1606 : : // Pass these escapes through to the string value
1607 : : // being parsed; it will be emitted into a C literal.
1608 : :
1609 : 44386 : n->content.push_back('\\');
1610 : :
1611 : : // fall through
1612 : : default:
1613 : 48859 : n->content.push_back(c);
1614 : 48859 : break;
1615 : : }
1616 : : }
1617 : : else
1618 : 180323603 : n->content.push_back(c);
1619 : : }
1620 : 16327116 : return n;
1621 : : }
1622 : :
1623 [ + - ]: 145043174 : else if (ispunct (c))
1624 : : {
1625 : 145043174 : int c3 = input_peek (1);
1626 : :
1627 : : // NB: if we were to recognize negative numeric literals here,
1628 : : // we'd introduce another grammar ambiguity:
1629 : : // 1-1 would be parsed as tok_number(1) and tok_number(-1)
1630 : : // instead of tok_number(1) tok_operator('-') tok_number(1)
1631 : :
1632 [ + + ]: 145043174 : if (c == '#') // shell comment
1633 : : {
1634 : 7240245 : unsigned this_line = cursor_line;
1635 [ + + ][ + + ]: 263168478 : do { c = input_get (); }
[ + + ]
1636 : : while (c >= 0 && cursor_line == this_line);
1637 : 7240245 : ate_comment = true;
1638 : 7240245 : ate_whitespace = true;
1639 : 7240245 : goto skip;
1640 : : }
1641 [ + + ][ + + ]: 137802929 : else if ((c == '/' && c2 == '/')) // C++ comment
1642 : : {
1643 : 4627867 : unsigned this_line = cursor_line;
1644 [ + - ][ + + ]: 164867590 : do { c = input_get (); }
[ + + ]
1645 : : while (c >= 0 && cursor_line == this_line);
1646 : 4627867 : ate_comment = true;
1647 : 4627867 : ate_whitespace = true;
1648 : 4627867 : goto skip;
1649 : : }
1650 [ + + ][ + + ]: 133175062 : else if (c == '/' && c2 == '*') // C comment
1651 : : {
1652 : 1762646 : (void) input_get (); // swallow '*' already in c2
1653 : 1762646 : c = input_get ();
1654 : 1762646 : c2 = input_get ();
1655 [ + + ]: 521626561 : while (c2 >= 0)
1656 : : {
1657 [ + + ][ + + ]: 521626560 : if (c == '*' && c2 == '/')
1658 : 1762645 : break;
1659 : 519863915 : c = c2;
1660 : 519863915 : c2 = input_get ();
1661 : : }
1662 : 1762646 : ate_comment = true;
1663 : 1762646 : ate_whitespace = true;
1664 : 1762646 : goto skip;
1665 : : }
1666 [ + + ][ + + ]: 131412416 : else if (c == '%' && c2 == '{') // embedded code
1667 : : {
1668 : 1195845 : n->type = tok_embedded;
1669 : 1195845 : (void) input_get (); // swallow '{' already in c2
1670 : 1195845 : c = input_get ();
1671 : 1195845 : c2 = input_get ();
1672 [ + + ]: 275189825 : while (c2 >= 0)
1673 : : {
1674 [ + + ][ + + ]: 275189824 : if (c == '%' && c2 == '}')
1675 : 1195844 : return n;
1676 : 273993980 : n->content += c;
1677 : 273993980 : c = c2;
1678 : 273993980 : c2 = input_get ();
1679 : : }
1680 : :
1681 [ + - ][ + - ]: 1 : n->make_junk(_("Could not find matching '%}' to close embedded function block"));
[ + - ]
1682 : 1 : return n;
1683 : : }
1684 : :
1685 : : // We're committed to recognizing at least the first character
1686 : : // as an operator.
1687 : 130216571 : n->type = tok_operator;
1688 : 130216571 : n->content = c;
1689 : :
1690 : : // match all valid operators, in decreasing size order
1691 [ + + ][ + + ]: 130216571 : if ((c == '<' && c2 == '<' && c3 == '<') ||
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ]
1692 : : (c == '<' && c2 == '<' && c3 == '=') ||
1693 : : (c == '>' && c2 == '>' && c3 == '='))
1694 : : {
1695 : 6733 : n->content += c2;
1696 : 6733 : n->content += c3;
1697 : 6733 : input_get (); input_get (); // swallow other two characters
1698 : : }
1699 [ + + ][ + + ]: 130209838 : else if ((c == '=' && c2 == '=') ||
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
1700 : : (c == '!' && c2 == '=') ||
1701 : : (c == '<' && c2 == '=') ||
1702 : : (c == '>' && c2 == '=') ||
1703 : : (c == '=' && c2 == '~') ||
1704 : : (c == '!' && c2 == '~') ||
1705 : : (c == '+' && c2 == '=') ||
1706 : : (c == '-' && c2 == '=') ||
1707 : : (c == '*' && c2 == '=') ||
1708 : : (c == '/' && c2 == '=') ||
1709 : : (c == '%' && c2 == '=') ||
1710 : : (c == '&' && c2 == '=') ||
1711 : : (c == '^' && c2 == '=') ||
1712 : : (c == '|' && c2 == '=') ||
1713 : : (c == '.' && c2 == '=') ||
1714 : : (c == '&' && c2 == '&') ||
1715 : : (c == '|' && c2 == '|') ||
1716 : : (c == '+' && c2 == '+') ||
1717 : : (c == '-' && c2 == '-') ||
1718 : : (c == '-' && c2 == '>') ||
1719 : : (c == '<' && c2 == '<') ||
1720 : : (c == '>' && c2 == '>') ||
1721 : : // preprocessor tokens
1722 : : (c == '%' && c2 == '(') ||
1723 : : (c == '%' && c2 == '?') ||
1724 : : (c == '%' && c2 == ':') ||
1725 : : (c == '%' && c2 == ')'))
1726 : : {
1727 : 6296485 : n->content += c2;
1728 : 6296485 : input_get (); // swallow other character
1729 : : }
1730 : :
1731 : 130216571 : return n;
1732 : : }
1733 : :
1734 : : else
1735 : : {
1736 : 0 : n->type = tok_junk;
1737 [ # # ]: 0 : ostringstream s;
1738 [ # # ][ # # ]: 0 : s << "\\x" << hex << setw(2) << setfill('0') << c;
[ # # ][ # # ]
[ # # ]
1739 [ # # ][ # # ]: 0 : n->content = s.str();
[ # # ]
1740 [ # # ]: 0 : n->msg = ""; // signal parser to emit "expected X, found junk" type error
1741 [ # # ]: 254464165 : return n;
1742 : : }
1743 : : }
1744 : :
1745 : : // ------------------------------------------------------------------------
1746 : :
1747 : : void
1748 : 68816 : token::make_junk (const string new_msg)
1749 : : {
1750 : 68816 : type = tok_junk;
1751 : 68816 : msg = new_msg;
1752 : 68816 : }
1753 : :
1754 : : // ------------------------------------------------------------------------
1755 : :
1756 : : stapfile*
1757 : 187511 : parser::parse ()
1758 : : {
1759 [ + - ]: 187511 : stapfile* f = new stapfile;
1760 : 187511 : input.set_current_file (f);
1761 : :
1762 : 187511 : bool empty = true;
1763 : :
1764 : 5859359 : while (1)
1765 : : {
1766 : : try
1767 : : {
1768 : 6046870 : systemtap_v_seen = 0;
1769 [ + + ]: 6046870 : const token* t = peek ();
1770 [ + + ]: 6046842 : if (! t) // nice clean EOF, modulo any preprocessing that occurred
1771 : 187511 : break;
1772 : :
1773 : 5859331 : empty = false;
1774 [ + + ][ + - ]: 5859331 : if (t->type == tok_keyword && t->content == "probe")
[ + + ][ + + ]
1775 : : {
1776 : 4360206 : context = con_probe;
1777 [ + + ]: 4360206 : parse_probe (f->probes, f->aliases);
1778 : : }
1779 [ + + ][ + - ]: 1499125 : else if (t->type == tok_keyword && t->content == "global")
[ + + ][ + + ]
1780 : : {
1781 : 115360 : context = con_global;
1782 [ + + ]: 115360 : parse_global (f->globals, f->probes);
1783 : : }
1784 [ + + ][ + - ]: 1383765 : else if (t->type == tok_keyword && t->content == "function")
[ + - ][ + + ]
1785 : : {
1786 : 1273818 : context = con_function;
1787 [ + + ]: 1273818 : parse_functiondecl (f->functions);
1788 : : }
1789 [ + + ]: 109947 : else if (t->type == tok_embedded)
1790 : : {
1791 : 109940 : context = con_embedded;
1792 [ + + ][ + - ]: 109940 : f->embeds.push_back (parse_embeddedcode ());
1793 : : }
1794 : : else
1795 : : {
1796 : 7 : context = con_unknown;
1797 [ + - ][ + - ]: 7 : throw parse_error (_("expected 'probe', 'global', 'function', or '%{'"));
1798 : : }
1799 : : }
1800 [ - + ]: 260 : catch (parse_error& pe)
1801 : : {
1802 [ - + ]: 130 : print_error (pe);
1803 : :
1804 : : // XXX: do we want tok_junk to be able to force skip_some behaviour?
1805 [ + + ]: 130 : if (pe.skip_some) // for recovery
1806 : : // Quietly swallow all tokens until the next keyword we can start parsing from.
1807 : 670 : while (1)
1808 : : try
1809 : : {
1810 : : {
1811 [ + + ]: 670 : const token* t = peek ();
1812 [ + + ]: 659 : if (! t)
1813 : 115 : break;
1814 [ + + ][ - + ]: 544 : if (t->type == tok_keyword && t->content == "probe") break;
[ + + ][ + + ]
1815 [ + + ][ - + ]: 531 : else if (t->type == tok_keyword && t->content == "global") break;
[ - + ][ - + ]
1816 [ + + ][ - + ]: 531 : else if (t->type == tok_keyword && t->content == "function") break;
[ - + ][ - + ]
1817 [ - + ]: 531 : else if (t->type == tok_embedded) break;
1818 [ - + ]: 531 : swallow (); // swallow it
1819 : : }
1820 : : }
1821 [ - + ][ - + ]: 22 : catch (parse_error& pe2)
1822 : : {
1823 : : // parse error during recovery ... ugh
1824 [ - + ]: 11 : print_error (pe2);
1825 : : }
1826 : : }
1827 : : }
1828 : :
1829 [ + + ]: 187511 : if (empty)
1830 : : {
1831 : : // vary message depending on whether file was *actually* empty:
1832 : : cerr << (input.saw_tokens
1833 : 14 : ? _F("Input file '%s' is empty after preprocessing.", input_name.c_str())
1834 [ + + ][ + - ]: 30 : : _F("Input file '%s' is empty.", input_name.c_str()))
1835 [ + - ]: 15 : << endl;
1836 [ + - ]: 15 : delete f;
1837 : 15 : f = 0;
1838 : : }
1839 [ + + ]: 187496 : else if (num_errors > 0)
1840 : : {
1841 [ + - ][ + - ]: 104 : cerr << _F(ngettext("%d parse error.", "%d parse errors.", num_errors), num_errors) << endl;
1842 [ + - ]: 104 : delete f;
1843 : 104 : f = 0;
1844 : : }
1845 : :
1846 : 187511 : input.set_current_file(0);
1847 : 187511 : return f;
1848 : : }
1849 : :
1850 : :
1851 : : void
1852 : 4360206 : parser::parse_probe (std::vector<probe *> & probe_ret,
1853 : : std::vector<probe_alias *> & alias_ret)
1854 : : {
1855 [ + - ]: 4360206 : const token* t0 = next ();
1856 [ + - ][ + - ]: 4360206 : if (! (t0->type == tok_keyword && t0->content == "probe"))
[ - + ][ - + ]
1857 [ # # ][ # # ]: 0 : throw parse_error (_("expected 'probe'"));
1858 : :
1859 [ + - ]: 4360206 : vector<probe_point *> aliases;
1860 [ + - ]: 4360206 : vector<probe_point *> locations;
1861 : :
1862 : 4360206 : bool equals_ok = true;
1863 : :
1864 : 4360206 : int epilogue_alias = 0;
1865 : :
1866 : 6644967 : while (1)
1867 : : {
1868 [ + + ]: 11005173 : probe_point * pp = parse_probe_point ();
1869 : :
1870 [ + - ]: 11005141 : const token* t = peek ();
1871 [ + + ][ + - ]: 19704700 : if (equals_ok && t
[ + - ][ + + ]
[ + + ]
1872 [ + - ]: 8699559 : && t->type == tok_operator && t->content == "=")
1873 : : {
1874 [ + + ][ - + ]: 4339380 : if (pp->optional || pp->sufficient)
1875 [ + - ][ + - ]: 1 : throw parse_error (_("probe point alias name cannot be optional nor sufficient"), pp->components.front()->tok);
[ + - ]
1876 [ + - ]: 4339379 : aliases.push_back(pp);
1877 [ + - ]: 4339379 : swallow ();
1878 : 4339379 : continue;
1879 : : }
1880 [ + + ][ + - ]: 11025940 : else if (equals_ok && t
[ + - ][ + + ]
[ + + ]
1881 [ + - ]: 4360179 : && t->type == tok_operator && t->content == "+=")
1882 : : {
1883 [ + - ][ - + ]: 4 : if (pp->optional || pp->sufficient)
1884 [ # # ][ # # ]: 0 : throw parse_error (_("probe point alias name cannot be optional nor sufficient"), pp->components.front()->tok);
[ # # ]
1885 [ + - ]: 4 : aliases.push_back(pp);
1886 : 4 : epilogue_alias = 1;
1887 [ + - ]: 4 : swallow ();
1888 : 4 : continue;
1889 : : }
1890 [ + - ][ + - ]: 6665757 : else if (t && t->type == tok_operator && t->content == ",")
[ + - ][ + + ]
[ + + ]
1891 : : {
1892 [ + - ]: 2305584 : locations.push_back(pp);
1893 : 2305584 : equals_ok = false;
1894 [ + - ]: 2305584 : swallow ();
1895 : 2305584 : continue;
1896 : : }
1897 [ + - ][ + - ]: 4360173 : else if (t && t->type == tok_operator && t->content == "{")
[ + - ][ + - ]
[ + - ]
1898 : : {
1899 [ + - ]: 4360173 : locations.push_back(pp);
1900 : : break;
1901 : : }
1902 : : else
1903 [ # # ][ # # ]: 33 : throw parse_error (_("expected probe point specifier"));
1904 : : }
1905 : :
1906 [ + - ][ + + ]: 4360173 : if (aliases.empty())
1907 : : {
1908 [ + - ][ + - ]: 20817 : probe* p = new probe;
1909 : 20792 : p->tok = t0;
1910 [ + - ]: 20792 : p->locations = locations;
1911 [ + + ]: 20792 : p->body = parse_stmt_block ();
1912 : 20767 : p->privileged = privileged;
1913 : 20767 : p->systemtap_v_conditional = systemtap_v_seen;
1914 [ + - ]: 20767 : probe_ret.push_back (p);
1915 : : }
1916 : : else
1917 : : {
1918 [ + - ][ + - ]: 4339381 : probe_alias* p = new probe_alias (aliases);
1919 [ + + ]: 4339381 : if(epilogue_alias)
1920 : 4 : p->epilogue_style = true;
1921 : : else
1922 : 4339377 : p->epilogue_style = false;
1923 : 4339381 : p->tok = t0;
1924 [ + - ]: 4339381 : p->locations = locations;
1925 [ + - ]: 4339381 : p->body = parse_stmt_block ();
1926 : 4339381 : p->privileged = privileged;
1927 : 4339381 : p->systemtap_v_conditional = systemtap_v_seen;
1928 [ + - ]: 4339381 : alias_ret.push_back (p);
1929 [ + - ][ + - ]: 4360206 : }
1930 : 4360148 : }
1931 : :
1932 : :
1933 : : embeddedcode*
1934 : 689615 : parser::parse_embeddedcode ()
1935 : : {
1936 [ + - ]: 689615 : embeddedcode* e = new embeddedcode;
1937 : 689615 : const token* t = next ();
1938 [ - + ]: 689615 : if (t->type != tok_embedded)
1939 [ # # ][ # # ]: 0 : throw parse_error (_("expected '%{'"));
1940 : :
1941 [ + + ]: 689615 : if (! privileged)
1942 : 2 : throw parse_error (_("embedded code in unprivileged script; need stap -g"),
1943 [ + - ][ + - ]: 2 : false /* don't skip tokens for parse resumption */);
1944 : :
1945 : 689613 : e->tok = t;
1946 : 689613 : e->code = t->content;
1947 : 689613 : return e;
1948 : : }
1949 : :
1950 : :
1951 : : block*
1952 : 5846599 : parser::parse_stmt_block ()
1953 : : {
1954 [ + - ]: 5846599 : block* pb = new block;
1955 : :
1956 : 5846599 : const token* t = next ();
1957 [ + - ][ - + ]: 5846599 : if (! (t->type == tok_operator && t->content == "{"))
[ - + ]
1958 [ # # ][ # # ]: 0 : throw parse_error (_("expected '{'"));
1959 : :
1960 : 5846599 : pb->tok = t;
1961 : :
1962 : 22314068 : while (1)
1963 : : {
1964 : 28160667 : t = peek ();
1965 [ + + ][ + + ]: 28160666 : if (t && t->type == tok_operator && t->content == "}")
[ + + ][ + + ]
1966 : : {
1967 : 5846555 : swallow ();
1968 : 5846555 : break;
1969 : : }
1970 [ + - ]: 22314111 : pb->statements.push_back (parse_statement ());
1971 : : }
1972 : :
1973 : 5846555 : return pb;
1974 : : }
1975 : :
1976 : :
1977 : : try_block*
1978 : 15133 : parser::parse_try_block ()
1979 : : {
1980 [ + - ]: 15133 : try_block* pb = new try_block;
1981 : :
1982 [ + - ][ + - ]: 15133 : pb->tok = expect_kw_token ("try");
[ + - ]
1983 : 15133 : pb->try_block = parse_stmt_block();
1984 [ + - ][ + - ]: 15133 : expect_kw ("catch");
[ + - ]
1985 : :
1986 : 15133 : const token* t = peek ();
1987 [ + - ][ + + ]: 15133 : if (t->type == tok_operator && t->content == "(")
[ + + ]
1988 : : {
1989 : 7 : swallow (); // swallow the '('
1990 : :
1991 : 7 : t = next();
1992 [ - + ]: 7 : if (! (t->type == tok_identifier))
1993 [ # # ][ # # ]: 0 : throw parse_error (_("expected identifier"));
1994 [ + - ]: 7 : symbol* sym = new symbol;
1995 : 7 : sym->tok = t;
1996 : 7 : sym->name = t->content;
1997 : 7 : pb->catch_error_var = sym;
1998 : :
1999 [ + - ][ + - ]: 7 : expect_op (")");
[ + - ]
2000 : : }
2001 : : else
2002 : 15126 : pb->catch_error_var = 0;
2003 : :
2004 : 15133 : pb->catch_block = parse_stmt_block();
2005 : :
2006 : 15133 : return pb;
2007 : : }
2008 : :
2009 : :
2010 : :
2011 : : statement*
2012 : 24835682 : parser::parse_statement ()
2013 : : {
2014 : : statement *ret;
2015 : 24835682 : const token* t = peek ();
2016 [ + + ][ + + ]: 24835682 : if (t && t->type == tok_operator && t->content == ";")
[ + + ][ + + ]
2017 [ + - ]: 174 : return new null_statement (next ());
2018 [ + + ][ + + ]: 24835508 : else if (t && t->type == tok_operator && t->content == "{")
[ + + ][ + + ]
2019 : 762025 : return parse_stmt_block (); // Don't squash semicolons.
2020 [ + + ][ + + ]: 24073483 : else if (t && t->type == tok_keyword && t->content == "try")
[ + + ][ + + ]
2021 : 15133 : return parse_try_block (); // Don't squash semicolons.
2022 [ + + ][ + + ]: 24058350 : else if (t && t->type == tok_keyword && t->content == "if")
[ + + ][ + + ]
2023 : 2102453 : return parse_if_statement (); // Don't squash semicolons.
2024 [ + + ][ + + ]: 21955897 : else if (t && t->type == tok_keyword && t->content == "for")
[ + + ][ + + ]
2025 : 6823 : return parse_for_loop (); // Don't squash semicolons.
2026 [ + + ][ + + ]: 21949074 : else if (t && t->type == tok_keyword && t->content == "foreach")
[ + + ][ + + ]
2027 : 17574 : return parse_foreach_loop (); // Don't squash semicolons.
2028 [ + + ][ + + ]: 21931500 : else if (t && t->type == tok_keyword && t->content == "while")
[ + + ][ + + ]
2029 : 25920 : return parse_while_loop (); // Don't squash semicolons.
2030 [ + + ][ + + ]: 21905580 : else if (t && t->type == tok_keyword && t->content == "return")
[ + + ][ + + ]
2031 : 1753741 : ret = parse_return_statement ();
2032 [ + + ][ + + ]: 20151839 : else if (t && t->type == tok_keyword && t->content == "delete")
[ + + ][ + + ]
2033 : 28254 : ret = parse_delete_statement ();
2034 [ + + ][ + + ]: 20123585 : else if (t && t->type == tok_keyword && t->content == "break")
[ + + ][ + + ]
2035 : 19431 : ret = parse_break_statement ();
2036 [ + + ][ + + ]: 20104154 : else if (t && t->type == tok_keyword && t->content == "continue")
[ + + ][ + + ]
2037 : 2223 : ret = parse_continue_statement ();
2038 [ + + ][ + + ]: 20101931 : else if (t && t->type == tok_keyword && t->content == "next")
[ + - ][ + + ]
2039 : 62712 : ret = parse_next_statement ();
2040 [ + + ][ + + ]: 20039219 : else if (t && (t->type == tok_operator || // expressions are flexible
[ + + ][ + + ]
[ + + ][ + + ]
2041 : : t->type == tok_identifier ||
2042 : : t->type == tok_number ||
2043 : : t->type == tok_string ||
2044 : : t->type == tok_embedded ))
2045 : 20039217 : ret = parse_expr_statement ();
2046 : : // XXX: consider generally accepting tok_embedded here too
2047 : : else
2048 [ + - ][ + - ]: 2 : throw parse_error (_("expected statement"));
2049 : :
2050 : : // Squash "empty" trailing colons after any "non-block-like" statement.
2051 : 21905558 : t = peek ();
2052 [ + - ][ + + ]: 21905558 : if (t && t->type == tok_operator && t->content == ";")
[ + + ][ + + ]
2053 : : {
2054 : 842063 : swallow (); // Silently eat trailing ; after statement
2055 : : }
2056 : :
2057 : 24835639 : return ret;
2058 : : }
2059 : :
2060 : :
2061 : : void
2062 : 115360 : parser::parse_global (vector <vardecl*>& globals, vector<probe*>&)
2063 : : {
2064 : 115360 : const token* t0 = next ();
2065 [ + - ][ - + ]: 115360 : if (! (t0->type == tok_keyword && t0->content == "global"))
[ - + ]
2066 [ # # ][ # # ]: 0 : throw parse_error (_("expected 'global'"));
2067 : 115360 : swallow ();
2068 : :
2069 : 48040 : while (1)
2070 : : {
2071 [ + - ]: 163400 : const token* t = next ();
2072 [ + + ]: 163400 : if (! (t->type == tok_identifier))
2073 [ + - ][ + - ]: 3 : throw parse_error (_("expected identifier"));
2074 : :
2075 [ + + ]: 640866 : for (unsigned i=0; i<globals.size(); i++)
2076 [ + - ][ + + ]: 477470 : if (globals[i]->name == t->content)
2077 [ + - ][ + - ]: 1 : throw parse_error (_("duplicate global name"));
2078 : :
2079 [ + - ][ + - ]: 163396 : vardecl* d = new vardecl;
2080 [ + - ]: 163396 : d->name = t->content;
2081 : 163396 : d->tok = t;
2082 : 163396 : d->systemtap_v_conditional = systemtap_v_seen;
2083 [ + - ]: 163396 : globals.push_back (d);
2084 : :
2085 [ + - ]: 163396 : t = peek ();
2086 : :
2087 [ + + ][ + + ]: 163396 : if(t && t->type == tok_operator && t->content == "%") //wrapping
[ + - ][ + + ]
[ + + ]
2088 : : {
2089 : 18 : d->wrap = true;
2090 [ + - ]: 18 : swallow ();
2091 [ + - ]: 18 : t = peek();
2092 : : }
2093 : :
2094 [ + + ][ + + ]: 163396 : if (t && t->type == tok_operator && t->content == "[") // array size
[ + - ][ + + ]
[ + + ]
2095 : : {
2096 : : int64_t size;
2097 [ + - ]: 23790 : swallow ();
2098 [ + - ]: 23790 : expect_number(size);
2099 [ + + ][ + + ]: 23790 : if (size <= 0 || size > 1000000) // arbitrary max
2100 [ + - ][ + - ]: 2 : throw parse_error(_("array size out of range"));
2101 : 23788 : d->maxsize = (int)size;
2102 [ + - ][ + - ]: 23790 : expect_known(tok_operator, "]");
[ + - ]
2103 [ + - ]: 23788 : t = peek ();
2104 : : }
2105 : :
2106 [ + + ][ + + ]: 163394 : if (t && t->type == tok_operator && t->content == "=") // initialization
[ + - ][ + + ]
[ + + ]
2107 : : {
2108 [ + - ][ + + ]: 28220 : if (!d->compatible_arity(0))
2109 [ + - ][ + - ]: 8 : throw parse_error(_("only scalar globals can be initialized"));
2110 [ + - ]: 28218 : d->set_arity(0, t);
2111 [ + - ]: 28218 : next (); // Don't swallow, set_arity() used the peeked token.
2112 [ + - ]: 28218 : d->init = parse_literal ();
2113 : 28218 : d->type = d->init->type;
2114 [ + - ]: 28218 : t = peek ();
2115 : : }
2116 : :
2117 [ + + ][ + + ]: 163392 : if (t && t->type == tok_operator && t->content == ";") // termination
[ + - ][ + + ]
[ + + ]
2118 : : {
2119 [ + - ]: 118 : swallow ();
2120 : : break;
2121 : : }
2122 : :
2123 [ + + ][ + + ]: 163274 : if (t && t->type == tok_operator && t->content == ",") // next global
[ + - ][ + - ]
[ + + ]
2124 : : {
2125 [ + - ]: 48040 : swallow ();
2126 : 48040 : continue;
2127 : : }
2128 : : else
2129 : : break;
2130 : : }
2131 : 115352 : }
2132 : :
2133 : :
2134 : : void
2135 : 1273818 : parser::parse_functiondecl (std::vector<functiondecl*>& functions)
2136 : : {
2137 [ + - ]: 1273818 : const token* t = next ();
2138 [ + - ][ + - ]: 1273818 : if (! (t->type == tok_keyword && t->content == "function"))
[ - + ][ - + ]
2139 [ # # ][ # # ]: 0 : throw parse_error (_("expected 'function'"));
2140 [ + - ]: 1273818 : swallow ();
2141 : :
2142 [ + - ]: 1273818 : t = next ();
2143 [ + + ][ + + ]: 1273819 : if (! (t->type == tok_identifier)
[ + + ]
2144 : : && ! (t->type == tok_keyword
2145 [ + - ][ + - ]: 1 : && (t->content == "string" || t->content == "long")))
[ + - ][ + - ]
2146 [ + - ][ + - ]: 2 : throw parse_error (_("expected identifier"));
2147 : :
2148 [ + + ]: 18589757 : for (unsigned i=0; i<functions.size(); i++)
2149 [ + - ][ + + ]: 17315942 : if (functions[i]->name == t->content)
2150 [ + - ][ + - ]: 1 : throw parse_error (_("duplicate function name"));
2151 : :
2152 [ + - ][ + - ]: 1273815 : functiondecl *fd = new functiondecl ();
2153 [ + - ]: 1273815 : fd->name = t->content;
2154 : 1273815 : fd->tok = t;
2155 : :
2156 [ + - ]: 1273815 : t = next ();
2157 [ + - ][ + - ]: 1273815 : if (t->type == tok_operator && t->content == ":")
[ + + ][ + + ]
2158 : : {
2159 [ + - ]: 1012715 : swallow ();
2160 [ + - ]: 1012715 : t = next ();
2161 [ + + ][ + - ]: 1012715 : if (t->type == tok_keyword && t->content == "string")
[ + + ][ + + ]
2162 : 325332 : fd->type = pe_string;
2163 [ + + ][ + - ]: 687383 : else if (t->type == tok_keyword && t->content == "long")
[ + - ][ + + ]
2164 : 687382 : fd->type = pe_long;
2165 [ + - ][ + - ]: 1 : else throw parse_error (_("expected 'string' or 'long'"));
2166 [ + - ]: 1012714 : swallow ();
2167 : :
2168 [ + - ]: 1012714 : t = next ();
2169 : : }
2170 : :
2171 [ + - ][ + - ]: 1273814 : if (! (t->type == tok_operator && t->content == "("))
[ + + ][ + + ]
2172 [ + - ][ + - ]: 1 : throw parse_error (_("expected '('"));
2173 [ + - ]: 1273813 : swallow ();
2174 : :
2175 : 222088 : while (1)
2176 : : {
2177 [ + - ]: 1495901 : t = next ();
2178 : :
2179 : : // permit zero-argument functions
2180 [ + + ][ + - ]: 1495901 : if (t->type == tok_operator && t->content == ")")
[ + + ][ + + ]
2181 : : {
2182 [ + - ]: 222245 : swallow ();
2183 : : break;
2184 : : }
2185 [ + + ]: 1273656 : else if (! (t->type == tok_identifier))
2186 [ + - ][ + - ]: 1 : throw parse_error (_("expected identifier"));
2187 [ + - ][ + - ]: 1273655 : vardecl* vd = new vardecl;
2188 [ + - ]: 1273655 : vd->name = t->content;
2189 : 1273655 : vd->tok = t;
2190 [ + - ]: 1273655 : fd->formal_args.push_back (vd);
2191 : 1273655 : fd->systemtap_v_conditional = systemtap_v_seen;
2192 : :
2193 [ + - ]: 1273655 : t = next ();
2194 [ + + ][ + - ]: 1273655 : if (t->type == tok_operator && t->content == ":")
[ + + ][ + + ]
2195 : : {
2196 [ + - ]: 1122669 : swallow ();
2197 [ + - ]: 1122669 : t = next ();
2198 [ + + ][ + - ]: 1122669 : if (t->type == tok_keyword && t->content == "string")
[ + + ][ + + ]
2199 : 146521 : vd->type = pe_string;
2200 [ + + ][ + - ]: 976148 : else if (t->type == tok_keyword && t->content == "long")
[ + - ][ + + ]
2201 : 976147 : vd->type = pe_long;
2202 [ + - ][ + - ]: 1 : else throw parse_error (_("expected 'string' or 'long'"));
2203 [ + - ]: 1122668 : swallow ();
2204 [ + - ]: 1122668 : t = next ();
2205 : : }
2206 [ + + ][ + - ]: 1273654 : if (t->type == tok_operator && t->content == ")")
[ + + ][ + + ]
2207 : : {
2208 [ + - ]: 1051565 : swallow ();
2209 : : break;
2210 : : }
2211 [ + + ][ + - ]: 222089 : if (t->type == tok_operator && t->content == ",")
[ + - ][ + + ]
2212 : : {
2213 [ + - ]: 222088 : swallow ();
2214 : 222088 : continue;
2215 : : }
2216 : : else
2217 [ + - ][ + - ]: 28 : throw parse_error (_("expected ',' or ')'"));
2218 : : }
2219 : :
2220 [ + - ]: 1273810 : t = peek ();
2221 [ + - ][ + + ]: 1273810 : if (t && t->type == tok_embedded)
2222 [ + + ]: 579675 : fd->body = parse_embeddedcode ();
2223 : : else
2224 [ + + ]: 694135 : fd->body = parse_stmt_block ();
2225 : :
2226 [ + - ]: 1273790 : functions.push_back (fd);
2227 : 1273790 : }
2228 : :
2229 : :
2230 : : probe_point*
2231 : 11005173 : parser::parse_probe_point ()
2232 : : {
2233 [ + - ]: 11005173 : probe_point* pl = new probe_point;
2234 : :
2235 : 18777247 : while (1)
2236 : : {
2237 [ + + ]: 29782420 : const token* t = next ();
2238 [ + + ]: 29782418 : if (! (t->type == tok_identifier
2239 : : // we must allow ".return" and ".function", which are keywords
2240 : : || t->type == tok_keyword
2241 : : // we must allow "*", due to being an operator
2242 [ + + ][ + + ]: 29782418 : || (t->type == tok_operator && t->content == "*")))
[ + - ][ + - ]
[ + + ]
2243 [ + - ][ + - ]: 8 : throw parse_error (_("expected identifier or '*'"));
2244 : :
2245 : : // loop which reconstitutes an identifier with wildcards
2246 [ + - ]: 29782410 : string content = t->content;
2247 : 301 : while (1)
2248 : : {
2249 [ + - ]: 29782711 : const token* u = peek();
2250 : : // ensure pieces of the identifier are adjacent:
2251 [ + + ]: 29782711 : if (input.ate_whitespace)
2252 : 8424063 : break;
2253 : : // ensure pieces of the identifier are valid:
2254 [ + + ]: 21358648 : if (! (u->type == tok_identifier
2255 : : // we must allow arbitrary keywords with a wildcard
2256 : : || u->type == tok_keyword
2257 : : // we must allow "*", due to being an operator
2258 [ + + ][ + - ]: 21358648 : || (u->type == tok_operator && u->content == "*")))
[ + - ][ + - ]
[ + + ]
2259 : 21358347 : break;
2260 : :
2261 : : // append u to t
2262 [ + - ][ + - ]: 301 : content = content + u->content;
[ + - ]
2263 : :
2264 : : // consume u
2265 [ + - ]: 301 : swallow ();
2266 : : }
2267 : : // get around const-ness of t:
2268 [ + - ][ + - ]: 29782410 : token* new_t = new token(*t);
2269 [ + - ]: 29782410 : new_t->content = content;
2270 [ + - ][ + - ]: 29782410 : delete t; t = new_t;
2271 : :
2272 [ + - ][ + - ]: 29782410 : probe_point::component* c = new probe_point::component;
2273 [ + - ]: 29782410 : c->functor = t->content;
2274 : 29782410 : c->tok = t;
2275 [ + - ]: 29782410 : pl->components.push_back (c);
2276 : : // NB we may add c->arg soon
2277 : :
2278 [ + - ]: 29782410 : t = peek ();
2279 : :
2280 : : // consume optional parameter
2281 [ + - ][ + + ]: 29782410 : if (t && t->type == tok_operator && t->content == "(")
[ + - ][ + + ]
[ + + ]
2282 : : {
2283 [ + - ]: 6704177 : swallow (); // consume "("
2284 [ + + ]: 6704177 : c->arg = parse_literal ();
2285 : :
2286 [ + - ]: 6704167 : t = next ();
2287 [ + + ][ + - ]: 6704167 : if (! (t->type == tok_operator && t->content == ")"))
[ + + ][ + + ]
2288 [ + - ][ + - ]: 3 : throw parse_error (_("expected ')'"));
2289 [ + - ]: 6704164 : swallow ();
2290 : :
2291 [ + - ]: 6704164 : t = peek ();
2292 : : }
2293 : :
2294 [ + - ][ + + ]: 29782397 : if (t && t->type == tok_operator && t->content == ".")
[ + - ][ + + ]
[ + + ]
2295 : : {
2296 [ + - ]: 18777247 : swallow ();
2297 : 18777247 : continue;
2298 : : }
2299 : :
2300 : : // We only fall through here at the end of a probe point (past
2301 : : // all the dotted/parametrized components).
2302 : :
2303 [ + - ][ + + ]: 29132414 : if (t && t->type == tok_operator &&
[ + + ][ + + ]
[ + + ]
2304 [ + - ][ + - ]: 18127264 : (t->content == "?" || t->content == "!"))
2305 : : {
2306 : 4598142 : pl->optional = true;
2307 [ + - ][ + + ]: 4598142 : if (t->content == "!") pl->sufficient = true;
2308 : : // NB: sufficient implies optional
2309 [ + - ]: 4598142 : swallow ();
2310 [ + - ]: 4598142 : t = peek ();
2311 : : // fall through
2312 : : }
2313 : :
2314 [ + - ][ + + ]: 11005150 : if (t && t->type == tok_keyword && t->content == "if")
[ + - ][ + - ]
[ + + ]
2315 : : {
2316 [ + - ]: 59 : swallow ();
2317 [ + - ]: 59 : t = peek ();
2318 [ + + ][ + - ]: 59 : if (!(t && t->type == tok_operator && t->content == "("))
[ + - ][ - + ]
[ + + ]
2319 [ + - ][ + - ]: 1 : throw parse_error (_("expected '('"));
2320 [ + - ]: 58 : swallow ();
2321 : :
2322 [ + - ]: 58 : pl->condition = parse_expression ();
2323 : :
2324 [ + - ]: 58 : t = peek ();
2325 [ + - ][ + - ]: 58 : if (!(t && t->type == tok_operator && t->content == ")"))
[ + - ][ + + ]
[ + + ]
2326 [ + - ][ + - ]: 1 : throw parse_error (_("expected ')'"));
2327 [ + - ]: 57 : swallow ();
2328 [ + - ]: 57 : t = peek ();
2329 : : // fall through
2330 : : }
2331 : :
2332 [ + - ][ + + ]: 32994661 : if (t && t->type == tok_operator
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ]
2333 [ + - ][ + - ]: 17650117 : && (t->content == "{" || t->content == "," ||
2334 [ + - ][ + - ]: 4339396 : t->content == "=" || t->content == "+=" ))
2335 : : break;
2336 : :
2337 [ + - ][ + - ]: 7 : throw parse_error (_("expected one of '. , ( ? ! { = +='"));
2338 [ + - ][ + + ]: 29782420 : }
2339 : :
2340 : 11005141 : return pl;
2341 : : }
2342 : :
2343 : :
2344 : : literal_string*
2345 : 12858457 : parser::consume_string_literals(const token *t)
2346 : : {
2347 [ + - ]: 12858457 : literal_string *ls = new literal_string (t->content);
2348 : :
2349 : : // PR11208: check if the next token is also a string literal;
2350 : : // auto-concatenate it. This is complicated to the extent that we
2351 : : // need to skip intermediate whitespace.
2352 : : //
2353 : : // NB for versions prior to 2.0: but don't skip over intervening comments
2354 : 12858457 : const token *n = peek();
2355 [ + + ]: 12858529 : while (n != NULL && n->type == tok_string
[ + + + + ]
[ + + ]
2356 : 36 : && ! (strverscmp(session.compatible.c_str(), "2.0") < 0
2357 [ - + ]: 1 : && input.ate_comment))
2358 : : {
2359 : 35 : ls->value.append(next()->content); // consume and append the token
2360 : 35 : n = peek();
2361 : : }
2362 : 12858457 : return ls;
2363 : : }
2364 : :
2365 : :
2366 : : // Parse a string literal and perform backslash escaping on the contents:
2367 : : literal_string*
2368 : 60 : parser::parse_literal_string ()
2369 : : {
2370 : 60 : const token* t = next ();
2371 : : literal_string* l;
2372 [ + + ]: 60 : if (t->type == tok_string)
2373 : 55 : l = consume_string_literals (t);
2374 : : else
2375 [ + - ][ + - ]: 5 : throw parse_error (_("expected literal string"));
2376 : :
2377 : 55 : l->tok = t;
2378 : 55 : return l;
2379 : : }
2380 : :
2381 : :
2382 : : literal*
2383 : 21064469 : parser::parse_literal ()
2384 : : {
2385 : 21064469 : const token* t = next ();
2386 : : literal* l;
2387 [ + + ]: 21064469 : if (t->type == tok_string)
2388 : : {
2389 : 12858402 : l = consume_string_literals (t);
2390 : : }
2391 : : else
2392 : : {
2393 : 8206067 : bool neg = false;
2394 [ + + ][ + + ]: 8206067 : if (t->type == tok_operator && t->content == "-")
[ + + ]
2395 : : {
2396 : 4378 : neg = true;
2397 : 4378 : swallow ();
2398 : 4378 : t = next ();
2399 : : }
2400 : :
2401 [ + + ]: 8206067 : if (t->type == tok_number)
2402 : : {
2403 [ + - ]: 8206055 : const char* startp = t->content.c_str ();
2404 : 8206055 : char* endp = (char*) startp;
2405 : :
2406 : : // NB: we allow controlled overflow from LLONG_MIN .. ULLONG_MAX
2407 : : // Actually, this allows all the way from -ULLONG_MAX to ULLONG_MAX,
2408 : : // since the lexer only gives us positive digit strings, but we'll
2409 : : // limit it to LLONG_MIN when a '-' operator is fed into the literal.
2410 : 8206055 : errno = 0;
2411 : 8206055 : long long value = (long long) strtoull (startp, & endp, 0);
2412 [ + + ][ + - ]: 8206055 : if (errno == ERANGE || errno == EINVAL || *endp != '\0'
[ + + ][ + + ]
[ - + ]
2413 : : || (neg && (unsigned long long) value > 9223372036854775808ULL)
2414 : : || (unsigned long long) value > 18446744073709551615ULL
2415 : : || value < -9223372036854775807LL-1)
2416 [ + - ][ + - ]: 5 : throw parse_error (_("number invalid or out of range"));
2417 : :
2418 [ + + ]: 8206050 : if (neg)
2419 : 4378 : value = -value;
2420 : :
2421 [ + - ][ + - ]: 8206055 : l = new literal_number (value);
2422 : : }
2423 : : else
2424 [ + - ][ + - ]: 12 : throw parse_error (_("expected literal string or number"));
2425 : : }
2426 : :
2427 : 21064452 : l->tok = t;
2428 : 21064452 : return l;
2429 : : }
2430 : :
2431 : :
2432 : : if_statement*
2433 : 2102453 : parser::parse_if_statement ()
2434 : : {
2435 : 2102453 : const token* t = next ();
2436 [ + - ][ - + ]: 2102453 : if (! (t->type == tok_keyword && t->content == "if"))
[ - + ]
2437 [ # # ][ # # ]: 0 : throw parse_error (_("expected 'if'"));
2438 [ + - ]: 2102453 : if_statement* s = new if_statement;
2439 : 2102453 : s->tok = t;
2440 : :
2441 : 2102453 : t = next ();
2442 [ + + ][ - + ]: 2102453 : if (! (t->type == tok_operator && t->content == "("))
[ + + ]
2443 [ + - ][ + - ]: 1 : throw parse_error (_("expected '('"));
2444 : 2102452 : swallow ();
2445 : :
2446 : 2102452 : s->condition = parse_expression ();
2447 : :
2448 : 2102451 : t = next ();
2449 [ + + ][ - + ]: 2102451 : if (! (t->type == tok_operator && t->content == ")"))
[ + + ]
2450 [ + - ][ + - ]: 1 : throw parse_error (_("expected ')'"));
2451 : 2102450 : swallow ();
2452 : :
2453 : 2102450 : s->thenblock = parse_statement ();
2454 : :
2455 : 2102450 : t = peek ();
2456 [ + - ][ + + ]: 2102450 : if (t && t->type == tok_keyword && t->content == "else")
[ + + ][ + + ]
2457 : : {
2458 : 368822 : swallow ();
2459 : 368822 : s->elseblock = parse_statement ();
2460 : : }
2461 : : else
2462 : 1733628 : s->elseblock = 0; // in case not otherwise initialized
2463 : :
2464 : 2102450 : return s;
2465 : : }
2466 : :
2467 : :
2468 : : expr_statement*
2469 : 20052787 : parser::parse_expr_statement ()
2470 : : {
2471 [ + - ]: 20052787 : expr_statement *es = new expr_statement;
2472 : 20052787 : const token* t = peek ();
2473 : : // Copy, we only peeked, parse_expression might swallow.
2474 [ + - ]: 20052787 : es->tok = new token (*t);
2475 : 20052787 : es->value = parse_expression ();
2476 : 20052769 : return es;
2477 : : }
2478 : :
2479 : :
2480 : : return_statement*
2481 : 1753741 : parser::parse_return_statement ()
2482 : : {
2483 : 1753741 : const token* t = next ();
2484 [ + - ][ - + ]: 1753741 : if (! (t->type == tok_keyword && t->content == "return"))
[ - + ]
2485 [ # # ][ # # ]: 0 : throw parse_error (_("expected 'return'"));
2486 [ + + ]: 1753741 : if (context != con_function)
2487 [ + - ][ + - ]: 1 : throw parse_error (_("found 'return' not in function context"));
2488 [ + - ]: 1753740 : return_statement* s = new return_statement;
2489 : 1753740 : s->tok = t;
2490 : 1753740 : s->value = parse_expression ();
2491 : 1753740 : return s;
2492 : : }
2493 : :
2494 : :
2495 : : delete_statement*
2496 : 28254 : parser::parse_delete_statement ()
2497 : : {
2498 : 28254 : const token* t = next ();
2499 [ + - ][ - + ]: 28254 : if (! (t->type == tok_keyword && t->content == "delete"))
[ - + ]
2500 [ # # ][ # # ]: 0 : throw parse_error (_("expected 'delete'"));
2501 [ + - ]: 28254 : delete_statement* s = new delete_statement;
2502 : 28254 : s->tok = t;
2503 : 28254 : s->value = parse_expression ();
2504 : 28254 : return s;
2505 : : }
2506 : :
2507 : :
2508 : : next_statement*
2509 : 62712 : parser::parse_next_statement ()
2510 : : {
2511 : 62712 : const token* t = next ();
2512 [ + - ][ - + ]: 62712 : if (! (t->type == tok_keyword && t->content == "next"))
[ - + ]
2513 [ # # ][ # # ]: 0 : throw parse_error (_("expected 'next'"));
2514 [ + + ]: 62712 : if (context != con_probe)
2515 [ + - ][ + - ]: 1 : throw parse_error (_("found 'next' not in probe context"));
2516 [ + - ]: 62711 : next_statement* s = new next_statement;
2517 : 62711 : s->tok = t;
2518 : 62711 : return s;
2519 : : }
2520 : :
2521 : :
2522 : : break_statement*
2523 : 19431 : parser::parse_break_statement ()
2524 : : {
2525 : 19431 : const token* t = next ();
2526 [ + - ][ - + ]: 19431 : if (! (t->type == tok_keyword && t->content == "break"))
[ - + ]
2527 [ # # ][ # # ]: 0 : throw parse_error (_("expected 'break'"));
2528 [ + - ]: 19431 : break_statement* s = new break_statement;
2529 : 19431 : s->tok = t;
2530 : 19431 : return s;
2531 : : }
2532 : :
2533 : :
2534 : : continue_statement*
2535 : 2223 : parser::parse_continue_statement ()
2536 : : {
2537 : 2223 : const token* t = next ();
2538 [ + - ][ - + ]: 2223 : if (! (t->type == tok_keyword && t->content == "continue"))
[ - + ]
2539 [ # # ][ # # ]: 0 : throw parse_error (_("expected 'continue'"));
2540 [ + - ]: 2223 : continue_statement* s = new continue_statement;
2541 : 2223 : s->tok = t;
2542 : 2223 : return s;
2543 : : }
2544 : :
2545 : :
2546 : : for_loop*
2547 : 6823 : parser::parse_for_loop ()
2548 : : {
2549 : 6823 : const token* t = next ();
2550 [ + - ][ - + ]: 6823 : if (! (t->type == tok_keyword && t->content == "for"))
[ - + ]
2551 [ # # ][ # # ]: 0 : throw parse_error (_("expected 'for'"));
2552 [ + - ]: 6823 : for_loop* s = new for_loop;
2553 : 6823 : s->tok = t;
2554 : :
2555 : 6823 : t = next ();
2556 [ + + ][ - + ]: 6823 : if (! (t->type == tok_operator && t->content == "("))
[ + + ]
2557 [ + - ][ + - ]: 1 : throw parse_error (_("expected '('"));
2558 : 6822 : swallow ();
2559 : :
2560 : : // initializer + ";"
2561 : 6822 : t = peek ();
2562 [ + - ][ + + ]: 6822 : if (t && t->type == tok_operator && t->content == ";")
[ + + ][ + + ]
2563 : : {
2564 : 34 : s->init = 0;
2565 : 34 : swallow ();
2566 : : }
2567 : : else
2568 : : {
2569 : 6788 : s->init = parse_expr_statement ();
2570 : 6788 : t = next ();
2571 [ + - ][ + + ]: 6788 : if (! (t->type == tok_operator && t->content == ";"))
[ + + ]
2572 [ + - ][ + - ]: 1 : throw parse_error (_("expected ';'"));
2573 : 6787 : swallow ();
2574 : : }
2575 : :
2576 : : // condition + ";"
2577 : 6821 : t = peek ();
2578 [ + - ][ + + ]: 6821 : if (t && t->type == tok_operator && t->content == ";")
[ + + ][ + + ]
2579 : : {
2580 [ + - ]: 16 : literal_number* l = new literal_number(1);
2581 : 16 : s->cond = l;
2582 : 16 : s->cond->tok = next ();
2583 : : }
2584 : : else
2585 : : {
2586 : 6805 : s->cond = parse_expression ();
2587 : 6805 : t = next ();
2588 [ + - ][ + + ]: 6805 : if (! (t->type == tok_operator && t->content == ";"))
[ + + ]
2589 [ + - ][ + - ]: 1 : throw parse_error (_("expected ';'"));
2590 : 6804 : swallow ();
2591 : : }
2592 : :
2593 : : // increment + ")"
2594 : 6820 : t = peek ();
2595 [ + - ][ + + ]: 6820 : if (t && t->type == tok_operator && t->content == ")")
[ + + ][ + + ]
2596 : : {
2597 : 38 : s->incr = 0;
2598 : 38 : swallow ();
2599 : : }
2600 : : else
2601 : : {
2602 : 6782 : s->incr = parse_expr_statement ();
2603 : 6782 : t = next ();
2604 [ + + ][ - + ]: 6782 : if (! (t->type == tok_operator && t->content == ")"))
[ + + ]
2605 [ + - ][ + - ]: 1 : throw parse_error (_("expected ')'"));
2606 : 6781 : swallow ();
2607 : : }
2608 : :
2609 : : // block
2610 : 6819 : s->block = parse_statement ();
2611 : :
2612 : 6819 : return s;
2613 : : }
2614 : :
2615 : :
2616 : : for_loop*
2617 : 25920 : parser::parse_while_loop ()
2618 : : {
2619 : 25920 : const token* t = next ();
2620 [ + - ][ - + ]: 25920 : if (! (t->type == tok_keyword && t->content == "while"))
[ - + ]
2621 [ # # ][ # # ]: 0 : throw parse_error (_("expected 'while'"));
2622 [ + - ]: 25920 : for_loop* s = new for_loop;
2623 : 25920 : s->tok = t;
2624 : :
2625 : 25920 : t = next ();
2626 [ + + ][ - + ]: 25920 : if (! (t->type == tok_operator && t->content == "("))
[ + + ]
2627 [ + - ][ + - ]: 1 : throw parse_error (_("expected '('"));
2628 : 25919 : swallow ();
2629 : :
2630 : : // dummy init and incr fields
2631 : 25919 : s->init = 0;
2632 : 25919 : s->incr = 0;
2633 : :
2634 : : // condition
2635 : 25919 : s->cond = parse_expression ();
2636 : :
2637 : 25919 : t = next ();
2638 [ + + ][ - + ]: 25919 : if (! (t->type == tok_operator && t->content == ")"))
[ + + ]
2639 [ + - ][ + - ]: 1 : throw parse_error (_("expected ')'"));
2640 : 25918 : swallow ();
2641 : :
2642 : : // block
2643 : 25918 : s->block = parse_statement ();
2644 : :
2645 : 25918 : return s;
2646 : : }
2647 : :
2648 : :
2649 : : foreach_loop*
2650 : 17574 : parser::parse_foreach_loop ()
2651 : : {
2652 [ + - ]: 17574 : const token* t = next ();
2653 [ + - ][ + - ]: 17574 : if (! (t->type == tok_keyword && t->content == "foreach"))
[ - + ][ - + ]
2654 [ # # ][ # # ]: 0 : throw parse_error (_("expected 'foreach'"));
2655 [ + - ][ + - ]: 17574 : foreach_loop* s = new foreach_loop;
2656 : 17574 : s->tok = t;
2657 : 17574 : s->sort_direction = 0;
2658 : 17574 : s->sort_aggr = sc_none;
2659 : 17574 : s->value = NULL;
2660 : 17574 : s->limit = NULL;
2661 : :
2662 [ + - ]: 17574 : t = next ();
2663 [ + + ][ + - ]: 17574 : if (! (t->type == tok_operator && t->content == "("))
[ - + ][ + + ]
2664 [ + - ][ + - ]: 1 : throw parse_error (_("expected '('"));
2665 [ + - ]: 17573 : swallow ();
2666 : :
2667 : 17573 : symbol* lookahead_sym = NULL;
2668 : 17573 : int lookahead_sort = 0;
2669 : :
2670 [ + - ]: 17573 : t = peek ();
2671 [ + - ][ + + ]: 17573 : if (t && t->type == tok_identifier)
2672 : : {
2673 [ + - ]: 10984 : next ();
2674 [ + - ][ + - ]: 10984 : lookahead_sym = new symbol;
2675 : 10984 : lookahead_sym->tok = t;
2676 [ + - ]: 10984 : lookahead_sym->name = t->content;
2677 : :
2678 [ + - ]: 10984 : t = peek ();
2679 [ + - ][ + + ]: 11029 : if (t && t->type == tok_operator &&
[ + + ][ + + ]
[ + + ]
2680 [ + - ][ + - ]: 45 : (t->content == "+" || t->content == "-"))
2681 : : {
2682 [ + - ][ + + ]: 23 : lookahead_sort = (t->content == "+") ? 1 : -1;
2683 [ + - ]: 23 : swallow ();
2684 : : }
2685 : :
2686 [ + - ]: 10984 : t = peek ();
2687 [ + - ][ + + ]: 10984 : if (t && t->type == tok_operator && t->content == "=")
[ + - ][ + + ]
[ + + ]
2688 : : {
2689 [ + - ]: 10 : swallow ();
2690 : 10 : s->value = lookahead_sym;
2691 [ + + ]: 10 : if (lookahead_sort)
2692 : : {
2693 : 2 : s->sort_direction = lookahead_sort;
2694 : 2 : s->sort_column = 0;
2695 : : }
2696 : 10 : lookahead_sym = NULL;
2697 : : }
2698 : : }
2699 : :
2700 : : // see also parse_array_in
2701 : :
2702 : 17573 : bool parenthesized = false;
2703 [ + - ]: 17573 : t = peek ();
2704 [ + + ][ + - ]: 17573 : if (!lookahead_sym && t && t->type == tok_operator && t->content == "[")
[ + + ][ + - ]
[ + + ][ + + ]
2705 : : {
2706 [ + - ]: 6589 : swallow ();
2707 : 6589 : parenthesized = true;
2708 : : }
2709 : :
2710 [ + + ]: 17573 : if (lookahead_sym)
2711 : : {
2712 [ + - ]: 10974 : s->indexes.push_back (lookahead_sym);
2713 [ + + ]: 10974 : if (lookahead_sort)
2714 : : {
2715 : 21 : s->sort_direction = lookahead_sort;
2716 : 21 : s->sort_column = 1;
2717 : : }
2718 : 10974 : lookahead_sym = NULL;
2719 : : }
2720 : 6627 : else while (1)
2721 : : {
2722 [ + - ]: 13226 : t = next ();
2723 [ + + ]: 13226 : if (! (t->type == tok_identifier))
2724 [ + - ][ + - ]: 1 : throw parse_error (_("expected identifier"));
2725 [ + - ][ + - ]: 13225 : symbol* sym = new symbol;
2726 : 13225 : sym->tok = t;
2727 [ + - ]: 13225 : sym->name = t->content;
2728 [ + - ]: 13225 : s->indexes.push_back (sym);
2729 : :
2730 [ + - ]: 13225 : t = peek ();
2731 [ + - ][ + + ]: 37484 : if (t && t->type == tok_operator &&
[ + + ][ + + ]
[ + + ]
2732 [ + - ][ + - ]: 24259 : (t->content == "+" || t->content == "-"))
2733 : : {
2734 [ + + ]: 2181 : if (s->sort_direction)
2735 [ + - ][ + - ]: 1 : throw parse_error (_("multiple sort directives"));
2736 [ + - ][ + + ]: 2180 : s->sort_direction = (t->content == "+") ? 1 : -1;
2737 : 2180 : s->sort_column = s->indexes.size();
2738 [ + - ]: 2180 : swallow ();
2739 : : }
2740 : :
2741 [ + + ]: 13224 : if (parenthesized)
2742 : : {
2743 [ + - ]: 13215 : t = peek ();
2744 [ + - ][ + + ]: 13215 : if (t && t->type == tok_operator && t->content == ",")
[ + - ][ + + ]
[ + + ]
2745 : : {
2746 [ + - ]: 6627 : swallow ();
2747 : 6627 : continue;
2748 : : }
2749 [ + - ][ + + ]: 6588 : else if (t && t->type == tok_operator && t->content == "]")
[ + - ][ + - ]
[ + + ]
2750 : : {
2751 [ + - ]: 6587 : swallow ();
2752 : : break;
2753 : : }
2754 : : else
2755 [ + - ][ + - ]: 6599 : throw parse_error (_("expected ',' or ']'"));
2756 : : }
2757 : : else
2758 : : break; // expecting only one expression
2759 : : }
2760 : :
2761 [ + - ]: 17570 : t = next ();
2762 [ + + ][ + - ]: 17570 : if (! (t->type == tok_keyword && t->content == "in"))
[ - + ][ + + ]
2763 [ + - ][ + - ]: 1 : throw parse_error (_("expected 'in'"));
2764 [ + - ]: 17569 : swallow ();
2765 : :
2766 [ + + ]: 17569 : s->base = parse_indexable();
2767 : :
2768 : : // check for atword, see also expect_ident_or_atword,
2769 [ + - ]: 17568 : t = peek ();
2770 [ + - ][ + + ]: 17568 : if (t && t->type == tok_operator && t->content[0] == '@')
[ + - ][ + + ]
[ + + ]
2771 : : {
2772 [ + - ][ + + ]: 16 : if (t->content == "@avg") s->sort_aggr = sc_average;
2773 [ + - ][ + + ]: 14 : else if (t->content == "@min") s->sort_aggr = sc_min;
2774 [ + - ][ + + ]: 12 : else if (t->content == "@max") s->sort_aggr = sc_max;
2775 [ + - ][ + + ]: 10 : else if (t->content == "@count") s->sort_aggr = sc_count;
2776 [ + - ][ + + ]: 8 : else if (t->content == "@sum") s->sort_aggr = sc_sum;
2777 [ + - ][ + - ]: 1 : else throw parse_error(_("expected statistical operation"));
2778 [ + - ]: 15 : swallow();
2779 : :
2780 [ + - ]: 15 : t = peek ();
2781 [ + - ][ + - ]: 15 : if (! (t && t->type == tok_operator && (t->content == "+" || t->content == "-")))
[ + - ][ + + ]
[ + - ][ + + ]
[ + + ]
2782 [ + - ][ + - ]: 1 : throw parse_error(_("expected sort directive"));
2783 : : }
2784 : :
2785 [ + - ]: 17566 : t = peek ();
2786 [ + - ][ + + ]: 50467 : if (t && t->type == tok_operator &&
[ + + ][ + + ]
[ + + ]
2787 [ + - ][ + - ]: 32901 : (t->content == "+" || t->content == "-"))
2788 : : {
2789 [ + + ]: 2273 : if (s->sort_direction)
2790 [ + - ][ + - ]: 1 : throw parse_error (_("multiple sort directives"));
2791 [ + - ][ + + ]: 2272 : s->sort_direction = (t->content == "+") ? 1 : -1;
2792 : 2272 : s->sort_column = 0;
2793 [ + - ]: 2272 : swallow ();
2794 : : }
2795 : :
2796 [ + - ]: 17565 : t = peek ();
2797 [ + - ][ + - ]: 17565 : if (tok_is(t, tok_keyword, "limit"))
[ + - ][ + + ]
2798 : : {
2799 [ + - ]: 77 : swallow (); // get past the "limit"
2800 [ + + ]: 77 : s->limit = parse_expression ();
2801 : : }
2802 : :
2803 [ + - ]: 17564 : t = next ();
2804 [ + + ][ + - ]: 17564 : if (! (t->type == tok_operator && t->content == ")"))
[ - + ][ + + ]
2805 [ + - ][ + - ]: 12 : throw parse_error ("expected ')'");
2806 [ + - ]: 17562 : swallow ();
2807 : :
2808 [ + - ]: 17562 : s->block = parse_statement ();
2809 : 17562 : return s;
2810 : : }
2811 : :
2812 : :
2813 : : expression*
2814 : 64679728 : parser::parse_expression ()
2815 : : {
2816 : 64679728 : return parse_assignment ();
2817 : : }
2818 : :
2819 : :
2820 : : expression*
2821 : 64679728 : parser::parse_assignment ()
2822 : : {
2823 : 64679728 : expression* op1 = parse_ternary ();
2824 : :
2825 : 64679707 : const token* t = peek ();
2826 : : // right-associative operators
2827 [ + - ][ + + : 466436601 : if (t && t->type == tok_operator
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ ][ + + ]
2828 : 48631486 : && (t->content == "=" ||
2829 : 29520189 : t->content == "<<<" ||
2830 : 29513476 : t->content == "+=" ||
2831 : 29422827 : t->content == "-=" ||
2832 : 29418492 : t->content == "*=" ||
2833 : 29418467 : t->content == "/=" ||
2834 : 29418446 : t->content == "%=" ||
2835 : 29418431 : t->content == "<<=" ||
2836 : 29418420 : t->content == ">>=" ||
2837 : 29418411 : t->content == "&=" ||
2838 : 29386092 : t->content == "^=" ||
2839 : 29386083 : t->content == "|=" ||
2840 : 29386074 : t->content == ".=" ||
2841 : : false))
2842 : : {
2843 : : // NB: lvalueness is checked during elaboration / translation
2844 [ + - ]: 19273449 : assignment* e = new assignment;
2845 : 19273449 : e->left = op1;
2846 : 19273449 : e->op = t->content;
2847 : 19273449 : e->tok = t;
2848 : 19273449 : next ();
2849 : 19273449 : e->right = parse_expression ();
2850 : 19273441 : op1 = e;
2851 : : }
2852 : :
2853 : 64679699 : return op1;
2854 : : }
2855 : :
2856 : :
2857 : : expression*
2858 : 64679728 : parser::parse_ternary ()
2859 : : {
2860 : 64679728 : expression* op1 = parse_logical_or ();
2861 : :
2862 : 64679708 : const token* t = peek ();
2863 [ + - ][ + + ]: 64679708 : if (t && t->type == tok_operator && t->content == "?")
[ + + ][ + + ]
2864 : : {
2865 [ + - ]: 743414 : ternary_expression* e = new ternary_expression;
2866 : 743414 : e->tok = t;
2867 : 743414 : e->cond = op1;
2868 : 743414 : next ();
2869 : 743414 : e->truevalue = parse_expression (); // XXX
2870 : :
2871 : 743414 : t = next ();
2872 [ + - ][ + + ]: 743414 : if (! (t->type == tok_operator && t->content == ":"))
[ + + ]
2873 [ + - ][ + - ]: 1 : throw parse_error (_("expected ':'"));
2874 : 743413 : swallow ();
2875 : :
2876 : 743413 : e->falsevalue = parse_expression (); // XXX
2877 : 743413 : return e;
2878 : : }
2879 : : else
2880 : 64679707 : return op1;
2881 : : }
2882 : :
2883 : :
2884 : : expression*
2885 : 64679728 : parser::parse_logical_or ()
2886 : : {
2887 : 64679728 : expression* op1 = parse_logical_and ();
2888 : :
2889 : 64679708 : const token* t = peek ();
2890 [ + - ][ + + ]: 64707869 : while (t && t->type == tok_operator && t->content == "||")
[ + + ][ + + ]
2891 : : {
2892 [ + - ]: 28161 : logical_or_expr* e = new logical_or_expr;
2893 : 28161 : e->tok = t;
2894 : 28161 : e->op = t->content;
2895 : 28161 : e->left = op1;
2896 : 28161 : next ();
2897 : 28161 : e->right = parse_logical_and ();
2898 : 28161 : op1 = e;
2899 : 28161 : t = peek ();
2900 : : }
2901 : :
2902 : 64679708 : return op1;
2903 : : }
2904 : :
2905 : :
2906 : : expression*
2907 : 64707889 : parser::parse_logical_and ()
2908 : : {
2909 : 64707889 : expression* op1 = parse_boolean_or ();
2910 : :
2911 : 64707869 : const token* t = peek ();
2912 [ + - ][ + + ]: 64764094 : while (t && t->type == tok_operator && t->content == "&&")
[ + + ][ + + ]
2913 : : {
2914 [ + - ]: 56225 : logical_and_expr *e = new logical_and_expr;
2915 : 56225 : e->left = op1;
2916 : 56225 : e->op = t->content;
2917 : 56225 : e->tok = t;
2918 : 56225 : next ();
2919 : 56225 : e->right = parse_boolean_or ();
2920 : 56225 : op1 = e;
2921 : 56225 : t = peek ();
2922 : : }
2923 : :
2924 : 64707869 : return op1;
2925 : : }
2926 : :
2927 : :
2928 : : expression*
2929 : 64764114 : parser::parse_boolean_or ()
2930 : : {
2931 : 64764114 : expression* op1 = parse_boolean_xor ();
2932 : :
2933 : 64764094 : const token* t = peek ();
2934 [ + - ][ + + ]: 64766267 : while (t && t->type == tok_operator && t->content == "|")
[ + + ][ + + ]
2935 : : {
2936 [ + - ]: 2173 : binary_expression* e = new binary_expression;
2937 : 2173 : e->left = op1;
2938 : 2173 : e->op = t->content;
2939 : 2173 : e->tok = t;
2940 : 2173 : next ();
2941 : 2173 : e->right = parse_boolean_xor ();
2942 : 2173 : op1 = e;
2943 : 2173 : t = peek ();
2944 : : }
2945 : :
2946 : 64764094 : return op1;
2947 : : }
2948 : :
2949 : :
2950 : : expression*
2951 : 64766287 : parser::parse_boolean_xor ()
2952 : : {
2953 : 64766287 : expression* op1 = parse_boolean_and ();
2954 : :
2955 : 64766267 : const token* t = peek ();
2956 [ + - ][ + + ]: 64766283 : while (t && t->type == tok_operator && t->content == "^")
[ + + ][ + + ]
2957 : : {
2958 [ + - ]: 16 : binary_expression* e = new binary_expression;
2959 : 16 : e->left = op1;
2960 : 16 : e->op = t->content;
2961 : 16 : e->tok = t;
2962 : 16 : next ();
2963 : 16 : e->right = parse_boolean_and ();
2964 : 16 : op1 = e;
2965 : 16 : t = peek ();
2966 : : }
2967 : :
2968 : 64766267 : return op1;
2969 : : }
2970 : :
2971 : :
2972 : : expression*
2973 : 64766303 : parser::parse_boolean_and ()
2974 : : {
2975 : 64766303 : expression* op1 = parse_array_in ();
2976 : :
2977 : 64766283 : const token* t = peek ();
2978 [ + - ][ + + ]: 65011925 : while (t && t->type == tok_operator && t->content == "&")
[ + + ][ + + ]
2979 : : {
2980 [ + - ]: 245642 : binary_expression* e = new binary_expression;
2981 : 245642 : e->left = op1;
2982 : 245642 : e->op = t->content;
2983 : 245642 : e->tok = t;
2984 : 245642 : next ();
2985 : 245642 : e->right = parse_array_in ();
2986 : 245642 : op1 = e;
2987 : 245642 : t = peek ();
2988 : : }
2989 : :
2990 : 64766283 : return op1;
2991 : : }
2992 : :
2993 : :
2994 : : expression*
2995 : 65011945 : parser::parse_array_in ()
2996 : : {
2997 : : // This is a very tricky case. All these are legit expressions:
2998 : : // "a in b" "a+0 in b" "[a,b] in c" "[c,(d+0)] in b"
2999 [ + - ]: 65011945 : vector<expression*> indexes;
3000 : 65011945 : bool parenthesized = false;
3001 : :
3002 [ + - ]: 65011945 : const token* t = peek ();
3003 [ + - ][ + + ]: 65011945 : if (t && t->type == tok_operator && t->content == "[")
[ + - ][ + + ]
[ + + ]
3004 : : {
3005 [ + - ]: 2217 : swallow ();
3006 : 2217 : parenthesized = true;
3007 : : }
3008 : :
3009 : 33 : while (1)
3010 : : {
3011 [ + + ]: 65011978 : expression* op1 = parse_comparison_or_regex_query ();
3012 [ + - ]: 65011958 : indexes.push_back (op1);
3013 : :
3014 [ + + ]: 65011958 : if (parenthesized)
3015 : : {
3016 [ + - ]: 2249 : const token* t = peek ();
3017 [ + - ][ + - ]: 2249 : if (t && t->type == tok_operator && t->content == ",")
[ + - ][ + + ]
[ + + ]
3018 : : {
3019 [ + - ]: 33 : swallow ();
3020 : 33 : continue;
3021 : : }
3022 [ + - ][ + - ]: 2216 : else if (t && t->type == tok_operator && t->content == "]")
[ + - ][ + - ]
[ + - ]
3023 : : {
3024 [ + - ]: 2216 : swallow ();
3025 : : break;
3026 : : }
3027 : : else
3028 [ # # ][ # # ]: 20 : throw parse_error (_("expected ',' or ']'"));
3029 : : }
3030 : : else
3031 : : break; // expecting only one expression
3032 : : }
3033 : :
3034 [ + - ]: 65011925 : t = peek ();
3035 [ + - ][ + + ]: 65011925 : if (t && t->type == tok_keyword && t->content == "in")
[ + - ][ + + ]
[ + + ]
3036 : : {
3037 [ + - ][ + - ]: 34629 : array_in *e = new array_in;
3038 : 34629 : e->tok = t;
3039 [ + - ]: 34629 : next ();
3040 : :
3041 [ + - ][ + - ]: 34629 : arrayindex* a = new arrayindex;
3042 [ + - ]: 34629 : a->indexes = indexes;
3043 [ + - ]: 34629 : a->base = parse_indexable();
3044 : 34629 : a->tok = a->base->tok;
3045 : 34629 : e->operand = a;
3046 : 34629 : return e;
3047 : : }
3048 [ + - ]: 64977296 : else if (indexes.size() == 1) // no "in" - need one expression only
3049 : 64977296 : return indexes[0];
3050 : : else
3051 [ # # ][ # # ]: 65011945 : throw parse_error (_("unexpected comma-separated expression list"));
[ + - ]
3052 : : }
3053 : :
3054 : :
3055 : : expression*
3056 : 65011978 : parser::parse_comparison_or_regex_query ()
3057 : : {
3058 : 65011978 : expression* op1 = parse_shift ();
3059 : :
3060 : : // TODOXXX for now, =~ is nonassociative
3061 : : // TODOXXX maybe instead a =~ b == c =~ d --> (a =~ b) == (c =~ d) ??
3062 : 65011962 : const token *t = peek();
3063 [ + - ][ + + : 163159080 : if (t && t->type == tok_operator
+ + + + ]
[ + + ]
3064 : 49073574 : && (t->content == "=~" ||
3065 : 49073544 : t->content == "!~"))
3066 : : {
3067 [ + - ]: 51 : regex_query* r = new regex_query;
3068 : 51 : r->left = op1;
3069 : 51 : r->op = t->content;
3070 : 51 : r->tok = t;
3071 : 51 : next ();
3072 : 51 : r->right = r->re = parse_literal_string();
3073 : 47 : op1 = r;
3074 : 47 : t = peek ();
3075 : : }
3076 [ + - ][ + + : 366504641 : else while (t && t->type == tok_operator
+ + + + +
+ + + + +
+ + ][ + + ]
3077 : 50871971 : && (t->content == ">" ||
3078 : 50721040 : t->content == "<" ||
3079 : 50662557 : t->content == "==" ||
3080 : 49231210 : t->content == "!=" ||
3081 : 49112381 : t->content == "<=" ||
3082 : 49095081 : t->content == ">="))
3083 : : {
3084 [ + - ]: 1798490 : comparison* e = new comparison;
3085 : 1798490 : e->left = op1;
3086 : 1798490 : e->op = t->content;
3087 : 1798490 : e->tok = t;
3088 : 1798490 : next ();
3089 : 1798490 : e->right = parse_shift ();
3090 : 1798490 : op1 = e;
3091 : 1798490 : t = peek ();
3092 : : }
3093 : :
3094 : 65011958 : return op1;
3095 : : }
3096 : :
3097 : :
3098 : : expression*
3099 : 66810468 : parser::parse_shift ()
3100 : : {
3101 : 66810468 : expression* op1 = parse_concatenation ();
3102 : :
3103 : 66810452 : const token* t = peek ();
3104 [ + - ][ + + : 168597725 : while (t && t->type == tok_operator &&
+ + + + ]
[ + + ]
3105 : 101769982 : (t->content == "<<" || t->content == ">>"))
3106 : : {
3107 [ + - ]: 17291 : binary_expression* e = new binary_expression;
3108 : 17291 : e->left = op1;
3109 : 17291 : e->op = t->content;
3110 : 17291 : e->tok = t;
3111 : 17291 : next ();
3112 : 17291 : e->right = parse_concatenation ();
3113 : 17291 : op1 = e;
3114 : 17291 : t = peek ();
3115 : : }
3116 : :
3117 : 66810452 : return op1;
3118 : : }
3119 : :
3120 : :
3121 : : expression*
3122 : 66827759 : parser::parse_concatenation ()
3123 : : {
3124 : 66827759 : expression* op1 = parse_additive ();
3125 : :
3126 : 66827743 : const token* t = peek ();
3127 : : // XXX: the actual awk string-concatenation operator is *whitespace*.
3128 : : // I don't know how to easily to model that here.
3129 [ + - ][ + + ]: 67026271 : while (t && t->type == tok_operator && t->content == ".")
[ + + ][ + + ]
3130 : : {
3131 [ + - ]: 198528 : concatenation* e = new concatenation;
3132 : 198528 : e->left = op1;
3133 : 198528 : e->op = t->content;
3134 : 198528 : e->tok = t;
3135 : 198528 : next ();
3136 : 198528 : e->right = parse_additive ();
3137 : 198528 : op1 = e;
3138 : 198528 : t = peek ();
3139 : : }
3140 : :
3141 : 66827743 : return op1;
3142 : : }
3143 : :
3144 : :
3145 : : expression*
3146 : 67026287 : parser::parse_additive ()
3147 : : {
3148 : 67026287 : expression* op1 = parse_multiplicative ();
3149 : :
3150 : 67026272 : const token* t = peek ();
3151 [ + - ][ + + : 169607498 : while (t && t->type == tok_operator
+ + + + ]
[ + + ]
3152 : 102420606 : && (t->content == "+" || t->content == "-"))
3153 : : {
3154 [ + - ]: 160621 : binary_expression* e = new binary_expression;
3155 : 160621 : e->op = t->content;
3156 : 160621 : e->left = op1;
3157 : 160621 : e->tok = t;
3158 : 160621 : next ();
3159 : 160621 : e->right = parse_multiplicative ();
3160 : 160620 : op1 = e;
3161 : 160620 : t = peek ();
3162 : : }
3163 : :
3164 : 67026271 : return op1;
3165 : : }
3166 : :
3167 : :
3168 : : expression*
3169 : 67186908 : parser::parse_multiplicative ()
3170 : : {
3171 : 67186908 : expression* op1 = parse_unary ();
3172 : :
3173 : 67186892 : const token* t = peek ();
3174 [ + - ][ + + : 221232781 : while (t && t->type == tok_operator
+ + + + +
+ ][ + + ]
3175 : 153944218 : && (t->content == "*" || t->content == "/" || t->content == "%"))
3176 : : {
3177 [ + - ]: 101671 : binary_expression* e = new binary_expression;
3178 : 101671 : e->op = t->content;
3179 : 101671 : e->left = op1;
3180 : 101671 : e->tok = t;
3181 : 101671 : next ();
3182 : 101671 : e->right = parse_unary ();
3183 : 101671 : op1 = e;
3184 : 101671 : t = peek ();
3185 : : }
3186 : :
3187 : 67186892 : return op1;
3188 : : }
3189 : :
3190 : :
3191 : : expression*
3192 : 67571349 : parser::parse_unary ()
3193 : : {
3194 : 67571349 : const token* t = peek ();
3195 [ + - ][ + + : 80982409 : if (t && t->type == tok_operator
+ + + + +
+ + + ]
[ + + ]
3196 : 3477920 : && (t->content == "+" ||
3197 : 3477895 : t->content == "-" ||
3198 : 3255749 : t->content == "!" ||
3199 : 3199496 : t->content == "~" ||
3200 : : false))
3201 : : {
3202 [ + - ]: 282770 : unary_expression* e = new unary_expression;
3203 : 282770 : e->op = t->content;
3204 : 282770 : e->tok = t;
3205 : 282770 : next ();
3206 : 282770 : e->operand = parse_unary ();
3207 : 282769 : return e;
3208 : : }
3209 : : else
3210 : 67571348 : return parse_crement ();
3211 : : }
3212 : :
3213 : :
3214 : : expression*
3215 : 67288579 : parser::parse_crement () // as in "increment" / "decrement"
3216 : : {
3217 : : // NB: Ideally, we'd parse only a symbol as an operand to the
3218 : : // *crement operators, instead of a general expression value. We'd
3219 : : // need more complex lookahead code to tell apart the postfix cases.
3220 : : // So we just punt, and leave it to pass-3 to signal errors on
3221 : : // cases like "4++".
3222 : :
3223 : 67288579 : const token* t = peek ();
3224 [ + - ][ + + : 73678780 : if (t && t->type == tok_operator
+ + + + ]
[ + + ]
3225 : 6390201 : && (t->content == "++" || t->content == "--"))
3226 : : {
3227 [ + - ]: 119 : pre_crement* e = new pre_crement;
3228 : 119 : e->op = t->content;
3229 : 119 : e->tok = t;
3230 : 119 : next ();
3231 : 119 : e->operand = parse_value ();
3232 : 119 : return e;
3233 : : }
3234 : :
3235 : : // post-crement or non-crement
3236 : 67288460 : expression *op1 = parse_value ();
3237 : :
3238 : 67288444 : t = peek ();
3239 [ + - ][ + + : 169981879 : if (t && t->type == tok_operator
+ + + + ]
[ + + ]
3240 : 102693435 : && (t->content == "++" || t->content == "--"))
3241 : : {
3242 [ + - ]: 24389 : post_crement* e = new post_crement;
3243 : 24389 : e->op = t->content;
3244 : 24389 : e->tok = t;
3245 : 24389 : next ();
3246 : 24389 : e->operand = op1;
3247 : 24389 : return e;
3248 : : }
3249 : : else
3250 : 67288563 : return op1;
3251 : : }
3252 : :
3253 : :
3254 : : expression*
3255 : 67288579 : parser::parse_value ()
3256 : : {
3257 : 67288579 : const token* t = peek ();
3258 [ - + ]: 67288579 : if (! t)
3259 [ # # ][ # # ]: 0 : throw parse_error (_("expected value"));
3260 : :
3261 [ + + ]: 67288579 : if (t->type == tok_embedded)
3262 : : {
3263 [ - + ]: 626882 : if (! privileged)
3264 [ # # ][ # # ]: 0 : throw parse_error (_("embedded expression code in unprivileged script; need stap -g"), false);
3265 : :
3266 [ + - ]: 626882 : embedded_expr *e = new embedded_expr;
3267 : 626882 : e->tok = t;
3268 : 626882 : e->code = t->content;
3269 : 626882 : next ();
3270 : 626882 : return e;
3271 : : }
3272 : :
3273 [ + + ][ + + ]: 66661697 : if (t->type == tok_operator && t->content == "(")
[ + + ]
3274 : : {
3275 : 1606488 : swallow ();
3276 : 1606488 : expression* e = parse_expression ();
3277 : 1606488 : t = next ();
3278 [ + - ][ - + ]: 1606488 : if (! (t->type == tok_operator && t->content == ")"))
[ - + ]
3279 [ # # ][ # # ]: 0 : throw parse_error (_("expected ')'"));
3280 : 1606488 : swallow ();
3281 : 1606488 : return e;
3282 : : }
3283 [ + + ][ + + ]: 65055209 : else if (t->type == tok_operator && t->content == "&")
[ + + ]
3284 : : {
3285 : 148667 : next (); // Cannot swallow, passing token on...
3286 : 148667 : return parse_target_symbol (t);
3287 : : }
3288 [ + + ]: 66346428 : else if (t->type == tok_identifier
[ + + + + ]
[ + + ]
3289 : 1439886 : || (t->type == tok_operator && t->content[0] == '@'))
3290 : 50574468 : return parse_symbol ();
3291 : : else
3292 : 67288570 : return parse_literal ();
3293 : : }
3294 : :
3295 : :
3296 : : const token *
3297 : 50626767 : parser::parse_hist_op_or_bare_name (hist_op *&hop, string &name)
3298 : : {
3299 : 50626767 : hop = NULL;
3300 : 50626767 : const token* t = expect_ident_or_atword (name);
3301 [ + + ][ + + ]: 50626766 : if (name == "@hist_linear" || name == "@hist_log")
[ + + ]
3302 : : {
3303 [ + - ][ + - ]: 135 : hop = new hist_op;
3304 [ + - ][ + + ]: 135 : if (name == "@hist_linear")
3305 : 56 : hop->htype = hist_linear;
3306 [ + - ][ + - ]: 79 : else if (name == "@hist_log")
3307 : 79 : hop->htype = hist_log;
3308 : 135 : hop->tok = t;
3309 [ + - ][ + - ]: 135 : expect_op("(");
[ + - ]
3310 [ + - ]: 135 : hop->stat = parse_expression ();
3311 : : int64_t tnum;
3312 [ + + ]: 135 : if (hop->htype == hist_linear)
3313 : : {
3314 [ + + ]: 224 : for (size_t i = 0; i < 3; ++i)
3315 : : {
3316 [ + - ][ + - ]: 168 : expect_op (",");
[ + - ]
3317 [ + - ]: 168 : expect_number (tnum);
3318 [ + - ]: 168 : hop->params.push_back (tnum);
3319 : : }
3320 : : }
3321 [ + - ][ + - ]: 135 : expect_op(")");
[ + - ]
3322 : : }
3323 : 50626766 : return t;
3324 : : }
3325 : :
3326 : :
3327 : : indexable*
3328 : 52198 : parser::parse_indexable ()
3329 : : {
3330 : 52198 : hist_op *hop = NULL;
3331 [ + - ]: 52198 : string name;
3332 [ + + ]: 52198 : const token *tok = parse_hist_op_or_bare_name(hop, name);
3333 [ + + ]: 52197 : if (hop)
3334 : 10 : return hop;
3335 : : else
3336 : : {
3337 [ + - ][ + - ]: 52187 : symbol* sym = new symbol;
3338 [ + - ]: 52187 : sym->name = name;
3339 : 52187 : sym->tok = tok;
3340 : 52187 : return sym;
3341 [ + - ]: 52198 : }
3342 : : }
3343 : :
3344 : :
3345 : : // var, indexable[index], func(parms), printf("...", ...), $var,r
3346 : : // @cast, @defined, @entry, @var, $var->member, @stat_op(stat)
3347 : 50574468 : expression* parser::parse_symbol ()
3348 : : {
3349 : 50574468 : hist_op *hop = NULL;
3350 : 50574468 : symbol *sym = NULL;
3351 [ + - ]: 50574468 : string name;
3352 [ + - ]: 50574468 : const token *t = parse_hist_op_or_bare_name(hop, name);
3353 : :
3354 [ + + ]: 50574468 : if (!hop)
3355 : : {
3356 : : // If we didn't get a hist_op, then we did get an identifier. We can
3357 : : // now scrutinize this identifier for the various magic forms of identifier
3358 : : // (printf, @stat_op, and $var...)
3359 : :
3360 [ + - ][ + + ]: 199964446 : if (name == "@cast"
[ + + ][ + - ]
[ + + ][ + + ]
3361 [ + - ]: 49796668 : || name == "@var"
3362 [ + - ][ + - ]: 99593334 : || (name.size() > 0 && name[0] == '$'))
3363 [ + - ]: 10299001 : return parse_target_symbol (t);
3364 : :
3365 : : // NB: PR11343: @defined() is not incompatible with earlier versions
3366 : : // of stap, so no need to check session.compatible for 1.2
3367 [ + - ][ + + ]: 40275443 : if (name == "@defined")
3368 [ + - ]: 629151 : return parse_defined_op (t);
3369 : :
3370 [ + - ][ + + ]: 39646292 : if (name == "@entry")
3371 [ + - ]: 32354 : return parse_entry_op (t);
3372 : :
3373 [ + - ][ + + ]: 39613938 : if (name == "@perf")
3374 [ + + ]: 9 : return parse_perf_op (t);
3375 : :
3376 [ + - ][ + - ]: 39613929 : if (name.size() > 0 && name[0] == '@')
[ + - ][ + + ]
[ + + ]
3377 : : {
3378 [ + - ][ + - ]: 567 : stat_op *sop = new stat_op;
3379 [ + - ][ + + ]: 567 : if (name == "@avg")
3380 : 80 : sop->ctype = sc_average;
3381 [ + - ][ + + ]: 487 : else if (name == "@count")
3382 : 250 : sop->ctype = sc_count;
3383 [ + - ][ + + ]: 237 : else if (name == "@sum")
3384 : 100 : sop->ctype = sc_sum;
3385 [ + - ][ + + ]: 137 : else if (name == "@min")
3386 : 65 : sop->ctype = sc_min;
3387 [ + - ][ + + ]: 72 : else if (name == "@max")
3388 : 71 : sop->ctype = sc_max;
3389 : : else
3390 [ + - ][ + - ]: 1 : throw parse_error(_("unknown operator ") + name);
3391 [ + - ][ + - ]: 566 : expect_op("(");
[ + - ]
3392 : 566 : sop->tok = t;
3393 [ + - ]: 566 : sop->stat = parse_expression ();
3394 [ + - ][ + - ]: 566 : expect_op(")");
[ + - ]
3395 : 566 : return sop;
3396 : : }
3397 : :
3398 [ + - ][ + + ]: 39613362 : else if (print_format *fmt = print_format::create(t))
3399 : : {
3400 [ + - ][ + + ]: 2166387 : expect_op("(");
[ + - ]
3401 [ + - ][ + + ]: 8775452 : if ((name == "print" || name == "println" ||
[ + - ][ + + ]
[ + + ][ + + ]
[ + + ][ + + ]
[ + + ]
3402 [ + - ][ + - ]: 4196038 : name == "sprint" || name == "sprintln") &&
3403 [ + - ][ + - ]: 2413028 : (peek_op("@hist_linear") || peek_op("@hist_log")))
[ + - ][ + - ]
[ + + ][ + - ]
[ + + ][ + + ]
[ + - ][ + + ]
[ # # # #
# # # # ]
3404 : : {
3405 : : // We have a special case where we recognize
3406 : : // print(@hist_foo(bar)) as a magic print-the-histogram
3407 : : // construct. This is sort of gross but it avoids
3408 : : // promoting histogram references to typeful
3409 : : // expressions.
3410 : :
3411 : 101 : hop = NULL;
3412 [ + - ]: 101 : t = parse_hist_op_or_bare_name(hop, name);
3413 [ - + ]: 101 : assert(hop);
3414 : :
3415 : : // It is, sadly, possible that even while parsing a
3416 : : // hist_op, we *mis-guessed* and the user wishes to
3417 : : // print(@hist_op(foo)[bucket]), a scalar. In that case
3418 : : // we must parse the arrayindex and print an expression.
3419 : : //
3420 : : // XXX: This still fails if the arrayindex is part of a
3421 : : // larger expression. To really handle everything, we'd
3422 : : // need to push back all the hist tokens start over.
3423 : :
3424 [ + - ][ + - ]: 101 : if (!peek_op ("["))
[ + - ][ + + ]
3425 : 100 : fmt->hist = hop;
3426 : : else
3427 : : {
3428 : : // This is simplified version of the
3429 : : // multi-array-index parser below, because we can
3430 : : // only ever have one index on a histogram anyways.
3431 [ + - ][ + - ]: 1 : expect_op("[");
[ + - ]
3432 [ + - ][ + - ]: 1 : struct arrayindex* ai = new arrayindex;
3433 : 1 : ai->tok = t;
3434 : 1 : ai->base = hop;
3435 [ + - ][ + - ]: 1 : ai->indexes.push_back (parse_expression ());
3436 [ + - ][ + - ]: 1 : expect_op("]");
[ + - ]
3437 [ + - ]: 1 : fmt->args.push_back(ai);
3438 : :
3439 : : // Consume any subsequent arguments.
3440 [ + - ][ + - ]: 2 : while (!peek_op (")"))
[ + - ][ + + ]
3441 : : {
3442 [ + - ][ + - ]: 1 : expect_op(",");
[ + - ]
3443 [ + - ]: 1 : expression *e = parse_expression ();
3444 [ + - ]: 1 : fmt->args.push_back(e);
3445 : : }
3446 : : }
3447 : : }
3448 : : else
3449 : : {
3450 : 2166285 : int min_args = 0;
3451 [ + + ]: 2166285 : if (fmt->print_with_format)
3452 : : {
3453 : : // Consume and convert a format string. Agreement between the
3454 : : // format string and the arguments is postponed to the
3455 : : // typechecking phase.
3456 [ + - ]: 2042985 : string tmp;
3457 [ + - ]: 2042985 : expect_unknown (tok_string, tmp);
3458 [ + - ]: 2042985 : fmt->raw_components = tmp;
3459 [ + - ][ + - ]: 2042985 : fmt->components = print_format::string_to_components (tmp);
[ + - ][ + - ]
3460 : : }
3461 [ + + ]: 123300 : else if (fmt->print_with_delim)
3462 : : {
3463 : : // Consume a delimiter to separate arguments.
3464 [ + - ]: 32 : fmt->delimiter.clear();
3465 : 32 : fmt->delimiter.type = print_format::conv_literal;
3466 [ + + ]: 32 : expect_unknown (tok_string, fmt->delimiter.literal_string);
3467 : 30 : min_args = 2;
3468 : : }
3469 : : else
3470 : : {
3471 : : // If we are not printing with a format string, we must have
3472 : : // at least one argument (of any type).
3473 [ + - ]: 123268 : expression *e = parse_expression ();
3474 [ + - ]: 123268 : fmt->args.push_back(e);
3475 : : }
3476 : :
3477 : : // Consume any subsequent arguments.
3478 [ + + ][ + - ]: 7383889 : while (min_args || !peek_op (")"))
[ + - ][ + + ]
[ + + ][ + - ]
[ + + ][ + +
# # # # ]
3479 : : {
3480 [ + - ][ + + ]: 5217610 : expect_op(",");
[ + - ]
3481 [ + + ]: 5217607 : expression *e = parse_expression ();
3482 [ + - ]: 5217606 : fmt->args.push_back(e);
3483 [ + + ]: 5217606 : if (min_args)
3484 : 5217606 : --min_args;
3485 : : }
3486 : : }
3487 [ + - ][ + - ]: 2166381 : expect_op(")");
[ + - ]
3488 : 2166381 : return fmt;
3489 : : }
3490 : :
3491 [ + - ][ + - ]: 37446975 : else if (peek_op ("(")) // function call
[ + - ][ + + ]
3492 : : {
3493 [ + - ]: 9779318 : swallow ();
3494 [ + - ][ + - ]: 9779318 : struct functioncall* f = new functioncall;
3495 : 9779318 : f->tok = t;
3496 [ + - ]: 9779318 : f->function = name;
3497 : : // Allow empty actual parameter list
3498 [ + - ][ + - ]: 9779318 : if (peek_op (")"))
[ + - ][ + + ]
3499 : : {
3500 [ + - ]: 864052 : swallow ();
3501 : 864052 : return f;
3502 : : }
3503 : 1957294 : while (1)
3504 : : {
3505 [ + - ][ + - ]: 10872560 : f->args.push_back (parse_expression ());
3506 [ + - ][ + - ]: 10872560 : if (peek_op (")"))
[ + - ][ + + ]
3507 : : {
3508 [ + - ]: 8915266 : swallow ();
3509 : 8915266 : break;
3510 : : }
3511 [ + - ][ + - ]: 1957294 : else if (peek_op (","))
[ + - ][ + - ]
3512 : : {
3513 [ + - ]: 1957294 : swallow ();
3514 : 1957294 : continue;
3515 : : }
3516 : : else
3517 [ # # ][ # # ]: 0 : throw parse_error (_("expected ',' or ')'"));
3518 : : }
3519 : 8915266 : return f;
3520 : : }
3521 : :
3522 : : else
3523 : : {
3524 [ + - ][ + - ]: 27667657 : sym = new symbol;
3525 [ + - ]: 27667657 : sym->name = name;
3526 : 27667657 : sym->tok = t;
3527 : : }
3528 : : }
3529 : :
3530 : : // By now, either we had a hist_op in the first place, or else
3531 : : // we had a plain word and it was converted to a symbol.
3532 : :
3533 [ - + ]: 27667681 : assert (!hop != !sym); // logical XOR
3534 : :
3535 : : // All that remains is to check for array indexing
3536 : :
3537 [ + - ][ + - ]: 27667681 : if (peek_op ("[")) // array
[ + - ][ + + ]
3538 : : {
3539 [ + - ]: 1046313 : swallow ();
3540 [ + - ][ + - ]: 1046313 : struct arrayindex* ai = new arrayindex;
3541 : 1046313 : ai->tok = t;
3542 : :
3543 [ + + ]: 1046313 : if (hop)
3544 : 24 : ai->base = hop;
3545 : : else
3546 : 1046289 : ai->base = sym;
3547 : :
3548 : 15828 : while (1)
3549 : : {
3550 [ + - ][ + - ]: 1062141 : ai->indexes.push_back (parse_expression ());
3551 [ + - ][ + - ]: 1062141 : if (peek_op ("]"))
[ + - ][ + + ]
3552 : : {
3553 [ + - ]: 1046313 : swallow ();
3554 : 1046313 : break;
3555 : : }
3556 [ + - ][ + - ]: 15828 : else if (peek_op (","))
[ + - ][ + - ]
3557 : : {
3558 [ + - ]: 15828 : swallow ();
3559 : 15828 : continue;
3560 : : }
3561 : : else
3562 [ # # ][ # # ]: 0 : throw parse_error (_("expected ',' or ']'"));
3563 : : }
3564 : 1046313 : return ai;
3565 : : }
3566 : :
3567 : : // If we got to here, we *should* have a symbol; if we have
3568 : : // a hist_op on its own, it doesn't count as an expression,
3569 : : // so we throw a parse error.
3570 : :
3571 [ - + ]: 26621368 : if (hop)
3572 [ # # ][ # # ]: 0 : throw parse_error(_("base histogram operator where expression expected"), t);
3573 : :
3574 [ + - ]: 50574468 : return sym;
3575 : : }
3576 : :
3577 : : // Parse a @cast or $var. Given head token has already been consumed.
3578 : 11076819 : target_symbol* parser::parse_target_symbol (const token* t)
3579 : : {
3580 : 11076819 : bool addressof = false;
3581 [ + + ][ + + ]: 11076819 : if (t->type == tok_operator && t->content == "&")
[ + + ]
3582 : : {
3583 : 159443 : addressof = true;
3584 [ + - ]: 159443 : delete t;
3585 : 159443 : t = next ();
3586 : : }
3587 : :
3588 [ + + ][ + + ]: 11076819 : if (t->type == tok_operator && t->content == "@cast")
[ + + ]
3589 : : {
3590 [ + - ]: 993217 : cast_op *cop = new cast_op;
3591 : 993217 : cop->tok = t;
3592 : 993217 : cop->name = t->content;
3593 [ + - ][ + - ]: 993217 : expect_op("(");
[ + - ]
3594 : 993217 : cop->operand = parse_expression ();
3595 [ + - ][ + - ]: 993217 : expect_op(",");
[ + - ]
3596 : 993217 : expect_unknown(tok_string, cop->type_name);
3597 [ + - ][ + - ]: 993217 : if (peek_op (","))
[ + - ][ + + ]
3598 : : {
3599 : 458835 : swallow ();
3600 : 458835 : expect_unknown(tok_string, cop->module);
3601 : : }
3602 [ + - ][ + - ]: 993217 : expect_op(")");
[ + - ]
3603 : 993217 : parse_target_symbol_components(cop);
3604 : 993217 : cop->addressof = addressof;
3605 : 993217 : return cop;
3606 : : }
3607 : :
3608 [ + + ][ + - ]: 10083602 : if (t->type == tok_identifier && t->content[0]=='$')
[ + + ]
3609 : : {
3610 : : // target_symbol time
3611 [ + - ]: 10083601 : target_symbol *tsym = new target_symbol;
3612 : 10083601 : tsym->tok = t;
3613 : 10083601 : tsym->name = t->content;
3614 : 10083601 : tsym->target_name = "";
3615 : 10083601 : tsym->cu_name = "";
3616 : 10083601 : parse_target_symbol_components(tsym);
3617 : 10083601 : tsym->addressof = addressof;
3618 : 10083601 : return tsym;
3619 : : }
3620 : :
3621 [ + - ][ + - ]: 1 : if (t->type == tok_operator && t->content == "@var")
[ + - ]
3622 : : {
3623 [ + - ]: 1 : target_symbol *tsym = new target_symbol;
3624 : 1 : tsym->tok = t;
3625 : 1 : tsym->name = t->content;
3626 [ + - ][ + - ]: 1 : expect_op("(");
[ + - ]
3627 : 1 : expect_unknown(tok_string, tsym->target_name);
3628 : 1 : size_t found_at = tsym->target_name.find("@");
3629 [ + - ]: 1 : if (found_at != string::npos)
3630 [ + - ]: 1 : tsym->cu_name = tsym->target_name.substr(found_at + 1);
3631 : : else
3632 : 0 : tsym->cu_name = "";
3633 [ + - ][ + - ]: 1 : expect_op(")");
[ + - ]
3634 : 1 : parse_target_symbol_components(tsym);
3635 : 1 : tsym->addressof = addressof;
3636 : 1 : return tsym;
3637 : : }
3638 : :
3639 [ # # ][ # # ]: 11076819 : throw parse_error (_("expected @cast, @var or $var"));
3640 : : }
3641 : :
3642 : :
3643 : : // Parse a @defined(). Given head token has already been consumed.
3644 : 629151 : expression* parser::parse_defined_op (const token* t)
3645 : : {
3646 [ + - ]: 629151 : defined_op* dop = new defined_op;
3647 : 629151 : dop->tok = t;
3648 [ + - ][ + - ]: 629151 : expect_op("(");
[ + - ]
3649 : : // no need for parse_hist_op... etc., as @defined takes only target_symbols as its operand.
3650 : 629151 : const token* tt = next ();
3651 : 629151 : dop->operand = parse_target_symbol (tt);
3652 [ + - ][ + - ]: 629151 : expect_op(")");
[ + - ]
3653 : 629151 : return dop;
3654 : : }
3655 : :
3656 : :
3657 : : // Parse a @entry(). Given head token has already been consumed.
3658 : 32354 : expression* parser::parse_entry_op (const token* t)
3659 : : {
3660 [ + - ]: 32354 : entry_op* eop = new entry_op;
3661 : 32354 : eop->tok = t;
3662 [ + - ][ + - ]: 32354 : expect_op("(");
[ + - ]
3663 : 32354 : eop->operand = parse_expression ();
3664 [ + - ][ + - ]: 32354 : expect_op(")");
[ + - ]
3665 : 32354 : return eop;
3666 : : }
3667 : :
3668 : :
3669 : : // Parse a @perf(). Given head token has already been consumed.
3670 : 9 : expression* parser::parse_perf_op (const token* t)
3671 : : {
3672 [ + - ]: 9 : perf_op* pop = new perf_op;
3673 : :
3674 [ - + ]: 9 : if (strverscmp(session.compatible.c_str(), "2.1") < 0)
3675 [ # # ][ # # ]: 0 : throw parse_error (_("expected @cast, @var or $var"));
3676 : :
3677 : 9 : pop->tok = t;
3678 [ + - ][ + - ]: 9 : expect_op("(");
[ + - ]
3679 : 9 : pop->operand = parse_literal_string ();
3680 [ + + ]: 8 : if (pop->operand->value == "")
3681 [ + - ][ + - ]: 1 : throw parse_error (_("expected non-empty string"));
3682 [ + - ][ + - ]: 7 : expect_op(")");
[ + - ]
3683 : 7 : return pop;
3684 : : }
3685 : :
3686 : :
3687 : :
3688 : : void
3689 : 11076819 : parser::parse_target_symbol_components (target_symbol* e)
3690 : : {
3691 : 11076819 : bool pprint = false;
3692 : :
3693 : : // check for pretty-print in the form $foo$
3694 : 11076819 : string &base = e->name;
3695 : 11076819 : size_t pprint_pos = base.find_last_not_of('$');
3696 [ + - ][ + + ]: 11076819 : if (0 < pprint_pos && pprint_pos < base.length() - 1)
[ + + ]
3697 : : {
3698 [ + - ]: 29 : string pprint_val = base.substr(pprint_pos + 1);
3699 [ + - ]: 29 : base.erase(pprint_pos + 1);
3700 [ + - ][ + - ]: 29 : e->components.push_back (target_symbol::component(e->tok, pprint_val, true));
[ + - ]
3701 [ + - ]: 29 : pprint = true;
3702 : : }
3703 : :
3704 [ + + ]: 14819020 : while (!pprint)
3705 : : {
3706 [ + - ][ + - ]: 14818915 : if (peek_op ("->"))
[ + - ][ + + ]
3707 : : {
3708 [ + - ]: 3701179 : const token* t = next();
3709 [ + - ]: 3701179 : string member;
3710 [ + - ]: 3701179 : expect_ident_or_keyword (member);
3711 : :
3712 : : // check for pretty-print in the form $foo->$ or $foo->bar$
3713 [ + - ]: 3701179 : pprint_pos = member.find_last_not_of('$');
3714 [ + - ]: 3701179 : string pprint_val;
3715 [ + + ][ + - ]: 3701179 : if (pprint_pos == string::npos || pprint_pos < member.length() - 1)
[ + + ][ + + ]
3716 : : {
3717 [ + - ][ + - ]: 76 : pprint_val = member.substr(pprint_pos + 1);
[ + - ]
3718 [ + - ]: 76 : member.erase(pprint_pos + 1);
3719 : 76 : pprint = true;
3720 : : }
3721 : :
3722 [ + - ][ + + ]: 3701179 : if (!member.empty())
3723 [ + - ][ + - ]: 3701135 : e->components.push_back (target_symbol::component(t, member));
[ + - ]
3724 [ + + ]: 3701179 : if (pprint)
3725 [ + - ][ + - ]: 3701179 : e->components.push_back (target_symbol::component(t, pprint_val, true));
[ + - ][ + - ]
[ + - ]
3726 : : }
3727 [ + - ][ + - ]: 11117736 : else if (peek_op ("["))
[ + - ][ + + ]
3728 : : {
3729 : 41022 : const token* t = next();
3730 : 41022 : expression* index = parse_expression();
3731 [ - + ]: 41022 : literal_number* ln = dynamic_cast<literal_number*>(index);
3732 [ + + ]: 41022 : if (ln)
3733 [ + - ]: 34531 : e->components.push_back (target_symbol::component(t, ln->value));
3734 : : else
3735 [ + - ]: 6491 : e->components.push_back (target_symbol::component(t, index));
3736 [ + - ][ + - ]: 41022 : expect_op ("]");
[ + - ]
3737 : : }
3738 : : else
3739 : 11076714 : break;
3740 : : }
3741 : :
3742 [ + + ]: 11076819 : if (!pprint)
3743 : : {
3744 : : // check for pretty-print in the form $foo $
3745 : : // i.e. as a separate token, esp. for $foo[i]$ and @cast(...)$
3746 : 11076714 : const token* t = peek();
3747 [ + + + + ]: 14411610 : if (t->type == tok_identifier &&
[ + + ]
3748 : 3334896 : t->content.find_first_not_of('$') == string::npos)
3749 : : {
3750 : 43 : t = next();
3751 [ + - ]: 43 : e->components.push_back (target_symbol::component(t, t->content, true));
3752 : 43 : pprint = true;
3753 : : }
3754 : : }
3755 : :
3756 [ + + ][ + - ]: 11076819 : if (pprint && (peek_op ("->") || peek_op("[")))
[ + - ][ + - ]
[ + - ][ + - ]
[ - + ][ + + ]
[ + - ][ + + ]
[ + + ][ + - ]
[ + + ][ - +
# # # # #
# # # ]
3757 [ # # ][ # # ]: 0 : throw parse_error(_("-> and [ are not accepted for a pretty-printing variable"));
3758 [ + - ][ + - ]: 11084061 : }
3759 : :
3760 : : /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
|