%{ #include #include #include #include #include #include extern char *fileToParse; char *fileToParse; int yylex(void); int yyparse(void); static int yyerror(char *s); void startTemplateLex(Template tmpl, FILE *in); static Template curTmpl; extern int tmpl_yylineno; %} %union { char *str; char punct; int varname; int flags; TemplateNode node; } %type node %type listnodes %type template %type condition %type condition_varname %type varname %type opt_escape %type opt_global %type opt_default %type opt_format %token OR_P %token STRING %token FILENAME %token TEXT_P %token LEXEME %token VAR_OPEN VAR_CLOSE EXPR_OPEN EXPR_CLOSE INCLUDE_OPEN INCLUDE_CLOSE %token HTMLESCAPE URLESCAPE IF_P ELSE_P LOOP_P ENDIF_P ENDLOOP_P NOT_P DEFINED_P %% template: listnodes { curTmpl->tree = $$ = $1; } | { curTmpl->tree = $$ = NULL; } ; listnodes: node { $$ = $1; } | listnodes node { if ( $1->type == CollectionNode ) { GListPush( $1->nodeData.children, $2 ); $$ = $1; } else { $$ = mc0alloc( curTmpl->templateContext, sizeof(TemplateNodeData) ); $$->type = CollectionNode; $$->nodeData.children = GListPush( $$->nodeData.children, $1 ); $$->nodeData.children = GListPush( $$->nodeData.children, $2 ); } } ; varname: LEXEME | HTMLESCAPE | URLESCAPE | IF_P | ELSE_P | LOOP_P | ENDIF_P | ENDLOOP_P | NOT_P | DEFINED_P ; opt_escape: '|' HTMLESCAPE { $$=TND_HTMLESCAPE; } | '|' URLESCAPE { $$=TND_URLESCAPE; } | { $$=0; } ; opt_global: '^' { $$=TND_GLOBAL; } | { $$=0; } ; opt_format: ',' STRING { $$=$2; } | { $$=NULL; } ; opt_default: OR_P STRING { $$=$2; } | { $$=NULL; } ; condition_varname: varname { $$ = mc0alloc( curTmpl->templateContext, sizeof(TemplateNodeData) ); $$->type = ConditionNode; $$->nodeData.condition.varName = $1; $$->nodeData.condition.varNameLength = strlen($1); } | '^' varname { $$ = mc0alloc( curTmpl->templateContext, sizeof(TemplateNodeData) ); $$->type = ConditionNode; $$->nodeData.condition.flags = TND_GLOBAL; $$->nodeData.condition.varName = $2; $$->nodeData.condition.varNameLength = strlen($2); } ; condition: condition_varname { $$ = $1; } | DEFINED_P condition_varname { $$ = $2; $$->nodeData.condition.flags |= TND_DEFINED; } | NOT_P condition { $$ = $2; if ( $$->nodeData.condition.flags & TND_NOT ) $$->nodeData.condition.flags &= ~TND_NOT; else $$->nodeData.condition.flags |= TND_NOT; } ; node: TEXT_P { $$ = mc0alloc( curTmpl->templateContext, sizeof(TemplateNodeData) ); $$->type = TextNode; $$->nodeData.text.value = $1; $$->nodeData.text.valueLength = strlen($1); } | VAR_OPEN opt_global varname opt_format opt_default opt_escape VAR_CLOSE { $$ = mc0alloc( curTmpl->templateContext, sizeof(TemplateNodeData) ); $$->type = VariableNode; $$->nodeData.variable.varName = $3; $$->nodeData.variable.varNameLength = strlen($3); $$->nodeData.variable.formatValue = $4; $$->nodeData.variable.defaultValue = $5; $$->nodeData.variable.flags = $2 | $6; } | INCLUDE_OPEN FILENAME INCLUDE_CLOSE { $$ = mc0alloc( curTmpl->templateContext, sizeof(TemplateNodeData) ); $$->type = IncludeNode; $$->nodeData.includeFile = $2; } | EXPR_OPEN LOOP_P varname EXPR_CLOSE listnodes EXPR_OPEN ENDLOOP_P EXPR_CLOSE { $$ = mc0alloc( curTmpl->templateContext, sizeof(TemplateNodeData) ); $$->type = LoopNode; $$->nodeData.loop.varName = $3; $$->nodeData.loop.varNameLength = strlen($3); $$->nodeData.loop.bodyNode = $5; } | EXPR_OPEN IF_P condition EXPR_CLOSE listnodes EXPR_OPEN ENDIF_P EXPR_CLOSE { $$ = $3; $$->nodeData.condition.ifNode = $5; } | EXPR_OPEN IF_P condition EXPR_CLOSE listnodes EXPR_OPEN ELSE_P EXPR_CLOSE listnodes EXPR_OPEN ENDIF_P EXPR_CLOSE { $$ = $3; $$->nodeData.condition.ifNode = $5; $$->nodeData.condition.elseNode = $9; } ; %% static int yyerror(char *s) { tlog(TL_CRIT,"template error at line %d in '%s': %s", tmpl_yylineno, fileToParse, s); return 1; } int parseTemplateFile(Template tmpl, char* filename ) { FILE *in = fopen(filename, "r"); int err; if ( in == NULL ) { tlog(TL_CRIT,"Can not open template file '%s': %s", filename, strerror(errno)); return 3; } curTmpl = tmpl; curTmpl->tree = NULL; fileToParse = filename; startTemplateLex(tmpl, in); err = yyparse(); fclose(in); return err; }