/** * parser.y * * Copyright (C) 2003 - 2006 Bojan Smojver, Rexursive * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public Licence as published by the Free * Software Foundation; either version 2 of the Licence, 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 General Public Licence for * more details. * * You should have received a copy of the GNU General Public Licence along * with this program; if not, write to the Free Software Foundation, Inc., 59 * Temple Place, Suite 330, Boston, MA 02111-1307 USA * * In addition, as two special exceptions, Bojan Smojver, Rexursive, gives * permission to: * * 1. Link, both statically and dynamically, the code of this program with * Apache HTTP Server, Apache Portable Runtime and Apache Portable Runtime * Utility Library from Apache Software Foundation (or with modified versions * of the above, that use the same licence - Apache Software Licence 1.1, 2.0 * or any later version), and distribute linked combinations including the * program and the above software from Apache Software Foundation. You must * obey the GNU General Public Licence in all respects for all of the code * used other than Apache HTTP Server, Apache Portable Runtime and Apache * Portable Runtime Utility Library. * * 2. Dynamically link any shared library with this program at run-time, * through the interface of SpinApplication or LoadModule run-time * configuration directives of Apache HTTP Server, as provided by this program * or Apache HTTP Server itself, regardless of licensing terms of those shared * libraries. You must obey the GNU General Public Licence in all respects for * all of the code used other than that of those shared libraries. * * If you modify this file, you may extend these exceptions to your version of * the file, but you are not obligated to do so. If you do not wish to do so, * delete one or both of these exception statements from your version. * */ %{ #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)) rxv_spin_extra_t *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_" %error-verbose %token FOR %token IF %token ELSE %token END %token CRF /* command reference, inside #for or #if */ %token CSZ /* command size of reference, inside #for or #if */ %token CIN /* command index of 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=yyget_extra(scanner); if($3){ ($1->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; } ; if_stmt: IF '(' CRF ')' stmt END { parse_if(yyget_extra(scanner),RXV_SPIN_OP_NONE, $1,$3,$5,NULL,NULL,NULL); } | IF '(' CRF ')' stmt ELSE END { parse_if(yyget_extra(scanner),RXV_SPIN_OP_NONE, $1,$3,$5,NULL,NULL,NULL); } | IF '(' CRF ')' stmt ELSE stmt END { parse_if(yyget_extra(scanner),RXV_SPIN_OP_NONE, $1,$3,$5,$7,NULL,NULL); } | IF '(' CRF ')' ELSE stmt END { parse_if(yyget_extra(scanner),RXV_SPIN_OP_NONE, $1,$3,NULL,$6,NULL,NULL); } ; if_stmt: IF '(' CRF MCH REG ')' stmt END { parse_if(yyget_extra(scanner),RXV_SPIN_OP_MATCH, $1,$3,$7,NULL,$5,NULL); } | IF '(' CRF MCH REG ')' stmt ELSE END { parse_if(yyget_extra(scanner),RXV_SPIN_OP_MATCH, $1,$3,$7,NULL,$5,NULL); } | IF '(' CRF MCH REG ')' stmt ELSE stmt END { parse_if(yyget_extra(scanner),RXV_SPIN_OP_MATCH, $1,$3,$7,$9,$5,NULL); } | IF '(' CRF MCH REG ')' ELSE stmt END { parse_if(yyget_extra(scanner),RXV_SPIN_OP_MATCH, $1,$3,NULL,$8,$5,NULL); } ; if_stmt: IF '(' CRF EQL LIT ')' stmt END { parse_if(yyget_extra(scanner),RXV_SPIN_OP_EQ_LIT, $1,$3,$7,NULL,$5,NULL); } | IF '(' CRF EQL LIT ')' stmt ELSE END { parse_if(yyget_extra(scanner),RXV_SPIN_OP_EQ_LIT, $1,$3,$7,NULL,$5,NULL); } | IF '(' CRF EQL LIT ')' stmt ELSE stmt END { parse_if(yyget_extra(scanner),RXV_SPIN_OP_EQ_LIT, $1,$3,$7,$9,$5,NULL); } | IF '(' CRF EQL LIT ')' ELSE stmt END { parse_if(yyget_extra(scanner),RXV_SPIN_OP_EQ_LIT, $1,$3,NULL,$8,$5,NULL); } ; if_stmt: IF '(' CRF EQL NUM ')' stmt END { parse_if(yyget_extra(scanner),RXV_SPIN_OP_EQ_NUM, $1,$3,$7,NULL,$5,NULL); } | IF '(' CRF EQL NUM ')' stmt ELSE END { parse_if(yyget_extra(scanner),RXV_SPIN_OP_EQ_NUM, $1,$3,$7,NULL,$5,NULL); } | IF '(' CRF EQL NUM ')' stmt ELSE stmt END { parse_if(yyget_extra(scanner),RXV_SPIN_OP_EQ_NUM, $1,$3,$7,$9,$5,NULL); } | IF '(' CRF EQL NUM ')' ELSE stmt END { parse_if(yyget_extra(scanner),RXV_SPIN_OP_EQ_NUM, $1,$3,NULL,$8,$5,NULL); } ; if_stmt: IF '(' CRF EQL CRF ')' stmt END { parse_if(yyget_extra(scanner),RXV_SPIN_OP_EQ_REF, $1,$3,$7,NULL,$5,NULL); } | IF '(' CRF EQL CRF ')' stmt ELSE END { parse_if(yyget_extra(scanner),RXV_SPIN_OP_EQ_REF, $1,$3,$7,NULL,$5,NULL); } | IF '(' CRF EQL CRF ')' stmt ELSE stmt END { parse_if(yyget_extra(scanner),RXV_SPIN_OP_EQ_REF, $1,$3,$7,$9,$5,NULL); } | IF '(' CRF EQL CRF ')' ELSE stmt END { parse_if(yyget_extra(scanner),RXV_SPIN_OP_EQ_REF, $1,$3,NULL,$8,$5,NULL); } ; if_stmt: IF '(' CRF '%' NUM EQL NUM ')' stmt END { if($5->num<=0){ yyerror("parse error, cannot take modulo of <= 0"); YYERROR; } parse_if(yyget_extra(scanner),RXV_SPIN_OP_MODULO, $1,$3,$9,NULL,$5,$7); } | IF '(' CRF '%' NUM EQL NUM ')' stmt ELSE END { if($5->num<=0){ yyerror("parse error, cannot take modulo of <= 0"); YYERROR; } parse_if(yyget_extra(scanner),RXV_SPIN_OP_MODULO, $1,$3,$9,NULL,$5,$7); } | IF '(' CRF '%' NUM EQL NUM ')' stmt ELSE stmt END { if($5->num<=0){ yyerror("parse error, cannot take modulo of <= 0"); YYERROR; } parse_if(yyget_extra(scanner),RXV_SPIN_OP_MODULO, $1,$3,$9,$11,$5,$7); } | IF '(' CRF '%' NUM EQL NUM ')' ELSE stmt END { if($5->num<=0){ yyerror("parse error, cannot take modulo of <= 0"); YYERROR; } parse_if(yyget_extra(scanner),RXV_SPIN_OP_MODULO, $1,$3,NULL,$10,$5,$7); } ; txt_stmt: TXT { rxv_spin_extra_t *extra=yyget_extra(scanner); if(!(extra->root || extra->depth)) extra->root=$1; if(EXTRA_TAIL) EXTRA_TAIL->next=$1; EXTRA_TAIL=$1; if(extra->iseof){ if(extra->depth){ yyerror("parse error, unexpected $end, expecting END"); YYERROR; } else{ YYACCEPT; } } } ; ref_stmt: REF { if($1){ rxv_spin_extra_t *extra=yyget_extra(scanner); if(!(extra->root || extra->depth)) extra->root=$1; if(EXTRA_TAIL) EXTRA_TAIL->next=$1; EXTRA_TAIL=$1; } } ; err_stmt: error { rxv_spin_extra_t *extra=yyget_extra(scanner); extra->error=apr_pstrcat(extra->tpool, extra->error?extra->error:"generic parse error", ": row:",apr_off_t_toa(extra->pool,extra->row), " col:",apr_off_t_toa(extra->pool,extra->col),NULL); 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){ /* finish the node */ (nif->cond)->oper=oper; switch(oper){ case RXV_SPIN_OP_MATCH: (nif->cond)->reg=nval1->reg; break; case RXV_SPIN_OP_EQ_REF: (nif->cond)->rfr=nval1->ref; break; case RXV_SPIN_OP_EQ_LIT: (nif->cond)->lit=nval1->lit; break; case RXV_SPIN_OP_EQ_NUM: (nif->cond)->num=nval1->num; break; case RXV_SPIN_OP_MODULO: (nif->cond)->num=nval1->num; (nif->cond)->res=nval2->num; break; default: break; } /* assign branches and root */ if(nref){ /* if or unless with a valid reference */ (nif->cond)->ref=nref->ref; if(nif->cond->type){ /* unless */ (nif->cond)->pos=nneg; (nif->cond)->neg=npos; } else{ (nif->cond)->pos=npos; (nif->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(nif->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 yyerror(char *s){ char *time=malloc(APR_CTIME_LEN); apr_ctime(time,apr_time_now()); fprintf(stderr,"[%s] [error] [spin parser] %s\n",time,s); fflush(stderr); free(time); }