/** * parser.y * * Copyright (C) 2003 - 2008 Bojan Smojver, Rexursive * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 2.1 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * */ %{ #include "private.h" #define YYSTYPE rxv_spin_node_t* #define YYPARSE_PARAM scanner #define YYLEX_PARAM scanner #define PARSER_FLUSH \ if(!extra->depth){ \ extra->pos=extra->offset; \ if(extra->count>RXV_SPIN_FLUSH_COUNT) YYACCEPT; \ } rxv_spin_extra_t *rxv_spin_yyget_extra(void *scanner); static rxv_spin_node_t *parse_if(rxv_spin_extra_t *extra,unsigned char oper, rxv_spin_node_t *nif,rxv_spin_node_t *nref, rxv_spin_node_t *npos,rxv_spin_node_t *nneg, rxv_spin_node_t *nval1,rxv_spin_node_t *nval2); %} %pure_parser %defines %name_prefix="rxv_spin_yy" %error-verbose %token FOR %token IF %token ELSE %token END %token CRF /* command reference, inside #for or #if */ %token REF /* reference */ %token REG /* regular expression */ %token NUM /* number, integer 0 or greater */ %token LIT /* literal string */ %token MCH /* regex match operator: =~ */ %token EQL /* equality operator: == */ %token TXT %token ERR %% /* Grammar rules */ stmt: for_stmt | if_stmt | txt_stmt | ref_stmt | err_stmt | stmt for_stmt { rxv_spin_extra_t *extra=rxv_spin_yyget_extra(scanner); if($1){ if($2){ $2->next=$1->next; $1->next=$2; $$=$2; } else{ $$=$1; } } else if($2){ $$=$2; } else{ $$=NULL; } PARSER_FLUSH } | stmt if_stmt { rxv_spin_extra_t *extra=rxv_spin_yyget_extra(scanner); if($1){ if($2){ $2->next=$1->next; $1->next=$2; $$=$2; } else{ $$=$1; } } else if($2){ $$=$2; } else{ $$=NULL; } PARSER_FLUSH } | stmt txt_stmt { rxv_spin_extra_t *extra=rxv_spin_yyget_extra(scanner); if($1){ if($2){ if($1->type==RXV_SPIN_TXT && $1->ttyp==RXV_SPIN_TXT_OFF){ rxv_spin_txt_t *t1=(rxv_spin_txt_t*)$1, *t2=(rxv_spin_txt_t*)$2; if(t1->start+t1->length==t2->start){ t1->length+=t2->length; $$=$1; } else{ $2->next=$1->next; $1->next=$2; $$=$2; } } else{ $2->next=$1->next; $1->next=$2; $$=$2; } } else{ $$=$1; } } else if($2){ $$=$2; } else{ $$=NULL; } PARSER_FLUSH } | stmt ref_stmt { rxv_spin_extra_t *extra=rxv_spin_yyget_extra(scanner); if($1){ if($2){ $2->next=$1->next; $1->next=$2; $$=$2; } else{ $$=$1; } } else if($2){ $$=$2; } else{ $$=NULL; } PARSER_FLUSH } | stmt err_stmt ; for_stmt: FOR '(' CRF ')' stmt END { rxv_spin_extra_t *extra=rxv_spin_yyget_extra(scanner); rxv_spin_for_t *loop=(rxv_spin_for_t *)$1; if($3){ if($5) loop->stmt=$5->next; if(!(extra->root || extra->depth)) extra->root=$1; $$=$1; } else{ $$=NULL; } } ; if_stmt: IF '(' CRF ')' stmt END { rxv_spin_extra_t *extra=rxv_spin_yyget_extra(scanner); $$=parse_if(extra,RXV_SPIN_OP_NONE,$1,$3,$5,NULL,NULL,NULL); } | IF '(' CRF ')' stmt ELSE END { rxv_spin_extra_t *extra=rxv_spin_yyget_extra(scanner); $$=parse_if(extra,RXV_SPIN_OP_NONE,$1,$3,$5,NULL,NULL,NULL); } | IF '(' CRF ')' stmt ELSE stmt END { rxv_spin_extra_t *extra=rxv_spin_yyget_extra(scanner); $$=parse_if(extra,RXV_SPIN_OP_NONE,$1,$3,$5,$7,NULL,NULL); } | IF '(' CRF ')' ELSE stmt END { rxv_spin_extra_t *extra=rxv_spin_yyget_extra(scanner); $$=parse_if(extra,RXV_SPIN_OP_NONE,$1,$3,NULL,$6,NULL,NULL); } ; if_stmt: IF '(' CRF MCH REG ')' stmt END { rxv_spin_extra_t *extra=rxv_spin_yyget_extra(scanner); $$=parse_if(extra,RXV_SPIN_OP_MATCH,$1,$3,$7,NULL,$5,NULL); } | IF '(' CRF MCH REG ')' stmt ELSE END { rxv_spin_extra_t *extra=rxv_spin_yyget_extra(scanner); $$=parse_if(extra,RXV_SPIN_OP_MATCH,$1,$3,$7,NULL,$5,NULL); } | IF '(' CRF MCH REG ')' stmt ELSE stmt END { rxv_spin_extra_t *extra=rxv_spin_yyget_extra(scanner); $$=parse_if(extra,RXV_SPIN_OP_MATCH,$1,$3,$7,$9,$5,NULL); } | IF '(' CRF MCH REG ')' ELSE stmt END { rxv_spin_extra_t *extra=rxv_spin_yyget_extra(scanner); $$=parse_if(extra,RXV_SPIN_OP_MATCH,$1,$3,NULL,$8,$5,NULL); } ; if_stmt: IF '(' CRF EQL LIT ')' stmt END { rxv_spin_extra_t *extra=rxv_spin_yyget_extra(scanner); $$=parse_if(extra,RXV_SPIN_OP_EQ_LIT,$1,$3,$7,NULL,$5,NULL); } | IF '(' CRF EQL LIT ')' stmt ELSE END { rxv_spin_extra_t *extra=rxv_spin_yyget_extra(scanner); $$=parse_if(extra,RXV_SPIN_OP_EQ_LIT,$1,$3,$7,NULL,$5,NULL); } | IF '(' CRF EQL LIT ')' stmt ELSE stmt END { rxv_spin_extra_t *extra=rxv_spin_yyget_extra(scanner); $$=parse_if(extra,RXV_SPIN_OP_EQ_LIT,$1,$3,$7,$9,$5,NULL); } | IF '(' CRF EQL LIT ')' ELSE stmt END { rxv_spin_extra_t *extra=rxv_spin_yyget_extra(scanner); $$=parse_if(extra,RXV_SPIN_OP_EQ_LIT,$1,$3,NULL,$8,$5,NULL); } ; if_stmt: IF '(' CRF EQL NUM ')' stmt END { rxv_spin_extra_t *extra=rxv_spin_yyget_extra(scanner); $$=parse_if(extra,RXV_SPIN_OP_EQ_NUM,$1,$3,$7,NULL,$5,NULL); } | IF '(' CRF EQL NUM ')' stmt ELSE END { rxv_spin_extra_t *extra=rxv_spin_yyget_extra(scanner); $$=parse_if(extra,RXV_SPIN_OP_EQ_NUM,$1,$3,$7,NULL,$5,NULL); } | IF '(' CRF EQL NUM ')' stmt ELSE stmt END { rxv_spin_extra_t *extra=rxv_spin_yyget_extra(scanner); $$=parse_if(extra,RXV_SPIN_OP_EQ_NUM,$1,$3,$7,$9,$5,NULL); } | IF '(' CRF EQL NUM ')' ELSE stmt END { rxv_spin_extra_t *extra=rxv_spin_yyget_extra(scanner); $$=parse_if(extra,RXV_SPIN_OP_EQ_NUM,$1,$3,NULL,$8,$5,NULL); } ; if_stmt: IF '(' CRF EQL CRF ')' stmt END { rxv_spin_extra_t *extra=rxv_spin_yyget_extra(scanner); $$=parse_if(extra,RXV_SPIN_OP_EQ_REF,$1,$3,$7,NULL,$5,NULL); } | IF '(' CRF EQL CRF ')' stmt ELSE END { rxv_spin_extra_t *extra=rxv_spin_yyget_extra(scanner); $$=parse_if(extra,RXV_SPIN_OP_EQ_REF,$1,$3,$7,NULL,$5,NULL); } | IF '(' CRF EQL CRF ')' stmt ELSE stmt END { rxv_spin_extra_t *extra=rxv_spin_yyget_extra(scanner); $$=parse_if(extra,RXV_SPIN_OP_EQ_REF,$1,$3,$7,$9,$5,NULL); } | IF '(' CRF EQL CRF ')' ELSE stmt END { rxv_spin_extra_t *extra=rxv_spin_yyget_extra(scanner); $$=parse_if(extra,RXV_SPIN_OP_EQ_REF,$1,$3,NULL,$8,$5,NULL); } ; if_stmt: IF '(' CRF '%' NUM EQL NUM ')' stmt END { rxv_spin_extra_t *extra=rxv_spin_yyget_extra(scanner); rxv_spin_num_t *num=(rxv_spin_num_t *)$5; if(num->num<=0){ extra->error="cannot take modulo of <= 0"; YYERROR; } $$=parse_if(extra,RXV_SPIN_OP_MODULO,$1,$3,$9,NULL,$5,$7); } | IF '(' CRF '%' NUM EQL NUM ')' stmt ELSE END { rxv_spin_extra_t *extra=rxv_spin_yyget_extra(scanner); rxv_spin_num_t *num=(rxv_spin_num_t *)$5; if(num->num<=0){ extra->error="cannot take modulo of <= 0"; YYERROR; } $$=parse_if(extra,RXV_SPIN_OP_MODULO,$1,$3,$9,NULL,$5,$7); } | IF '(' CRF '%' NUM EQL NUM ')' stmt ELSE stmt END { rxv_spin_extra_t *extra=rxv_spin_yyget_extra(scanner); rxv_spin_num_t *num=(rxv_spin_num_t *)$5; if(num->num<=0){ extra->error="cannot take modulo of <= 0"; YYERROR; } $$=parse_if(extra,RXV_SPIN_OP_MODULO,$1,$3,$9,$11,$5,$7); } | IF '(' CRF '%' NUM EQL NUM ')' ELSE stmt END { rxv_spin_extra_t *extra=rxv_spin_yyget_extra(scanner); rxv_spin_num_t *num=(rxv_spin_num_t *)$5; if(num->num<=0){ extra->error="cannot take modulo of <= 0"; YYERROR; } $$=parse_if(extra,RXV_SPIN_OP_MODULO,$1,$3,NULL,$10,$5,$7); } ; txt_stmt: TXT { rxv_spin_extra_t *extra=rxv_spin_yyget_extra(scanner); if(!(extra->root || extra->depth)) extra->root=$1; $$=$1; extra->count++; } ; ref_stmt: REF { rxv_spin_extra_t *extra=rxv_spin_yyget_extra(scanner); if($1){ if(!(extra->root || extra->depth)) extra->root=$1; extra->count++; $$=$1; } else{ $$=NULL; } } ; err_stmt: error { rxv_spin_extra_t *extra=rxv_spin_yyget_extra(scanner); /* pretend we're all good */ if(extra->erow>0 || (extra->eof && extra->bpos>=extra->blen)) return 0; extra->error=apr_psprintf(extra->pool, "%s: row: %" APR_OFF_T_FMT " col:%" APR_OFF_T_FMT, extra->error?extra->error:"generic parse error", extra->row,extra->col); return 1; } ; %% static rxv_spin_node_t *parse_if(rxv_spin_extra_t *extra,unsigned char oper, rxv_spin_node_t *nif,rxv_spin_node_t *nref, rxv_spin_node_t *npos,rxv_spin_node_t *nneg, rxv_spin_node_t *nval1,rxv_spin_node_t *nval2){ rxv_spin_if_t *cond=(rxv_spin_if_t *)nif; /* finish the node */ cond->node.iopr=oper; switch(oper){ case RXV_SPIN_OP_MATCH: cond->srg=((rxv_spin_reg_t *)nval1)->srg; cond->reg=&((rxv_spin_reg_t *)nval1)->reg; break; case RXV_SPIN_OP_EQ_REF: cond->rfr=(rxv_spin_ref_t *)nval1; break; case RXV_SPIN_OP_EQ_LIT: cond->lit=((rxv_spin_lit_t *)nval1)->lit; break; case RXV_SPIN_OP_EQ_NUM: cond->num=((rxv_spin_num_t *)nval1)->num; break; case RXV_SPIN_OP_MODULO: cond->num=((rxv_spin_num_t *)nval1)->num; cond->res=((rxv_spin_num_t *)nval2)->num; break; default: break; } /* assign branches and root */ if(nref){ /* if or unless with a valid reference */ cond->ref=(rxv_spin_ref_t *)nref; if(cond->node.ityp){ /* unless */ if(nneg) cond->pos=nneg->next; if(npos) cond->neg=npos->next; } else{ if(npos) cond->pos=npos->next; if(nneg) cond->neg=nneg->next; } if(!(extra->root || extra->depth)) extra->root=nif; return nif; } else{ /* if or unless with an impossible reference */ if(cond->node.ityp){ /* unless */ if(npos){ if(!(extra->root || extra->depth)) extra->root=npos->next; return npos->next; } } else{ if(nneg){ if(!(extra->root || extra->depth)) extra->root=nneg->next; return nneg->next; } } } return NULL; } void rxv_spin_yyerror(char *s){ /* be silent */ }