Implemented conditional blocks. The grammar is complete
Showing
1 changed file
with
176 additions
and
38 deletions
... | @@ -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 | } | ... | ... |
-
Please register or sign in to post a comment