/** * scanner.l * * 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 YY_DECL int rxv_spin_yylex(YYSTYPE *yylval_param,yyscan_t yyscanner) #include "parser.h" /* * Error recovery macro: * * Check if we've been here before and if so, just accept it, it was obviosly * meant to be there. Otherwise, attempt to get more input by trying to fill * the buffer completely. If that doesn't work, terminate the scan and wait * for next brigade to hopefully take care of the error. * */ #define YYERROR_RECOVER \ if(!(yyextra->erow==yyextra->row && yyextra->col==yyextra->ecol) && \ yyextra->bpos+yyleng>=yyextra->blen){ \ yyextra->erow=yyextra->row; \ yyextra->ecol=yyextra->col; \ \ yywrap(yyscanner); \ \ if(yyextra->eof && yyextra->blenpool,sizeof(*txt)); \ rxv_spin_node_t *node=(rxv_spin_node_t *)txt; \ size_t i; \ \ yyextra->erow=-1; \ \ node->type=RXV_SPIN_TXT; \ \ if(yyextra->f){ \ txt->bucket=apr_bucket_heap_create(yytext,yyleng,NULL, \ yyextra->text->bucket_alloc); \ } else{ \ apr_bucket_copy(yyextra->scan,&txt->bucket); \ txt->bucket->start=yyextra->offset; \ txt->bucket->length=yyleng; \ } \ APR_BRIGADE_INSERT_TAIL(yyextra->text,txt->bucket); \ \ yyextra->offset+=yyleng; yyextra->bpos+=yyleng; \ yyextra->row+=(n); yyextra->col=0; \ \ for(i=yyleng-1;*(yytext+i)!='\n';yyextra->col++,i--); \ \ *yylval=node; return TXT; #define YYLINE_LINE_NL(n) \ rxv_spin_txt_t *txt=apr_pcalloc(yyextra->pool,sizeof(*txt)); \ rxv_spin_node_t *node=(rxv_spin_node_t *)txt; \ \ yyextra->erow=-1; \ \ node->type=RXV_SPIN_TXT; \ \ if(yyextra->f){ \ txt->bucket=apr_bucket_heap_create(yytext,yyleng,NULL, \ yyextra->text->bucket_alloc); \ } else{ \ apr_bucket_copy(yyextra->scan,&txt->bucket); \ txt->bucket->start=yyextra->offset; \ txt->bucket->length=yyleng; \ } \ APR_BRIGADE_INSERT_TAIL(yyextra->text,txt->bucket); \ \ yyextra->offset+=yyleng; yyextra->bpos+=yyleng; \ yyextra->row+=(n); yyextra->col=0; \ \ *yylval=node; return TXT; static apr_status_t regex_cleanup(void *data); %} %option prefix="rxv_spin_yy" %option 8bit reentrant bison-bridge stack %option warn nodefault %option never-interactive %option yywrap %option full %option header-file="scanner.h" %option backup %option nounput noyy_top_state REF \$[#@]*\{[[:alpha:]][[:alnum:]_-]*(\.[[:alpha:]][[:alnum:]_-]*)*\} REG \/([^/]|\\\/)*\/ LIT \"([^"]|\\\")*\" %x command %% /* initial scanner */ {REF} { apr_size_t chunks,noff=2; int ldepth; char *p; rxv_spin_ref_t *ref=apr_pcalloc(yyextra->pool,sizeof(*ref)); rxv_spin_node_t *node=(rxv_spin_node_t *)ref;; yyextra->erow=-1; /* reset scanning error */ /* populate node */ node->type=RXV_SPIN_REF; if(*(yytext+1)=='#' || *(yytext+1)=='@') noff++; ref->name=apr_pstrmemdup(yyextra->pool,yytext+noff,yyleng-(noff+1)); /* count chunks of the name */ for(chunks=0,p=ref->name;p;p=strchr(p,'.')){ p++; chunks++; } /* find the last part of the reference name */ if((ref->chunk=strrchr(ref->name,'.'))) ref->chunk=apr_pstrmemdup(yyextra->pool,ref->chunk+1, strlen(ref->name)-(ref->chunk-ref->name)-1); else ref->chunk=ref->name; /* link the index of the nesting for loop */ for(ldepth=yyextra->ldepth-1;ldepth>=0 && !ref->loop;ldepth--){ char *name=(*(yyextra->loop+ldepth))->ref->name; apr_size_t length=strlen(name); if(lengthname,length) && *(ref->name+length)=='.' && !strchr(ref->name+length+1,'.')) ref->loop=*(yyextra->loop+ldepth); } /* impossible reference, ignore */ if(chunks>1 && !ref->loop) node=NULL; *yylval=node; switch(*(yytext+1)){ case '#': ref->type=RXV_SPIN_REF_SIZ; break; case '@': ref->type=RXV_SPIN_REF_IND; break; default: ref->type=RXV_SPIN_REF_REG; break; } yyextra->offset+=yyleng; yyextra->bpos+=yyleng; yyextra->col+=yyleng; return REF; } "#for" { rxv_spin_for_t *loop=apr_pcalloc(yyextra->pool,sizeof(*loop)); rxv_spin_node_t *node=(rxv_spin_node_t *)loop; yyextra->erow=-1; /* reset scanning error */ /* populate node */ node->type=RXV_SPIN_FOR; *(yyextra->loop+yyextra->ldepth)=loop; *(yyextra->nest+yyextra->depth)=RXV_SPIN_FOR; yyextra->depth++; yyextra->ldepth++; if(yyextra->depth>=RXV_SPIN_MAX_DEPTH){ yyextra->error="maximum nesting depth exceeded"; *yylval=NULL; return ERR; } *(yyextra->boff+yyextra->depth)=0; yy_push_state(command,yyscanner); yyextra->offset+=yyleng; yyextra->bpos+=yyleng; yyextra->col+=yyleng; *yylval=node; return FOR; } "#if"|"#unless" { rxv_spin_if_t *cond=apr_pcalloc(yyextra->pool,sizeof(*cond)); rxv_spin_node_t *node=(rxv_spin_node_t *)cond; yyextra->erow=-1; /* reset scanning error */ /* populate node */ node->type=RXV_SPIN_IF; /* are we if (always 0) or unless (always 1) */ if(*(yytext+1)=='u') cond->type=RXV_SPIN_IF_UNLESS; *(yyextra->nest+yyextra->depth)=RXV_SPIN_IF; yyextra->depth++; if(yyextra->depth>=RXV_SPIN_MAX_DEPTH){ yyextra->error="maximum nesting depth exceeded"; *yylval=NULL; return ERR; } *(yyextra->boff+yyextra->depth)=0; yy_push_state(command,yyscanner); yyextra->offset+=yyleng; yyextra->bpos+=yyleng; yyextra->col+=yyleng; *yylval=node; return IF; } "#else" { yyextra->erow=-1; /* reset scanning error */ *(yyextra->boff+yyextra->depth)=RXV_SPIN_MAX_DEPTH; yyextra->offset+=yyleng; yyextra->bpos+=yyleng; yyextra->col+=yyleng; *yylval=NULL; return ELSE; } "#end" { yyextra->erow=-1; /* reset scanning error */ *(yyextra->boff+yyextra->depth)=0; /* previous node was a #for loop */ if(*(yyextra->nest+yyextra->depth-1)==RXV_SPIN_FOR){ *(yyextra->loop+yyextra->ldepth)=NULL; yyextra->ldepth--; } yyextra->depth--; if(yyextra->depth<0){ yyextra->error="minimum nesting depth exceeded"; *yylval=NULL; return ERR; } yyextra->offset+=yyleng; yyextra->bpos+=yyleng; yyextra->col+=yyleng; *yylval=NULL; return END; } . | "#f" | "#fo" | "#e" | "#en" | "#i" | "#u" | "#un" | "#unl" | "#unle" | "#unles" | "#el" | "#els" | \$[#@]* | \$[#@]*\{ | \$[#@]*\{[[:alpha:]] | \$[#@]*\{[[:alpha:]][[:alnum:]._-]* { rxv_spin_node_t *node; rxv_spin_txt_t *txt; YYERROR_RECOVER yyextra->erow=-1; /* reset scanning error */ txt=apr_pcalloc(yyextra->pool,sizeof(*txt)); node=(rxv_spin_node_t *)txt; node->type=RXV_SPIN_TXT; if(yyextra->f){ txt->bucket=apr_bucket_heap_create(yytext,yyleng,NULL, yyextra->text->bucket_alloc); } else{ apr_bucket_copy(yyextra->scan,&txt->bucket); txt->bucket->start=yyextra->offset; txt->bucket->length=yyleng; } APR_BRIGADE_INSERT_TAIL(yyextra->text,txt->bucket); yyextra->offset+=yyleng; yyextra->bpos+=yyleng; yyextra->col+=yyleng; *yylval=node; return TXT; } [^$#\n]+ { rxv_spin_txt_t *txt=apr_pcalloc(yyextra->pool,sizeof(*txt)); rxv_spin_node_t *node=(rxv_spin_node_t *)txt; yyextra->erow=-1; /* reset scanning error */ node->type=RXV_SPIN_TXT; if(yyextra->f){ txt->bucket=apr_bucket_heap_create(yytext,yyleng,NULL, yyextra->text->bucket_alloc); } else{ apr_bucket_copy(yyextra->scan,&txt->bucket); txt->bucket->start=yyextra->offset; txt->bucket->length=yyleng; } APR_BRIGADE_INSERT_TAIL(yyextra->text,txt->bucket); yyextra->offset+=yyleng; yyextra->bpos+=yyleng; yyextra->col+=yyleng; *yylval=node; return TXT; } "#f\n" | "#fo\n" | "#e\n" | "#en\n" | "#i\n" | "#u\n" | "#un\n" | "#unl\n" | "#unle\n" | "#unles\n" | "#el\n" | "#els\n" | \$[#@]*\n | \$[#@]*\{\n | \$[#@]*\{[[:alpha:]]\n | \$[#@]*\{[[:alpha:]][[:alnum:]._-]*\n | [^$#\n]+\n { YYLINE_LINE_NL(1) } /* multiple line matching for better performance */ [^$#\n]+\n[^$#\n]+ { YYLINE_LINE_NONL(1) } ([^$#\n]+\n){2} { YYLINE_LINE_NL(2) } ([^$#\n]+\n){2}[^$#\n]+ { YYLINE_LINE_NONL(2) } ([^$#\n]+\n){3} { YYLINE_LINE_NL(3) } ([^$#\n]+\n){3}[^$#\n]+ { YYLINE_LINE_NONL(3) } ([^$#\n]+\n){4} { YYLINE_LINE_NL(4) } ([^$#\n]+\n){4}[^$#\n]+ { YYLINE_LINE_NONL(4) } ([^$#\n]+\n){5} { YYLINE_LINE_NL(5) } ([^$#\n]+\n){5}[^$#\n]+ { YYLINE_LINE_NONL(5) } ([^$#\n]+\n){6} { YYLINE_LINE_NL(6) } ([^$#\n]+\n){6}[^$#\n]+ { YYLINE_LINE_NONL(6) } ([^$#\n]+\n){7} { YYLINE_LINE_NL(7) } ([^$#\n]+\n){7}[^$#\n]+ { YYLINE_LINE_NONL(7) } ([^$#\n]+\n){8} { YYLINE_LINE_NL(8) } ([^$#\n]+\n){8}[^$#\n]+ { YYLINE_LINE_NONL(8) } ([^$#\n]+\n){9} { YYLINE_LINE_NL(9) } ([^$#\n]+\n){9}[^$#\n]+ { YYLINE_LINE_NONL(9) } ([^$#\n]+\n){10} { YYLINE_LINE_NL(10) } ([^$#\n]+\n){10}[^$#\n]+ { YYLINE_LINE_NONL(10) } ([^$#\n]+\n){11} { YYLINE_LINE_NL(11) } ([^$#\n]+\n){11}[^$#\n]+ { YYLINE_LINE_NONL(11) } ([^$#\n]+\n){12} { YYLINE_LINE_NL(12) } ([^$#\n]+\n){12}[^$#\n]+ { YYLINE_LINE_NONL(12) } ([^$#\n]+\n){13} { YYLINE_LINE_NL(13) } ([^$#\n]+\n){13}[^$#\n]+ { YYLINE_LINE_NONL(13) } ([^$#\n]+\n){14} { YYLINE_LINE_NL(14) } ([^$#\n]+\n){14}[^$#\n]+ { YYLINE_LINE_NONL(14) } ([^$#\n]+\n){15} { YYLINE_LINE_NL(15) } ([^$#\n]+\n){15}[^$#\n]+ { YYLINE_LINE_NONL(15) } ([^$#\n]+\n){16} { YYLINE_LINE_NL(16) } ([^$#\n]+\n){16}[^$#\n]+ { YYLINE_LINE_NONL(16) } ([^$#\n]+\n){17} { YYLINE_LINE_NL(17) } ([^$#\n]+\n){17}[^$#\n]+ { YYLINE_LINE_NONL(17) } ([^$#\n]+\n){18} { YYLINE_LINE_NL(18) } ([^$#\n]+\n){18}[^$#\n]+ { YYLINE_LINE_NONL(18) } ([^$#\n]+\n){19} { YYLINE_LINE_NL(19) } ([^$#\n]+\n){19}[^$#\n]+ { YYLINE_LINE_NONL(19) } ([^$#\n]+\n){20} { YYLINE_LINE_NL(20) } \n+ { rxv_spin_txt_t *txt=apr_pcalloc(yyextra->pool,sizeof(*txt)); rxv_spin_node_t *node=(rxv_spin_node_t *)txt; yyextra->erow=-1; /* reset scanning error */ node->type=RXV_SPIN_TXT; if(yyextra->f){ txt->bucket=apr_bucket_heap_create(yytext,yyleng,NULL, yyextra->text->bucket_alloc); } else{ apr_bucket_copy(yyextra->scan,&txt->bucket); txt->bucket->start=yyextra->offset; txt->bucket->length=yyleng; } APR_BRIGADE_INSERT_TAIL(yyextra->text,txt->bucket); yyextra->offset+=yyleng; yyextra->bpos+=yyleng; yyextra->row+=yyleng; yyextra->col=0; *yylval=node; return TXT; } /* command scanner */ { {REF} { apr_size_t chunks,noff=2; int ldepth,loffset=0; char *p; rxv_spin_ref_t *ref=apr_pcalloc(yyextra->pool,sizeof(*ref)); rxv_spin_node_t *node=(rxv_spin_node_t *)ref; yyextra->erow=-1; /* reset scanning error */ /* populate node */ node->type=RXV_SPIN_REF; if(*(yytext+1)=='#' || *(yytext+1)=='@') noff++; ref->name=apr_pstrmemdup(yyextra->pool,yytext+noff,yyleng-(noff+1)); /* count chunks of the name */ for(chunks=0,p=ref->name;p;p=strchr(p,'.')){ p++; chunks++; } /* find the last part of the reference name */ if((ref->chunk=strrchr(ref->name,'.'))) ref->chunk=apr_pstrmemdup(yyextra->pool,ref->chunk+1, strlen(ref->name)-(ref->chunk-ref->name)-1); else ref->chunk=ref->name; /* was this a #for or an #if? */ if(*(yyextra->nest+yyextra->depth-1)==RXV_SPIN_FOR) loffset++; /* link the index of the nesting for loop */ for(ldepth=yyextra->ldepth-1-loffset;ldepth>=0 && !ref->loop;ldepth--){ char *name=(*(yyextra->loop+ldepth))->ref->name; apr_size_t length=strlen(name); if(lengthname,length) && *(ref->name+length)=='.' && !strchr(ref->name+length+1,'.')) ref->loop=*(yyextra->loop+ldepth); } /* impossible reference, ignore */ if(chunks>1 && !ref->loop) node=NULL; /* link the reference to the #for loop */ if(loffset) (*(yyextra->loop+yyextra->ldepth-1))->ref=ref; *yylval=node; switch(*(yytext+1)){ case '#': ref->type=RXV_SPIN_REF_SIZ; break; case '@': ref->type=RXV_SPIN_REF_IND; break; default: ref->type=RXV_SPIN_REF_REG; break; } yyextra->offset+=yyleng; yyextra->bpos+=yyleng; yyextra->col+=yyleng; return CRF; } {REG} { rxv_spin_reg_t *reg=apr_pcalloc(yyextra->pool,sizeof(*reg)); rxv_spin_node_t *node=(rxv_spin_node_t *)reg; char *sreg,*p,*r; yyextra->erow=-1; /* reset scanning error */ /* populate node */ node->type=RXV_SPIN_REG; sreg=apr_pstrmemdup(yyextra->pool,yytext+1,yyleng-2); /* turn escaped '\/' into '/' */ for(p=sreg;*p;p++) if(*p=='\\' && *(p+1)=='/') for(r=p;r;r++) *r=*(r+1); if(ap_regcomp(®->reg,sreg,AP_REG_EXTENDED|AP_REG_NOSUB)!=APR_SUCCESS){ yyextra->error="invalid regular expression"; *yylval=NULL; return ERR; } apr_pool_cleanup_register(yyextra->pool,®->reg, regex_cleanup,apr_pool_cleanup_null); yyextra->offset+=yyleng; yyextra->bpos+=yyleng; yyextra->col+=yyleng; *yylval=node; return REG; } {LIT} { rxv_spin_lit_t *lit=apr_pcalloc(yyextra->pool,sizeof(*lit)); rxv_spin_node_t *node=(rxv_spin_node_t *)lit; char *p,*r; yyextra->erow=-1; /* reset scanning error */ /* populate node */ node->type=RXV_SPIN_LIT; lit->lit=apr_pstrmemdup(yyextra->pool,yytext+1,yyleng-2); /* turn escaped '\"' into '"' */ for(p=lit->lit;*p;p++) if(*p=='\\' && *(p+1)=='"') for(r=p;r;r++) *r=*(r+1); yyextra->offset+=yyleng; yyextra->bpos+=yyleng; yyextra->col+=yyleng; *yylval=node; return LIT; } [[:digit:]]+ { rxv_spin_num_t *num; rxv_spin_node_t *node; YYERROR_RECOVER num=apr_pcalloc(yyextra->pool,sizeof(*num)); node=(rxv_spin_node_t *)num; yyextra->erow=-1; /* reset scanning error */ /* populate node */ node->type=RXV_SPIN_NUM; num->num=atol(yytext); yyextra->offset+=yyleng; yyextra->bpos+=yyleng; yyextra->col+=yyleng; *yylval=node; return NUM; } "(" { yyextra->erow=-1; /* reset scanning error */ yyextra->offset++; yyextra->bpos++; yyextra->col++; *yylval=NULL; return '('; } ")" { yyextra->erow=-1; /* reset scanning error */ yy_pop_state(yyscanner); yyextra->offset++; yyextra->bpos++; yyextra->col++; *yylval=NULL; return ')'; } "=~" { yyextra->erow=-1; /* reset scanning error */ yyextra->offset+=yyleng; yyextra->bpos+=yyleng; yyextra->col+=yyleng; *yylval=NULL; return MCH; } "==" { yyextra->erow=-1; /* reset scanning error */ yyextra->offset+=yyleng; yyextra->bpos+=yyleng; yyextra->col+=yyleng; *yylval=NULL; return EQL; } "%" { yyextra->erow=-1; /* reset scanning error */ yyextra->offset++; yyextra->bpos++; yyextra->col++; *yylval=NULL; return '%'; } [ \r\t]+ { /* ignore whitespace */ yyextra->erow=-1; /* reset scanning error */ yyextra->offset+=yyleng; yyextra->bpos+=yyleng; yyextra->col+=yyleng; } \n+ { /* ignore whitespace */ yyextra->erow=-1; /* reset scanning error */ yyextra->offset+=yyleng; yyextra->bpos+=yyleng; yyextra->row+=yyleng; yyextra->col=0; } =[^=~]* | \$[#@]* | \$[#@]*\{ | \$[#@]*\{[[:alpha:]] | \$[#@]*\{[[:alpha:]][[:alnum:]._-]* | \/([^/]|\\\/)* | \"([^"]|\\\")* { /* garbage */ YYERROR_RECOVER yyextra->erow=-1; /* reset scanning error */ yyextra->error="garbage text in command"; yyextra->offset+=yyleng; yyextra->bpos+=yyleng; yyextra->col+=yyleng; *yylval=NULL; return ERR; } [^$()=%\"\/[:digit:]\n]+ { /* garbage */ yyextra->erow=-1; /* reset scanning error */ yyextra->error="garbage text in command"; yyextra->offset+=yyleng; yyextra->bpos+=yyleng; yyextra->col+=yyleng; *yylval=NULL; return ERR; } } %% #define yyg ((struct yyguts_t *)scanner) static apr_status_t regex_cleanup(void *data){ ap_regfree((ap_regex_t *)data); return APR_SUCCESS; } int rxv_spin_yywrap(yyscan_t scanner){ apr_size_t len,left,need,max,nbuck=0,soff; const char *s; rxv_spin_extra_t *extra=rxv_spin_yyget_extra(scanner); apr_bucket *b=extra->scan; extra->blen=0; while(extra->bleninput)){ extra->eof=b; break; } /* end of stream */ if(APR_BUCKET_IS_EOS(b)){ extra->eos=b; break; } /* some filter only magic */ if(extra->f){ /* send metadata buckets down the filter chain */ if(APR_BUCKET_IS_METADATA(b)){ apr_bucket *e=b; b=APR_BUCKET_NEXT(b); APR_BUCKET_REMOVE(e); APR_BRIGADE_INSERT_TAIL(extra->metabb,e); continue; } /* filters should try non-blocking read first */ switch(apr_bucket_read(b,&s,&len,APR_NONBLOCK_READ)){ case APR_EAGAIN: /* send FLUSH bucket down the filter chain */ APR_BRIGADE_INSERT_TAIL(extra->output, apr_bucket_flush_create(extra->output->bucket_alloc)); if(ap_pass_brigade(extra->f->next,extra->output)!=APR_SUCCESS){ extra->error="cannot pass flush bucket to filters"; return 1; } apr_brigade_cleanup(extra->output); /* empty brigade for real data */ break; case APR_SUCCESS: goto read_done; default: extra->error="input read error"; return 1; } } if(apr_bucket_read(b,&s,&len,APR_BLOCK_READ)!=APR_SUCCESS){ extra->error="input read error"; return 1; } read_done: /* skipping until buffer offset is zero */ if(!nbuck && extra->bpos>0){ /* nothing to copy from this bucket */ if(extra->soff+extra->bpos>=len){ extra->bpos-=len-extra->soff; extra->soff=0; extra->scan=b=APR_BUCKET_NEXT(b); continue; } else{ extra->soff+=extra->bpos; extra->bpos=0; } } /* subsequent buckets always have offset zero */ soff=nbuck++?0:extra->soff; left=len-soff; need=RXV_SPIN_SCAN_MAX-extra->blen; max=left>need?need:left; memcpy(extra->buf+extra->blen,s+soff,max); extra->blen+=max; b=APR_BUCKET_NEXT(b); } /* nothing to scan */ if(!extra->blen) return 1; /* terminate flex buffer properly */ memset(extra->buf+extra->blen,0,2); rxv_spin_yy_delete_buffer(YY_CURRENT_BUFFER,scanner); rxv_spin_yy_scan_buffer(extra->buf,extra->blen+2,scanner); return 0; }