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/ael_structs.h"
30 static pval *npval(pvaltype type, int first_line, int last_line,
31 int first_column, int last_column);
32 static void linku1(pval *head, pval *tail);
34 void reset_parencount(yyscan_t yyscanner);
35 void reset_semicount(yyscan_t yyscanner);
36 void reset_argcount(yyscan_t yyscanner );
38 #define YYLEX_PARAM ((struct parse_io *)parseio)->scanner
39 #define YYERROR_VERBOSE 1
43 int ael_is_funcname(char *name);
45 static char *ael_token_subst(char *mess);
56 /* declaring these AFTER the union makes things a lot simpler! */
57 void yyerror(YYLTYPE *locp, struct parse_io *parseio, char const *s);
58 int ael_yylex (YYSTYPE * yylval_param, YYLTYPE * yylloc_param , void * yyscanner);
63 %token KW_CONTEXT LC RC LP RP SEMI EQ COMMA COLON AMPER BAR AT
64 %token KW_MACRO KW_GLOBALS KW_IGNOREPAT KW_SWITCH KW_IF KW_IFTIME KW_ELSE KW_RANDOM KW_ABSTRACT
65 %token EXTENMARK KW_GOTO KW_JUMP KW_RETURN KW_BREAK KW_CONTINUE KW_REGEXTEN KW_HINT
66 %token KW_FOR KW_WHILE KW_CASE KW_PATTERN KW_DEFAULT KW_CATCH KW_SWITCHES KW_ESWITCHES
72 %type <pval>includeslist
73 %type <pval>switchlist
76 %type <pval>macro_statement
77 %type <pval>macro_statements
78 %type <pval>case_statement
79 %type <pval>case_statements
80 %type <pval>eval_arglist
81 %type <pval>application_call
82 %type <pval>application_call_head
83 %type <pval>macro_call
84 %type <pval>target jumptarget
86 %type <pval>switch_head
87 %type <str>word_list goto_word
89 %type <str>includedname
91 %type <pval>random_head
92 %type <pval>iftime_head
93 %type <pval>statements
99 %type <pval>global_statement
100 %type <pval>global_statements
111 %name-prefix="ael_yy"
112 /* the following option does two things:
113 it adds the locp arg to the yyerror
114 and it adds the NULL to the yyerrr arg list, and calls yyerror with NULL for that arg.
115 You can't get the locp arg without the NULL arg, don't ask me why. */
116 %parse-param {struct parse_io *parseio}
117 /* 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
118 the default action to shift will attach the else to the preceeding if. */
121 %destructor { if (yymsg[0] != 'C') {destroy_pval($$); prev_word=0;} else {printf("Cleanup destructor called for pvals\n");} } includes includeslist switchlist eswitches switches macro_statement macro_statements case_statement case_statements eval_arglist application_call
122 application_call_head macro_call target jumptarget statement switch_head if_head random_head iftime_head statements extension ignorepat element
123 elements arglist global_statement global_statements globals macro context object objects
124 %destructor { free($$);} word word_list goto_word word3_list includedname
129 file : objects { $$ = parseio->pval = $1; }
132 objects : object {$$=$1;}
144 | objects error {$$=$1;}
147 object : context {$$=$1;}
150 | SEMI {$$=0;/* allow older docs to be read */}
153 context : KW_CONTEXT word LC elements RC {
154 $$ = npval(PV_CONTEXT, @1.first_line, @5.last_line,
155 @1.first_column, @5.last_column);
157 $$->u2.statements = $4; }
158 | KW_CONTEXT word LC RC /* empty context OK */ {
159 $$ = npval(PV_CONTEXT, @1.first_line, @4.last_line,
160 @1.first_column, @4.last_column);
162 | KW_CONTEXT KW_DEFAULT LC elements RC {
163 $$ = npval(PV_CONTEXT, @1.first_line, @5.last_line,
164 @1.first_column, @5.last_column);
165 $$->u1.str = strdup("default");
166 $$->u2.statements = $4; }
167 | KW_CONTEXT KW_DEFAULT LC RC /* empty context OK */ {
168 $$ = npval(PV_CONTEXT, @1.first_line, @4.last_line,
169 @1.first_column, @4.last_column);
170 $$->u1.str = strdup("default"); }
171 | KW_ABSTRACT KW_CONTEXT word LC elements RC {
172 $$ = npval(PV_CONTEXT, @1.first_line, @6.last_line,
173 @1.first_column, @6.last_column);
175 $$->u2.statements = $5;
176 $$->u3.abstract = 1; }
177 | KW_ABSTRACT KW_CONTEXT word LC RC /* empty context OK */ {
178 $$ = npval(PV_CONTEXT, @1.first_line, @5.last_line,
179 @1.first_column, @5.last_column);
181 $$->u3.abstract = 1; }
182 | KW_ABSTRACT KW_CONTEXT KW_DEFAULT LC elements RC {
183 $$ = npval(PV_CONTEXT, @1.first_line, @6.last_line,
184 @1.first_column, @6.last_column);
185 $$->u1.str = strdup("default");
186 $$->u2.statements = $5;
187 $$->u3.abstract = 1; }
188 | KW_ABSTRACT KW_CONTEXT KW_DEFAULT LC RC /* empty context OK */ {
189 $$ = npval(PV_CONTEXT, @1.first_line, @5.last_line,
190 @1.first_column, @5.last_column);
191 $$->u1.str = strdup("default");
192 $$->u3.abstract = 1; }
195 macro : KW_MACRO word LP arglist RP LC macro_statements RC {$$=npval(PV_MACRO,@1.first_line,@8.last_line, @1.first_column, @8.last_column);
196 $$->u1.str = $2; $$->u2.arglist = $4; $$->u3.macro_statements = $7; }
197 | KW_MACRO word LP arglist RP LC RC {$$=npval(PV_MACRO,@1.first_line,@7.last_line, @1.first_column, @7.last_column); $$->u1.str = $2; $$->u2.arglist = $4; }
198 | KW_MACRO word LP RP LC macro_statements RC {$$=npval(PV_MACRO,@1.first_line,@7.last_line, @1.first_column, @7.last_column); $$->u1.str = $2; $$->u3.macro_statements = $6; }
199 | KW_MACRO word LP RP LC RC {$$=npval(PV_MACRO,@1.first_line,@6.last_line, @1.first_column, @6.last_column); $$->u1.str = $2; /* pretty empty! */ }
202 globals : KW_GLOBALS LC global_statements RC {$$=npval(PV_GLOBALS,@1.first_line,@4.last_line, @1.first_column, @4.last_column); $$->u1.statements = $3;}
203 | KW_GLOBALS LC RC /* empty global is OK */ {$$=npval(PV_GLOBALS,@1.first_line,@3.last_line, @1.first_column, @3.last_column); /* and that's all */ }
206 global_statements : global_statement {$$=$1;}
207 | global_statements global_statement {$$=$1; linku1($$,$2);}
208 | global_statements error {$$=$1;}
211 global_statement : word EQ { reset_semicount(parseio->scanner); } word SEMI {$$=npval(PV_VARDEC,@1.first_line,@5.last_line, @1.first_column, @5.last_column); $$->u1.str = $1;$$->u2.val = $4; }
214 arglist : word {$$= npval(PV_WORD,@1.first_line,@1.last_line, @1.first_column, @1.last_column); $$->u1.str = $1; }
215 | arglist COMMA word {pval *z = npval(PV_WORD,@1.first_line,@3.last_line, @1.first_column, @3.last_column); z->u1.str = $3; $$=$1; linku1($$,z); }
216 | arglist error {$$=$1;}
219 elements : element { $$=$1;}
221 | elements element { if ( $1 && $2 ) {$$=$1; linku1($$,$2);}
222 else if ( $1 ) {$$=$1;}
223 else if ( $2 ) {$$=$2;} }
224 | elements error { $$=$1;}
227 element : extension {$$=$1;}
232 | word EQ { reset_semicount(parseio->scanner); } word SEMI {$$=npval(PV_VARDEC,@1.first_line,@5.last_line, @1.first_column, @5.last_column); $$->u1.str = $1;$$->u2.val = $4; }
233 | word error {free($1); $$=0;}
234 | SEMI {$$=0;/* allow older docs to be read */}
237 ignorepat : KW_IGNOREPAT EXTENMARK word SEMI { $$=npval(PV_IGNOREPAT,@1.first_line,@4.last_line, @1.first_column, @4.last_column); $$->u1.str = $3;}
240 extension : word EXTENMARK statement {$$ = npval(PV_EXTENSION,@1.first_line,@3.last_line, @1.first_column, @3.last_column); $$->u1.str = $1; $$->u2.statements = $3; }
241 | KW_REGEXTEN word EXTENMARK statement {$$ = npval(PV_EXTENSION,@1.first_line,@3.last_line, @1.first_column, @4.last_column); $$->u1.str = $2; $$->u2.statements = $4; $$->u4.regexten=1;}
242 | KW_HINT LP word3_list RP word EXTENMARK statement {$$ = npval(PV_EXTENSION,@1.first_line,@7.last_line, @1.first_column, @7.last_column); $$->u1.str = $5; $$->u2.statements = $7; $$->u3.hints = $3;}
243 | KW_REGEXTEN KW_HINT LP word3_list RP word EXTENMARK statement {$$ = npval(PV_EXTENSION,@1.first_line,@4.last_line, @1.first_column, @8.last_column); $$->u1.str = $6; $$->u2.statements = $8; $$->u4.regexten=1;$$->u3.hints = $4;}
247 statements : statement {$$=$1;}
248 | statements statement {if ( $1 && $2 ) {$$=$1; linku1($$,$2);}
249 else if ( $1 ) {$$=$1;}
250 else if ( $2 ) {$$=$2;} }
251 | statements error {$$=$1;}
254 if_head : KW_IF LP { reset_parencount(parseio->scanner); } word_list RP { $$= npval(PV_IF,@1.first_line,@5.last_line, @1.first_column, @5.last_column); $$->u1.str = $4; }
257 random_head : KW_RANDOM LP { reset_parencount(parseio->scanner); } word_list RP { $$= npval(PV_RANDOM,@1.first_line,@5.last_line, @1.first_column, @5.last_column); $$->u1.str=$4;}
260 iftime_head : KW_IFTIME LP word3_list COLON word3_list COLON word3_list BAR word3_list BAR word3_list BAR word3_list RP { $$= npval(PV_IFTIME,@1.first_line,@5.last_line, @1.first_column, @5.last_column);
261 $$->u1.list = npval(PV_WORD,@3.first_line,@3.last_line, @3.first_column, @3.last_column);
262 $$->u1.list->u1.str = (char*)malloc(strlen($3)+strlen($5)+strlen($7)+4);
263 strcpy($$->u1.list->u1.str,$3);
264 strcat($$->u1.list->u1.str,":");
265 strcat($$->u1.list->u1.str,$5);
266 strcat($$->u1.list->u1.str,":");
267 strcat($$->u1.list->u1.str,$7);
271 $$->u1.list->next = npval(PV_WORD,@9.first_line,@9.last_line, @9.first_column, @9.last_column);
272 $$->u1.list->next->u1.str = $9;
273 $$->u1.list->next->next = npval(PV_WORD,@11.first_line,@11.last_line, @11.first_column, @11.last_column);
274 $$->u1.list->next->next->u1.str = $11;
275 $$->u1.list->next->next->next = npval(PV_WORD,@13.first_line,@13.last_line, @13.first_column, @13.last_column);
276 $$->u1.list->next->next->next->u1.str = $13;
279 | KW_IFTIME LP word BAR word3_list BAR word3_list BAR word3_list RP { $$= npval(PV_IFTIME,@1.first_line,@5.last_line, @1.first_column, @5.last_column);
280 $$->u1.list = npval(PV_WORD,@3.first_line,@3.last_line, @3.first_column, @3.last_column);
281 $$->u1.list->u1.str = $3;
282 $$->u1.list->next = npval(PV_WORD,@5.first_line,@5.last_line, @5.first_column, @5.last_column);
283 $$->u1.list->next->u1.str = $5;
284 $$->u1.list->next->next = npval(PV_WORD,@7.first_line,@7.last_line, @7.first_column, @7.last_column);
285 $$->u1.list->next->next->u1.str = $7;
286 $$->u1.list->next->next->next = npval(PV_WORD,@9.first_line,@9.last_line, @9.first_column, @9.last_column);
287 $$->u1.list->next->next->next->u1.str = $9;
293 /* word_list is a hack to fix a problem with context switching between bison and flex;
294 by the time you register a new context with flex, you've already got a look-ahead token
295 from the old context, with no way to put it back and start afresh. So, we kludge this
296 and merge the words back together. */
298 word_list : word { $$ = $1;}
299 | word word { $$ = (char*)malloc(strlen($1)+strlen($2)+1); strcpy($$, $1); strcat($$, $2); free($1); free($2);prev_word = $$;}
301 word3_list : word { $$ = $1;}
302 | word word { $$ = (char*)malloc(strlen($1)+strlen($2)+1); strcpy($$, $1); strcat($$, $2); free($1); free($2);prev_word = $$;}
303 | word word word { $$ = (char*)malloc(strlen($1)+strlen($2)+strlen($3)+1); strcpy($$, $1); strcat($$, $2); strcat($$, $3); free($1); free($2); free($3);prev_word=$$;}
306 goto_word : word { $$ = $1;}
307 | word word { $$ = (char*)malloc(strlen($1)+strlen($2)+1); strcpy($$, $1); strcat($$, $2); free($1); free($2);}
308 | word COLON word { $$ = (char*)malloc(strlen($1)+strlen($3)+2); strcpy($$, $1); strcat($$,":"); strcat($$, $3); free($1); free($3);}
311 switch_head : KW_SWITCH LP { reset_parencount(parseio->scanner); } word RP LC
312 {$$=npval(PV_SWITCH,@1.first_line,@6.last_line, @1.first_column, @6.last_column);
316 statement : LC statements RC {$$=npval(PV_STATEMENTBLOCK,@1.first_line,@3.last_line, @1.first_column, @3.last_column); $$->u1.list = $2; }
317 | word EQ {reset_semicount(parseio->scanner);} word SEMI
318 {$$=npval(PV_VARDEC,@1.first_line,@5.last_line, @1.first_column, @5.last_column);
319 $$->u1.str = $1; $$->u2.val = $4; }
320 | KW_GOTO target SEMI {$$=npval(PV_GOTO,@1.first_line,@3.last_line, @1.first_column, @3.last_column); $$->u1.list = $2;}
321 | KW_JUMP jumptarget SEMI {$$=npval(PV_GOTO,@1.first_line,@3.last_line, @1.first_column, @3.last_column); $$->u1.list = $2;}
322 | word COLON {$$=npval(PV_LABEL,@1.first_line,@2.last_line, @1.first_column, @2.last_column); $$->u1.str = $1; }
323 | KW_FOR LP {reset_semicount(parseio->scanner);} word SEMI
324 {reset_semicount(parseio->scanner);} word SEMI
325 {reset_parencount(parseio->scanner);} word RP statement
326 { $$=npval(PV_FOR,@1.first_line,@12.last_line, @1.first_column, @12.last_column);
327 $$->u1.for_init = $4; $$->u2.for_test=$7; $$->u3.for_inc = $10; $$->u4.for_statements = $12;}
328 | KW_WHILE LP {reset_parencount(parseio->scanner);} word RP statement
329 {$$=npval(PV_WHILE,@1.first_line,@6.last_line, @1.first_column, @6.last_column);
330 $$->u1.str = $4; $$->u2.statements = $6; }
331 | switch_head RC /* empty list OK */ {$$=$1;$$->endline = @2.last_line; $$->endcol = @2.last_column;}
332 | switch_head case_statements RC {$$=$1; $$->u2.statements = $2;$$->endline = @3.last_line; $$->endcol = @3.last_column;}
333 | AMPER macro_call SEMI {$$ = $2;$$->endline = @2.last_line; $$->endcol = @2.last_column;}
334 | application_call SEMI { $$ = $1;$$->endline = @2.last_line; $$->endcol = @2.last_column;}
335 | word SEMI { $$= npval(PV_APPLICATION_CALL,@1.first_line,@2.last_line, @1.first_column, @2.last_column);
337 | application_call EQ {reset_semicount(parseio->scanner);} word SEMI {
342 $$ = npval(PV_VARDEC,@1.first_line,@5.last_line, @1.first_column, @5.last_column);
344 /* rebuild the original string-- this is not an app call, it's an unwrapped vardec, with a func call on the LHS */
345 /* string to big to fit in the buffer? */
346 tot+=strlen($1->u1.str);
347 for(pptr=$1->u2.arglist;pptr;pptr=pptr->next) {
348 tot+=strlen(pptr->u1.str);
349 tot++; /* for a sep like a comma */
351 tot+=4; /* for safety */
352 bufx = (char *)malloc(tot);
353 strcpy(bufx,$1->u1.str);
355 for (pptr=$1->u2.arglist;pptr;pptr=pptr->next) {
356 if ( pptr != $1->u2.arglist )
358 strcat(bufx,pptr->u1.str);
362 if ( !ael_is_funcname($1->u1.str) )
363 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",
364 my_file, @1.first_line, @1.first_column, @1.last_column, $1->u1.str);
367 destroy_pval($1); /* the app call it is not, get rid of that chain */
370 | KW_BREAK SEMI { $$ = npval(PV_BREAK,@1.first_line,@2.last_line, @1.first_column, @2.last_column);}
371 | KW_RETURN SEMI {$$ = npval(PV_RETURN,@1.first_line,@2.last_line, @1.first_column, @2.last_column);}
372 | KW_CONTINUE SEMI {$$ = npval(PV_CONTINUE,@1.first_line,@2.last_line, @1.first_column, @2.last_column);}
373 | random_head statement {$$=$1; $$->u2.statements = $2;$$->endline = @2.last_line; $$->endcol = @2.last_column;}
374 | random_head statement KW_ELSE statement {$$=$1; $$->u2.statements = $2;$$->endline = @2.last_line; $$->endcol = @2.last_column; $$->u3.else_statements = $4;}
375 | if_head statement {$$=$1; $$->u2.statements = $2;$$->endline = @2.last_line; $$->endcol = @2.last_column;}
376 | if_head statement KW_ELSE statement {$$=$1; $$->u2.statements = $2;$$->endline = @2.last_line; $$->endcol = @2.last_column; $$->u3.else_statements = $4;}
377 | iftime_head statement {$$=$1; $$->u2.statements = $2;$$->endline = @2.last_line; $$->endcol = @2.last_column;}
378 | iftime_head statement KW_ELSE statement {$$=$1; $$->u2.statements = $2;$$->endline = @2.last_line; $$->endcol = @2.last_column; $$->u3.else_statements = $4;}
382 target : goto_word { $$ = npval(PV_WORD,@1.first_line,@1.last_line, @1.first_column, @1.last_column); $$->u1.str = $1;}
383 | goto_word BAR goto_word {$$=npval(PV_WORD,@1.first_line,@1.last_line, @1.first_column, @1.last_column);
384 $$->u1.str = $1; $$->next = npval(PV_WORD,@3.first_line,@3.last_line, @3.first_column, @3.last_column);
385 $$->next->u1.str = $3;}
386 | goto_word COMMA goto_word {$$=npval(PV_WORD,@1.first_line,@1.last_line, @1.first_column, @1.last_column);
387 $$->u1.str = $1; $$->next = npval(PV_WORD,@3.first_line,@3.last_line, @3.first_column, @3.last_column);
388 $$->next->u1.str = $3;}
389 | goto_word BAR goto_word BAR goto_word {$$=npval(PV_WORD,@1.first_line,@1.last_line, @1.first_column, @1.last_column);
390 $$->u1.str = $1; $$->next = npval(PV_WORD,@3.first_line,@3.last_line, @3.first_column, @3.last_column);
391 $$->next->u1.str = $3;
392 $$->next->next = npval(PV_WORD,@5.first_line,@5.last_line, @5.first_column, @5.last_column);
393 $$->next->next->u1.str = $5; }
394 | goto_word COMMA goto_word COMMA goto_word {$$=npval(PV_WORD,@1.first_line,@1.last_line, @1.first_column, @1.last_column);
395 $$->u1.str = $1; $$->next = npval(PV_WORD,@3.first_line,@3.last_line, @3.first_column, @3.last_column);
396 $$->next->u1.str = $3;
397 $$->next->next = npval(PV_WORD,@5.first_line,@5.last_line, @5.first_column, @5.last_column);
398 $$->next->next->u1.str = $5; }
399 | KW_DEFAULT BAR goto_word BAR goto_word {$$=npval(PV_WORD,@1.first_line,@1.last_line, @1.first_column, @1.last_column);
400 $$->u1.str = strdup("default"); $$->next = npval(PV_WORD,@3.first_line,@3.last_line, @3.first_column, @3.last_column);
401 $$->next->u1.str = $3;
402 $$->next->next = npval(PV_WORD,@5.first_line,@5.last_line, @5.first_column, @5.last_column);
403 $$->next->next->u1.str = $5; }
404 | KW_DEFAULT COMMA goto_word COMMA goto_word {$$=npval(PV_WORD,@1.first_line,@1.last_line, @1.first_column, @1.last_column);
405 $$->u1.str = strdup("default"); $$->next = npval(PV_WORD,@3.first_line,@3.last_line, @3.first_column, @3.last_column);
406 $$->next->u1.str = $3;
407 $$->next->next = npval(PV_WORD,@5.first_line,@5.last_line, @5.first_column, @5.last_column);
408 $$->next->next->u1.str = $5; }
411 jumptarget : goto_word {$$=npval(PV_WORD,@1.first_line,@1.last_line, @1.first_column, @1.last_column);
412 $$->u1.str = $1; $$->next = npval(PV_WORD,@1.first_line,@1.last_line, @1.first_column, @1.last_column);
413 $$->next->u1.str = strdup("1");} /* jump extension[,priority][@context] */
414 | goto_word COMMA goto_word {$$=npval(PV_WORD,@1.first_line,@1.last_line, @1.first_column, @1.last_column);
415 $$->u1.str = $1; $$->next = npval(PV_WORD,@3.first_line,@3.last_line, @3.first_column, @3.last_column);
416 $$->next->u1.str = $3;}
417 | goto_word COMMA word AT word {$$=npval(PV_WORD,@1.first_line,@1.last_line, @1.first_column, @1.last_column);
418 $$->u1.str = $5; $$->next = npval(PV_WORD,@3.first_line,@3.last_line, @3.first_column, @3.last_column);
419 $$->next->u1.str = $1;
420 $$->next->next = npval(PV_WORD,@5.first_line,@5.last_line, @5.first_column, @5.last_column);
421 $$->next->next->u1.str = $3; }
422 | goto_word AT goto_word {$$=npval(PV_WORD,@1.first_line,@1.last_line, @1.first_column, @1.last_column);
423 $$->u1.str = $3; $$->next = npval(PV_WORD,@3.first_line,@3.last_line, @3.first_column, @3.last_column);
424 $$->next->u1.str = $1;
425 $$->next->next = npval(PV_WORD,@3.first_line,@3.last_line, @3.first_column, @3.last_column);
426 $$->next->next->u1.str = strdup("1"); }
427 | goto_word COMMA word AT KW_DEFAULT {$$=npval(PV_WORD,@1.first_line,@1.last_line, @1.first_column, @1.last_column);
428 $$->u1.str = strdup("default"); $$->next = npval(PV_WORD,@3.first_line,@3.last_line, @3.first_column, @3.last_column);
429 $$->next->u1.str = $1;
430 $$->next->next = npval(PV_WORD,@5.first_line,@5.last_line, @5.first_column, @5.last_column);
431 $$->next->next->u1.str = $3; }
432 | goto_word AT KW_DEFAULT {$$=npval(PV_WORD,@1.first_line,@1.last_line, @1.first_column, @1.last_column);
433 $$->u1.str = strdup("default"); $$->next = npval(PV_WORD,@3.first_line,@3.last_line, @3.first_column, @3.last_column);
434 $$->next->u1.str = $1;
435 $$->next->next = npval(PV_WORD,@3.first_line,@3.last_line, @3.first_column, @3.last_column);
436 $$->next->next->u1.str = strdup("1"); }
439 macro_call : word LP {reset_argcount(parseio->scanner);} eval_arglist RP
440 {$$= npval(PV_MACRO_CALL,@1.first_line,@2.last_line, @1.first_column, @2.last_column);
441 $$->u1.str = $1; $$->u2.arglist = $4;}
442 | word LP RP {$$= npval(PV_MACRO_CALL,@1.first_line,@3.last_line, @1.first_column, @3.last_column); $$->u1.str = $1; }
445 application_call_head: word {reset_argcount(parseio->scanner);} LP {if (strcasecmp($1,"goto") == 0) {
446 $$= npval(PV_GOTO,@1.first_line,@3.last_line, @1.first_column, @3.last_column);
447 free($1); /* won't be using this */
448 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 );
450 $$= npval(PV_APPLICATION_CALL,@1.first_line,@3.last_line, @1.first_column, @3.last_column);
454 application_call : application_call_head eval_arglist RP {$$ = $1;
455 if( $$->type == PV_GOTO )
459 $$->endline = @3.last_line; $$->endcol = @3.last_column;}
460 | application_call_head RP {$$=$1;$$->endline = @2.last_line; $$->endcol = @2.last_column;}
463 eval_arglist : word_list { $$= npval(PV_WORD,@1.first_line,@1.last_line, @1.first_column, @1.last_column); $$->u1.str = $1;}
464 | /*nothing! */ { $$= npval(PV_WORD,0/*@1.first_line*/,0/*@1.last_line*/,0/* @1.first_column*/, 0/*@1.last_column*/); $$->u1.str = strdup(""); }
465 | eval_arglist COMMA word { pval *z = npval(PV_WORD,@3.first_line,@3.last_line, @3.first_column, @3.last_column); $$ = $1; linku1($1,z); z->u1.str = $3;}
466 | eval_arglist COMMA { pval *z = npval(PV_WORD,@2.first_line,@2.last_line, @2.first_column, @2.last_column); $$ = $1; linku1($1,z); z->u1.str = strdup("");}
469 case_statements: case_statement {$$=$1;}
470 | case_statements case_statement { if ( $1 && $2 ) {$$=$1; linku1($$,$2);}
471 else if ( $1 ) {$$=$1;}
472 else if ( $2 ) {$$=$2;} }
475 case_statement: KW_CASE word COLON statements {$$ = npval(PV_CASE,@1.first_line,@3.last_line, @1.first_column, @3.last_column); $$->u1.str = $2; $$->u2.statements = $4;}
476 | KW_DEFAULT COLON statements {$$ = npval(PV_DEFAULT,@1.first_line,@3.last_line, @1.first_column, @3.last_column); $$->u1.str = 0; $$->u2.statements = $3;}
477 | KW_PATTERN word COLON statements {$$ = npval(PV_PATTERN,@1.first_line,@3.last_line, @1.first_column, @3.last_column); $$->u1.str = $2; $$->u2.statements = $4;}
478 | KW_CASE word COLON {$$ = npval(PV_CASE,@1.first_line,@3.last_line, @1.first_column, @3.last_column); $$->u1.str = $2;}
479 | KW_DEFAULT COLON {$$ = npval(PV_DEFAULT,@1.first_line,@2.last_line, @1.first_column, @2.last_column); $$->u1.str = 0;}
480 | KW_PATTERN word COLON {$$ = npval(PV_PATTERN,@1.first_line,@3.last_line, @1.first_column, @3.last_column); $$->u1.str = $2;}
483 macro_statements: macro_statement {$$ = $1;}
484 | macro_statements macro_statement { if ( $1 && $2 ) {$$=$1; linku1($$,$2);}
485 else if ( $1 ) {$$=$1;}
486 else if ( $2 ) {$$=$2;} }
489 macro_statement : statement {$$=$1;}
490 | KW_CATCH word LC statements RC {$$=npval(PV_CATCH,@1.first_line,@5.last_line, @1.first_column, @5.last_column); $$->u1.str = $2; $$->u2.statements = $4;}
493 switches : KW_SWITCHES LC switchlist RC {$$= npval(PV_SWITCHES,@1.first_line,@4.last_line, @1.first_column, @4.last_column); $$->u1.list = $3; }
494 | KW_SWITCHES LC RC /* empty switch list OK */ {$$= npval(PV_SWITCHES,@1.first_line,@3.last_line, @1.first_column, @3.last_column);}
497 eswitches : KW_ESWITCHES LC switchlist RC {$$= npval(PV_ESWITCHES,@1.first_line,@4.last_line, @1.first_column, @4.last_column); $$->u1.list = $3; }
498 | KW_ESWITCHES LC RC /* empty switch list OK */ {$$= npval(PV_ESWITCHES,@1.first_line,@3.last_line, @1.first_column, @3.last_column); } /* if there's nothing to declare, why include it? */
501 switchlist : word SEMI {$$=npval(PV_WORD,@1.first_line,@2.last_line, @1.first_column, @2.last_column); $$->u1.str = $1;}
502 | switchlist word SEMI {pval *z = npval(PV_WORD,@2.first_line,@3.last_line, @2.first_column, @3.last_column); $$=$1; z->u1.str = $2; linku1($$,z); }
503 | switchlist error {$$=$1;}
506 includeslist : includedname SEMI {$$=npval(PV_WORD,@1.first_line,@2.last_line, @1.first_column, @2.last_column); $$->u1.str = $1;}
507 | includedname BAR word3_list COLON word3_list COLON word3_list BAR word3_list BAR word3_list BAR word3_list SEMI {
508 $$=npval(PV_WORD,@1.first_line,@2.last_line, @1.first_column, @2.last_column);
510 $$->u2.arglist = npval(PV_WORD,@3.first_line,@7.last_line, @3.first_column, @7.last_column);
511 $$->u2.arglist->u1.str = (char*)malloc(strlen($3)+strlen($5)+strlen($7)+4);
512 strcpy($$->u2.arglist->u1.str,$3);
513 strcat($$->u2.arglist->u1.str,":");
514 strcat($$->u2.arglist->u1.str,$5);
515 strcat($$->u2.arglist->u1.str,":");
516 strcat($$->u2.arglist->u1.str,$7);
520 $$->u2.arglist->next = npval(PV_WORD,@9.first_line,@9.last_line, @9.first_column, @9.last_column);
521 $$->u2.arglist->next->u1.str = $9;
522 $$->u2.arglist->next->next = npval(PV_WORD,@11.first_line,@11.last_line, @11.first_column, @11.last_column);
523 $$->u2.arglist->next->next->u1.str = $11;
524 $$->u2.arglist->next->next->next = npval(PV_WORD,@13.first_line,@13.last_line, @13.first_column, @13.last_column);
525 $$->u2.arglist->next->next->next->u1.str = $13;
528 | includedname BAR word BAR word3_list BAR word3_list BAR word3_list SEMI {
529 $$=npval(PV_WORD,@1.first_line,@2.last_line, @1.first_column, @2.last_column);
531 $$->u2.arglist = npval(PV_WORD,@3.first_line,@3.last_line, @3.first_column, @3.last_column);
532 $$->u2.arglist->u1.str = $3;
533 $$->u2.arglist->next = npval(PV_WORD,@5.first_line,@5.last_line, @5.first_column, @5.last_column);
534 $$->u2.arglist->next->u1.str = $5;
535 $$->u2.arglist->next->next = npval(PV_WORD,@7.first_line,@7.last_line, @7.first_column, @7.last_column);
536 $$->u2.arglist->next->next->u1.str = $7;
537 $$->u2.arglist->next->next->next = npval(PV_WORD,@9.first_line,@9.last_line, @9.first_column, @9.last_column);
538 $$->u2.arglist->next->next->next->u1.str = $9;
541 | includeslist includedname SEMI {pval *z = npval(PV_WORD,@2.first_line,@3.last_line, @2.first_column, @3.last_column); $$=$1; z->u1.str = $2; linku1($$,z); }
542 | includeslist includedname BAR word3_list COLON word3_list COLON word3_list BAR word3_list BAR word3_list BAR word3_list SEMI {pval *z = npval(PV_WORD,@2.first_line,@3.last_line, @2.first_column, @3.last_column);
543 $$=$1; z->u1.str = $2; linku1($$,z);
544 z->u2.arglist = npval(PV_WORD,@4.first_line,@4.last_line, @4.first_column, @4.last_column);
545 $$->u2.arglist->u1.str = (char*)malloc(strlen($4)+strlen($6)+strlen($8)+4);
546 strcpy($$->u2.arglist->u1.str,$4);
547 strcat($$->u2.arglist->u1.str,":");
548 strcat($$->u2.arglist->u1.str,$6);
549 strcat($$->u2.arglist->u1.str,":");
550 strcat($$->u2.arglist->u1.str,$8);
554 z->u2.arglist->next = npval(PV_WORD,@10.first_line,@10.last_line, @10.first_column, @10.last_column);
555 z->u2.arglist->next->u1.str = $10;
556 z->u2.arglist->next->next = npval(PV_WORD,@12.first_line,@12.last_line, @12.first_column, @12.last_column);
557 z->u2.arglist->next->next->u1.str = $12;
558 z->u2.arglist->next->next->next = npval(PV_WORD,@14.first_line,@14.last_line, @14.first_column, @14.last_column);
559 z->u2.arglist->next->next->next->u1.str = $14;
562 | includeslist includedname BAR word BAR word3_list BAR word3_list BAR word3_list SEMI
563 {pval *z = npval(PV_WORD,@2.first_line,@2.last_line, @2.first_column, @3.last_column);
564 $$=$1; z->u1.str = $2; linku1($$,z);
565 z->u2.arglist = npval(PV_WORD,@4.first_line,@4.last_line, @4.first_column, @4.last_column);
566 $$->u2.arglist->u1.str = $4;
567 z->u2.arglist->next = npval(PV_WORD,@6.first_line,@6.last_line, @6.first_column, @6.last_column);
568 z->u2.arglist->next->u1.str = $6;
569 z->u2.arglist->next->next = npval(PV_WORD,@8.first_line,@8.last_line, @8.first_column, @8.last_column);
570 z->u2.arglist->next->next->u1.str = $8;
571 z->u2.arglist->next->next->next = npval(PV_WORD,@10.first_line,@10.last_line, @10.first_column, @10.last_column);
572 z->u2.arglist->next->next->next->u1.str = $10;
575 | includeslist error {$$=$1;}
578 includedname : word { $$ = $1;}
579 | KW_DEFAULT {$$=strdup("default");}
582 includes : KW_INCLUDES LC includeslist RC {$$= npval(PV_INCLUDES,@1.first_line,@4.last_line, @1.first_column, @4.last_column); $$->u1.list = $3;}
583 | KW_INCLUDES LC RC {$$= npval(PV_INCLUDES,@1.first_line,@3.last_line, @1.first_column, @3.last_column);}
589 static char *token_equivs1[] =
629 static char *token_equivs2[] =
670 static char *ael_token_subst(char *mess)
672 /* calc a length, malloc, fill, and return; yyerror had better free it! */
676 int token_equivs_entries = sizeof(token_equivs1)/sizeof(char*);
678 for (p=mess; *p; p++) {
679 for (i=0; i<token_equivs_entries; i++) {
680 if ( strncmp(p,token_equivs1[i],strlen(token_equivs1[i])) == 0 )
682 len+=strlen(token_equivs2[i])+2;
683 p += strlen(token_equivs1[i])-1;
689 res = (char*)malloc(len+1);
694 for (i=0; i<token_equivs_entries; i++) {
695 if ( strncmp(p,token_equivs1[i],strlen(token_equivs1[i])) == 0 ) {
697 for (t=token_equivs2[i]; *t;) {
701 p += strlen(token_equivs1[i]);
713 void yyerror(YYLTYPE *locp, struct parse_io *parseio, char const *s)
715 char *s2 = ael_token_subst((char *)s);
716 if (locp->first_line == locp->last_line) {
717 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);
719 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);
722 parseio->syntax_error_count++;
725 static struct pval *npval(pvaltype type,int first_line, int last_line, int first_column, int last_column)
727 extern char *my_file;
728 pval *z = (pval *)calloc(sizeof(struct pval),1);
730 z->startline = first_line;
731 z->endline = last_line;
732 z->startcol = first_column;
733 z->endcol = last_column;
734 z->filename = strdup(my_file);
738 /* append second element to the list in the first one */
739 static void linku1(pval *head, pval *tail)
744 head->u1_last->next = tail;
746 head->u1_last = tail;