bt_parse.y revision 1.33
1/* $OpenBSD: bt_parse.y,v 1.33 2021/04/22 11:36:11 mpi Exp $ */ 2 3/* 4 * Copyright (c) 2019-2021 Martin Pieuchot <mpi@openbsd.org> 5 * Copyright (c) 2019 Tobias Heider <tobhe@openbsd.org> 6 * Copyright (c) 2015 Ted Unangst <tedu@openbsd.org> 7 * 8 * Permission to use, copy, modify, and distribute this software for any 9 * purpose with or without fee is hereby granted, provided that the above 10 * copyright notice and this permission notice appear in all copies. 11 * 12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 */ 20 21/* 22 * B tracing language parser. 23 * 24 * The dialect of the language understood by this parser aims to be 25 * compatible with the one understood by bpftrace(8), see: 26 * 27 * https://github.com/iovisor/bpftrace/blob/master/docs/reference_guide.md 28 * 29 */ 30 31%{ 32#include <sys/queue.h> 33 34#include <assert.h> 35#include <ctype.h> 36#include <err.h> 37#include <limits.h> 38#include <stdarg.h> 39#include <stdint.h> 40#include <stdio.h> 41 42#include "bt_parser.h" 43 44/* Name for the default map @[], hopefully nobody will use this one ;) */ 45#define UNNAMED_MAP "___unnamed_map_doesnt_have_any_name" 46 47/* Number of rules to evaluate. */ 48struct bt_ruleq g_rules = TAILQ_HEAD_INITIALIZER(g_rules); 49 50/* Number of probes except BEGIN/END. */ 51int g_nprobes; 52 53/* List of global variables, including maps. */ 54SLIST_HEAD(, bt_var) g_variables; 55 56/* List of local variables, cleaned for each new rule. */ 57SLIST_HEAD(, bt_var) l_variables; 58 59struct bt_rule *br_new(struct bt_probe *, struct bt_filter *, struct bt_stmt *, 60 enum bt_rtype); 61struct bt_probe *bp_new(const char *, const char *, const char *, int32_t); 62struct bt_arg *ba_append(struct bt_arg *, struct bt_arg *); 63struct bt_arg *ba_op(enum bt_argtype, struct bt_arg *, struct bt_arg *); 64struct bt_stmt *bs_new(enum bt_action, struct bt_arg *, struct bt_var *); 65struct bt_stmt *bs_append(struct bt_stmt *, struct bt_stmt *); 66 67struct bt_var *bg_lookup(const char *); 68struct bt_stmt *bg_store(const char *, struct bt_arg *); 69struct bt_arg *bg_find(const char *); 70struct bt_var *bg_get(const char *); 71 72struct bt_var *bl_lookup(const char *); 73struct bt_stmt *bl_store(const char *, struct bt_arg *); 74struct bt_arg *bl_find(const char *); 75 76struct bt_arg *bm_find(const char *, struct bt_arg *); 77struct bt_stmt *bm_insert(const char *, struct bt_arg *, struct bt_arg *); 78struct bt_stmt *bm_op(enum bt_action, struct bt_arg *, struct bt_arg *); 79 80struct bt_stmt *bh_inc(const char *, struct bt_arg *, struct bt_arg *); 81 82/* 83 * Lexer 84 */ 85const char *pbuf; 86size_t plen; 87size_t pindex; 88int perrors = 0; 89 90typedef struct { 91 union { 92 long number; 93 int i; 94 const char *string; 95 struct bt_probe *probe; 96 struct bt_filter *filter; 97 struct bt_stmt *stmt; 98 struct bt_arg *arg; 99 } v; 100 const char *filename; 101 int lineno; 102 int colno; 103} yystype; 104#define YYSTYPE yystype 105 106static void yyerror(const char *, ...); 107static int yylex(void); 108 109static int pflag; 110%} 111 112%token <v.i> ERROR ENDPRED OP_EQ OP_NE OP_LE OP_GE OP_LAND OP_LOR 113/* Builtins */ 114%token <v.i> BUILTIN BEGIN END HZ 115/* Functions and Map operators */ 116%token <v.i> F_DELETE F_PRINT FUNC0 FUNC1 FUNCN OP1 OP4 MOP0 MOP1 117%token <v.string> STRING CSTRING 118%token <v.number> NUMBER 119 120%type <v.string> gvar lvar 121%type <v.number> staticval 122%type <v.i> beginend 123%type <v.probe> probe probename 124%type <v.filter> predicate 125%type <v.stmt> action stmt stmtlist 126%type <v.arg> expr vargs mentry mexpr printargs term globalvar variable 127 128%right '=' 129%nonassoc OP_EQ OP_NE OP_LE OP_GE OP_LAND OP_LOR 130%left '&' '|' 131%left '+' '-' 132%left '/' '*' 133%% 134 135grammar : /* empty */ 136 | grammar '\n' 137 | grammar rule 138 | grammar error 139 ; 140 141rule : beginend action { br_new(NULL, NULL, $2, $1); } 142 | probe predicate action { br_new($1, $2, $3, B_RT_PROBE); } 143 ; 144 145beginend : BEGIN | END ; 146 147probe : { pflag = 1; } probename { $$ = $2; pflag = 0; } 148 149probename : STRING ':' STRING ':' STRING { $$ = bp_new($1, $3, $5, 0); } 150 | STRING ':' HZ ':' NUMBER { $$ = bp_new($1, "hz", NULL, $5); } 151 ; 152 153staticval : NUMBER 154 | '$' NUMBER { $$ = get_varg($2); } 155 ; 156 157gvar : '@' STRING { $$ = $2; } 158 | '@' { $$ = UNNAMED_MAP; } 159 ; 160 161lvar : '$' STRING { $$ = $2; } 162 ; 163 164mentry : gvar '[' vargs ']' { $$ = bm_find($1, $3); } 165 ; 166 167globalvar : gvar { $$ = bg_find($1); } 168 | mentry 169 ; 170 171variable : globalvar 172 | lvar { $$ = bl_find($1); } 173 ; 174 175mexpr : MOP0 '(' ')' { $$ = ba_new(NULL, $1); } 176 | MOP1 '(' expr ')' { $$ = ba_new($3, $1); } 177 | expr 178 ; 179 180expr : CSTRING { $$ = ba_new($1, B_AT_STR); } 181 | term 182 ; 183 184predicate : /* empty */ { $$ = NULL; } 185 | '/' term ENDPRED { $$ = bc_new(NULL, B_AT_OP_NE, $2); } 186 ; 187 188term : '(' term ')' { $$ = $2; } 189 | term OP_EQ term { $$ = ba_op(B_AT_OP_EQ, $1, $3); } 190 | term OP_NE term { $$ = ba_op(B_AT_OP_NE, $1, $3); } 191 | term OP_LE term { $$ = ba_op(B_AT_OP_LE, $1, $3); } 192 | term OP_GE term { $$ = ba_op(B_AT_OP_GE, $1, $3); } 193 | term OP_LAND term { $$ = ba_op(B_AT_OP_LAND, $1, $3); } 194 | term OP_LOR term { $$ = ba_op(B_AT_OP_LOR, $1, $3); } 195 | term '+' term { $$ = ba_op(B_AT_OP_PLUS, $1, $3); } 196 | term '-' term { $$ = ba_op(B_AT_OP_MINUS, $1, $3); } 197 | term '*' term { $$ = ba_op(B_AT_OP_MULT, $1, $3); } 198 | term '/' term { $$ = ba_op(B_AT_OP_DIVIDE, $1, $3); } 199 | term '&' term { $$ = ba_op(B_AT_OP_BAND, $1, $3); } 200 | term '|' term { $$ = ba_op(B_AT_OP_BOR, $1, $3); } 201 | staticval { $$ = ba_new($1, B_AT_LONG); } 202 | BUILTIN { $$ = ba_new(NULL, $1); } 203 | variable 204 ; 205 206 207vargs : expr 208 | vargs ',' expr { $$ = ba_append($1, $3); } 209 ; 210 211printargs : term 212 | gvar ',' expr { $$ = ba_append(bg_find($1), $3); } 213 ; 214 215NL : /* empty */ | '\n' 216 ; 217 218stmt : ';' NL { $$ = NULL; } 219 | gvar '=' expr { $$ = bg_store($1, $3); } 220 | lvar '=' expr { $$ = bl_store($1, $3); } 221 | gvar '[' vargs ']' '=' mexpr { $$ = bm_insert($1, $3, $6); } 222 | FUNCN '(' vargs ')' { $$ = bs_new($1, $3, NULL); } 223 | FUNC1 '(' expr ')' { $$ = bs_new($1, $3, NULL); } 224 | FUNC0 '(' ')' { $$ = bs_new($1, NULL, NULL); } 225 | F_DELETE '(' mentry ')' { $$ = bm_op($1, $3, NULL); } 226 | F_PRINT '(' printargs ')' { $$ = bs_new($1, $3, NULL); } 227 | gvar '=' OP1 '(' expr ')' { $$ = bh_inc($1, $5, NULL); } 228 | gvar '=' OP4 '(' expr ',' vargs ')' {$$ = bh_inc($1, $5, $7);} 229 ; 230 231stmtlist : stmt 232 | stmtlist stmt { $$ = bs_append($1, $2); } 233 ; 234 235action : '{' stmtlist '}' { $$ = $2; } 236 ; 237 238%% 239 240int 241get_varg(int index) 242{ 243 extern int vargs[]; 244 245 assert(index == 1); 246 247 return vargs[index - 1]; 248} 249 250/* Create a new rule, representing "probe / filter / { action }" */ 251struct bt_rule * 252br_new(struct bt_probe *probe, struct bt_filter *filter, struct bt_stmt *head, 253 enum bt_rtype rtype) 254{ 255 struct bt_rule *br; 256 257 br = calloc(1, sizeof(*br)); 258 if (br == NULL) 259 err(1, "bt_rule: calloc"); 260 br->br_probe = probe; 261 br->br_filter = filter; 262 /* SLIST_INSERT_HEAD() nullify the next pointer. */ 263 SLIST_FIRST(&br->br_action) = head; 264 br->br_type = rtype; 265 266 SLIST_FIRST(&br->br_variables) = SLIST_FIRST(&l_variables); 267 SLIST_INIT(&l_variables); 268 269 if (rtype == B_RT_PROBE) { 270 g_nprobes++; 271 TAILQ_INSERT_TAIL(&g_rules, br, br_next); 272 } else { 273 TAILQ_INSERT_HEAD(&g_rules, br, br_next); 274 } 275 276 return br; 277} 278 279/* Create a new condition */ 280struct bt_filter * 281bc_new(struct bt_arg *term, enum bt_argtype op, struct bt_arg *ba) 282{ 283 struct bt_filter *bf; 284 285 bf = calloc(1, sizeof(*bf)); 286 if (bf == NULL) 287 err(1, "bt_filter: calloc"); 288 289 bf->bf_condition = bs_new(B_AC_TEST, ba_op(op, term, ba), NULL); 290 291 return bf; 292} 293 294/* Create a new probe */ 295struct bt_probe * 296bp_new(const char *prov, const char *func, const char *name, int32_t rate) 297{ 298 struct bt_probe *bp; 299 300 if (rate < 0 || rate > INT32_MAX) 301 errx(1, "only positive values permitted"); 302 303 bp = calloc(1, sizeof(*bp)); 304 if (bp == NULL) 305 err(1, "bt_probe: calloc"); 306 bp->bp_prov = prov; 307 bp->bp_func = func; 308 bp->bp_name = name; 309 bp->bp_rate = rate; 310 311 return bp; 312} 313 314/* Create a new argument */ 315struct bt_arg * 316ba_new0(void *val, enum bt_argtype type) 317{ 318 struct bt_arg *ba; 319 320 ba = calloc(1, sizeof(*ba)); 321 if (ba == NULL) 322 err(1, "bt_arg: calloc"); 323 ba->ba_value = val; 324 ba->ba_type = type; 325 326 return ba; 327} 328 329/* 330 * Link two arguments together, to build an argument list used in 331 * function calls. 332 */ 333struct bt_arg * 334ba_append(struct bt_arg *da0, struct bt_arg *da1) 335{ 336 struct bt_arg *ba = da0; 337 338 assert(da1 != NULL); 339 340 if (da0 == NULL) 341 return da1; 342 343 while (SLIST_NEXT(ba, ba_next) != NULL) 344 ba = SLIST_NEXT(ba, ba_next); 345 346 SLIST_INSERT_AFTER(ba, da1, ba_next); 347 348 return da0; 349} 350 351/* Create an operator argument */ 352struct bt_arg * 353ba_op(enum bt_argtype op, struct bt_arg *da0, struct bt_arg *da1) 354{ 355 return ba_new(ba_append(da0, da1), op); 356} 357 358/* Create a new statement: function call or assignment. */ 359struct bt_stmt * 360bs_new(enum bt_action act, struct bt_arg *head, struct bt_var *var) 361{ 362 struct bt_stmt *bs; 363 364 bs = calloc(1, sizeof(*bs)); 365 if (bs == NULL) 366 err(1, "bt_stmt: calloc"); 367 bs->bs_act = act; 368 bs->bs_var = var; 369 /* SLIST_INSERT_HEAD() nullify the next pointer. */ 370 SLIST_FIRST(&bs->bs_args) = head; 371 372 return bs; 373} 374 375/* Link two statements together, to build an 'action'. */ 376struct bt_stmt * 377bs_append(struct bt_stmt *ds0, struct bt_stmt *ds1) 378{ 379 struct bt_stmt *bs = ds0; 380 381 if (ds0 == NULL) 382 return ds1; 383 384 if (ds1 == NULL) 385 return ds0; 386 387 while (SLIST_NEXT(bs, bs_next) != NULL) 388 bs = SLIST_NEXT(bs, bs_next); 389 390 SLIST_INSERT_AFTER(bs, ds1, bs_next); 391 392 return ds0; 393} 394 395const char * 396bv_name(struct bt_var *bv) 397{ 398 if (strncmp(bv->bv_name, UNNAMED_MAP, strlen(UNNAMED_MAP)) == 0) 399 return ""; 400 return bv->bv_name; 401} 402 403/* Allocate a variable. */ 404struct bt_var * 405bv_new(const char *vname) 406{ 407 struct bt_var *bv; 408 409 bv = calloc(1, sizeof(*bv)); 410 if (bv == NULL) 411 err(1, "bt_var: calloc"); 412 bv->bv_name = vname; 413 414 return bv; 415} 416 417/* Return the global variable corresponding to `vname'. */ 418struct bt_var * 419bg_lookup(const char *vname) 420{ 421 struct bt_var *bv; 422 423 SLIST_FOREACH(bv, &g_variables, bv_next) { 424 if (strcmp(vname, bv->bv_name) == 0) 425 break; 426 } 427 428 return bv; 429} 430 431/* Find or allocate a global variable corresponding to `vname' */ 432struct bt_var * 433bg_get(const char *vname) 434{ 435 struct bt_var *bv; 436 437 bv = bg_lookup(vname); 438 if (bv == NULL) { 439 bv = bv_new(vname); 440 SLIST_INSERT_HEAD(&g_variables, bv, bv_next); 441 } 442 443 return bv; 444} 445 446/* Create an "argument" that points to an existing untyped variable. */ 447struct bt_arg * 448bg_find(const char *vname) 449{ 450 struct bt_var *bv; 451 452 bv = bg_lookup(vname); 453 if (bv == NULL) 454 yyerror("variable '%s' accessed before being set", vname); 455 456 return ba_new(bv, B_AT_VAR); 457} 458 459/* Create a 'store' statement to assign a value to a global variable. */ 460struct bt_stmt * 461bg_store(const char *vname, struct bt_arg *vval) 462{ 463 return bs_new(B_AC_STORE, vval, bg_get(vname)); 464} 465 466/* Return the local variable corresponding to `vname'. */ 467struct bt_var * 468bl_lookup(const char *vname) 469{ 470 struct bt_var *bv; 471 472 SLIST_FOREACH(bv, &l_variables, bv_next) { 473 if (strcmp(vname, bv->bv_name) == 0) 474 break; 475 } 476 477 return bv; 478} 479 480/* Find or create a local variable corresponding to `vname' */ 481struct bt_arg * 482bl_find(const char *vname) 483{ 484 struct bt_var *bv; 485 486 bv = bl_lookup(vname); 487 if (bv == NULL) { 488 bv = bv_new(vname); 489 SLIST_INSERT_HEAD(&l_variables, bv, bv_next); 490 } 491 492 return ba_new(bv, B_AT_VAR); 493} 494 495/* Create a 'store' statement to assign a value to a local variable. */ 496struct bt_stmt * 497bl_store(const char *vname, struct bt_arg *vval) 498{ 499 struct bt_var *bv; 500 501 bv = bl_lookup(vname); 502 if (bv == NULL) { 503 bv = bv_new(vname); 504 SLIST_INSERT_HEAD(&l_variables, bv, bv_next); 505 } 506 507 return bs_new(B_AC_STORE, vval, bv); 508} 509 510struct bt_stmt * 511bm_op(enum bt_action mact, struct bt_arg *ba, struct bt_arg *mval) 512{ 513 return bs_new(mact, ba, (struct bt_var *)mval); 514} 515 516/* Create a 'map store' statement to assign a value to a map entry. */ 517struct bt_stmt * 518bm_insert(const char *mname, struct bt_arg *mkey, struct bt_arg *mval) 519{ 520 struct bt_arg *ba; 521 522 ba = ba_new(bg_get(mname), B_AT_MAP); 523 ba->ba_key = mkey; 524 525 return bs_new(B_AC_INSERT, ba, (struct bt_var *)mval); 526} 527 528/* Create an argument that points to a variable and attach a key to it. */ 529struct bt_arg * 530bm_find(const char *vname, struct bt_arg *mkey) 531{ 532 struct bt_var *bv; 533 struct bt_arg *ba; 534 535 bv = bg_lookup(vname); 536 if (bv == NULL) 537 yyerror("variable '%s' accessed before being set", vname); 538 539 ba = ba_new(bv, B_AT_MAP); 540 ba->ba_key = mkey; 541 return ba; 542} 543 544/* 545 * Histograms implemented using associative arrays (maps). In the case 546 * of linear histograms `ba_key' points to a list of (min, max, step) 547 * necessary to "bucketize" any value. 548 */ 549struct bt_stmt * 550bh_inc(const char *hname, struct bt_arg *hval, struct bt_arg *hrange) 551{ 552 struct bt_arg *ba; 553 554 if (hrange == NULL) { 555 /* Power-of-2 histogram */ 556 } else { 557 long min = 0, max; 558 int count = 0; 559 560 /* Linear histogram */ 561 for (ba = hrange; ba != NULL; ba = SLIST_NEXT(ba, ba_next)) { 562 if (++count > 3) 563 yyerror("too many arguments"); 564 if (ba->ba_type != B_AT_LONG) 565 yyerror("type invalid"); 566 567 switch (count) { 568 case 1: 569 min = (long)ba->ba_value; 570 if (min >= 0) 571 break; 572 yyerror("negative minium"); 573 case 2: 574 max = (long)ba->ba_value; 575 if (max > min) 576 break; 577 yyerror("maximum smaller than minium (%d < %d)", 578 max, min); 579 case 3: 580 break; 581 default: 582 assert(0); 583 } 584 } 585 if (count < 3) 586 yyerror("%d missing arguments", 3 - count); 587 } 588 589 ba = ba_new(bg_get(hname), B_AT_HIST); 590 ba->ba_key = hrange; 591 return bs_new(B_AC_BUCKETIZE, ba, (struct bt_var *)hval); 592} 593 594struct keyword { 595 const char *word; 596 int token; 597 int type; 598}; 599 600int 601kw_cmp(const void *str, const void *xkw) 602{ 603 return (strcmp(str, ((const struct keyword *)xkw)->word)); 604} 605 606struct keyword * 607lookup(char *s) 608{ 609 static const struct keyword kws[] = { 610 { "BEGIN", BEGIN, B_RT_BEGIN }, 611 { "END", END, B_RT_END }, 612 { "arg0", BUILTIN, B_AT_BI_ARG0 }, 613 { "arg1", BUILTIN, B_AT_BI_ARG1 }, 614 { "arg2", BUILTIN, B_AT_BI_ARG2 }, 615 { "arg3", BUILTIN, B_AT_BI_ARG3 }, 616 { "arg4", BUILTIN, B_AT_BI_ARG4 }, 617 { "arg5", BUILTIN, B_AT_BI_ARG5 }, 618 { "arg6", BUILTIN, B_AT_BI_ARG6 }, 619 { "arg7", BUILTIN, B_AT_BI_ARG7 }, 620 { "arg8", BUILTIN, B_AT_BI_ARG8 }, 621 { "arg9", BUILTIN, B_AT_BI_ARG9 }, 622 { "clear", FUNC1, B_AC_CLEAR }, 623 { "comm", BUILTIN, B_AT_BI_COMM }, 624 { "count", MOP0, B_AT_MF_COUNT }, 625 { "cpu", BUILTIN, B_AT_BI_CPU }, 626 { "delete", F_DELETE, B_AC_DELETE }, 627 { "exit", FUNC0, B_AC_EXIT }, 628 { "hist", OP1, 0 }, 629 { "hz", HZ, 0 }, 630 { "kstack", BUILTIN, B_AT_BI_KSTACK }, 631 { "lhist", OP4, 0 }, 632 { "max", MOP1, B_AT_MF_MAX }, 633 { "min", MOP1, B_AT_MF_MIN }, 634 { "nsecs", BUILTIN, B_AT_BI_NSECS }, 635 { "pid", BUILTIN, B_AT_BI_PID }, 636 { "print", F_PRINT, B_AC_PRINT }, 637 { "printf", FUNCN, B_AC_PRINTF }, 638 { "retval", BUILTIN, B_AT_BI_RETVAL }, 639 { "sum", MOP1, B_AT_MF_SUM }, 640 { "tid", BUILTIN, B_AT_BI_TID }, 641 { "time", FUNC1, B_AC_TIME }, 642 { "ustack", BUILTIN, B_AT_BI_USTACK }, 643 { "zero", FUNC1, B_AC_ZERO }, 644 }; 645 646 return bsearch(s, kws, nitems(kws), sizeof(kws[0]), kw_cmp); 647} 648 649int 650peek(void) 651{ 652 if (pbuf != NULL) { 653 if (pindex < plen) 654 return pbuf[pindex]; 655 } 656 return EOF; 657} 658 659int 660lgetc(void) 661{ 662 if (pbuf != NULL) { 663 if (pindex < plen) { 664 yylval.colno++; 665 return pbuf[pindex++]; 666 } 667 } 668 return EOF; 669} 670 671void 672lungetc(void) 673{ 674 if (pbuf != NULL && pindex > 0) { 675 yylval.colno--; 676 pindex--; 677 } 678} 679 680int 681yylex(void) 682{ 683 unsigned char buf[1024]; 684 unsigned char *ebuf, *p, *str; 685 int c; 686 687 ebuf = buf + sizeof(buf); 688 p = buf; 689 690again: 691 /* skip whitespaces */ 692 for (c = lgetc(); isspace(c); c = lgetc()) { 693 if (c == '\n') { 694 yylval.lineno++; 695 yylval.colno = 0; 696 } 697 } 698 699 /* skip single line comments and shell magic */ 700 if ((c == '/' && peek() == '/') || 701 (yylval.lineno == 1 && yylval.colno == 1 && c == '#' && 702 peek() == '!')) { 703 for (c = lgetc(); c != EOF; c = lgetc()) { 704 if (c == '\n') { 705 yylval.lineno++; 706 yylval.colno = 0; 707 goto again; 708 } 709 } 710 } 711 712 /* skip multi line comments */ 713 if (c == '/' && peek() == '*') { 714 int pc; 715 716 for (pc = 0, c = lgetc(); c != EOF; c = lgetc()) { 717 if (pc == '*' && c == '/') 718 goto again; 719 else if (c == '\n') 720 yylval.lineno++; 721 pc = c; 722 } 723 } 724 725 switch (c) { 726 case '!': 727 case '=': 728 if (peek() == '=') { 729 lgetc(); 730 return (c == '=') ? OP_EQ : OP_NE; 731 } 732 case '&': 733 if (peek() == '&') { 734 lgetc(); 735 return OP_LAND; 736 } 737 case '|': 738 if (peek() == '|') { 739 lgetc(); 740 return OP_LOR; 741 } 742 case '/': 743 if (peek() == '{' || peek() == '/' || peek() == '\n') { 744 return ENDPRED; 745 } 746 /* FALLTHROUGH */ 747 case ',': 748 case '(': 749 case ')': 750 case '{': 751 case '}': 752 case ':': 753 case ';': 754 return c; 755 case EOF: 756 return 0; 757 case '"': 758 /* parse C-like string */ 759 while ((c = lgetc()) != EOF && c != '"') { 760 if (c == '\\') { 761 c = lgetc(); 762 switch (c) { 763 case '\\': c = '\\'; break; 764 case '\'': c = '\''; break; 765 case '"': c = '"'; break; 766 case 'a': c = '\a'; break; 767 case 'b': c = '\b'; break; 768 case 'e': c = 033; break; 769 case 'f': c = '\f'; break; 770 case 'n': c = '\n'; break; 771 case 'r': c = '\r'; break; 772 case 't': c = '\t'; break; 773 case 'v': c = '\v'; break; 774 default: 775 yyerror("'%c' unsuported escape", c); 776 return ERROR; 777 } 778 } 779 *p++ = c; 780 if (p == ebuf) { 781 yyerror("too long line"); 782 return ERROR; 783 } 784 } 785 if (c == EOF) { 786 yyerror("\"%s\" invalid EOF", buf); 787 return ERROR; 788 } 789 *p++ = '\0'; 790 if ((str = strdup(buf)) == NULL) 791 err(1, "%s", __func__); 792 yylval.v.string = str; 793 return CSTRING; 794 default: 795 break; 796 } 797 798#define allowed_to_end_number(x) \ 799 (isspace(x) || x == ')' || x == '/' || x == '{' || x == ';' || x == ']' || x == ',') 800 801 /* parsing number */ 802 if (isdigit(c)) { 803 do { 804 *p++ = c; 805 if (p == ebuf) { 806 yyerror("too long line"); 807 return ERROR; 808 } 809 } while ((c = lgetc()) != EOF && isdigit(c)); 810 lungetc(); 811 if (c == EOF || allowed_to_end_number(c)) { 812 const char *errstr = NULL; 813 814 *p = '\0'; 815 yylval.v.number = strtonum(buf, LONG_MIN, LONG_MAX, 816 &errstr); 817 if (errstr) { 818 yyerror("invalid number '%s' (%s)", buf, 819 errstr); 820 return ERROR; 821 } 822 return NUMBER; 823 } else { 824 while (p > buf + 1) { 825 --p; 826 lungetc(); 827 } 828 c = *--p; 829 } 830 } 831 832#define allowed_in_string(x) (isalnum(c) || c == '_') 833 834 /* parsing next word */ 835 if (allowed_in_string(c)) { 836 struct keyword *kwp; 837 do { 838 *p++ = c; 839 if (p == ebuf) { 840 yyerror("too long line"); 841 return ERROR; 842 } 843 } while ((c = lgetc()) != EOF && (allowed_in_string(c))); 844 lungetc(); 845 *p = '\0'; 846 kwp = lookup(buf); 847 if (kwp == NULL) { 848 if ((yylval.v.string = strdup(buf)) == NULL) 849 err(1, "%s", __func__); 850 return STRING; 851 } 852 if (pflag) { 853 /* 854 * Probe lexer backdoor, interpret the token as a string 855 * rather than a keyword. Otherwise, reserved keywords 856 * would conflict with syscall names. The exception to 857 * this is 'hz', which hopefully will never be a 858 * syscall. 859 */ 860 if (kwp->token != HZ) { 861 yylval.v.string = kwp->word; 862 return STRING; 863 } 864 } 865 yylval.v.i = kwp->type; 866 return kwp->token; 867 } 868 869 if (c == '\n') { 870 yylval.lineno++; 871 yylval.colno = 0; 872 } 873 if (c == EOF) 874 return 0; 875 return c; 876} 877 878void 879pprint_syntax_error(void) 880{ 881 char line[BUFSIZ]; 882 int c, indent = yylval.colno; 883 size_t i; 884 885 strlcpy(line, &pbuf[pindex - yylval.colno], sizeof(line)); 886 887 for (i = 0; line[i] != '\0' && (c = line[i]) != '\n'; i++) { 888 if (c == '\t') 889 indent += (8 - 1); 890 fputc(c, stderr); 891 } 892 893 fprintf(stderr, "\n%*c\n", indent, '^'); 894} 895 896void 897yyerror(const char *fmt, ...) 898{ 899 const char *prefix; 900 va_list va; 901 902 prefix = (yylval.filename != NULL) ? yylval.filename : getprogname(); 903 904 fprintf(stderr, "%s:%d:%d: ", prefix, yylval.lineno, yylval.colno); 905 va_start(va, fmt); 906 vfprintf(stderr, fmt, va); 907 va_end(va); 908 fprintf(stderr, ":\n"); 909 910 pprint_syntax_error(); 911 912 perrors++; 913} 914 915int 916btparse(const char *str, size_t len, const char *filename, int debug) 917{ 918 if (debug > 0) 919 yydebug = 1; 920 pbuf = str; 921 plen = len; 922 pindex = 0; 923 yylval.filename = filename; 924 yylval.lineno = 1; 925 926 yyparse(); 927 928 assert(SLIST_EMPTY(&l_variables)); 929 930 return perrors; 931} 932