b3a56ed596ab1737443013ffb37a49caf4a48445
[tedtools.git] / tmpl_gram.y
1 %{
2 #include <errno.h>
3 #include <string.h>
4 #include <tlog.h>
5 #include <tmalloc.h>
6 #include <template.h>
7 #include <tmpl_gram.h>
8
9 extern char *fileToParse;
10 char *fileToParse;
11
12 int yylex(void);
13 int yyparse(void);
14 static int yyerror(char *s);
15 void startTemplateLex(Template tmpl, FILE *in);
16
17 static Template curTmpl;        
18 extern int tmpl_yylineno;
19 static TemplateNode     newExpressionNode(char *op, GList *args);  
20 static GList *makeList2(void *a, void *b);
21
22
23 %}
24
25 %union {
26         char                                            *str;
27         char                                            punct;
28         int                                                     flags;
29         int                                                     intval;
30         double                                          floatval;
31         TemplateNode                            node;
32         GList                                           *list;
33 }
34
35 %type <node>                    node
36 %type <node>                    listnodes
37 %type <node>                    template
38 %type <node>                    expression
39 %type <list>                    list_expression
40 %type <str>                             varname
41
42 %type <flags>                   opt_escape
43 %type <str>                             opt_format
44 %type <str>                             opt_default
45
46 %token  <str>                   STRING
47 %token  <str>                   FILENAME
48 %token  <str>                   TEXT_P
49 %token  <str>                   LEXEME
50 %token  <str>                   VAR_OPEN VAR_CLOSE EXPR_OPEN EXPR_CLOSE 
51                                                 INCLUDE_OPEN INCLUDE_CLOSE
52 %token  <str>                   HTMLESCAPE URLESCAPE IF_P ELSE_P LOOP_P ENDIF_P ENDLOOP_P SELF_P 
53 %token  <str>                   CMP_P
54
55 %token <intval>                 INTEGER
56 %token <floatval>               DOUBLE
57
58
59 %left '+' '-' 
60 %left '*' '/' '%'
61 %left '?' ':'
62 %left NEG
63
64 %left OR_P 
65 %left AND_P
66 %left NOT_P
67
68 %left CMP_P
69
70 %%
71
72 template:
73         listnodes       { curTmpl->tree = $$ = $1; }
74         |                       { curTmpl->tree = $$ = NULL; }
75         ;
76
77 listnodes:
78         node    { $$ = $1; }
79         | listnodes node {
80                         if ( $1->type == CollectionNode ) {
81                                 GListPush( $1->nodeData.children, $2 );
82                                 $$ = $1;
83                         } else {
84                                 $$ = mc0alloc( curTmpl->templateContext, sizeof(TemplateNodeData) );
85                                 $$->type = CollectionNode;
86                                 $$->nodeData.children = GListPush( $$->nodeData.children, $1 );
87                                 $$->nodeData.children = GListPush( $$->nodeData.children, $2 );
88                         }
89                 }
90         ;
91
92 varname:
93         LEXEME  
94         | HTMLESCAPE
95         | URLESCAPE
96         | IF_P
97         | ELSE_P
98         | LOOP_P
99         | SELF_P
100         | ENDIF_P
101         | ENDLOOP_P
102         ;
103
104 opt_escape:
105         '|'     HTMLESCAPE              { $$=TND_HTMLESCAPE; }
106         | '|'   URLESCAPE       { $$=TND_URLESCAPE; }
107         |                               { $$=0; }
108         ;
109
110 opt_format:
111         ','     STRING          { $$=$2; }
112         |                       { $$=NULL; }
113         ;
114
115 opt_default:
116         '#'     STRING          { $$=$2; }
117         |                       { $$=NULL; }
118         ;
119
120 list_expression:
121         expression ',' expression                       { 
122                         $$ = makeList2($1, $3); 
123                 }
124         | list_expression ',' expression        {
125                         $$ = GListPush($$, $3);
126         }
127         ;
128
129 expression:
130         varname { 
131                         $$ = mc0alloc( curTmpl->templateContext, sizeof(TemplateNodeData) );
132                         $$->type = VariableNode;
133                         $$->nodeData.variable.varName = $1; 
134                         $$->nodeData.variable.varNameLength = strlen($1);
135                 }
136         | '^' varname   { 
137                         $$ = mc0alloc( curTmpl->templateContext, sizeof(TemplateNodeData) );
138                         $$->type = VariableNode;
139                         $$->nodeData.variable.flags = TND_GLOBAL; 
140                         $$->nodeData.variable.varName = $2; 
141                         $$->nodeData.variable.varNameLength = strlen($2);
142                 }
143         | STRING        { 
144                         $$ = mc0alloc( curTmpl->templateContext, sizeof(TemplateNodeData) );
145                         $$->type = ConstNode;
146                         $$->nodeData.value.type = valueString;
147                         $$->nodeData.value.flags = TND_DEFINED;
148                         $$->nodeData.value.value.stringValue = $1;
149                 }
150         | INTEGER       { 
151                         $$ = mc0alloc( curTmpl->templateContext, sizeof(TemplateNodeData) );
152                         $$->type = ConstNode;
153                         $$->nodeData.value.type = valueInt;
154                         $$->nodeData.value.flags = TND_DEFINED;
155                         $$->nodeData.value.value.intValue = $1;
156                 }
157         | DOUBLE        {
158                         $$ = mc0alloc( curTmpl->templateContext, sizeof(TemplateNodeData) );
159                         $$->type = ConstNode;
160                         $$->nodeData.value.type = valueDouble;
161                         $$->nodeData.value.flags = TND_DEFINED;
162                         $$->nodeData.value.value.doubleValue = $1;
163                 }
164         | expression '+' expression     { 
165                         $$ = newExpressionNode( "+", makeList2( $1, $3 ) ); 
166                 }
167         | expression '-' expression     { 
168                         $$ = newExpressionNode( "-", makeList2( $1, $3 ) ); 
169                 }
170         | expression '*' expression     { 
171                         $$ = newExpressionNode( "*", makeList2( $1, $3 ) ); 
172                 }
173         | expression '/' expression     { 
174                         $$ = newExpressionNode( "/", makeList2( $1, $3 ) ); 
175                 }
176         | expression '%' expression     { 
177                         $$ = newExpressionNode( "%", makeList2( $1, $3 ) ); 
178                 }
179         | '-' expression %prec NEG              { 
180                         $$ = newExpressionNode( "-", GListPush( NULL, $2 ) ); 
181                 }
182         | expression AND_P expression   { 
183                         $$ = newExpressionNode( "&&", makeList2( $1, $3 ) ); 
184                 }
185         | expression OR_P expression    { 
186                         $$ = newExpressionNode( "||", makeList2( $1, $3 ) ); 
187                 }
188         | expression '?' expression ':' expression      { 
189                         $$ = newExpressionNode( "?", GListPush( makeList2( $1, $3 ), $5 ) ); 
190                 }
191         | NOT_P expression                              { 
192                         $$ = newExpressionNode( "!", GListPush( NULL, $2 ) ); 
193                 }
194         | expression CMP_P expression   {
195                         $$ = newExpressionNode( $2, makeList2( $1, $3 ) ); 
196                 }
197         | varname '(' ')'                               { 
198                         $$ = newExpressionNode( $1, NULL ); 
199                 }
200         | varname '(' expression ')'    { 
201                         $$ = newExpressionNode( $1, GListPush( NULL, $3 ) ); 
202                 }
203         | varname '(' list_expression ')'       { 
204                         $$ = newExpressionNode( $1, $3 ); 
205                 }
206         | '(' expression ')'                    { $$=$2; }
207         ;
208
209 node:   
210         TEXT_P  {
211                                 $$ = mc0alloc( curTmpl->templateContext, sizeof(TemplateNodeData) );
212                                 $$->type = TextNode;
213                                 $$->nodeData.text.value = $1;
214                                 $$->nodeData.text.valueLength = strlen($1);
215                         }
216         | VAR_OPEN expression opt_format opt_default opt_escape VAR_CLOSE {
217                                 $$ = mc0alloc( curTmpl->templateContext, sizeof(TemplateNodeData) );
218                                 $$->type = PrintNode;
219                                 $$->nodeData.print.expressionNode = $2;
220                                 $$->nodeData.print.formatValue = $3;
221                                 $$->nodeData.print.defaultValue = $4;
222                                 $$->nodeData.print.flags = $5;
223                         }
224         | INCLUDE_OPEN FILENAME INCLUDE_CLOSE   {
225                                 $$ = mc0alloc( curTmpl->templateContext, sizeof(TemplateNodeData) );
226                                 $$->type = IncludeNode;
227                                 $$->nodeData.includeFile = $2;
228                         }
229         | EXPR_OPEN     SELF_P EXPR_CLOSE {
230                                 $$ = mc0alloc( curTmpl->templateContext, sizeof(TemplateNodeData) );
231                                 $$->type = NestNode;
232                         }
233         | EXPR_OPEN     LOOP_P varname EXPR_CLOSE listnodes EXPR_OPEN ENDLOOP_P EXPR_CLOSE {
234                                 $$ = mc0alloc( curTmpl->templateContext, sizeof(TemplateNodeData) );
235                                 $$->type = LoopNode;
236                                 $$->nodeData.loop.varName = $3; 
237                                 $$->nodeData.loop.varNameLength = strlen($3);
238                                 $$->nodeData.loop.bodyNode = $5;
239                 }
240         | EXPR_OPEN IF_P expression EXPR_CLOSE listnodes EXPR_OPEN ENDIF_P EXPR_CLOSE {
241                                 $$ = mc0alloc( curTmpl->templateContext, sizeof(TemplateNodeData) );
242                                 $$->type = ConditionNode;
243                                 $$->nodeData.condition.expressionNode = $3;
244                                 $$->nodeData.condition.ifNode = $5;
245                 }
246         | EXPR_OPEN IF_P expression EXPR_CLOSE listnodes EXPR_OPEN ELSE_P EXPR_CLOSE listnodes EXPR_OPEN ENDIF_P EXPR_CLOSE {
247                                 $$ = mc0alloc( curTmpl->templateContext, sizeof(TemplateNodeData) );
248                                 $$->type = ConditionNode;
249                                 $$->nodeData.condition.expressionNode = $3;
250                                 $$->nodeData.condition.ifNode = $5;
251                                 $$->nodeData.condition.elseNode = $9;
252                 }
253         ;
254
255 %%
256
257 static int
258 yyerror(char *s) {
259         tlog(TL_CRIT,"template error at line %d in '%s': %s", tmpl_yylineno, fileToParse, s);
260         return 1;
261 }
262
263 int
264 parseTemplateFile(Template tmpl, char* filename ) {
265         FILE *in  = fopen(filename, "r");
266         int     err;
267
268         if ( in == NULL ) {
269                 tlog(TL_CRIT,"Can not open template file '%s': %s",
270                                                 filename, strerror(errno));
271                 return 3;
272         }
273
274         curTmpl = tmpl;
275         curTmpl->tree = NULL;
276
277         fileToParse = filename;
278         startTemplateLex(tmpl, in);
279         err = yyparse();
280
281         fclose(in);
282
283         return err;
284 }
285
286 static TemplateNode     
287 newExpressionNode(char *op, GList *args) {
288         TemplateNode    res;
289
290         res =  mc0alloc( curTmpl->templateContext, sizeof(TemplateNodeData) );
291         res->type = ExpressionNode;
292         res->nodeData.expression.functionName = op;
293         res->nodeData.expression.argsNode = args;
294
295         return res;
296 }
297
298 static GList *
299 makeList2(void *a, void *b) {
300         return GListPush( GListPush(NULL, a), b );
301 }