Commit bbc96354 bbc963549d99c9f133e053dea82e5e86ec1cb2ef by Sergey Poznyakoff

Implemented conditional blocks. The grammar is complete

1 parent 2588fc83
...@@ -25,7 +25,10 @@ ...@@ -25,7 +25,10 @@
25 #include <sieve.h> 25 #include <sieve.h>
26 26
27 sieve_machine_t *sieve_machine; 27 sieve_machine_t *sieve_machine;
28 int sieve_error_count; 28 int sieve_error_count;
29
30 static void branch_fixup __P((size_t start, size_t end));
31
29 %} 32 %}
30 33
31 %union { 34 %union {
...@@ -39,6 +42,11 @@ int sieve_error_count; ...@@ -39,6 +42,11 @@ int sieve_error_count;
39 char *ident; 42 char *ident;
40 list_t args; 43 list_t args;
41 } command; 44 } command;
45 struct {
46 size_t begin;
47 size_t cond;
48 size_t branch;
49 } branch;
42 } 50 }
43 51
44 %token <string> IDENT TAG 52 %token <string> IDENT TAG
...@@ -47,10 +55,11 @@ int sieve_error_count; ...@@ -47,10 +55,11 @@ int sieve_error_count;
47 %token REQUIRE IF ELSIF ELSE ANYOF ALLOF NOT 55 %token REQUIRE IF ELSIF ELSE ANYOF ALLOF NOT
48 56
49 %type <value> arg 57 %type <value> arg
50 %type <list> slist stringlist arglist maybe_arglist 58 %type <list> slist stringlist stringorlist arglist maybe_arglist
51 %type <command> command 59 %type <command> command
52 %type <number> testlist 60 %type <number> testlist
53 %type <pc> action test statement list 61 %type <pc> action test statement list elsif else cond begin if block
62 %type <branch> elsif_branch maybe_elsif else_part
54 63
55 %% 64 %%
56 65
...@@ -63,43 +72,108 @@ list : statement ...@@ -63,43 +72,108 @@ list : statement
63 | list statement 72 | list statement
64 ; 73 ;
65 74
66 statement : REQUIRE stringlist ';' 75 statement : REQUIRE stringorlist ';'
67 { 76 {
68 sieve_require ($2); 77 sieve_require ($2);
69 sieve_slist_destroy (&$2); 78 sieve_slist_destroy (&$2);
70 $$ = sieve_machine->pc; 79 $$ = sieve_machine->pc;
71 } 80 }
72 | action ';' 81 | action ';'
73 | IF cond block maybe_elsif maybe_else 82 /* 1 2 3 4 */
83 | if cond block else_part
84 {
85 sieve_machine->prog[$2].pc = $4.begin - $2 - 1;
86 if ($4.branch)
87 branch_fixup ($4.branch, sieve_machine->pc);
88 }
89 ;
90
91 if : IF
74 { 92 {
75 /* FIXME!! */
76 $$ = sieve_machine->pc; 93 $$ = sieve_machine->pc;
77 } 94 }
78 ; 95 ;
79 96
97 else_part : maybe_elsif
98 {
99 if ($1.begin)
100 sieve_machine->prog[$1.cond].pc =
101 sieve_machine->pc - $1.cond - 1;
102 else
103 {
104 $$.begin = sieve_machine->pc;
105 $$.branch = 0;
106 }
107 }
108 | maybe_elsif else block
109 {
110 if ($1.begin)
111 {
112 sieve_machine->prog[$1.cond].pc = $3 - $1.cond - 1;
113 sieve_machine->prog[$2].pc = $1.branch;
114 $$.begin = $1.begin;
115 $$.branch = $2;
116 }
117 else
118 {
119 $$.begin = $3;
120 $$.branch = $2;
121 }
122 }
123 ;
124
80 maybe_elsif : /* empty */ 125 maybe_elsif : /* empty */
81 | elsif 126 {
127 $$.begin = 0;
128 }
129 | elsif_branch
130 ;
131
132 elsif_branch : elsif begin cond block
133 {
134 $$.begin = $2;
135 $$.branch = $1;
136 $$.cond = $3;
137 }
138 | elsif_branch elsif begin cond block
139 {
140 sieve_machine->prog[$1.cond].pc = $3 - $1.cond - 1;
141 sieve_machine->prog[$2].pc = $1.branch;
142 $$.begin = $1.begin;
143 $$.branch = $2;
144 $$.cond = $4;
145 }
82 ; 146 ;
83 147
84 elsif : ELSIF cond block 148 elsif : ELSIF
85 | elsif ELSIF cond block 149 {
150 sieve_code_instr (instr_branch);
151 $$ = sieve_machine->pc;
152 sieve_code_number (0);
153 }
86 ; 154 ;
87 155
88 maybe_else : /* empty */ 156 else : ELSE
89 | ELSE block 157 {
158 sieve_code_instr (instr_branch);
159 $$ = sieve_machine->pc;
160 sieve_code_number (0);
161 }
90 ; 162 ;
91 163
92 block : '{' list '}' 164 block : '{' list '}'
165 {
166 $$ = $2;
167 }
93 ; 168 ;
94 169
95 170 testlist : cond_expr
96 testlist : cond
97 { 171 {
98 if (sieve_code_instr (instr_push)) 172 if (sieve_code_instr (instr_push))
99 YYERROR; 173 YYERROR;
100 $$ = 1; 174 $$ = 1;
101 } 175 }
102 | testlist ',' cond 176 | testlist ',' cond_expr
103 { 177 {
104 if (sieve_code_instr (instr_push)) 178 if (sieve_code_instr (instr_push))
105 YYERROR; 179 YYERROR;
...@@ -107,7 +181,15 @@ testlist : cond ...@@ -107,7 +181,15 @@ testlist : cond
107 } 181 }
108 ; 182 ;
109 183
110 cond : test 184 cond : cond_expr
185 {
186 sieve_code_instr (instr_brz);
187 $$ = sieve_machine->pc;
188 sieve_code_number (0);
189 }
190 ;
191
192 cond_expr : test
111 { /* to placate bison */ } 193 { /* to placate bison */ }
112 | ANYOF '(' testlist ')' 194 | ANYOF '(' testlist ')'
113 { 195 {
...@@ -121,27 +203,33 @@ cond : test ...@@ -121,27 +203,33 @@ cond : test
121 || sieve_code_number ($3)) 203 || sieve_code_number ($3))
122 YYERROR; 204 YYERROR;
123 } 205 }
124 | NOT cond 206 | NOT cond_expr
125 { 207 {
126 if (sieve_code_instr (instr_not)) 208 if (sieve_code_instr (instr_not))
127 YYERROR; 209 YYERROR;
128 } 210 }
129 ; 211 ;
130 212
213 begin : /* empty */
214 {
215 $$ = sieve_machine->pc;
216 }
217 ;
218
131 test : command 219 test : command
132 { 220 {
133 sieve_register_t *reg = sieve_test_lookup ($1.ident); 221 sieve_register_t *reg = sieve_test_lookup ($1.ident);
134 $$ = sieve_machine->pc; 222 $$ = sieve_machine->pc;
135 223
136 if (!reg) 224 if (!reg)
137 sieve_error ("%s:%d: unknown test: %s", 225 sieve_compile_error (sieve_filename, sieve_line_num,
138 sieve_filename, sieve_line_num, 226 "unknown test: %s",
139 $1.ident); 227 $1.ident);
140 else if (!reg->required) 228 else if (!reg->required)
141 sieve_error ("%s:%d: test `%s' has not been required", 229 sieve_compile_error (sieve_filename, sieve_line_num,
142 sieve_filename, sieve_line_num, 230 "test `%s' has not been required",
143 $1.ident); 231 $1.ident);
144 if (sieve_code_test (reg, $1.args)) 232 else if (sieve_code_test (reg, $1.args))
145 YYERROR; 233 YYERROR;
146 } 234 }
147 ; 235 ;
...@@ -159,14 +247,15 @@ action : command ...@@ -159,14 +247,15 @@ action : command
159 247
160 $$ = sieve_machine->pc; 248 $$ = sieve_machine->pc;
161 if (!reg) 249 if (!reg)
162 sieve_error ("%s:%d: unknown action: %s", 250 sieve_compile_error (sieve_filename, sieve_line_num,
163 sieve_filename, sieve_line_num, 251 "unknown action: %s",
164 $1.ident); 252 $1.ident);
165 else if (!reg->required) 253 else if (!reg->required)
166 sieve_error ("%s:%d: action `%s' has not been required", 254 sieve_compile_error (sieve_filename, sieve_line_num,
255 "action `%s' has not been required",
167 sieve_filename, sieve_line_num, 256 sieve_filename, sieve_line_num,
168 $1.ident); 257 $1.ident);
169 if (sieve_code_action (reg, $1.args)) 258 else if (sieve_code_action (reg, $1.args))
170 YYERROR; 259 YYERROR;
171 } 260 }
172 ; 261 ;
...@@ -194,6 +283,10 @@ arg : stringlist ...@@ -194,6 +283,10 @@ arg : stringlist
194 { 283 {
195 $$ = sieve_value_create (SVT_STRING_LIST, $1); 284 $$ = sieve_value_create (SVT_STRING_LIST, $1);
196 } 285 }
286 | STRING
287 {
288 $$ = sieve_value_create (SVT_STRING, $1);
289 }
197 | MULTILINE 290 | MULTILINE
198 { 291 {
199 $$ = sieve_value_create (SVT_STRING, $1); 292 $$ = sieve_value_create (SVT_STRING, $1);
...@@ -207,13 +300,16 @@ arg : stringlist ...@@ -207,13 +300,16 @@ arg : stringlist
207 $$ = sieve_value_create (SVT_TAG, $1); 300 $$ = sieve_value_create (SVT_TAG, $1);
208 } 301 }
209 ; 302 ;
210 303
211 stringlist : STRING 304 stringorlist : STRING
212 { 305 {
213 list_create (&$$); 306 list_create (&$$);
214 list_append ($$, $1); 307 list_append ($$, $1);
215 } 308 }
216 | '[' slist ']' 309 | stringlist
310 ;
311
312 stringlist : '[' slist ']'
217 { 313 {
218 $$ = $2; 314 $$ = $2;
219 } 315 }
...@@ -236,20 +332,47 @@ slist : STRING ...@@ -236,20 +332,47 @@ slist : STRING
236 int 332 int
237 yyerror (char *s) 333 yyerror (char *s)
238 { 334 {
239 sieve_error ("%s:%d: %s", sieve_filename, sieve_line_num, s); 335 sieve_compile_error (sieve_filename, sieve_line_num, "%s", s);
240 return 0; 336 return 0;
241 } 337 }
242 338
243 /* FIXME: When posix thread support is added, sieve_machine_begin() should
244 aquire the global mutex, locking the current compilation session, and
245 sieve_machine_finish() should release it */
246 void 339 void
247 sieve_machine_begin (sieve_machine_t *mach, sieve_printf_t err, void *data) 340 sieve_machine_init (sieve_machine_t *mach, void *data)
248 { 341 {
249 memset (mach, 0, sizeof (*mach)); 342 memset (mach, 0, sizeof (*mach));
250
251 mach->error_printer = err ? err : _sieve_default_error_printer;
252 mach->data = data; 343 mach->data = data;
344 mach->error_printer = _sieve_default_error_printer;
345 mach->parse_error_printer = _sieve_default_parse_error;
346 }
347
348 void
349 sieve_machine_set_error (sieve_machine_t *mach, sieve_printf_t error_printer)
350 {
351 mach->error_printer = error_printer ?
352 error_printer : _sieve_default_error_printer;
353 }
354
355 void
356 sieve_machine_set_parse_error (sieve_machine_t *mach, sieve_parse_error_t p)
357 {
358 mach->parse_error_printer = p ? p : _sieve_default_parse_error;
359 }
360
361 void
362 sieve_machine_set_debug (sieve_machine_t *mach,
363 sieve_printf_t debug, int level)
364 {
365 if (debug)
366 mach->debug_printer = debug;
367 mach->debug_level = level;
368 }
369
370 /* FIXME: When posix thread support is added, sieve_machine_begin() should
371 acquire the global mutex, locking the current compilation session, and
372 sieve_machine_finish() should release it */
373 void
374 sieve_machine_begin (sieve_machine_t *mach)
375 {
253 sieve_machine = mach; 376 sieve_machine = mach;
254 sieve_error_count = 0; 377 sieve_error_count = 0;
255 sieve_code_instr (NULL); 378 sieve_code_instr (NULL);
...@@ -262,12 +385,11 @@ sieve_machine_finish (sieve_machine_t *mach) ...@@ -262,12 +385,11 @@ sieve_machine_finish (sieve_machine_t *mach)
262 } 385 }
263 386
264 int 387 int
265 sieve_compile (sieve_machine_t *mach, const char *name, 388 sieve_compile (sieve_machine_t *mach, const char *name)
266 void *extra_data, sieve_printf_t err)
267 { 389 {
268 int rc; 390 int rc;
269 391
270 sieve_machine_begin (mach, err, extra_data); 392 sieve_machine_begin (mach);
271 sieve_register_standard_actions (); 393 sieve_register_standard_actions ();
272 sieve_register_standard_tests (); 394 sieve_register_standard_tests ();
273 sieve_lex_begin (name); 395 sieve_lex_begin (name);
...@@ -279,3 +401,19 @@ sieve_compile (sieve_machine_t *mach, const char *name, ...@@ -279,3 +401,19 @@ sieve_compile (sieve_machine_t *mach, const char *name,
279 return rc; 401 return rc;
280 } 402 }
281 403
404 static void
405 _branch_fixup (size_t start, size_t end)
406 {
407 size_t prev = sieve_machine->prog[start].pc;
408 if (!prev)
409 return;
410 branch_fixup (prev, end);
411 sieve_machine->prog[prev].pc = end - prev - 1;
412 }
413
414 void
415 branch_fixup (size_t start, size_t end)
416 {
417 _branch_fixup (start, end);
418 sieve_machine->prog[start].pc = end - start - 1;
419 }
......