trafgen: parser: Support "etype"/"type" keywords for Ethertype
[netsniff-ng.git] / trafgen_parser.y
blob71f88d8f38c25f65ddf4ce91387e0a94204bbfd7
1 /*
2 * netsniff-ng - the packet sniffing beast
3 * By Daniel Borkmann <daniel@netsniff-ng.org>
4 * Copyright 2012 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,
5 * Swiss federal institute of technology (ETH Zurich)
6 * Subject to the GPL, version 2.
7 */
9 /* yaac-func-prefix: yy */
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <signal.h>
16 #include <stdint.h>
17 #include <errno.h>
18 #include <stdbool.h>
19 #include <libgen.h>
20 #include <net/if_arp.h>
21 #include <netinet/in.h>
23 #include "xmalloc.h"
24 #include "trafgen_parser.tab.h"
25 #include "trafgen_conf.h"
26 #include "trafgen_proto.h"
27 #include "trafgen_l2.h"
28 #include "trafgen_l3.h"
29 #include "trafgen_l4.h"
30 #include "built_in.h"
31 #include "die.h"
32 #include "str.h"
33 #include "csum.h"
34 #include "cpp.h"
36 #define YYERROR_VERBOSE 0
37 #define YYDEBUG 0
38 #define YYENABLE_NLS 1
39 #define YYLTYPE_IS_TRIVIAL 1
40 #define ENABLE_NLS 1
42 extern FILE *yyin;
43 extern int yylex(void);
44 extern void yy_scan_string(char *);
45 extern void yylex_destroy();
46 extern void yyerror(const char *);
47 extern int yylineno;
48 extern char *yytext;
50 extern struct packet *packets;
51 extern size_t plen;
53 #define packet_last (plen - 1)
55 #define payload_last (packets[packet_last].len - 1)
57 extern struct packet_dyn *packet_dyn;
58 extern size_t dlen;
60 #define packetd_last (dlen - 1)
62 #define packetdc_last (packet_dyn[packetd_last].clen - 1)
63 #define packetdr_last (packet_dyn[packetd_last].rlen - 1)
64 #define packetds_last (packet_dyn[packetd_last].slen - 1)
66 static int our_cpu, min_cpu = -1, max_cpu = -1;
68 static struct proto_hdr *hdr;
70 static inline int test_ignore(void)
72 if (min_cpu < 0 && max_cpu < 0)
73 return 0;
74 else if (max_cpu >= our_cpu && min_cpu <= our_cpu)
75 return 0;
76 else
77 return 1;
80 static inline void __init_new_packet_slot(struct packet *slot)
82 slot->payload = NULL;
83 slot->len = 0;
86 static inline void __init_new_counter_slot(struct packet_dyn *slot)
88 slot->cnt = NULL;
89 slot->clen = 0;
92 static inline void __init_new_randomizer_slot(struct packet_dyn *slot)
94 slot->rnd = NULL;
95 slot->rlen = 0;
98 static inline void __init_new_csum_slot(struct packet_dyn *slot)
100 slot->csum = NULL;
101 slot->slen = 0;
104 static inline void __setup_new_counter(struct counter *c, uint8_t start,
105 uint8_t stop, uint8_t stepping,
106 int type)
108 c->min = start;
109 c->max = stop;
110 c->inc = stepping;
111 c->val = (type == TYPE_INC) ? start : stop;
112 c->off = payload_last;
113 c->type = type;
116 static inline void __setup_new_randomizer(struct randomizer *r)
118 r->off = payload_last;
121 static inline void __setup_new_csum16(struct csum16 *s, off_t from, off_t to,
122 enum csum which)
124 s->off = payload_last - 1;
125 s->from = from;
126 s->to = to;
127 s->which = which;
130 static void realloc_packet(void)
132 if (test_ignore())
133 return;
135 plen++;
136 packets = xrealloc(packets, plen * sizeof(*packets));
138 __init_new_packet_slot(&packets[packet_last]);
140 dlen++;
141 packet_dyn = xrealloc(packet_dyn, dlen * sizeof(*packet_dyn));
143 __init_new_counter_slot(&packet_dyn[packetd_last]);
144 __init_new_randomizer_slot(&packet_dyn[packetd_last]);
145 __init_new_csum_slot(&packet_dyn[packetd_last]);
148 struct packet *current_packet(void)
150 return &packets[packet_last];
153 static void set_byte(uint8_t val)
155 struct packet *pkt = &packets[packet_last];
157 if (test_ignore())
158 return;
160 pkt->len++;
161 pkt->payload = xrealloc(pkt->payload, pkt->len);
162 pkt->payload[payload_last] = val;
165 static void set_multi_byte(uint8_t *s, size_t len)
167 size_t i;
169 for (i = 0; i < len; ++i)
170 set_byte(s[i]);
173 void set_fill(uint8_t val, size_t len)
175 size_t i;
176 struct packet *pkt = &packets[packet_last];
178 if (test_ignore())
179 return;
181 pkt->len += len;
182 pkt->payload = xrealloc(pkt->payload, pkt->len);
183 for (i = 0; i < len; ++i)
184 pkt->payload[payload_last - i] = val;
187 static void __set_csum16_dynamic(size_t from, size_t to, enum csum which)
189 struct packet *pkt = &packets[packet_last];
190 struct packet_dyn *pktd = &packet_dyn[packetd_last];
192 pkt->len += 2;
193 pkt->payload = xrealloc(pkt->payload, pkt->len);
195 pktd->slen++;
196 pktd->csum = xrealloc(pktd->csum, pktd->slen * sizeof(struct csum16));
198 __setup_new_csum16(&pktd->csum[packetds_last], from, to, which);
201 static void __set_csum16_static(size_t from, size_t to, enum csum which __maybe_unused)
203 struct packet *pkt = &packets[packet_last];
204 uint16_t sum;
205 uint8_t *psum;
207 sum = htons(calc_csum(pkt->payload + from, to - from));
208 psum = (uint8_t *) &sum;
210 set_byte(psum[0]);
211 set_byte(psum[1]);
214 static inline bool is_dynamic_csum(enum csum which)
216 switch (which) {
217 case CSUM_UDP:
218 case CSUM_TCP:
219 case CSUM_UDP6:
220 case CSUM_TCP6:
221 return true;
222 default:
223 return false;
227 static void set_csum16(size_t from, size_t to, enum csum which)
229 struct packet *pkt = &packets[packet_last];
230 struct packet_dyn *pktd = &packet_dyn[packetd_last];
232 if (test_ignore())
233 return;
235 if (to < from) {
236 size_t tmp = to;
238 to = from;
239 from = tmp;
242 bug_on(!(from < to));
244 if (packet_dyn_has_elems(pktd) || to >= pkt->len || is_dynamic_csum(which))
245 __set_csum16_dynamic(from, to, which);
246 else
247 __set_csum16_static(from, to, which);
250 static void set_rnd(size_t len)
252 size_t i;
253 struct packet *pkt = &packets[packet_last];
255 if (test_ignore())
256 return;
258 pkt->len += len;
259 pkt->payload = xrealloc(pkt->payload, pkt->len);
260 for (i = 0; i < len; ++i)
261 pkt->payload[payload_last - i] = (uint8_t) rand();
264 static void set_sequential_inc(uint8_t start, size_t len, uint8_t stepping)
266 size_t i;
267 struct packet *pkt = &packets[packet_last];
269 if (test_ignore())
270 return;
272 pkt->len += len;
273 pkt->payload = xrealloc(pkt->payload, pkt->len);
274 for (i = 0; i < len; ++i) {
275 off_t off = len - 1 - i;
277 pkt->payload[payload_last - off] = start;
278 start += stepping;
282 static void set_sequential_dec(uint8_t start, size_t len, uint8_t stepping)
284 size_t i;
285 struct packet *pkt = &packets[packet_last];
287 if (test_ignore())
288 return;
290 pkt->len += len;
291 pkt->payload = xrealloc(pkt->payload, pkt->len);
292 for (i = 0; i < len; ++i) {
293 int off = len - 1 - i;
295 pkt->payload[payload_last - off] = start;
296 start -= stepping;
300 static void set_dynamic_rnd(void)
302 struct packet *pkt = &packets[packet_last];
303 struct packet_dyn *pktd = &packet_dyn[packetd_last];
305 if (test_ignore())
306 return;
308 pkt->len++;
309 pkt->payload = xrealloc(pkt->payload, pkt->len);
311 pktd->rlen++;
312 pktd->rnd = xrealloc(pktd->rnd, pktd->rlen * sizeof(struct randomizer));
314 __setup_new_randomizer(&pktd->rnd[packetdr_last]);
317 static void set_dynamic_incdec(uint8_t start, uint8_t stop, uint8_t stepping,
318 int type)
320 struct packet *pkt = &packets[packet_last];
321 struct packet_dyn *pktd = &packet_dyn[packetd_last];
323 if (test_ignore())
324 return;
326 pkt->len++;
327 pkt->payload = xrealloc(pkt->payload, pkt->len);
329 pktd->clen++;
330 pktd->cnt = xrealloc(pktd->cnt, pktd->clen * sizeof(struct counter));
332 __setup_new_counter(&pktd->cnt[packetdc_last], start, stop, stepping, type);
335 static void proto_add(enum proto_id pid)
337 proto_header_init(pid);
338 hdr = proto_current_header();
343 %union {
344 struct in_addr ip_addr;
345 long long int number;
346 uint8_t bytes[256];
347 char *str;
350 %token K_COMMENT K_FILL K_RND K_SEQINC K_SEQDEC K_DRND K_DINC K_DDEC K_WHITE
351 %token K_CPU K_CSUMIP K_CSUMUDP K_CSUMTCP K_CSUMUDP6 K_CSUMTCP6 K_CONST8 K_CONST16 K_CONST32 K_CONST64
353 %token K_DADDR K_SADDR K_ETYPE
354 %token K_OPER K_SHA K_SPA K_THA K_TPA K_REQUEST K_REPLY K_PTYPE K_HTYPE
355 %token K_PROT K_TTL K_DSCP K_ECN K_TOS K_LEN K_ID K_FLAGS K_FRAG K_IHL K_VER K_CSUM K_DF K_MF
356 %token K_SPORT K_DPORT
358 %token K_ETH
359 %token K_ARP
360 %token K_IP4
361 %token K_UDP
363 %token ',' '{' '}' '(' ')' '[' ']' ':' '-' '+' '*' '/' '%' '&' '|' '<' '>' '^'
365 %token number string mac ip_addr
367 %type <number> number expression
368 %type <str> string
369 %type <bytes> mac
370 %type <ip_addr> ip_addr
372 %left '-' '+' '*' '/' '%' '&' '|' '<' '>' '^'
376 packets
377 : { }
378 | packets packet { }
379 | packets inline_comment { }
380 | packets K_WHITE { }
383 inline_comment
384 : K_COMMENT { }
387 cpu_delim
388 : ':' { }
389 | '-' { }
392 delimiter_nowhite
393 : ',' { }
394 | ',' K_WHITE { }
397 noenforce_white
398 : { }
399 | K_WHITE { }
400 | delimiter_nowhite { }
403 skip_white
404 : { }
405 | K_WHITE { }
407 packet
408 : '{' noenforce_white payload noenforce_white '}' {
409 min_cpu = max_cpu = -1;
411 proto_packet_finish();
413 realloc_packet();
415 | K_CPU '(' number cpu_delim number ')' ':' noenforce_white '{' noenforce_white payload noenforce_white '}' {
416 min_cpu = $3;
417 max_cpu = $5;
419 if (min_cpu > max_cpu) {
420 int tmp = min_cpu;
422 min_cpu = max_cpu;
423 max_cpu = tmp;
426 proto_packet_finish();
428 realloc_packet();
430 | K_CPU '(' number ')' ':' noenforce_white '{' noenforce_white payload noenforce_white '}' {
431 min_cpu = max_cpu = $3;
433 proto_packet_finish();
435 realloc_packet();
439 payload
440 : elem { }
441 | payload elem_delimiter { }
444 delimiter
445 : delimiter_nowhite { }
446 | K_WHITE { }
449 elem_delimiter
450 : delimiter elem { }
453 elem
454 : number { set_byte((uint8_t) $1); }
455 | string { set_multi_byte((uint8_t *) $1 + 1, strlen($1) - 2); }
456 | fill { }
457 | rnd { }
458 | drnd { }
459 | seqinc { }
460 | seqdec { }
461 | dinc { }
462 | ddec { }
463 | csum { }
464 | const { }
465 | proto { proto_header_finish(hdr); }
466 | inline_comment { }
469 expression
470 : number
471 { $$ = $1; }
472 | expression '+' expression
473 { $$ = $1 + $3; }
474 | expression '-' expression
475 { $$ = $1 - $3; }
476 | expression '*' expression
477 { $$ = $1 * $3; }
478 | expression '/' expression
479 { $$ = $1 / $3; }
480 | expression '%' expression
481 { $$ = $1 % $3; }
482 | expression '&' expression
483 { $$ = $1 & $3; }
484 | expression '|' expression
485 { $$ = $1 | $3; }
486 | expression '^' expression
487 { $$ = $1 ^ $3; }
488 | expression '<' '<' expression
489 { $$ = $1 << $4; }
490 | expression '>' '>' expression
491 { $$ = $1 >> $4; }
492 | '-' expression
493 { $$ = -1 * $2; }
494 | '(' expression ')'
495 { $$ = $2;}
498 fill
499 : K_FILL '(' number delimiter number ')'
500 { set_fill($3, $5); }
503 const
504 : K_CONST8 '(' expression ')'
505 { set_byte((uint8_t) $3); }
506 | K_CONST16 '(' expression ')' {
507 uint16_t __c = cpu_to_be16((uint16_t) $3);
509 set_multi_byte((uint8_t *) &__c, sizeof(__c));
511 | K_CONST32 '(' expression ')' {
512 uint32_t __c = cpu_to_be32((uint32_t) $3);
514 set_multi_byte((uint8_t *) &__c, sizeof(__c));
516 | K_CONST64 '(' expression ')' {
517 uint64_t __c = cpu_to_be64((uint64_t) $3);
519 set_multi_byte((uint8_t *) &__c, sizeof(__c));
524 : K_RND '(' number ')'
525 { set_rnd($3); }
528 csum
529 : K_CSUMIP '(' number delimiter number ')'
530 { set_csum16($3, $5, CSUM_IP); }
531 | K_CSUMTCP '(' number delimiter number ')'
532 { set_csum16($3, $5, CSUM_TCP); }
533 | K_CSUMUDP '(' number delimiter number ')'
534 { set_csum16($3, $5, CSUM_UDP); }
535 | K_CSUMTCP6 '(' number delimiter number ')'
536 { set_csum16($3, $5, CSUM_TCP6); }
537 | K_CSUMUDP6 '(' number delimiter number ')'
538 { set_csum16($3, $5, CSUM_UDP6); }
541 seqinc
542 : K_SEQINC '(' number delimiter number ')'
543 { set_sequential_inc($3, $5, 1); }
544 | K_SEQINC '(' number delimiter number delimiter number ')'
545 { set_sequential_inc($3, $5, $7); }
548 seqdec
549 : K_SEQDEC '(' number delimiter number ')'
550 { set_sequential_dec($3, $5, 1); }
551 | K_SEQDEC '(' number delimiter number delimiter number ')'
552 { set_sequential_dec($3, $5, $7); }
555 drnd
556 : K_DRND '(' ')'
557 { set_dynamic_rnd(); }
558 | K_DRND '(' number ')'
560 int i, max = $3;
561 for (i = 0; i < max; ++i)
562 set_dynamic_rnd();
566 dinc
567 : K_DINC '(' number delimiter number ')'
568 { set_dynamic_incdec($3, $5, 1, TYPE_INC); }
569 | K_DINC '(' number delimiter number delimiter number ')'
570 { set_dynamic_incdec($3, $5, $7, TYPE_INC); }
573 ddec
574 : K_DDEC '(' number delimiter number ')'
575 { set_dynamic_incdec($3, $5, 1, TYPE_DEC); }
576 | K_DDEC '(' number delimiter number delimiter number ')'
577 { set_dynamic_incdec($3, $5, $7, TYPE_DEC); }
580 proto
581 : eth_proto { }
582 | arp_proto { }
583 | ip4_proto { }
584 | udp_proto { }
587 eth_proto
588 : eth '(' eth_param_list ')' { }
592 : K_ETH { proto_add(PROTO_ETH); }
595 eth_param_list
596 : { }
597 | eth_field { }
598 | eth_field delimiter eth_param_list { }
601 eth_field
602 : K_DADDR skip_white '=' skip_white mac
603 { proto_field_set_bytes(hdr, ETH_DST_ADDR, $5); }
604 | K_SADDR skip_white '=' skip_white mac
605 { proto_field_set_bytes(hdr, ETH_SRC_ADDR, $5); }
606 | K_ETYPE skip_white '=' skip_white number
607 { proto_field_set_be16(hdr, ETH_TYPE, $5); }
610 arp_proto
611 : arp '(' arp_param_list ')' { }
614 arp_param_list
615 : { }
616 | arp_field { }
617 | arp_field delimiter arp_param_list { }
620 arp_field
621 : K_OPER skip_white '=' skip_white K_REQUEST
622 { proto_field_set_be16(hdr, ARP_OPER, ARPOP_REQUEST); }
623 | K_OPER skip_white '=' skip_white K_REPLY
624 { proto_field_set_be16(hdr, ARP_OPER, ARPOP_REPLY); }
625 | K_OPER skip_white '=' skip_white number
626 { proto_field_set_be16(hdr, ARP_OPER, $5); }
627 | K_REQUEST
628 { proto_field_set_be16(hdr, ARP_OPER, ARPOP_REQUEST); }
629 | K_REPLY
630 { proto_field_set_be16(hdr, ARP_OPER, ARPOP_REPLY); }
631 | K_HTYPE skip_white '=' skip_white number
632 { proto_field_set_be16(hdr, ARP_HTYPE, $5); }
633 | K_PTYPE skip_white '=' skip_white number
634 { proto_field_set_be16(hdr, ARP_PTYPE, $5); }
635 | K_SHA skip_white '=' skip_white mac
636 { proto_field_set_bytes(hdr, ARP_SHA, $5); }
637 | K_THA skip_white '=' skip_white mac
638 { proto_field_set_bytes(hdr, ARP_THA, $5); }
639 | K_SPA skip_white '=' skip_white ip_addr
640 { proto_field_set_u32(hdr, ARP_SPA, $5.s_addr); }
641 | K_TPA skip_white '=' skip_white ip_addr
642 { proto_field_set_u32(hdr, ARP_TPA, $5.s_addr); }
645 : K_ARP { proto_add(PROTO_ARP); }
648 ip4_proto
649 : ip4 '(' ip4_param_list ')' { }
652 ip4_param_list
653 : { }
654 | ip4_field { }
655 | ip4_field delimiter ip4_param_list { }
658 ip4_field
659 : K_VER skip_white '=' skip_white number
660 { proto_field_set_u8(hdr, IP4_VER, $5); }
661 | K_IHL skip_white '=' skip_white number
662 { proto_field_set_u8(hdr, IP4_IHL, $5); }
663 | K_DADDR skip_white '=' skip_white ip_addr
664 { proto_field_set_u32(hdr, IP4_DADDR, $5.s_addr); }
665 | K_SADDR skip_white '=' skip_white ip_addr
666 { proto_field_set_u32(hdr, IP4_SADDR, $5.s_addr); }
667 | K_PROT skip_white '=' skip_white number
668 { proto_field_set_u8(hdr, IP4_PROTO, $5); }
669 | K_TTL skip_white '=' skip_white number
670 { proto_field_set_u8(hdr, IP4_TTL, $5); }
671 | K_DSCP skip_white '=' skip_white number
672 { proto_field_set_u8(hdr, IP4_DSCP, $5); }
673 | K_ECN skip_white '=' skip_white number
674 { proto_field_set_u8(hdr, IP4_ECN, $5); }
675 | K_TOS skip_white '=' skip_white number
676 { proto_field_set_u8(hdr, IP4_TOS, $5); }
677 | K_LEN skip_white '=' skip_white number
678 { proto_field_set_be16(hdr, IP4_LEN, $5); }
679 | K_ID skip_white '=' skip_white number
680 { proto_field_set_be16(hdr, IP4_ID, $5); }
681 | K_FLAGS skip_white '=' skip_white number
682 { proto_field_set_be16(hdr, IP4_FLAGS, $5); }
683 | K_DF { proto_field_set_be16(hdr, IP4_DF, 1); }
684 | K_MF { proto_field_set_be16(hdr, IP4_MF, 1); }
685 | K_FRAG skip_white '=' skip_white number
686 { proto_field_set_be16(hdr, IP4_FRAG_OFFS, $5); }
687 | K_CSUM skip_white '=' skip_white number
688 { proto_field_set_be16(hdr, IP4_CSUM, $5); }
692 : K_IP4 { proto_add(PROTO_IP4); }
695 udp_proto
696 : udp '(' udp_param_list ')' { }
699 udp_param_list
700 : { }
701 | udp_field { }
702 | udp_field delimiter udp_param_list { }
705 udp_field
706 : K_SPORT skip_white '=' skip_white number
707 { proto_field_set_be16(hdr, UDP_SPORT, $5); }
708 | K_DPORT skip_white '=' skip_white number
709 { proto_field_set_be16(hdr, UDP_DPORT, $5); }
710 | K_LEN skip_white '=' skip_white number
711 { proto_field_set_be16(hdr, UDP_LEN, $5); }
712 | K_CSUM skip_white '=' skip_white number
713 { proto_field_set_be16(hdr, UDP_CSUM, $5); }
717 : K_UDP { proto_add(PROTO_UDP); }
722 static void finalize_packet(void)
724 /* XXX hack ... we allocated one packet pointer too much */
725 plen--;
726 dlen--;
729 static void dump_conf(void)
731 size_t i, j;
733 for (i = 0; i < plen; ++i) {
734 printf("[%zu] pkt\n", i);
735 printf(" len %zu cnts %zu rnds %zu\n",
736 packets[i].len,
737 packet_dyn[i].clen,
738 packet_dyn[i].rlen);
740 printf(" payload ");
741 for (j = 0; j < packets[i].len; ++j)
742 printf("%02x ", packets[i].payload[j]);
743 printf("\n");
745 for (j = 0; j < packet_dyn[i].clen; ++j)
746 printf(" cnt%zu [%u,%u], inc %u, off %jd type %s\n", j,
747 packet_dyn[i].cnt[j].min,
748 packet_dyn[i].cnt[j].max,
749 packet_dyn[i].cnt[j].inc,
750 (intmax_t)packet_dyn[i].cnt[j].off,
751 packet_dyn[i].cnt[j].type == TYPE_INC ?
752 "inc" : "dec");
754 for (j = 0; j < packet_dyn[i].rlen; ++j)
755 printf(" rnd%zu off %jd\n", j,
756 (intmax_t)packet_dyn[i].rnd[j].off);
760 void cleanup_packets(void)
762 size_t i;
764 for (i = 0; i < plen; ++i) {
765 if (packets[i].len > 0)
766 xfree(packets[i].payload);
769 free(packets);
771 for (i = 0; i < dlen; ++i) {
772 free(packet_dyn[i].cnt);
773 free(packet_dyn[i].rnd);
776 free(packet_dyn);
779 void compile_packets(char *file, bool verbose, unsigned int cpu,
780 bool invoke_cpp, char *const cpp_argv[])
782 char tmp_file[128];
783 int ret = -1;
785 memset(tmp_file, 0, sizeof(tmp_file));
786 our_cpu = cpu;
788 if (invoke_cpp) {
789 if (cpp_exec(file, tmp_file, sizeof(tmp_file), cpp_argv)) {
790 fprintf(stderr, "Failed to invoke C preprocessor!\n");
791 goto err;
793 file = tmp_file;
796 if (!strncmp("-", file, strlen("-")))
797 yyin = stdin;
798 else
799 yyin = fopen(file, "r");
800 if (!yyin) {
801 fprintf(stderr, "Cannot open %s: %s!\n", file, strerror(errno));
802 goto err;
805 realloc_packet();
806 if (yyparse() != 0)
807 goto err;
808 finalize_packet();
810 if (our_cpu == 0 && verbose)
811 dump_conf();
813 ret = 0;
814 err:
815 if (yyin && yyin != stdin)
816 fclose(yyin);
818 if (invoke_cpp)
819 unlink(tmp_file);
820 if (ret)
821 die();
824 void compile_packets_str(char *str, bool verbose, unsigned int cpu)
826 int ret = 1;
828 our_cpu = cpu;
829 realloc_packet();
831 yy_scan_string(str);
832 if (yyparse() != 0)
833 goto err;
835 finalize_packet();
836 if (our_cpu == 0 && verbose)
837 dump_conf();
839 ret = 0;
840 err:
841 yylex_destroy();
843 if (ret)
844 die();
847 void yyerror(const char *err)
849 fprintf(stderr, "Syntax error at line %d, char '%s': %s\n", yylineno, yytext, err);