/** * parser.y * * Copyright (C) 2003 - 2007 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 EXTRA_TAIL (*(extra->tail+extra->depth+(*(extra->boff+extra->depth)))) #define EXTRA_TAIL_POS (*(extra->tail+extra->depth+1)) #define EXTRA_TAIL_NEG (*(extra->tail+extra->depth+1+RXV_SPIN_MAX_DEPTH)) #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 void 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 | stmt if_stmt | stmt txt_stmt | stmt ref_stmt | 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){ loop->stmt=$5; if(!(extra->root || extra->depth)) extra->root=$1; if(EXTRA_TAIL) EXTRA_TAIL->next=$1; EXTRA_TAIL=$1; } EXTRA_TAIL_POS=EXTRA_TAIL_NEG=NULL; PARSER_FLUSH } ; 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); PARSER_FLUSH } | 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); PARSER_FLUSH } | 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); PARSER_FLUSH } | 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); PARSER_FLUSH } ; 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); PARSER_FLUSH } | 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); PARSER_FLUSH } | 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); PARSER_FLUSH } | 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); PARSER_FLUSH } ; 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); PARSER_FLUSH } | 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); PARSER_FLUSH } | 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); PARSER_FLUSH } | 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); PARSER_FLUSH } ; 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); PARSER_FLUSH } | 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); PARSER_FLUSH } | 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); PARSER_FLUSH } | 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); PARSER_FLUSH } ; 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); PARSER_FLUSH } | 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); PARSER_FLUSH } | 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); PARSER_FLUSH } | 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); PARSER_FLUSH } ; 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); PARSER_FLUSH } | 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); PARSER_FLUSH } | 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); PARSER_FLUSH } | 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); PARSER_FLUSH } ; txt_stmt: TXT { rxv_spin_extra_t *extra=rxv_spin_yyget_extra(scanner); if(!(extra->root || extra->depth)) extra->root=$1; if(EXTRA_TAIL) EXTRA_TAIL->next=$1; EXTRA_TAIL=$1; extra->count++; PARSER_FLUSH } ; ref_stmt: REF { rxv_spin_extra_t *extra=rxv_spin_yyget_extra(scanner); if($1){ if(!(extra->root || extra->depth)) extra->root=$1; if(EXTRA_TAIL) EXTRA_TAIL->next=$1; EXTRA_TAIL=$1; extra->count++; } PARSER_FLUSH } ; 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 void 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->oper=oper; switch(oper){ case RXV_SPIN_OP_MATCH: 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->type){ /* unless */ cond->pos=nneg; cond->neg=npos; } else{ cond->pos=npos; cond->neg=nneg; } if(!(extra->root || extra->depth)) extra->root=nif; if(EXTRA_TAIL) EXTRA_TAIL->next=nif; EXTRA_TAIL=nif; } else{ /* if or unless with an impossible reference */ if(cond->type){ /* unless */ if(npos){ if(!(extra->root || extra->depth)) extra->root=npos; if(EXTRA_TAIL) EXTRA_TAIL->next=npos; EXTRA_TAIL=npos; } } else{ if(nneg){ if(!(extra->root || extra->depth)) extra->root=nneg; if(EXTRA_TAIL) EXTRA_TAIL->next=nneg; EXTRA_TAIL=nneg; } } } EXTRA_TAIL_POS=EXTRA_TAIL_NEG=NULL; } void rxv_spin_yyerror(char *s){ /* be silent */ }