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