%{ #include #include #include #include #include #include "g2m.h" #define STRSIZE 32384 int yyerror(char* s) { fprintf (stderr, "%s", s); } extern char yytext[]; char *stradd(char **dst, char *fmt, ...); char *straddp(char **dst, char *fmt, ...); char *newstr(char *fmt, ...); char *delciapki(char* str){ if(str[0]=='"'){ char *a; a = strdup(&str[1]); a[strlen(a)-1]='\0'; return(a); } return(strdup(str)); } /**************/ typedef struct{ char *key; char *val; } ATTR; typedef struct{ ATTR attributes[32]; int pos; char *str_beg; char *str_end; int ignore; } ATTA; ATTA stack[32]; int stack_pos = 0; void attribute_start(char *name){ char *key = name; ATTA *atta = &stack[stack_pos]; atta->attributes[atta->pos].key = strdup(key); atta->attributes[atta->pos].val = strdup(""); atta->pos++; if(strcmp(key,"py:for")==0){ atta->ignore=1; } if(strcmp(key,"py:if")==0){ atta->ignore=2; } if(strcmp(key,"py:with")==0){ atta->ignore=3; } } int attribute_add(char *key, char *val){ char *vals; vals = delciapki(val); /**/ ATTA *atta = &stack[stack_pos]; atta->attributes[atta->pos].key = strdup(key); atta->attributes[atta->pos].val = vals; atta->pos++; /**/ char ind[STRSIZE]; memset(ind, ' ', stack_pos*4); ind[stack_pos*4]='\0'; /**/ if(strcmp(key,"py:for")==0 || (atta->ignore==1 && strcmp(key,"each")==0)) { stradd(&atta->str_beg, "\n%s%% for %s\n", ind, vals); straddp(&atta->str_end, "\n%s%% endfor\n", ind); return(0); } if(strcmp(key,"py:if")==0 || (atta->ignore==2 && strcmp(key,"test")==0)){ stradd(&atta->str_beg, "\n%s%% if %s\n", ind, vals); straddp(&atta->str_end, "\n%s%% endif\n", ind); return(0); } if(strcmp(key,"py:with")==0 || (atta->ignore==3 && strcmp(key,"vars")==0)){ stradd(&atta->str_beg, "\n%s%% %s\n", ind, vals); straddp(&atta->str_end, "\n%s%% #endwith\n", ind); return(0); } return(1); } void attribute_push(){ stack_pos++; } int attribute_getlast_ignore(){ return(stack[stack_pos-1].ignore); } int attribute_pop(char **pre, char **post){ stack_pos--; *pre = stack[stack_pos].str_beg; *post = stack[stack_pos].str_end; if(!*pre) *pre=strdup(""); if(!*post) *post=strdup(""); int ignore = stack[stack_pos].ignore; memset(&stack[stack_pos],0, sizeof(ATTA)); return(ignore); } char *straddp(char **dst, char *fmt, ...){ char b[STRSIZE]; va_list ap; va_start(ap, fmt); vsnprintf(b, sizeof(b)-1, fmt, ap); va_end(ap); char buf[STRSIZE]; if(*dst == NULL) *dst = strdup(""); strncpy(buf, *dst, sizeof(buf)-1); strcat(b,buf); free(*dst); *dst = strdup(b); return(*dst); } char *stradd(char **dst, char *fmt, ...){ char b[STRSIZE]; va_list ap; va_start(ap, fmt); vsnprintf(b, sizeof(b)-1, fmt, ap); va_end(ap); char buf[STRSIZE]; if(*dst == NULL) *dst = strdup(""); strncpy(buf, *dst, sizeof(buf)-1); strcat(buf, b); free(*dst); *dst = strdup(buf); return(*dst); } char *newstr(char *fmt, ...){ char buf[STRSIZE]; va_list ap; va_start(ap, fmt); vsnprintf(buf, sizeof(buf)-1, fmt, ap); va_end(ap); return(strdup(buf)); } %} %union {char *s;} %token VERSION ATTDEF ENDDEF EQ SLASH CLOSE END %token ENCODING NAME VALUE DATA COMMENT START STARTHDR WS %type ws attribute_seq_opt attribute empty_or_content content comment element top_ele_seq top_header top_data %% document : top_ele_seq {printf("%s",$1); free($1);} ; top_ele_seq : top_ele_seq comment {$$ = newstr("%s%s",$1,$2); free($1); free($2);} | top_ele_seq top_header {$$ = newstr("%s%s",$1,$2); free($1); free($2);} | top_ele_seq element {$$ = newstr("%s%s",$1,$2); free($1); free($2);} | top_ele_seq top_data {$$ = newstr("%s%s",$1,$2); free($1); free($2);} | /*empty*/ {$$ = strdup("");} ; top_data : DATA {$$ = $1;} ; top_header : STARTHDR ws { } attribute_seq_opt slash_opt CLOSE { $$ = newstr("",$1,$2,$4); free($1);free($2);free($4); } ; slash_opt : SLASH | /*empty*/ comment : COMMENT {$$ = $1;} ; element : START ws{ attribute_start($1); } attribute_seq_opt{ attribute_push(); } empty_or_content{ char *pre; char *post; int ignore = attribute_pop(&pre, &post); if(!ignore) $$ = newstr("%s<%s%s%s%s%s", pre, $1, $2, $4, $6, post); else{ $$ = newstr("%s%% # <%s%s%s%s%s", pre, $1, $2, $4, $6, post); } free($1);free($2);free($4);free($6); free(pre); free(post); } ; empty_or_content : SLASH CLOSE {$$ = strdup("/>");} | CLOSE content END NAME CLOSE { if(!attribute_getlast_ignore()) $$ = newstr(">%s", $2, $4); else $$ = newstr(">%s%% # ", $2, $4); free($2); free($4); } ; content : content DATA {$$ = newstr("%s%s",$1,$2); free($1); free($2);} | content comment {$$ = newstr("%s%s",$1,$2); free($1); free($2);} | content element {$$ = newstr("%s%s",$1,$2); free($1); free($2);} | /*empty*/ {$$ = strdup("");} ; attribute_seq_opt : attribute_seq_opt attribute {$$ = newstr("%s%s", $1, $2); free($1);free($2);} | /*empty*/ {$$ = strdup("");} ; attribute : NAME ws EQ ws NAME ws{ if(attribute_add($1,$5)){ $$ = newstr("%s%s=%s%s%s",$1,$2,$4,$5,$6); }else $$ = strdup(""); free($1); free($2);free($4);free($5);free($6); } | NAME ws{ if(attribute_add($1,"")){ $$ = newstr("%s%s", $1, $2); }else $$ = strdup(""); free($1); free($2) } ; ws : WS {$$ = $1;} | /*empty*/ {$$ = strdup("");} ; %% int main(void) { memset(stack, 0, sizeof(stack)); return yyparse(); }