PageRenderTime 50ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/radtest/gram.y

#
Happy | 1030 lines | 940 code | 90 blank | 0 comment | 0 complexity | 16852599927e3b24038fe5d322305f01 MD5 | raw file
Possible License(s): GPL-3.0, CC-BY-SA-3.0, LGPL-3.0
  1. %{
  2. /* This file is part of GNU Radius.
  3. Copyright (C) 2000, 2001, 2002, 2003, 2004, 2006, 2007, 2010,
  4. 2013 Free Software Foundation, Inc.
  5. Written by Sergey Poznyakoff
  6. GNU Radius is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 3 of the License, or
  9. (at your option) any later version.
  10. GNU Radius is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with GNU Radius. If not, see <http://www.gnu.org/licenses/>. */
  16. #if defined(HAVE_CONFIG_H)
  17. # include <config.h>
  18. #endif
  19. #include <sys/types.h>
  20. #include <sys/socket.h>
  21. #include <sys/time.h>
  22. #include <sys/file.h>
  23. #include <sys/stat.h>
  24. #include <netinet/in.h>
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <netdb.h>
  28. #include <fcntl.h>
  29. #include <ctype.h>
  30. #include <unistd.h>
  31. #include <signal.h>
  32. #include <errno.h>
  33. #include <sys/wait.h>
  34. #include <common.h>
  35. #include <radtest.h>
  36. #define YYERROR_VERBOSE 1
  37. extern int yylex();
  38. /* Local variables */
  39. static int current_nesting_level; /* Nesting level of WHILE/DO statements */
  40. static int error_count; /* In interactive mode: number of errors
  41. in the statement being compiled. Gets
  42. reset to 0 after each statement.
  43. In batch mode: total number of errors
  44. encountered so far */
  45. static struct { /* Definition of the function currently
  46. being compiled */
  47. char *function; /* Function name */
  48. grad_locus_t locus; /* Location of the beginning of
  49. the definition */
  50. } defn;
  51. /* Context stack support. This is used for improving diagnostic
  52. messages and after-error synchronization */
  53. struct context_stack {
  54. struct context_stack *next;
  55. enum context ctx;
  56. };
  57. static struct context_stack *context_stack;
  58. static enum context
  59. push_ctx(enum context ctx)
  60. {
  61. struct context_stack *p = grad_emalloc(sizeof(*p));
  62. p->ctx = ctx;
  63. p->next = context_stack;
  64. context_stack = p;
  65. return ctx;
  66. }
  67. enum context
  68. pop_ctx()
  69. {
  70. enum context ctx;
  71. struct context_stack *p = context_stack;
  72. if (!context_stack)
  73. return ctx_none;
  74. ctx = p->ctx;
  75. context_stack = p->next;
  76. grad_free(p);
  77. return ctx;
  78. }
  79. enum context
  80. peek_ctx()
  81. {
  82. return context_stack ? context_stack->ctx : ctx_none;
  83. }
  84. /* Forward declarations */
  85. static void run_statement(radtest_node_t *node);
  86. static void errsync();
  87. int yyerror(char *s);
  88. %}
  89. %token EOL AUTH ACCT SEND EXPECT T_BEGIN T_END
  90. %token IF ELSE WHILE DO BREAK CONTINUE INPUT SHIFT GETOPT CASE IN
  91. %token T_RETURN
  92. %token <set> SET
  93. %token PRINT
  94. %token EXIT
  95. %token T_BOGUS
  96. %token ARGCOUNT
  97. %token <deref> IDENT
  98. %token <parm> PARM
  99. %token <string> NAME
  100. %token <number> NUMBER
  101. %token <string> QUOTE
  102. %token <bstring> BSTRING
  103. %token <ipaddr> IPADDRESS
  104. %left PRITEM
  105. %left OR
  106. %left AND
  107. %nonassoc EQ NE
  108. %nonassoc LT LE GT GE
  109. %left '+' '-'
  110. %left '*' '/' '%'
  111. %left UMINUS NOT
  112. %nonassoc '['
  113. %type <op> op
  114. %type <pair> pair
  115. %type <list> pair_list maybe_pair_list prlist maybe_prlist list caselist
  116. %type <i> closure req_code nesting_level port_type
  117. %type <node> stmt lstmt expr maybe_expr value bool cond expr_or_pair_list
  118. pritem
  119. %type <var> send_flag imm_value
  120. %type <symtab> send_flags send_flag_list
  121. %type <string> name string
  122. %type <case_branch> casecond
  123. %type <fun> function_def
  124. %union {
  125. int i;
  126. long number;
  127. char *string;
  128. radtest_node_t *node;
  129. radtest_node_deref_var_t deref;
  130. radtest_node_deref_parm_t parm;
  131. grad_uint32_t ipaddr;
  132. enum grad_operator op;
  133. radtest_pair_t *pair;
  134. grad_list_t *list;
  135. radtest_variable_t *var;
  136. grad_symtab_t *symtab;
  137. struct {
  138. int argc;
  139. char **argv;
  140. } set;
  141. radtest_case_branch_t *case_branch;
  142. radtest_function_t *fun;
  143. radtest_bstring_t bstring;
  144. }
  145. %%
  146. program : /* empty */
  147. | input
  148. | input stmt
  149. ;
  150. input : lstmt
  151. {
  152. run_statement($1);
  153. }
  154. | input lstmt
  155. {
  156. run_statement($2);
  157. }
  158. ;
  159. list : lstmt
  160. {
  161. $$ = grad_list_create();
  162. if ($1)
  163. grad_list_append($$, $1);
  164. }
  165. | list lstmt
  166. {
  167. if ($2)
  168. grad_list_append($1, $2);
  169. $$ = $1;
  170. }
  171. ;
  172. lstmt : /* empty */ EOL
  173. {
  174. $$ = NULL;
  175. }
  176. | stmt EOL
  177. {
  178. switch (peek_ctx()) {
  179. case ctx_iferr:
  180. case ctx_doerr:
  181. pop_ctx();
  182. break;
  183. default:
  184. break;
  185. }
  186. }
  187. | error EOL
  188. {
  189. errsync();
  190. yyclearin;
  191. yyerrok;
  192. }
  193. ;
  194. maybe_eol :
  195. | EOL
  196. ;
  197. stmt : T_BEGIN list T_END
  198. {
  199. $$ = radtest_node_alloc(radtest_node_stmt);
  200. $$->v.list = $2;
  201. }
  202. | if cond maybe_eol stmt
  203. {
  204. pop_ctx();
  205. $$ = radtest_node_alloc(radtest_node_cond);
  206. $$->v.cond.cond = $2;
  207. $$->v.cond.iftrue = $4;
  208. $$->v.cond.iffalse = NULL;
  209. }
  210. | if cond maybe_eol stmt else stmt
  211. {
  212. pop_ctx();
  213. $$ = radtest_node_alloc(radtest_node_cond);
  214. $$->v.cond.cond = $2;
  215. $$->v.cond.iftrue = $4;
  216. $$->v.cond.iffalse = $6;
  217. }
  218. | case expr in caselist T_END
  219. {
  220. pop_ctx();
  221. $$ = radtest_node_alloc(radtest_node_case);
  222. $$->locus = $2->locus;
  223. $$->v.branch.expr = $2;
  224. $$->v.branch.branchlist = $4;
  225. }
  226. | while { current_nesting_level++; } cond EOL stmt
  227. {
  228. pop_ctx();
  229. current_nesting_level--;
  230. $$ = radtest_node_alloc(radtest_node_loop);
  231. $$->v.loop.cond = $3;
  232. $$->v.loop.body = $5;
  233. $$->v.loop.first_pass = 0;
  234. }
  235. | do EOL { current_nesting_level++; } stmt EOL WHILE { current_nesting_level--; } cond
  236. {
  237. pop_ctx();
  238. $$ = radtest_node_alloc(radtest_node_loop);
  239. $$->v.loop.cond = $8;
  240. $$->v.loop.body = $4;
  241. $$->v.loop.first_pass = 1;
  242. }
  243. | PRINT prlist
  244. {
  245. $$ = radtest_node_alloc(radtest_node_print);
  246. $$->v.list = $2;
  247. }
  248. | NAME EQ expr
  249. {
  250. $$ = radtest_node_alloc(radtest_node_asgn);
  251. $$->v.asgn.name = $1;
  252. $$->v.asgn.expr = $3;
  253. }
  254. | SEND send_flags port_type req_code expr_or_pair_list
  255. {
  256. $$ = radtest_node_alloc(radtest_node_send);
  257. $$->v.send.cntl = $2;
  258. $$->v.send.port_type = $3;
  259. $$->v.send.code = $4;
  260. $$->v.send.expr = $5;
  261. }
  262. | EXPECT req_code expr_or_pair_list
  263. {
  264. $$ = radtest_node_alloc(radtest_node_expect);
  265. $$->v.expect.code = $2;
  266. $$->v.expect.expr = $3;
  267. }
  268. | EXIT maybe_expr
  269. {
  270. $$ = radtest_node_alloc(radtest_node_exit);
  271. $$->v.expr = $2;
  272. }
  273. | BREAK nesting_level
  274. {
  275. if ($2 > current_nesting_level) {
  276. parse_error(_("not enough 'while's to break from"));
  277. }
  278. $$ = radtest_node_alloc(radtest_node_break);
  279. $$->v.level = $2;
  280. }
  281. | CONTINUE nesting_level
  282. {
  283. if ($2 > current_nesting_level) {
  284. parse_error(_("not enough 'while's to continue"));
  285. }
  286. $$ = radtest_node_alloc(radtest_node_continue);
  287. $$->v.level = $2;
  288. }
  289. | INPUT
  290. {
  291. $$ = radtest_node_alloc(radtest_node_input);
  292. $$->v.input.expr = NULL;
  293. $$->v.input.var = (radtest_variable_t*)
  294. grad_sym_lookup_or_install(vartab,
  295. "INPUT",
  296. 1);
  297. }
  298. | INPUT expr NAME
  299. {
  300. $$ = radtest_node_alloc(radtest_node_input);
  301. $$->v.input.expr = $2;
  302. $$->v.input.var = (radtest_variable_t*)
  303. grad_sym_lookup_or_install(vartab,
  304. $3,
  305. 1);
  306. }
  307. | SET
  308. {
  309. $$ = radtest_node_alloc(radtest_node_set);
  310. $$->v.set.argc = $1.argc;
  311. $$->v.set.argv = $1.argv;
  312. }
  313. | SHIFT maybe_expr
  314. {
  315. $$ = radtest_node_alloc(radtest_node_shift);
  316. $$->v.expr = $2;
  317. }
  318. | function_def list T_END
  319. {
  320. $1->body = $2;
  321. radtest_fix_mem();
  322. $$ = NULL;
  323. defn.function = NULL;
  324. }
  325. | T_RETURN maybe_expr
  326. {
  327. if (!defn.function) {
  328. parse_error(_("return outside of a function definition"));
  329. }
  330. $$ = radtest_node_alloc(radtest_node_return);
  331. $$->v.expr = $2;
  332. }
  333. | NAME '(' maybe_prlist ')'
  334. {
  335. radtest_function_t *fun;
  336. fun = (radtest_function_t*)
  337. grad_sym_lookup(functab, $1);
  338. if (!fun) {
  339. parse_error(_("undefined function `%s'"), $1);
  340. }
  341. $$ = radtest_node_alloc(radtest_node_call);
  342. $$->v.call.fun = fun;
  343. $$->v.call.args = $3;
  344. }
  345. ;
  346. function_def : NAME EOL T_BEGIN EOL
  347. {
  348. radtest_function_t *fun;
  349. if (defn.function) {
  350. parse_error(_("nested function definitions "
  351. "are not allowed"));
  352. parse_error_loc(&defn.locus,
  353. _("the current function "
  354. "definition begins here"));
  355. YYERROR; /* FIXME */
  356. }
  357. defn.function = $1;
  358. defn.locus = source_locus;
  359. fun = (radtest_function_t*)
  360. grad_sym_lookup_or_install(functab, $1, 1);
  361. if (fun->body) {
  362. parse_error(_("redefinition of function `%s'"), $1);
  363. parse_error_loc(&fun->locus,
  364. _("`%s' previously defined here"),
  365. $1);
  366. YYERROR; /* FIXME */
  367. }
  368. fun->locus = source_locus;
  369. $$ = fun;
  370. }
  371. ;
  372. if : IF
  373. {
  374. push_ctx(ctx_if);
  375. }
  376. ;
  377. case : CASE
  378. {
  379. push_ctx(ctx_case);
  380. }
  381. ;
  382. do : DO
  383. {
  384. push_ctx(ctx_do);
  385. }
  386. ;
  387. while : WHILE
  388. {
  389. push_ctx(ctx_while);
  390. }
  391. ;
  392. else : ELSE maybe_eol
  393. {
  394. pop_ctx();
  395. }
  396. ;
  397. in : IN maybe_eol
  398. ;
  399. caselist : casecond
  400. {
  401. $$ = grad_list_create();
  402. grad_list_append($$, $1);
  403. }
  404. | caselist casecond
  405. {
  406. grad_list_append($1, $2);
  407. $$ = $1;
  408. }
  409. ;
  410. casecond : expr ')' stmt nls
  411. {
  412. radtest_case_branch_t *p = radtest_branch_alloc();
  413. p->cond = $1;
  414. p->node = $3;
  415. $$ = p;
  416. }
  417. ;
  418. nls : EOL
  419. | nls EOL
  420. ;
  421. name : /* empty */
  422. {
  423. $$ = NULL;
  424. }
  425. | NAME
  426. ;
  427. string : NAME
  428. | QUOTE
  429. | BSTRING
  430. {
  431. parse_error(_("warning: truncating binary string"));
  432. $$ = $1.ptr;
  433. }
  434. ;
  435. nesting_level : /* empty */
  436. {
  437. $$ = 1;
  438. }
  439. | NUMBER
  440. {
  441. $$ = $1;
  442. }
  443. ;
  444. port_type : AUTH
  445. {
  446. $$ = GRAD_PORT_AUTH;
  447. }
  448. | ACCT
  449. {
  450. $$ = GRAD_PORT_ACCT;
  451. }
  452. ;
  453. req_code : NUMBER
  454. {
  455. $$ = $1;
  456. }
  457. | NAME
  458. {
  459. $$ = grad_request_name_to_code($1);
  460. if ($$ == 0)
  461. parse_error(_("expected integer value or request code name"));
  462. }
  463. ;
  464. send_flags : /* empty */
  465. {
  466. $$ = NULL;
  467. }
  468. | send_flag_list
  469. ;
  470. send_flag_list: send_flag
  471. {
  472. radtest_variable_t *var;
  473. $$ = grad_symtab_create(sizeof(*var), var_free);
  474. var = (radtest_variable_t*) grad_sym_install($$,
  475. $1->name);
  476. radtest_var_copy (var, $1);
  477. }
  478. | send_flag_list send_flag
  479. {
  480. radtest_variable_t *var;
  481. var = (radtest_variable_t*) grad_sym_install($1,
  482. $2->name);
  483. radtest_var_copy (var, $2); /* FIXME: check this */
  484. }
  485. ;
  486. send_flag : NAME EQ NUMBER
  487. {
  488. $$ = radtest_var_alloc(rtv_integer);
  489. $$->name = $1;
  490. $$->datum.number = $3;
  491. }
  492. ;
  493. expr_or_pair_list: /* empty */
  494. {
  495. $$ = NULL;
  496. }
  497. | pair_list
  498. {
  499. radtest_variable_t *var = radtest_var_alloc(rtv_pairlist);
  500. var->datum.list = $1;
  501. $$ = radtest_node_alloc(radtest_node_value);
  502. $$->v.var = var;
  503. }
  504. | expr
  505. ;
  506. cond : bool
  507. | NOT cond
  508. {
  509. $$ = radtest_node_alloc(radtest_node_unary);
  510. $$->v.unary.op = radtest_op_not;
  511. $$->v.unary.operand = $2;
  512. }
  513. | '(' cond ')'
  514. {
  515. $$ = $2;
  516. }
  517. | cond AND cond
  518. {
  519. $$ = radtest_node_alloc(radtest_node_bin);
  520. $$->v.bin.op = radtest_op_and;
  521. $$->v.bin.left = $1;
  522. $$->v.bin.right = $3;
  523. }
  524. | cond OR cond
  525. {
  526. $$ = radtest_node_alloc(radtest_node_bin);
  527. $$->v.bin.op = radtest_op_or;
  528. $$->v.bin.left = $1;
  529. $$->v.bin.right = $3;
  530. }
  531. | cond EQ cond
  532. {
  533. $$ = radtest_node_alloc(radtest_node_bin);
  534. $$->v.bin.op = radtest_op_eq;
  535. $$->v.bin.left = $1;
  536. $$->v.bin.right = $3;
  537. }
  538. | cond LT cond
  539. {
  540. $$ = radtest_node_alloc(radtest_node_bin);
  541. $$->v.bin.op = radtest_op_lt;
  542. $$->v.bin.left = $1;
  543. $$->v.bin.right = $3;
  544. }
  545. | cond GT cond
  546. {
  547. $$ = radtest_node_alloc(radtest_node_bin);
  548. $$->v.bin.op = radtest_op_gt;
  549. $$->v.bin.left = $1;
  550. $$->v.bin.right = $3;
  551. }
  552. | cond NE cond
  553. {
  554. $$ = radtest_node_alloc(radtest_node_bin);
  555. $$->v.bin.op = radtest_op_ne;
  556. $$->v.bin.left = $1;
  557. $$->v.bin.right = $3;
  558. }
  559. | cond LE cond
  560. {
  561. $$ = radtest_node_alloc(radtest_node_bin);
  562. $$->v.bin.op = radtest_op_le;
  563. $$->v.bin.left = $1;
  564. $$->v.bin.right = $3;
  565. }
  566. | cond GE cond
  567. {
  568. $$ = radtest_node_alloc(radtest_node_bin);
  569. $$->v.bin.op = radtest_op_ge;
  570. $$->v.bin.left = $1;
  571. $$->v.bin.right = $3;
  572. }
  573. ;
  574. bool : expr
  575. ;
  576. expr : value
  577. | GETOPT string name name
  578. {
  579. char *name = $3 ? $3 : "OPTVAR";
  580. $$ = radtest_node_alloc(radtest_node_getopt);
  581. $$->v.gopt.last = 0;
  582. $$->v.gopt.optstr = $2;
  583. $$->v.gopt.var = (radtest_variable_t*)
  584. grad_sym_lookup_or_install(vartab, name, 1);
  585. name = $4 ? $4 : "OPTARG";
  586. $$->v.gopt.arg = (radtest_variable_t*)
  587. grad_sym_lookup_or_install(vartab, name, 1);
  588. name = $4 ? $4 : "OPTIND";
  589. $$->v.gopt.ind = (radtest_variable_t*)
  590. grad_sym_lookup_or_install(vartab, name, 1);
  591. }
  592. | '(' expr ')'
  593. {
  594. $$ = $2;
  595. }
  596. | expr '[' NAME closure ']'
  597. {
  598. grad_dict_attr_t *dict = grad_attr_name_to_dict($3);
  599. if (!dict) {
  600. parse_error(_("unknown attribute `%s'"), $3);
  601. $$ = NULL;
  602. } else {
  603. $$ = radtest_node_alloc(radtest_node_attr);
  604. $$->v.attr.node = $1;
  605. $$->v.attr.dict = dict;
  606. $$->v.attr.all = $4;
  607. if ($4 && dict->type != GRAD_TYPE_STRING)
  608. parse_error(
  609. _("warning: '*' is meaningless for this attribute type"));
  610. }
  611. }
  612. | expr '+' expr
  613. {
  614. $$ = radtest_node_alloc(radtest_node_bin);
  615. $$->v.bin.op = radtest_op_add;
  616. $$->v.bin.left = $1;
  617. $$->v.bin.right = $3;
  618. }
  619. | expr '-' expr
  620. {
  621. $$ = radtest_node_alloc(radtest_node_bin);
  622. $$->v.bin.op = radtest_op_sub;
  623. $$->v.bin.left = $1;
  624. $$->v.bin.right = $3;
  625. }
  626. | expr '*' expr
  627. {
  628. $$ = radtest_node_alloc(radtest_node_bin);
  629. $$->v.bin.op = radtest_op_mul;
  630. $$->v.bin.left = $1;
  631. $$->v.bin.right = $3;
  632. }
  633. | expr '/' expr
  634. {
  635. $$ = radtest_node_alloc(radtest_node_bin);
  636. $$->v.bin.op = radtest_op_div;
  637. $$->v.bin.left = $1;
  638. $$->v.bin.right = $3;
  639. }
  640. | expr '%' expr
  641. {
  642. $$ = radtest_node_alloc(radtest_node_bin);
  643. $$->v.bin.op = radtest_op_mod;
  644. $$->v.bin.left = $1;
  645. $$->v.bin.right = $3;
  646. }
  647. | '-' expr %prec UMINUS
  648. {
  649. $$ = radtest_node_alloc(radtest_node_unary);
  650. $$->v.unary.op = radtest_op_neg;
  651. $$->v.unary.operand = $2;
  652. }
  653. | '+' expr %prec UMINUS
  654. {
  655. $$ = $2;
  656. }
  657. ;
  658. maybe_expr : /* empty */
  659. {
  660. $$ = NULL;
  661. }
  662. | expr
  663. ;
  664. value : imm_value
  665. {
  666. $$ = radtest_node_alloc(radtest_node_value);
  667. $$->v.var = $1;
  668. }
  669. | IDENT
  670. {
  671. $$ = radtest_node_alloc(radtest_node_deref);
  672. $$->v.deref = $1;
  673. }
  674. | PARM
  675. {
  676. $$ = radtest_node_alloc(radtest_node_parm);
  677. $$->v.parm = $1;
  678. }
  679. | ARGCOUNT
  680. {
  681. $$ = radtest_node_alloc(radtest_node_argcount);
  682. }
  683. | NAME '(' maybe_prlist ')'
  684. {
  685. radtest_function_t *fun;
  686. fun = (radtest_function_t*)
  687. grad_sym_lookup(functab, $1);
  688. if (!fun) {
  689. parse_error(_("undefined function `%s'"), $1);
  690. $$ = NULL;
  691. } else {
  692. $$ = radtest_node_alloc(radtest_node_call);
  693. $$->v.call.fun = fun;
  694. $$->v.call.args = $3;
  695. }
  696. }
  697. ;
  698. closure : /* empty */
  699. {
  700. $$ = 0;
  701. }
  702. | '*'
  703. {
  704. $$ = 1;
  705. }
  706. ;
  707. imm_value : NUMBER
  708. {
  709. $$ = radtest_var_alloc(rtv_integer);
  710. $$->datum.number = $1;
  711. }
  712. | IPADDRESS
  713. {
  714. $$ = radtest_var_alloc(rtv_ipaddress);
  715. $$->datum.ipaddr = $1;
  716. }
  717. | QUOTE
  718. {
  719. $$ = radtest_var_alloc(rtv_string);
  720. $$->datum.string = $1;
  721. }
  722. | BSTRING
  723. {
  724. $$ = radtest_var_alloc(rtv_bstring);
  725. $$->datum.bstring = $1;
  726. }
  727. | NAME
  728. {
  729. $$ = radtest_var_alloc(rtv_string);
  730. $$->datum.string = $1;
  731. }
  732. | '(' maybe_pair_list ')'
  733. {
  734. $$ = radtest_var_alloc(rtv_pairlist);
  735. $$->datum.list = $2;
  736. }
  737. ;
  738. maybe_prlist : /* empty */
  739. {
  740. $$ = NULL;
  741. }
  742. | prlist
  743. ;
  744. maybe_pair_list: /* empty */
  745. {
  746. $$ = NULL;
  747. }
  748. | pair_list
  749. ;
  750. pair_list : pair
  751. {
  752. $$ = grad_list_create();
  753. grad_list_append($$, $1);
  754. }
  755. | pair_list pair
  756. {
  757. grad_list_append($1, $2);
  758. $$ = $1;
  759. }
  760. | pair_list ',' pair
  761. {
  762. grad_list_append($1, $3);
  763. $$ = $1;
  764. }
  765. | pair_list error
  766. ;
  767. pair : NAME op expr
  768. {
  769. grad_dict_attr_t *attr = grad_attr_name_to_dict($1);
  770. if (!attr)
  771. parse_error(_("unknown attribute `%s'"), $1);
  772. $$ = radtest_pair_alloc();
  773. $$->attr = attr;
  774. $$->op = $2;
  775. $$->node = $3;
  776. }
  777. ;
  778. op : EQ
  779. {
  780. $$ = grad_operator_equal;
  781. }
  782. | LT
  783. {
  784. $$ = grad_operator_less_than;
  785. }
  786. | GT
  787. {
  788. $$ = grad_operator_greater_than;
  789. }
  790. | NE
  791. {
  792. $$ = grad_operator_not_equal;
  793. }
  794. | LE
  795. {
  796. $$ = grad_operator_less_equal;
  797. }
  798. | GE
  799. {
  800. $$ = grad_operator_greater_equal;
  801. }
  802. ;
  803. prlist : pritem
  804. {
  805. $$ = grad_list_create();
  806. grad_list_append($$, $1);
  807. }
  808. | prlist ',' pritem
  809. {
  810. grad_list_append($1, $3);
  811. $$ = $1;
  812. }
  813. | prlist pritem
  814. {
  815. grad_list_append($1, $2);
  816. $$ = $1;
  817. }
  818. ;
  819. pritem : expr %prec PRITEM
  820. ;
  821. %%
  822. int
  823. yyerror(char *s)
  824. {
  825. if (strcmp(s, "parse error") == 0
  826. || strcmp(s, "syntax error") == 0) {
  827. if (yychar == T_END)
  828. parse_error(_("Misplaced `end'"));
  829. else if (yychar == EOL) {
  830. grad_locus_t loc = source_locus;
  831. loc.line--;
  832. parse_error_loc(&loc, _("Unexpected end of line"));
  833. } else if (peek_ctx() == ctx_doerr)
  834. ;
  835. else
  836. parse_error(s);
  837. } else if (yychar == EOL) {
  838. grad_locus_t loc = source_locus;
  839. loc.line--;
  840. parse_error_loc(&loc, s);
  841. } else
  842. parse_error(s);
  843. }
  844. static char *funcname_displayed = NULL;
  845. static int
  846. namecmp(char *a, char *b)
  847. {
  848. if (!a || !b)
  849. return a != b;
  850. return strcmp(a, b);
  851. }
  852. static void
  853. print_function_name()
  854. {
  855. if (namecmp(funcname_displayed, defn.function)) {
  856. if (defn.function)
  857. fprintf(stderr, _("In function `%s':\n"),
  858. defn.function);
  859. else
  860. fprintf(stderr, _("At top level:\n"));
  861. funcname_displayed = defn.function;
  862. }
  863. }
  864. void
  865. parse_error(const char *fmt, ...)
  866. {
  867. va_list ap;
  868. print_function_name();
  869. va_start(ap, fmt);
  870. fprintf(stderr, "%s:%lu: ",
  871. source_locus.file,
  872. (unsigned long) source_locus.line);
  873. vfprintf(stderr, fmt, ap);
  874. va_end(ap);
  875. fprintf(stderr, "\n");
  876. error_count++;
  877. }
  878. void
  879. parse_error_loc(grad_locus_t *locus, const char *fmt, ...)
  880. {
  881. va_list ap;
  882. print_function_name();
  883. va_start(ap, fmt);
  884. fprintf(stderr, "%s:%lu: ",
  885. locus->file, (unsigned long) locus->line);
  886. vfprintf(stderr, fmt, ap);
  887. va_end(ap);
  888. fprintf(stderr, "\n");
  889. error_count++;
  890. }
  891. void
  892. set_yydebug()
  893. {
  894. extern int yydebug;
  895. if (GRAD_DEBUG_LEVEL(1)) {
  896. yydebug = 1;
  897. }
  898. }
  899. static void
  900. run_statement(radtest_node_t *node)
  901. {
  902. if (!dry_run) {
  903. if (!error_count)
  904. radtest_eval(node, toplevel_env);
  905. /* Clear error_count only if we are in interactive
  906. mode. There is no use continuing executing of a script
  907. after an erroneous statement. */
  908. if (interactive)
  909. error_count = 0;
  910. }
  911. radtest_free_mem();
  912. }
  913. int
  914. read_and_eval(char *filename)
  915. {
  916. if (open_input(filename))
  917. return 1;
  918. return (yyparse() || error_count) ? 1 : 0;
  919. }
  920. static void
  921. errsync()
  922. {
  923. enum context ctx = pop_ctx();
  924. switch (ctx) {
  925. case ctx_none:
  926. break;
  927. case ctx_if:
  928. push_ctx(ctx_iferr);
  929. break;
  930. case ctx_do:
  931. current_nesting_level--;
  932. push_ctx(ctx_doerr);
  933. break;
  934. case ctx_while:
  935. current_nesting_level--;
  936. break;
  937. case ctx_case:
  938. ;
  939. }
  940. }