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