3 * Asterisk -- An open source telephony toolkit.
5 * Copyright (C) 2006, Digium, Inc.
7 * Steve Murphy <murf@parsetree.com>
9 * See http://www.asterisk.org for more information about
10 * the Asterisk project. Please do not directly contact
11 * any of the maintainers of this project for assistance;
12 * the project provides a web site, mailing lists and IRC
13 * channels for your use.
15 * This program is free software, distributed under the terms of
16 * the GNU General Public License Version 2. See the LICENSE file
17 * at the top of the source tree.
21 * \brief Bison Grammar description of AEL2.
27 #include "asterisk/logger.h"
28 #include "asterisk/utils.h" /* ast_calloc() */
29 #include "asterisk/ael_structs.h"
31 /* create a new object with start-end marker */
32 static pval *npval(pvaltype type, int first_line, int last_line,
33 int first_column, int last_column);
35 static pval * linku1(pval *head, pval *tail);
37 void reset_parencount(yyscan_t yyscanner);
38 void reset_semicount(yyscan_t yyscanner);
39 void reset_argcount(yyscan_t yyscanner );
41 #define YYLEX_PARAM ((struct parse_io *)parseio)->scanner
42 #define YYERROR_VERBOSE 1
46 int ael_is_funcname(char *name);
48 static char *ael_token_subst(char *mess);
59 /* declaring these AFTER the union makes things a lot simpler! */
60 void yyerror(YYLTYPE *locp, struct parse_io *parseio, char const *s);
61 int ael_yylex (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , void * yyscanner);
63 /* create a new object with start-end marker, simplified interface.
64 * Must be declared here because YYLTYPE is not known before
66 static pval *npval2(pvaltype type, YYLTYPE *first, YYLTYPE *last);
70 %token KW_CONTEXT LC RC LP RP SEMI EQ COMMA COLON AMPER BAR AT
71 %token KW_MACRO KW_GLOBALS KW_IGNOREPAT KW_SWITCH KW_IF KW_IFTIME KW_ELSE KW_RANDOM KW_ABSTRACT
72 %token EXTENMARK KW_GOTO KW_JUMP KW_RETURN KW_BREAK KW_CONTINUE KW_REGEXTEN KW_HINT
73 %token KW_FOR KW_WHILE KW_CASE KW_PATTERN KW_DEFAULT KW_CATCH KW_SWITCHES KW_ESWITCHES
79 %type <pval>includeslist
80 %type <pval>switchlist
83 %type <pval>macro_statement
84 %type <pval>macro_statements
85 %type <pval>case_statement
86 %type <pval>case_statements
87 %type <pval>eval_arglist
88 %type <pval>application_call
89 %type <pval>application_call_head
90 %type <pval>macro_call
91 %type <pval>target jumptarget
93 %type <pval>switch_head
96 %type <pval>random_head
97 %type <pval>iftime_head
98 %type <pval>statements
100 %type <pval>ignorepat
104 %type <pval>global_statement
105 %type <pval>global_statements
115 %type <str>word3_list
116 %type <str>includedname
122 %locations /* track source location using @n variables (yylloc in flex) */
123 %pure-parser /* pass yylval and yylloc as arguments to yylex(). */
124 %name-prefix="ael_yy"
126 * add an additional argument, parseio, to yyparse(),
127 * which is then accessible in the grammar actions
129 %parse-param {struct parse_io *parseio}
131 /* there will be two shift/reduce conflicts, they involve the if statement, where a single statement occurs not wrapped in curlies in the "true" section
132 the default action to shift will attach the else to the preceeding if. */
137 * declare destructors for objects.
138 * The former is for pval, the latter for strings.
139 * NOTE: we must not have a destructor for a 'file' object.
144 } includes includeslist switchlist eswitches switches
145 macro_statement macro_statements case_statement case_statements
146 eval_arglist application_call application_call_head
147 macro_call target jumptarget statement switch_head
148 if_head random_head iftime_head statements extension
149 ignorepat element elements arglist global_statement
150 global_statements globals macro context object objects
152 %destructor { free($$);} word word_list goto_word word3_list includedname
157 file : objects { $$ = parseio->pval = $1; }
160 objects : object {$$=$1;}
172 | objects error {$$=$1;}
175 object : context {$$=$1;}
178 | SEMI {$$=0;/* allow older docs to be read */}
181 context : KW_CONTEXT word LC elements RC {
182 $$ = npval2(PV_CONTEXT, &@1, &@5);
184 $$->u2.statements = $4; }
185 | KW_CONTEXT word LC RC /* empty context OK */ {
186 $$ = npval2(PV_CONTEXT, &@1, &@4);
188 | KW_CONTEXT KW_DEFAULT LC elements RC {
189 $$ = npval2(PV_CONTEXT, &@1, &@5);
190 $$->u1.str = strdup("default");
191 $$->u2.statements = $4; }
192 | KW_CONTEXT KW_DEFAULT LC RC /* empty context OK */ {
193 $$ = npval2(PV_CONTEXT, &@1, &@4);
194 $$->u1.str = strdup("default"); }
195 | KW_ABSTRACT KW_CONTEXT word LC elements RC {
196 $$ = npval2(PV_CONTEXT, &@1, &@6);
198 $$->u2.statements = $5;
199 $$->u3.abstract = 1; }
200 | KW_ABSTRACT KW_CONTEXT word LC RC /* empty context OK */ {
201 $$ = npval2(PV_CONTEXT, &@1, &@5);
203 $$->u3.abstract = 1; }
204 | KW_ABSTRACT KW_CONTEXT KW_DEFAULT LC elements RC {
205 $$ = npval2(PV_CONTEXT, &@1, &@6);
206 $$->u1.str = strdup("default");
207 $$->u2.statements = $5;
208 $$->u3.abstract = 1; }
209 | KW_ABSTRACT KW_CONTEXT KW_DEFAULT LC RC /* empty context OK */ {
210 $$ = npval2(PV_CONTEXT, &@1, &@5);
211 $$->u1.str = strdup("default");
212 $$->u3.abstract = 1; }
215 macro : KW_MACRO word LP arglist RP LC macro_statements RC {
216 $$ = npval2(PV_MACRO, &@1, &@8);
217 $$->u1.str = $2; $$->u2.arglist = $4; $$->u3.macro_statements = $7; }
218 | KW_MACRO word LP arglist RP LC RC {
219 $$ = npval2(PV_MACRO, &@1, &@7);
220 $$->u1.str = $2; $$->u2.arglist = $4; }
221 | KW_MACRO word LP RP LC macro_statements RC {
222 $$ = npval2(PV_MACRO, &@1, &@7);
224 $$->u3.macro_statements = $6; }
225 | KW_MACRO word LP RP LC RC {
226 $$ = npval2(PV_MACRO, &@1, &@6);
230 globals : KW_GLOBALS LC global_statements RC {
231 $$ = npval2(PV_GLOBALS, &@1, &@4);
232 $$->u1.statements = $3;}
233 | KW_GLOBALS LC RC { /* empty globals is OK */
234 $$ = npval2(PV_GLOBALS, &@1, &@3); }
237 global_statements : global_statement {$$=$1;}
238 | global_statements global_statement {$$=$1; linku1($$,$2);}
239 | global_statements error {$$=$1;}
242 global_statement : word EQ { reset_semicount(parseio->scanner); } word SEMI {
243 $$ = npval2(PV_VARDEC, &@1, &@5);
249 $$= npval2(PV_WORD, &@1, &@1);
251 | arglist COMMA word {
252 pval *z = npval2(PV_WORD, &@1, &@3);
256 | arglist error {$$=$1;}
259 elements : element { $$=$1;}
261 | elements element { if ( $1 && $2 ) {$$=$1; linku1($$,$2);}
262 else if ( $1 ) {$$=$1;}
263 else if ( $2 ) {$$=$2;} }
264 | elements error { $$=$1;}
267 element : extension {$$=$1;}
272 | word EQ { reset_semicount(parseio->scanner); } word SEMI {
273 $$ = npval2(PV_VARDEC, &@1, &@5);
276 | word error {free($1); $$=0;}
277 | SEMI {$$=0;/* allow older docs to be read */}
280 ignorepat : KW_IGNOREPAT EXTENMARK word SEMI {
281 $$ = npval2(PV_IGNOREPAT, &@1, &@4);
285 extension : word EXTENMARK statement {
286 $$ = npval2(PV_EXTENSION, &@1, &@3);
288 $$->u2.statements = $3; }
289 | KW_REGEXTEN word EXTENMARK statement {
290 $$ = npval2(PV_EXTENSION, &@1, &@4);
292 $$->u2.statements = $4;
294 | KW_HINT LP word3_list RP word EXTENMARK statement {
295 $$ = npval2(PV_EXTENSION, &@1, &@7);
297 $$->u2.statements = $7;
299 | KW_REGEXTEN KW_HINT LP word3_list RP word EXTENMARK statement {
300 $$ = npval2(PV_EXTENSION, &@1, &@8);
302 $$->u2.statements = $8;
308 statements : statement {$$=$1;}
309 | statements statement {if ( $1 && $2 ) {$$=$1; linku1($$,$2);}
310 else if ( $1 ) {$$=$1;}
311 else if ( $2 ) {$$=$2;} }
312 | statements error {$$=$1;}
315 if_head : KW_IF LP { reset_parencount(parseio->scanner); } word_list RP {
316 $$= npval2(PV_IF, &@1, &@5);
320 random_head : KW_RANDOM LP { reset_parencount(parseio->scanner); } word_list RP {
321 $$ = npval2(PV_RANDOM, &@1, &@5);
325 iftime_head : KW_IFTIME LP word3_list COLON word3_list COLON word3_list
326 BAR word3_list BAR word3_list BAR word3_list RP {
327 $$ = npval2(PV_IFTIME, &@1, &@5); /* XXX really @5 or more ? */
328 $$->u1.list = npval2(PV_WORD, &@3, &@3);
329 asprintf(&($$->u1.list->u1.str), "%s:%s:%s", $3, $5, $7);
333 $$->u1.list->next = npval2(PV_WORD, &@9, &@9);
334 $$->u1.list->next->u1.str = $9;
335 $$->u1.list->next->next = npval2(PV_WORD, &@11, &@11);
336 $$->u1.list->next->next->u1.str = $11;
337 $$->u1.list->next->next->next = npval2(PV_WORD, &@13, &@13);
338 $$->u1.list->next->next->next->u1.str = $13;
341 | KW_IFTIME LP word BAR word3_list BAR word3_list BAR word3_list RP {
342 $$ = npval2(PV_IFTIME, &@1, &@5); /* XXX @5 or greater ? */
343 $$->u1.list = npval2(PV_WORD, &@3, &@3);
344 $$->u1.list->u1.str = $3;
345 $$->u1.list->next = npval2(PV_WORD, &@5, &@5);
346 $$->u1.list->next->u1.str = $5;
347 $$->u1.list->next->next = npval2(PV_WORD, &@7, &@7);
348 $$->u1.list->next->next->u1.str = $7;
349 $$->u1.list->next->next->next = npval2(PV_WORD, &@9, &@9);
350 $$->u1.list->next->next->next->u1.str = $9;
356 /* word_list is a hack to fix a problem with context switching between bison and flex;
357 by the time you register a new context with flex, you've already got a look-ahead token
358 from the old context, with no way to put it back and start afresh. So, we kludge this
359 and merge the words back together. */
361 word_list : word { $$ = $1;}
363 asprintf(&($$), "%s%s", $1, $2);
369 word3_list : word { $$ = $1;}
371 asprintf(&($$), "%s%s", $1, $2);
376 asprintf(&($$), "%s%s%s", $1, $2, $3);
383 goto_word : word { $$ = $1;}
385 asprintf(&($$), "%s%s", $1, $2);
389 asprintf(&($$), "%s:%s", $1, $3);
394 switch_head : KW_SWITCH LP { reset_parencount(parseio->scanner); } word RP LC {
395 $$ = npval2(PV_SWITCH, &@1, &@6);
400 * Definition of a statememt in our language
402 statement : LC statements RC {
403 $$ = npval2(PV_STATEMENTBLOCK, &@1, &@3);
405 | word EQ {reset_semicount(parseio->scanner);} word SEMI {
406 $$ = npval2(PV_VARDEC, &@1, &@5);
409 | KW_GOTO target SEMI {
410 $$ = npval2(PV_GOTO, &@1, &@3);
412 | KW_JUMP jumptarget SEMI {
413 $$ = npval2(PV_GOTO, &@1, &@3);
416 $$ = npval2(PV_LABEL, &@1, &@2);
418 | KW_FOR LP {reset_semicount(parseio->scanner);} word SEMI
419 {reset_semicount(parseio->scanner);} word SEMI
420 {reset_parencount(parseio->scanner);} word RP statement {
421 $$ = npval2(PV_FOR, &@1, &@12);
422 $$->u1.for_init = $4;
424 $$->u3.for_inc = $10;
425 $$->u4.for_statements = $12;}
426 | KW_WHILE LP {reset_parencount(parseio->scanner);} word RP statement {
427 $$ = npval2(PV_WHILE, &@1, &@6);
429 $$->u2.statements = $6; }
430 | switch_head RC /* empty list OK */ {
432 $$->endline = @2.last_line;
433 $$->endcol = @2.last_column;}
434 | switch_head case_statements RC {
436 $$->u2.statements = $2;
437 $$->endline = @3.last_line;
438 $$->endcol = @3.last_column;}
439 | AMPER macro_call SEMI {
441 $$->endline = @2.last_line;
442 $$->endcol = @2.last_column;}
443 | application_call SEMI {
445 $$->endline = @2.last_line;
446 $$->endcol = @2.last_column;}
448 $$= npval2(PV_APPLICATION_CALL, &@1, &@2);
450 | application_call EQ {reset_semicount(parseio->scanner);} word SEMI {
454 $$ = npval2(PV_VARDEC, &@1, &@5);
456 /* rebuild the original string-- this is not an app call, it's an unwrapped vardec, with a func call on the LHS */
457 /* string to big to fit in the buffer? */
458 tot+=strlen($1->u1.str);
459 for(pptr=$1->u2.arglist;pptr;pptr=pptr->next) {
460 tot+=strlen(pptr->u1.str);
461 tot++; /* for a sep like a comma */
463 tot+=4; /* for safety */
464 bufx = ast_calloc(1, tot);
465 strcpy(bufx,$1->u1.str);
467 /* XXX need to advance the pointer or the loop is very inefficient */
468 for (pptr=$1->u2.arglist;pptr;pptr=pptr->next) {
469 if ( pptr != $1->u2.arglist )
471 strcat(bufx,pptr->u1.str);
475 if ( !ael_is_funcname($1->u1.str) )
476 ast_log(LOG_WARNING, "==== File: %s, Line %d, Cols: %d-%d: Function call? The name %s is not in my internal list of function names\n",
477 my_file, @1.first_line, @1.first_column, @1.last_column, $1->u1.str);
480 destroy_pval($1); /* the app call it is not, get rid of that chain */
483 | KW_BREAK SEMI { $$ = npval2(PV_BREAK, &@1, &@2); }
484 | KW_RETURN SEMI { $$ = npval2(PV_RETURN, &@1, &@2); }
485 | KW_CONTINUE SEMI { $$ = npval2(PV_CONTINUE, &@1, &@2); }
486 | random_head statement {
488 $$->u2.statements = $2;
489 $$->endline = @2.last_line;
490 $$->endcol = @2.last_column;}
491 | random_head statement KW_ELSE statement {
493 $$->u2.statements = $2;
494 $$->endline = @2.last_line;
495 $$->endcol = @2.last_column;
496 $$->u3.else_statements = $4;}
497 | if_head statement {
499 $$->u2.statements = $2;
500 $$->endline = @2.last_line;
501 $$->endcol = @2.last_column;}
502 | if_head statement KW_ELSE statement {
504 $$->u2.statements = $2;
505 $$->endline = @2.last_line;
506 $$->endcol = @2.last_column;
507 $$->u3.else_statements = $4;}
508 | iftime_head statement {
510 $$->u2.statements = $2;
511 $$->endline = @2.last_line;
512 $$->endcol = @2.last_column;}
513 | iftime_head statement KW_ELSE statement {
515 $$->u2.statements = $2;
516 $$->endline = @2.last_line;
517 $$->endcol = @2.last_column;
518 $$->u3.else_statements = $4;}
522 target : goto_word { $$ = npval2(PV_WORD, &@1, &@1);
524 | goto_word BAR goto_word {
525 $$ = npval2(PV_WORD, &@1, &@1);
527 $$->next = npval2(PV_WORD, &@3, &@3);
528 $$->next->u1.str = $3;}
529 | goto_word COMMA goto_word {
530 $$ = npval2(PV_WORD, &@1, &@1);
532 $$->next = npval2(PV_WORD, &@3, &@3);
533 $$->next->u1.str = $3;}
534 | goto_word BAR goto_word BAR goto_word {
535 $$ = npval2(PV_WORD, &@1, &@1);
537 $$->next = npval2(PV_WORD, &@3, &@3);
538 $$->next->u1.str = $3;
539 $$->next->next = npval2(PV_WORD, &@5, &@5);
540 $$->next->next->u1.str = $5; }
541 | goto_word COMMA goto_word COMMA goto_word {
542 $$ = npval2(PV_WORD, &@1, &@1);
544 $$->next = npval2(PV_WORD, &@3, &@3);
545 $$->next->u1.str = $3;
546 $$->next->next = npval2(PV_WORD, &@5, &@5);
547 $$->next->next->u1.str = $5; }
548 | KW_DEFAULT BAR goto_word BAR goto_word {
549 $$ = npval2(PV_WORD, &@1, &@1);
550 $$->u1.str = strdup("default");
551 $$->next = npval2(PV_WORD, &@3, &@3);
552 $$->next->u1.str = $3;
553 $$->next->next = npval2(PV_WORD, &@5, &@5);
554 $$->next->next->u1.str = $5; }
555 | KW_DEFAULT COMMA goto_word COMMA goto_word {
556 $$ = npval2(PV_WORD, &@1, &@1);
557 $$->u1.str = strdup("default");
558 $$->next = npval2(PV_WORD, &@3, &@3);
559 $$->next->u1.str = $3;
560 $$->next->next = npval2(PV_WORD, &@5, &@5);
561 $$->next->next->u1.str = $5; }
564 jumptarget : goto_word {
565 $$ = npval2(PV_WORD, &@1, &@1);
567 $$->next = npval2(PV_WORD, &@1, &@1); /* XXX not really @1 */
568 $$->next->u1.str = strdup("1");} /* jump extension[,priority][@context] */
569 | goto_word COMMA goto_word {
570 $$ = npval2(PV_WORD, &@1, &@1);
572 $$->next = npval2(PV_WORD, &@3, &@3);
573 $$->next->u1.str = $3;}
574 | goto_word COMMA word AT word {
575 $$ = npval2(PV_WORD, &@1, &@1);
577 $$->next = npval2(PV_WORD, &@3, &@3);
578 $$->next->u1.str = $1;
579 $$->next->next = npval2(PV_WORD, &@5, &@5);
580 $$->next->next->u1.str = $3; }
581 | goto_word AT goto_word {
582 $$ = npval2(PV_WORD, &@1, &@1);
584 $$->next = npval2(PV_WORD, &@3, &@3);
585 $$->next->u1.str = $1;
586 $$->next->next = npval2(PV_WORD, &@3, &@3);
587 $$->next->next->u1.str = strdup("1"); }
588 | goto_word COMMA word AT KW_DEFAULT {
589 $$ = npval2(PV_WORD, &@1, &@1);
590 $$->u1.str = strdup("default");
591 $$->next = npval2(PV_WORD, &@3, &@3);
592 $$->next->u1.str = $1;
593 $$->next->next = npval2(PV_WORD, &@5, &@5);
594 $$->next->next->u1.str = $3; }
595 | goto_word AT KW_DEFAULT {
596 $$ = npval2(PV_WORD, &@1, &@1);
597 $$->u1.str = strdup("default");
598 $$->next = npval2(PV_WORD, &@3, &@3);
599 $$->next->u1.str = $1;
600 $$->next->next = npval2(PV_WORD, &@3, &@3);
601 $$->next->next->u1.str = strdup("1"); }
604 macro_call : word LP {reset_argcount(parseio->scanner);} eval_arglist RP {
605 /* XXX original code had @2 but i think we need @5 */
606 $$ = npval2(PV_MACRO_CALL, &@1, &@5);
608 $$->u2.arglist = $4;}
610 $$= npval2(PV_MACRO_CALL, &@1, &@3);
614 application_call_head: word {reset_argcount(parseio->scanner);} LP {
615 if (strcasecmp($1,"goto") == 0) {
616 $$= npval2(PV_GOTO, &@1, &@3);
617 free($1); /* won't be using this */
618 ast_log(LOG_WARNING, "==== File: %s, Line %d, Cols: %d-%d: Suggestion: Use the goto statement instead of the Goto() application call in AEL.\n", my_file, @1.first_line, @1.first_column, @1.last_column );
620 $$= npval2(PV_APPLICATION_CALL, &@1, &@3);
624 application_call : application_call_head eval_arglist RP {$$ = $1;
625 if( $$->type == PV_GOTO )
629 $$->endline = @3.last_line; $$->endcol = @3.last_column;}
630 | application_call_head RP {$$=$1;$$->endline = @2.last_line; $$->endcol = @2.last_column;}
633 eval_arglist : word_list {
634 $$= npval2(PV_WORD, &@1, &@1);
637 $$= npval(PV_WORD,0/*@1.first_line*/,0/*@1.last_line*/,0/* @1.first_column*/, 0/*@1.last_column*/);
638 $$->u1.str = strdup(""); }
639 | eval_arglist COMMA word {
640 pval *z = npval2(PV_WORD, &@3, &@3);
644 | eval_arglist COMMA {
645 pval *z = npval2(PV_WORD, &@2, &@2);
648 z->u1.str = strdup("");}
651 case_statements: case_statement {$$=$1;}
652 | case_statements case_statement { if ( $1 && $2 ) {$$=$1; linku1($$,$2);}
653 else if ( $1 ) {$$=$1;}
654 else if ( $2 ) {$$=$2;} }
657 case_statement: KW_CASE word COLON statements {
658 $$ = npval2(PV_CASE, &@1, &@3); /* XXX 3 or 4 ? */
660 $$->u2.statements = $4;}
661 | KW_DEFAULT COLON statements {
662 $$ = npval2(PV_DEFAULT, &@1, &@3);
664 $$->u2.statements = $3;}
665 | KW_PATTERN word COLON statements {
666 $$ = npval2(PV_PATTERN, &@1, &@4); /* XXX@3 or @4 ? */
668 $$->u2.statements = $4;}
669 | KW_CASE word COLON {
670 $$ = npval2(PV_CASE, &@1, &@3);
673 $$ = npval2(PV_DEFAULT, &@1, &@2);
675 | KW_PATTERN word COLON {
676 $$ = npval2(PV_PATTERN, &@1, &@3);
680 macro_statements: macro_statement {$$ = $1;}
681 | macro_statements macro_statement { if ( $1 && $2 ) {$$=$1; linku1($$,$2);}
682 else if ( $1 ) {$$=$1;}
683 else if ( $2 ) {$$=$2;} }
686 macro_statement : statement {$$=$1;}
687 | KW_CATCH word LC statements RC {
688 $$ = npval2(PV_CATCH, &@1, &@5);
690 $$->u2.statements = $4;}
693 switches : KW_SWITCHES LC switchlist RC {
694 $$ = npval2(PV_SWITCHES, &@1, &@4);
696 | KW_SWITCHES LC RC /* empty switch list OK */ {
697 $$ = npval2(PV_SWITCHES, &@1, &@3); }
700 eswitches : KW_ESWITCHES LC switchlist RC {
701 $$ = npval2(PV_ESWITCHES, &@1, &@4);
703 | KW_ESWITCHES LC RC { /* empty switch list OK */
704 $$ = npval2(PV_ESWITCHES, &@1, &@3); } /* if there's nothing to declare, why include it? */
707 switchlist : word SEMI {
708 $$ = npval2(PV_WORD, &@1, &@2);
710 | switchlist word SEMI {
711 pval *z = npval2(PV_WORD, &@2, &@3);
715 | switchlist error {$$=$1;}
718 includeslist : includedname SEMI {
719 $$ = npval2(PV_WORD, &@1, &@2);
721 | includedname BAR word3_list COLON word3_list COLON word3_list
722 BAR word3_list BAR word3_list BAR word3_list SEMI {
723 $$ = npval2(PV_WORD, &@1, &@2);
725 $$->u2.arglist = npval2(PV_WORD, &@3, &@7);
726 asprintf( &($$->u2.arglist->u1.str), "%s:%s:%s", $3, $5, $7);
730 $$->u2.arglist->next = npval2(PV_WORD, &@9, &@9);
731 $$->u2.arglist->next->u1.str = $9;
732 $$->u2.arglist->next->next = npval2(PV_WORD, &@11, &@11);
733 $$->u2.arglist->next->next->u1.str = $11;
734 $$->u2.arglist->next->next->next = npval2(PV_WORD, &@13, &@13);
735 $$->u2.arglist->next->next->next->u1.str = $13;
738 | includedname BAR word BAR word3_list BAR word3_list BAR word3_list SEMI {
739 $$ = npval2(PV_WORD, &@1, &@2);
741 $$->u2.arglist = npval2(PV_WORD, &@3, &@3);
742 $$->u2.arglist->u1.str = $3;
743 $$->u2.arglist->next = npval2(PV_WORD, &@5, &@5);
744 $$->u2.arglist->next->u1.str = $5;
745 $$->u2.arglist->next->next = npval2(PV_WORD, &@7, &@7);
746 $$->u2.arglist->next->next->u1.str = $7;
747 $$->u2.arglist->next->next->next = npval2(PV_WORD, &@9, &@9);
748 $$->u2.arglist->next->next->next->u1.str = $9;
751 | includeslist includedname SEMI {
752 pval *z = npval2(PV_WORD, &@2, &@3); /* XXX don't we need @1-@4 ?*/
756 | includeslist includedname BAR word3_list COLON word3_list COLON word3_list
757 BAR word3_list BAR word3_list BAR word3_list SEMI {
758 pval *z = npval2(PV_WORD, &@2, &@3);
759 $$=$1; z->u1.str = $2;
761 z->u2.arglist = npval2(PV_WORD, &@4, &@4);
762 asprintf( &($$->u2.arglist->u1.str), "%s:%s:%s", $4, $6, $8);
766 z->u2.arglist->next = npval2(PV_WORD, &@10, &@10);
767 z->u2.arglist->next->u1.str = $10;
768 z->u2.arglist->next->next = npval2(PV_WORD, &@12, &@12);
769 z->u2.arglist->next->next->u1.str = $12;
770 z->u2.arglist->next->next->next = npval2(PV_WORD, &@14, &@14);
771 z->u2.arglist->next->next->next->u1.str = $14;
774 | includeslist includedname BAR word BAR word3_list BAR word3_list BAR word3_list SEMI {
775 pval *z = npval2(PV_WORD, &@2, &@3);
777 z->u1.str = $2; linku1($$,z);
778 z->u2.arglist = npval2(PV_WORD, &@4, &@4);
779 $$->u2.arglist->u1.str = $4;
780 z->u2.arglist->next = npval2(PV_WORD, &@6, &@6);
781 z->u2.arglist->next->u1.str = $6;
782 z->u2.arglist->next->next = npval2(PV_WORD, &@8, &@8);
783 z->u2.arglist->next->next->u1.str = $8;
784 z->u2.arglist->next->next->next = npval2(PV_WORD, &@10, &@10);
785 z->u2.arglist->next->next->next->u1.str = $10;
788 | includeslist error {$$=$1;}
791 includedname : word { $$ = $1;}
792 | KW_DEFAULT {$$=strdup("default");}
795 includes : KW_INCLUDES LC includeslist RC {
796 $$ = npval2(PV_INCLUDES, &@1, &@4);
798 | KW_INCLUDES LC RC {
799 $$ = npval2(PV_INCLUDES, &@1, &@3);}
805 static char *token_equivs1[] =
845 static char *token_equivs2[] =
886 static char *ael_token_subst(char *mess)
888 /* calc a length, malloc, fill, and return; yyerror had better free it! */
892 int token_equivs_entries = sizeof(token_equivs1)/sizeof(char*);
894 for (p=mess; *p; p++) {
895 for (i=0; i<token_equivs_entries; i++) {
896 if ( strncmp(p,token_equivs1[i],strlen(token_equivs1[i])) == 0 )
898 len+=strlen(token_equivs2[i])+2;
899 p += strlen(token_equivs1[i])-1;
905 res = ast_calloc(1, len+1);
910 for (i=0; i<token_equivs_entries; i++) {
911 if ( strncmp(p,token_equivs1[i],strlen(token_equivs1[i])) == 0 ) {
913 for (t=token_equivs2[i]; *t;) {
917 p += strlen(token_equivs1[i]);
929 void yyerror(YYLTYPE *locp, struct parse_io *parseio, char const *s)
931 char *s2 = ael_token_subst((char *)s);
932 if (locp->first_line == locp->last_line) {
933 ast_log(LOG_ERROR, "==== File: %s, Line %d, Cols: %d-%d: Error: %s\n", my_file, locp->first_line, locp->first_column, locp->last_column, s2);
935 ast_log(LOG_ERROR, "==== File: %s, Line %d Col %d to Line %d Col %d: Error: %s\n", my_file, locp->first_line, locp->first_column, locp->last_line, locp->last_column, s2);
938 parseio->syntax_error_count++;
941 static struct pval *npval(pvaltype type, int first_line, int last_line,
942 int first_column, int last_column)
944 extern char *my_file;
945 pval *z = ast_calloc(1, sizeof(struct pval));
947 z->startline = first_line;
948 z->endline = last_line;
949 z->startcol = first_column;
950 z->endcol = last_column;
951 z->filename = strdup(my_file);
955 static struct pval *npval2(pvaltype type, YYLTYPE *first, YYLTYPE *last)
957 return npval(type, first->first_line, last->last_line,
958 first->first_column, last->last_column);
961 /* append second element to the list in the first one */
962 static pval * linku1(pval *head, pval *tail)
969 head->u1_last->next = tail;
971 head->u1_last = tail;