1
2 #include <stdlib.h> /* for exit */
3 #include <string.h> /* for strlen */
4 #include <stdio.h> /* for fprintf etc */
5 #include "header.h"
6
7 /* prototypes */
8
9 static void generate(struct generator * g, struct node * p);
10 static void w(struct generator * g, const char * s);
11 static void writef(struct generator * g, const char * s, struct node * p);
12
new_label(struct generator * g)13 static int new_label(struct generator * g) {
14 return g->next_label++;
15 }
16
vars_newname(struct generator * g)17 static struct str * vars_newname(struct generator * g) {
18
19 struct str * output;
20 g->var_number++;
21 output = str_new();
22 str_append_string(output, "v_");
23 str_append_int(output, g->var_number);
24 return output;
25 }
26
27
28 /* Write routines for items from the syntax tree */
29
write_varname(struct generator * g,struct name * p)30 static void write_varname(struct generator * g, struct name * p) {
31
32 switch (p->type) {
33 case t_external:
34 break;
35 default: {
36 int ch = "SbirxG"[p->type];
37 write_char(g, ch);
38 write_char(g, '_');
39 break;
40 }
41 }
42 write_b(g, p->b);
43 }
44
write_varref(struct generator * g,struct name * p)45 static void write_varref(struct generator * g, struct name * p) {
46 write_string(g, "context.");
47 write_varname(g, p);
48 }
49
write_hexdigit(struct generator * g,int n)50 static void write_hexdigit(struct generator * g, int n) {
51
52 write_char(g, n < 10 ? n + '0' : n - 10 + 'A');
53 }
54
write_hex(struct generator * g,int ch)55 static void write_hex(struct generator * g, int ch) {
56
57 write_string(g, "\\u{");
58 {
59 int i;
60 for (i = 12; i >= 0; i -= 4) write_hexdigit(g, ch >> i & 0xf);
61 }
62 write_string(g, "}");
63 }
64
write_literal_string(struct generator * g,symbol * p)65 static void write_literal_string(struct generator * g, symbol * p) {
66
67 int i = 0;
68 write_string(g, "\"");
69 while (i < SIZE(p)) {
70 int ch;
71 i += get_utf8(p + i, &ch);
72 if (32 <= ch && ch < 127) {
73 if (ch == '\"' || ch == '\\') write_string(g, "\\");
74 write_char(g, ch);
75 } else {
76 write_hex(g, ch);
77 }
78 }
79 write_string(g, "\"");
80 }
81
write_margin(struct generator * g)82 static void write_margin(struct generator * g) {
83
84 int i;
85 for (i = 0; i < g->margin; i++) write_string(g, " ");
86 }
87
write_comment(struct generator * g,struct node * p)88 static void write_comment(struct generator * g, struct node * p) {
89 if (!g->options->comments) return;
90 write_margin(g);
91 write_string(g, "// ");
92 write_comment_content(g, p);
93 write_newline(g);
94 }
95
write_block_start(struct generator * g)96 static void write_block_start(struct generator * g) {
97
98 w(g, "~+{~N");
99 }
100
write_block_end(struct generator * g)101 static void write_block_end(struct generator * g) /* block end */ {
102
103 w(g, "~-~M}~N");
104 }
105
write_savecursor(struct generator * g,struct node * p,struct str * savevar)106 static void write_savecursor(struct generator * g, struct node * p,
107 struct str * savevar) {
108
109 g->B[0] = str_data(savevar);
110 g->S[1] = "";
111 if (p->mode != m_forward) g->S[1] = "env.limit - ";
112 writef(g, "~Mlet ~B0 = ~S1env.cursor;~N", p);
113 }
114
restore_string(struct node * p,struct str * out,struct str * savevar)115 static void restore_string(struct node * p, struct str * out, struct str * savevar) {
116
117 str_clear(out);
118 str_append_string(out, "env.cursor = ");
119 if (p->mode != m_forward) str_append_string(out, "env.limit - ");
120 str_append(out, savevar);
121 str_append_string(out, ";");
122 }
123
write_restorecursor(struct generator * g,struct node * p,struct str * savevar)124 static void write_restorecursor(struct generator * g, struct node * p,
125 struct str * savevar) {
126
127 struct str * temp = str_new();
128 write_margin(g);
129 restore_string(p, temp, savevar);
130 write_str(g, temp);
131 write_newline(g);
132 str_delete(temp);
133 }
134
write_inc_cursor(struct generator * g,struct node * p)135 static void write_inc_cursor(struct generator * g, struct node * p) {
136
137 write_margin(g);
138 write_string(g, p->mode == m_forward ? "env.next_char();" : "env.previous_char();");
139 write_newline(g);
140 }
141
wsetlab_begin(struct generator * g,int n)142 static void wsetlab_begin(struct generator * g, int n) {
143
144 g->I[0] = n;
145 w(g, "~M'lab~I0: loop {~N~+");
146 }
147
wsetlab_end(struct generator * g,int n)148 static void wsetlab_end(struct generator * g, int n) {
149 if (!g->unreachable) {
150 g->I[0] = n;
151 w(g, "~Mbreak 'lab~I0;~N");
152 }
153 w(g, "~-~M}~N");
154 }
155
wgotol(struct generator * g,int n)156 static void wgotol(struct generator * g, int n) {
157 g->I[0] = n;
158 w(g, "~Mbreak 'lab~I0;~N");
159 }
160
write_failure(struct generator * g)161 static void write_failure(struct generator * g) {
162
163 if (str_len(g->failure_str) != 0) {
164 write_margin(g);
165 write_str(g, g->failure_str);
166 write_newline(g);
167 }
168 switch (g->failure_label) {
169 case x_return:
170 w(g, "~Mreturn false;~N");
171 g->unreachable = true;
172 break;
173 default:
174 g->I[0] = g->failure_label;
175 w(g, "~Mbreak 'lab~I0;~N");
176 g->unreachable = true;
177 }
178 }
179
write_failure_if(struct generator * g,char * s,struct node * p)180 static void write_failure_if(struct generator * g, char * s, struct node * p) {
181
182 writef(g, "~Mif ", p);
183 writef(g, s, p);
184 writef(g, " ", p);
185 write_block_start(g);
186 write_failure(g);
187 write_block_end(g);
188 g->unreachable = false;
189 }
190
191 /* if at limit fail */
write_check_limit(struct generator * g,struct node * p)192 static void write_check_limit(struct generator * g, struct node * p) {
193
194 if (p->mode == m_forward) {
195 write_failure_if(g, "env.cursor >= env.limit", p);
196 } else {
197 write_failure_if(g, "env.cursor <= env.limit_backward", p);
198 }
199 }
200
201 /* Formatted write. */
writef(struct generator * g,const char * input,struct node * p)202 static void writef(struct generator * g, const char * input, struct node * p) {
203 int i = 0;
204 int l = strlen(input);
205
206 while (i < l) {
207 int ch = input[i++];
208 if (ch != '~') {
209 write_char(g, ch);
210 continue;
211 }
212 switch (input[i++]) {
213 default: write_char(g, input[i - 1]); continue;
214 case 'C': write_comment(g, p); continue;
215 case 'f': write_block_start(g);
216 write_failure(g);
217 g->unreachable = false;
218 write_block_end(g);
219 continue;
220 case 'M': write_margin(g); continue;
221 case 'N': write_newline(g); continue;
222 case '{': write_block_start(g); continue;
223 case '}': write_block_end(g); continue;
224 case 'S': write_string(g, g->S[input[i++] - '0']); continue;
225 case 'B': write_b(g, g->B[input[i++] - '0']); continue;
226 case 'I': write_int(g, g->I[input[i++] - '0']); continue;
227 case 'V': write_varref(g, g->V[input[i++] - '0']); continue;
228 case 'W': write_varname(g, g->V[input[i++] - '0']); continue;
229 case 'L': write_literal_string(g, g->L[input[i++] - '0']); continue;
230 case '+': g->margin++; continue;
231 case '-': g->margin--; continue;
232 case 'n': write_string(g, g->options->name); continue;
233 }
234 }
235 }
236
w(struct generator * g,const char * s)237 static void w(struct generator * g, const char * s) {
238 writef(g, s, 0);
239 }
240
generate_AE(struct generator * g,struct node * p)241 static void generate_AE(struct generator * g, struct node * p) {
242 const char * s;
243 switch (p->type) {
244 case c_name:
245 write_varref(g, p->name); break;
246 case c_number:
247 write_int(g, p->number); break;
248 case c_maxint:
249 write_string(g, "i32::MAX"); break;
250 case c_minint:
251 write_string(g, "i32::MIN"); break;
252 case c_neg:
253 write_char(g, '-'); generate_AE(g, p->right); break;
254 case c_multiply:
255 s = " * "; goto label0;
256 case c_plus:
257 s = " + "; goto label0;
258 case c_minus:
259 s = " - "; goto label0;
260 case c_divide:
261 s = " / ";
262 label0:
263 write_char(g, '('); generate_AE(g, p->left);
264 write_string(g, s); generate_AE(g, p->right); write_char(g, ')'); break;
265 case c_cursor:
266 w(g, "env.cursor"); break;
267 case c_limit:
268 w(g, p->mode == m_forward ? "env.limit" : "env.limit_backward"); break;
269 case c_lenof:
270 g->V[0] = p->name;
271 w(g, "(~V0.chars().count() as i32)");
272 break;
273 case c_sizeof:
274 g->V[0] = p->name;
275 w(g, "(~V0.len() as i32)");
276 break;
277 case c_len:
278 w(g, "(env.current.chars().count() as i32)");
279 break;
280 case c_size:
281 w(g, "(env.current.len() as i32)");
282 break;
283 }
284 }
285
generate_bra(struct generator * g,struct node * p)286 static void generate_bra(struct generator * g, struct node * p) {
287
288 write_comment(g, p);
289 p = p->left;
290 while (p) {
291 generate(g, p);
292 p = p->right;
293 }
294 }
295
generate_and(struct generator * g,struct node * p)296 static void generate_and(struct generator * g, struct node * p) {
297
298 struct str * savevar = vars_newname(g);
299 int keep_c = K_needed(g, p->left);
300
301 write_comment(g, p);
302
303 if (keep_c) write_savecursor(g, p, savevar);
304
305 p = p->left;
306 while (p) {
307 generate(g, p);
308 if (g->unreachable) break;
309 if (keep_c && p->right != 0) write_restorecursor(g, p, savevar);
310 p = p->right;
311 }
312 str_delete(savevar);
313 }
314
generate_or(struct generator * g,struct node * p)315 static void generate_or(struct generator * g, struct node * p) {
316
317 struct str * savevar = vars_newname(g);
318 int keep_c = K_needed(g, p->left);
319
320 int a0 = g->failure_label;
321 struct str * a1 = str_copy(g->failure_str);
322
323 int out_lab = new_label(g);
324 int end_unreachable = true;
325
326 write_comment(g, p);
327 wsetlab_begin(g, out_lab);
328
329 if (keep_c) write_savecursor(g, p, savevar);
330
331 p = p->left;
332 str_clear(g->failure_str);
333
334 if (p == 0) {
335 /* p should never be 0 after an or: there should be at least two
336 * sub nodes. */
337 fprintf(stderr, "Error: \"or\" node without children nodes.");
338 exit(1);
339 }
340 while (p->right != 0) {
341 int label = new_label(g);
342 g->failure_label = label;
343 wsetlab_begin(g, label);
344 generate(g, p);
345 if (!g->unreachable) {
346 wgotol(g, out_lab);
347 end_unreachable = false;
348 }
349 w(g, "~-~M}~N");
350 g->unreachable = false;
351 if (keep_c) write_restorecursor(g, p, savevar);
352 p = p->right;
353 }
354
355 g->failure_label = a0;
356 str_delete(g->failure_str);
357 g->failure_str = a1;
358
359 generate(g, p);
360 wsetlab_end(g, out_lab);
361 if (!end_unreachable) {
362 g->unreachable = false;
363 }
364 str_delete(savevar);
365 }
366
generate_backwards(struct generator * g,struct node * p)367 static void generate_backwards(struct generator * g, struct node * p) {
368
369 write_comment(g, p);
370 writef(g,"~Menv.limit_backward = env.cursor;~N"
371 "~Menv.cursor = env.limit;~N", p);
372 generate(g, p->left);
373 w(g, "~Menv.cursor = env.limit_backward;~N");
374 }
375
376
generate_not(struct generator * g,struct node * p)377 static void generate_not(struct generator * g, struct node * p) {
378
379 struct str * savevar = vars_newname(g);
380 int keep_c = K_needed(g, p->left);
381
382 int a0 = g->failure_label;
383 struct str * a1 = str_copy(g->failure_str);
384 int label = new_label(g);
385 g->failure_label = label;
386
387 write_comment(g, p);
388 if (keep_c) {
389 write_savecursor(g, p, savevar);
390 }
391
392 str_clear(g->failure_str);
393
394 wsetlab_begin(g, label);
395
396 generate(g, p->left);
397
398 g->failure_label = a0;
399 str_delete(g->failure_str);
400 g->failure_str = a1;
401
402 if (!g->unreachable) write_failure(g);
403 w(g, "~-~M}~N");
404
405 g->unreachable = false;
406
407 if (keep_c) write_restorecursor(g, p, savevar);
408 str_delete(savevar);
409 }
410
411
generate_try(struct generator * g,struct node * p)412 static void generate_try(struct generator * g, struct node * p) {
413
414 struct str * savevar = vars_newname(g);
415 int keep_c = K_needed(g, p->left);
416 int label = new_label(g);
417 g->failure_label = label;
418 str_clear(g->failure_str);
419
420 write_comment(g, p);
421 if (keep_c) {
422 write_savecursor(g, p, savevar);
423 restore_string(p, g->failure_str, savevar);
424 }
425 wsetlab_begin(g, label);
426 generate(g, p->left);
427 wsetlab_end(g, label);
428 g->unreachable = false;
429
430 str_delete(savevar);
431 }
432
generate_set(struct generator * g,struct node * p)433 static void generate_set(struct generator * g, struct node * p) {
434
435 write_comment(g, p);
436 g->V[0] = p->name;
437 writef(g, "~M~V0 = true;~N", p);
438 }
439
generate_unset(struct generator * g,struct node * p)440 static void generate_unset(struct generator * g, struct node * p) {
441
442 write_comment(g, p);
443 g->V[0] = p->name;
444 writef(g, "~M~V0 = false;~N", p);
445 }
446
generate_fail(struct generator * g,struct node * p)447 static void generate_fail(struct generator * g, struct node * p) {
448
449 write_comment(g, p);
450 generate(g, p->left);
451 if (!g->unreachable) write_failure(g);
452 }
453
454 /* generate_test() also implements 'reverse' */
455
generate_test(struct generator * g,struct node * p)456 static void generate_test(struct generator * g, struct node * p) {
457
458 struct str * savevar = vars_newname(g);
459 int keep_c = K_needed(g, p->left);
460
461 write_comment(g, p);
462
463 if (keep_c) {
464 write_savecursor(g, p, savevar);
465 }
466
467 generate(g, p->left);
468
469 if (!g->unreachable) {
470 if (keep_c) {
471 write_restorecursor(g, p, savevar);
472 }
473 }
474 str_delete(savevar);
475 }
476
generate_do(struct generator * g,struct node * p)477 static void generate_do(struct generator * g, struct node * p) {
478
479 struct str * savevar = vars_newname(g);
480 int keep_c = K_needed(g, p->left);
481 write_comment(g, p);
482 if (keep_c) write_savecursor(g, p, savevar);
483
484 if (p->left->type == c_call) {
485 /* Optimise do <call> */
486 write_comment(g, p->left);
487 g->V[0] = p->left->name;
488 w(g, "~M~W0(env, context);~N");
489 } else {
490 int label = new_label(g);
491 g->failure_label = label;
492 str_clear(g->failure_str);
493
494 wsetlab_begin(g, label);
495 generate(g, p->left);
496 wsetlab_end(g, label);
497 g->unreachable = false;
498 }
499
500 if (keep_c) write_restorecursor(g, p, savevar);
501 str_delete(savevar);
502 }
503
generate_GO(struct generator * g,struct node * p,int style)504 static void generate_GO(struct generator * g, struct node * p, int style) {
505
506 int end_unreachable = false;
507 struct str * savevar = vars_newname(g);
508 int keep_c = style == 1 || repeat_restore(g, p->left);
509
510 int a0 = g->failure_label;
511 struct str * a1 = str_copy(g->failure_str);
512
513 int golab = new_label(g);
514 g->I[0] = golab;
515 write_comment(g, p);
516 w(g, "~M'golab~I0: loop {~N~+");
517 if (keep_c) write_savecursor(g, p, savevar);
518
519 g->failure_label = new_label(g);
520 str_clear(g->failure_str);
521 wsetlab_begin(g, g->failure_label);
522 generate(g, p->left);
523
524 if (g->unreachable) {
525 /* Cannot break out of this loop: therefore the code after the
526 * end of the loop is unreachable.*/
527 end_unreachable = true;
528 } else {
529 /* include for goto; omit for gopast */
530 if (style == 1) write_restorecursor(g, p, savevar);
531 g->I[0] = golab;
532 w(g, "~Mbreak 'golab~I0;~N");
533 }
534 g->unreachable = false;
535 w(g, "~-~M}~N");
536 if (keep_c) write_restorecursor(g, p, savevar);
537
538 g->failure_label = a0;
539 str_delete(g->failure_str);
540 g->failure_str = a1;
541
542 write_check_limit(g, p);
543 write_inc_cursor(g, p);
544 write_block_end(g);
545
546 str_delete(savevar);
547 g->unreachable = end_unreachable;
548 }
549
generate_loop(struct generator * g,struct node * p)550 static void generate_loop(struct generator * g, struct node * p) {
551
552 struct str * loopvar = vars_newname(g);
553 write_comment(g, p);
554 w(g, "~Mfor _ in 0..");
555 generate_AE(g, p->AE);
556 writef(g, " {~+~N", p);
557
558 generate(g, p->left);
559
560 w(g, "~-~M}~N");
561 str_delete(loopvar);
562 g->unreachable = false;
563 }
564
generate_repeat_or_atleast(struct generator * g,struct node * p,struct str * loopvar)565 static void generate_repeat_or_atleast(struct generator * g, struct node * p, struct str * loopvar) {
566
567 struct str * savevar = vars_newname(g);
568 int keep_c = repeat_restore(g, p->left);
569 int replab = new_label(g);
570 g->I[0] = replab;
571 writef(g, "~M'replab~I0: loop{~N~+", p);
572
573 if (keep_c) write_savecursor(g, p, savevar);
574
575 g->failure_label = new_label(g);
576 str_clear(g->failure_str);
577 g->I[0] = g->failure_label;
578 w(g, "~M'lab~I0: for _ in 0..1 {~N~+");
579 generate(g, p->left);
580
581 if (!g->unreachable) {
582 if (loopvar != 0) {
583 g->B[0] = str_data(loopvar);
584 w(g, "~M~B0 -= 1;~N");
585 }
586
587 g->I[0] = replab;
588 w(g, "~Mcontinue 'replab~I0;~N");
589 }
590 w(g, "~-~M}~N");
591 g->unreachable = false;
592
593 if (keep_c) write_restorecursor(g, p, savevar);
594
595 g->I[0] = replab;
596 w(g, "~Mbreak 'replab~I0;~N~-~M}~N");
597 str_delete(savevar);
598 }
599
generate_repeat(struct generator * g,struct node * p)600 static void generate_repeat(struct generator * g, struct node * p) {
601 write_comment(g, p);
602 generate_repeat_or_atleast(g, p, NULL);
603 }
604
generate_atleast(struct generator * g,struct node * p)605 static void generate_atleast(struct generator * g, struct node * p) {
606
607 struct str * loopvar = vars_newname(g);
608 write_comment(g, p);
609 g->B[0] = str_data(loopvar);
610 w(g, "~Mlet mut ~B0 = ");
611 generate_AE(g, p->AE);
612 w(g, ";~N");
613 {
614 int a0 = g->failure_label;
615 struct str * a1 = str_copy(g->failure_str);
616
617 generate_repeat_or_atleast(g, p, loopvar);
618
619 g->failure_label = a0;
620 str_delete(g->failure_str);
621 g->failure_str = a1;
622 }
623 g->B[0] = str_data(loopvar);
624 write_failure_if(g, "~B0 > 0", p);
625 str_delete(loopvar);
626 }
627
generate_setmark(struct generator * g,struct node * p)628 static void generate_setmark(struct generator * g, struct node * p) {
629
630 write_comment(g, p);
631 g->V[0] = p->name;
632 writef(g, "~M~V0 = env.cursor;~N", p);
633 }
634
generate_tomark(struct generator * g,struct node * p)635 static void generate_tomark(struct generator * g, struct node * p) {
636
637 write_comment(g, p);
638 g->S[0] = p->mode == m_forward ? ">" : "<";
639
640 w(g, "~Mif env.cursor ~S0 "); generate_AE(g, p->AE);
641 writef(g, " ", p);
642 write_block_start(g);
643 write_failure(g);
644 write_block_end(g);
645 g->unreachable = false;
646 w(g, "~Menv.cursor = "); generate_AE(g, p->AE); writef(g, ";~N", p);
647 }
648
generate_atmark(struct generator * g,struct node * p)649 static void generate_atmark(struct generator * g, struct node * p) {
650
651 write_comment(g, p);
652 w(g, "~Mif env.cursor != "); generate_AE(g, p->AE);
653 writef(g, " ", p);
654 write_block_start(g);
655 write_failure(g);
656 write_block_end(g);
657 g->unreachable = false;
658 }
659
generate_hop(struct generator * g,struct node * p)660 static void generate_hop(struct generator * g, struct node * p) {
661 write_comment(g, p);
662 // Generate the AE to a temporary block so we can substitute it in
663 // write_failure_if().
664 struct str * ae = str_new();
665 struct str * s = g->outbuf;
666 g->outbuf = ae;
667 generate_AE(g, p->AE);
668 g->outbuf = s;
669 g->B[0] = str_data(ae);
670 g->S[0] = p->mode == m_forward ? "" : "_back";
671 g->S[1] = p->AE->type == c_number ? "" : "_checked";
672 write_failure_if(g, "!env.hop~S0~S1(~B0)", p);
673 str_delete(ae);
674 }
675
generate_delete(struct generator * g,struct node * p)676 static void generate_delete(struct generator * g, struct node * p) {
677
678 write_comment(g, p);
679 writef(g, "~Mif !env.slice_del() {~N"
680 "~+~Mreturn false;~N~-"
681 "~M}~N", p);
682 }
683
684
generate_next(struct generator * g,struct node * p)685 static void generate_next(struct generator * g, struct node * p) {
686
687 write_comment(g, p);
688 write_check_limit(g, p);
689 write_inc_cursor(g, p);
690 }
691
generate_tolimit(struct generator * g,struct node * p)692 static void generate_tolimit(struct generator * g, struct node * p) {
693
694 write_comment(g, p);
695 g->S[0] = p->mode == m_forward ? "env.limit" : "env.limit_backward";
696 writef(g, "~Menv.cursor = ~S0;~N", p);
697 }
698
generate_atlimit(struct generator * g,struct node * p)699 static void generate_atlimit(struct generator * g, struct node * p) {
700
701 write_comment(g, p);
702 g->S[0] = p->mode == m_forward ? "env.limit" : "env.limit_backward";
703 g->S[1] = p->mode == m_forward ? "<" : ">";
704 write_failure_if(g, "env.cursor ~S1 ~S0", p);
705 }
706
generate_leftslice(struct generator * g,struct node * p)707 static void generate_leftslice(struct generator * g, struct node * p) {
708
709 write_comment(g, p);
710 g->S[0] = p->mode == m_forward ? "env.bra" : "env.ket";
711 writef(g, "~M~S0 = env.cursor;~N", p);
712 }
713
generate_rightslice(struct generator * g,struct node * p)714 static void generate_rightslice(struct generator * g, struct node * p) {
715
716 write_comment(g, p);
717 g->S[0] = p->mode == m_forward ? "env.ket" : "env.bra";
718 writef(g, "~M~S0 = env.cursor;~N", p);
719 }
720
generate_assignto(struct generator * g,struct node * p)721 static void generate_assignto(struct generator * g, struct node * p) {
722
723 write_comment(g, p);
724 g->V[0] = p->name;
725 writef(g, "~M~V0 = env.assign_to();~N", p);
726 }
727
generate_sliceto(struct generator * g,struct node * p)728 static void generate_sliceto(struct generator * g, struct node * p) {
729
730 write_comment(g, p);
731 g->V[0] = p->name;
732 writef(g, "~M~V0 = env.slice_to();~N"
733 "~Mif ~V0.is_empty() {~N"
734 "~+~Mreturn false;~N~-~M}~N", p);
735 }
736
generate_address(struct generator * g,struct node * p)737 static void generate_address(struct generator * g, struct node * p) {
738
739 /* If we deal with a string variable which is of type String we need to
740 * pass it by reference not by value. Literalstrings on the other hand are
741 * of type &'static str so we can pass them by value.
742 */
743 symbol * b = p->literalstring;
744 if (b != 0) {
745 write_literal_string(g, b);
746 } else {
747 write_char(g, '&');
748 write_varref(g, p->name);
749 }
750 }
751
generate_insert(struct generator * g,struct node * p,int style)752 static void generate_insert(struct generator * g, struct node * p, int style) {
753
754 int keep_c = style == c_attach;
755 write_comment(g, p);
756 if (p->mode == m_backward) keep_c = !keep_c;
757 if (keep_c) w(g, "~Mlet c = env.cursor;~N");
758 w(g, "~Mlet (bra, ket) = (env.cursor, env.cursor);~N");
759 writef(g, "~Menv.insert(bra, ket, ", p);
760 generate_address(g, p);
761 writef(g, ");~N", p);
762 if (keep_c) w(g, "~Menv.cursor = c;~N");
763 }
764
generate_assignfrom(struct generator * g,struct node * p)765 static void generate_assignfrom(struct generator * g, struct node * p) {
766
767 int keep_c = p->mode == m_forward; /* like 'attach' */
768
769 write_comment(g, p);
770 if (keep_c) writef(g, "~Mlet c = env.cursor;~N", p);
771 /* Copying limits and cursors is necessary here because the rust
772 * borrowchecker does not like taking something from someone you are about
773 * to mutate... */
774 if (p->mode == m_forward) {
775 writef(g, "~Mlet (bra, ket) = (env.cursor, env.limit);~N", p);
776 } else {
777 writef(g, "~Mlet (bra, ket) = (env.limit_backward, env.cursor);~N", p);
778 }
779 writef(g, "~Menv.insert(bra, ket, ", p);
780 generate_address(g, p);
781 writef(g, ");~N", p);
782 if (keep_c) w(g, "~Menv.cursor = c;~N");
783 }
784
785
generate_slicefrom(struct generator * g,struct node * p)786 static void generate_slicefrom(struct generator * g, struct node * p) {
787
788 write_comment(g, p);
789 w(g, "~Mif !env.slice_from(");
790 generate_address(g, p);
791 writef(g, ") {~N"
792 "~+~Mreturn false;~N~-~M}~N", p);
793 }
794
generate_setlimit(struct generator * g,struct node * p)795 static void generate_setlimit(struct generator * g, struct node * p) {
796 struct str * savevar = vars_newname(g);
797 struct str * varname = vars_newname(g);
798 write_comment(g, p);
799 if (p->left && p->left->type == c_tomark) {
800 /* Special case for:
801 *
802 * setlimit tomark AE for C
803 *
804 * All uses of setlimit in the current stemmers we ship follow this
805 * pattern, and by special-casing we can avoid having to save and
806 * restore c.
807 */
808 struct node * q = p->left;
809 g->S[0] = q->mode == m_forward ? ">" : "<";
810 w(g, "~Mif env.cursor ~S0 "); generate_AE(g, q->AE); w(g, " ");
811 write_block_start(g);
812 write_failure(g);
813 write_block_end(g);
814 g->unreachable = false;
815
816 g->B[0] = str_data(varname);
817 if (p->mode == m_forward) {
818 w(g, "~Mlet ~B0 = env.limit - env.cursor;~N");
819 w(g, "~Menv.limit = ");
820 } else {
821 w(g, "~Mlet ~B0 = env.limit_backward;~N");
822 w(g, "~Menv.limit_backward = ");
823 }
824 generate_AE(g, q->AE); writef(g, ";~N", q);
825
826 if (p->mode == m_forward) {
827 str_assign(g->failure_str, "env.limit += ");
828 str_append(g->failure_str, varname);
829 str_append_string(g->failure_str, ";");
830 } else {
831 str_assign(g->failure_str, "env.limit_backward = ");
832 str_append(g->failure_str, varname);
833 str_append_string(g->failure_str, ";");
834 }
835 } else {
836 write_savecursor(g, p, savevar);
837 generate(g, p->left);
838
839 if (!g->unreachable) {
840 g->B[0] = str_data(varname);
841 if (p->mode == m_forward) {
842 w(g, "~Mlet ~B0 = env.limit - env.cursor;~N");
843 w(g, "~Menv.limit = env.cursor;~N");
844 } else {
845 w(g, "~Mlet ~B0 = env.limit_backward;~N");
846 w(g, "~Menv.limit_backward = env.cursor;~N");
847 }
848 write_restorecursor(g, p, savevar);
849
850 if (p->mode == m_forward) {
851 str_assign(g->failure_str, "env.limit += ");
852 str_append(g->failure_str, varname);
853 str_append_string(g->failure_str, ";");
854 } else {
855 str_assign(g->failure_str, "env.limit_backward = ");
856 str_append(g->failure_str, varname);
857 str_append_string(g->failure_str, ";");
858 }
859 }
860 }
861
862 if (!g->unreachable) {
863 generate(g, p->aux);
864
865 if (!g->unreachable) {
866 write_margin(g);
867 write_str(g, g->failure_str);
868 write_newline(g);
869 }
870 }
871 str_delete(varname);
872 str_delete(savevar);
873 }
874
875 /* dollar sets snowball up to operate on a string variable as if it were the
876 * current string */
generate_dollar(struct generator * g,struct node * p)877 static void generate_dollar(struct generator * g, struct node * p) {
878
879 struct str * savevar_env = vars_newname(g);
880 write_comment(g, p);
881 g->V[0] = p->name;
882 g->B[0] = str_data(savevar_env);
883 writef(g, "~Mlet ~B0 = env.clone();~N"
884 "~Menv.set_current_s(~V0.clone());~N"
885 "~Menv.cursor = 0;~N"
886 "~Menv.limit = env.current.len() as i32;~N", p);
887 generate(g, p->left);
888 if (!g->unreachable) {
889 g->V[0] = p->name;
890 g->B[0] = str_data(savevar_env);
891 /* Update string variable. */
892 w(g, "~M~V0 = env.current.clone().into_owned();~N");
893 /* Reset env */
894 w(g, "~M*env = ~B0;~N");
895 }
896 str_delete(savevar_env);
897 }
898
generate_integer_assign(struct generator * g,struct node * p,char * s)899 static void generate_integer_assign(struct generator * g, struct node * p, char * s) {
900
901 g->V[0] = p->name;
902 g->S[0] = s;
903 w(g, "~M~V0 ~S0 "); generate_AE(g, p->AE); w(g, ";~N");
904 }
905
generate_integer_test(struct generator * g,struct node * p,char * s)906 static void generate_integer_test(struct generator * g, struct node * p, char * s) {
907
908 w(g, "~Mif !(");
909 generate_AE(g, p->left);
910 write_char(g, ' ');
911 write_string(g, s);
912 write_char(g, ' ');
913 generate_AE(g, p->AE);
914 w(g, ")");
915 write_block_start(g);
916 write_failure(g);
917 write_block_end(g);
918 g->unreachable = false;
919 }
920
generate_call(struct generator * g,struct node * p)921 static void generate_call(struct generator * g, struct node * p) {
922
923 write_comment(g, p);
924 g->V[0] = p->name;
925 write_failure_if(g, "!~W0(env, context)", p);
926 }
927
generate_grouping(struct generator * g,struct node * p,int complement)928 static void generate_grouping(struct generator * g, struct node * p, int complement) {
929
930 struct grouping * q = p->name->grouping;
931 g->S[0] = p->mode == m_forward ? "" : "_b";
932 g->S[1] = complement ? "out" : "in";
933 g->V[0] = p->name;
934 g->I[0] = q->smallest_ch;
935 g->I[1] = q->largest_ch;
936 write_failure_if(g, "!env.~S1_grouping~S0(~W0, ~I0, ~I1)", p);
937 }
938
generate_namedstring(struct generator * g,struct node * p)939 static void generate_namedstring(struct generator * g, struct node * p) {
940
941 write_comment(g, p);
942 g->S[0] = p->mode == m_forward ? "" : "_b";
943 g->V[0] = p->name;
944 write_failure_if(g, "!env.eq_s~S0(&~V0)", p);
945 }
946
generate_literalstring(struct generator * g,struct node * p)947 static void generate_literalstring(struct generator * g, struct node * p) {
948 symbol * b = p->literalstring;
949 write_comment(g, p);
950 g->S[0] = p->mode == m_forward ? "" : "_b";
951 g->L[0] = b;
952 write_failure_if(g, "!env.eq_s~S0(&~L0)", p);
953 }
954
generate_setup_context(struct generator * g)955 static void generate_setup_context(struct generator * g) {
956
957 struct name * q;
958 w(g, "~Mlet mut context = &mut Context {~+~N");
959 for (q = g->analyser->names; q; q = q->next) {
960 g->V[0] = q;
961 switch (q->type) {
962 case t_string:
963 w(g, "~M~W0: String::new(),~N");
964 break;
965 case t_integer:
966 w(g, "~M~W0: 0,~N");
967 break;
968 case t_boolean:
969 w(g, "~M~W0: false,~N");
970 break;
971 }
972 }
973 w(g, "~-~M};~N");
974 }
975
generate_define(struct generator * g,struct node * p)976 static void generate_define(struct generator * g, struct node * p) {
977 struct name * q = p->name;
978
979 struct str * saved_output = g->outbuf;
980
981 g->V[0] = q;
982
983 if (q->type == t_routine) {
984 w(g, "~N~Mfn ~W0(env: &mut SnowballEnv, context: &mut Context) -> bool {~+~N");
985 } else {
986 w(g, "~N~Mpub fn ~W0(env: &mut SnowballEnv) -> bool {~+~N");
987 generate_setup_context(g);
988 }
989 if (p->amongvar_needed) w(g, "~Mlet mut among_var;~N");
990 g->outbuf = str_new();
991
992 g->next_label = 0;
993 g->var_number = 0;
994
995 str_clear(g->failure_str);
996 g->failure_label = x_return;
997 g->unreachable = false;
998 generate(g, p->left);
999 if (!g->unreachable) w(g, "~Mreturn true;~N");
1000 w(g, "~-~M}~N");
1001
1002 str_append(saved_output, g->outbuf);
1003 str_delete(g->outbuf);
1004 g->outbuf = saved_output;
1005 }
1006
generate_substring(struct generator * g,struct node * p)1007 static void generate_substring(struct generator * g, struct node * p) {
1008
1009 struct among * x = p->among;
1010
1011 write_comment(g, p);
1012
1013 g->S[0] = p->mode == m_forward ? "" : "_b";
1014 g->I[0] = x->number;
1015
1016 if (!x->amongvar_needed) {
1017 write_failure_if(g, "env.find_among~S0(~A_~I0, context) == 0", p);
1018 } else {
1019 writef(g, "~Mamong_var = env.find_among~S0(~A_~I0, context);~N", p);
1020 write_failure_if(g, "among_var == 0", p);
1021 }
1022 }
1023
generate_among(struct generator * g,struct node * p)1024 static void generate_among(struct generator * g, struct node * p) {
1025
1026 struct among * x = p->among;
1027
1028 if (x->substring == 0) generate_substring(g, p);
1029
1030 if (x->starter != 0) generate(g, x->starter);
1031
1032 if (x->command_count == 1 && x->nocommand_count == 0) {
1033 /* Only one outcome ("no match" already handled). */
1034 generate(g, x->commands[0]);
1035 } else if (x->command_count > 0) {
1036 int i;
1037 w(g, "~M");
1038 for (i = 1; i <= x->command_count; i++) {
1039 g->I[0] = i;
1040 if (i > 1) w(g, " else ");
1041 w(g, "if among_var == ~I0 {~N~+");
1042 generate(g, x->commands[i - 1]);
1043 w(g, "~-~M}");
1044 g->unreachable = false;
1045 }
1046 w(g, "~N");
1047 }
1048 }
1049
generate_booltest(struct generator * g,struct node * p)1050 static void generate_booltest(struct generator * g, struct node * p) {
1051
1052 write_comment(g, p);
1053 g->V[0] = p->name;
1054 write_failure_if(g, "!~V0", p);
1055 }
1056
generate_false(struct generator * g,struct node * p)1057 static void generate_false(struct generator * g, struct node * p) {
1058
1059 write_comment(g, p);
1060 write_failure(g);
1061 }
1062
generate_debug(struct generator * g,struct node * p)1063 static void generate_debug(struct generator * g, struct node * p) {
1064
1065 write_comment(g, p);
1066 g->I[0] = g->debug_count++;
1067 g->I[1] = p->line_number;
1068 writef(g, "~Menv.debug(~I0, ~I1);~N", p);
1069 }
1070
generate(struct generator * g,struct node * p)1071 static void generate(struct generator * g, struct node * p) {
1072
1073 int a0;
1074 struct str * a1;
1075
1076 if (g->unreachable) return;
1077
1078 a0 = g->failure_label;
1079 a1 = str_copy(g->failure_str);
1080
1081 switch (p->type) {
1082 case c_define: generate_define(g, p); break;
1083 case c_bra: generate_bra(g, p); break;
1084 case c_and: generate_and(g, p); break;
1085 case c_or: generate_or(g, p); break;
1086 case c_backwards: generate_backwards(g, p); break;
1087 case c_not: generate_not(g, p); break;
1088 case c_set: generate_set(g, p); break;
1089 case c_unset: generate_unset(g, p); break;
1090 case c_try: generate_try(g, p); break;
1091 case c_fail: generate_fail(g, p); break;
1092 case c_reverse:
1093 case c_test: generate_test(g, p); break;
1094 case c_do: generate_do(g, p); break;
1095 case c_goto: generate_GO(g, p, 1); break;
1096 case c_gopast: generate_GO(g, p, 0); break;
1097 case c_repeat: generate_repeat(g, p); break;
1098 case c_loop: generate_loop(g, p); break;
1099 case c_atleast: generate_atleast(g, p); break;
1100 case c_setmark: generate_setmark(g, p); break;
1101 case c_tomark: generate_tomark(g, p); break;
1102 case c_atmark: generate_atmark(g, p); break;
1103 case c_hop: generate_hop(g, p); break;
1104 case c_delete: generate_delete(g, p); break;
1105 case c_next: generate_next(g, p); break;
1106 case c_tolimit: generate_tolimit(g, p); break;
1107 case c_atlimit: generate_atlimit(g, p); break;
1108 case c_leftslice: generate_leftslice(g, p); break;
1109 case c_rightslice: generate_rightslice(g, p); break;
1110 case c_assignto: generate_assignto(g, p); break;
1111 case c_sliceto: generate_sliceto(g, p); break;
1112 case c_assign: generate_assignfrom(g, p); break;
1113 case c_insert:
1114 case c_attach: generate_insert(g, p, p->type); break;
1115 case c_slicefrom: generate_slicefrom(g, p); break;
1116 case c_setlimit: generate_setlimit(g, p); break;
1117 case c_dollar: generate_dollar(g, p); break;
1118 case c_mathassign: generate_integer_assign(g, p, "="); break;
1119 case c_plusassign: generate_integer_assign(g, p, "+="); break;
1120 case c_minusassign: generate_integer_assign(g, p, "-="); break;
1121 case c_multiplyassign:generate_integer_assign(g, p, "*="); break;
1122 case c_divideassign: generate_integer_assign(g, p, "/="); break;
1123 case c_eq: generate_integer_test(g, p, "=="); break;
1124 case c_ne: generate_integer_test(g, p, "!="); break;
1125 case c_gr: generate_integer_test(g, p, ">"); break;
1126 case c_ge: generate_integer_test(g, p, ">="); break;
1127 case c_ls: generate_integer_test(g, p, "<"); break;
1128 case c_le: generate_integer_test(g, p, "<="); break;
1129 case c_call: generate_call(g, p); break;
1130 case c_grouping: generate_grouping(g, p, false); break;
1131 case c_non: generate_grouping(g, p, true); break;
1132 case c_name: generate_namedstring(g, p); break;
1133 case c_literalstring: generate_literalstring(g, p); break;
1134 case c_among: generate_among(g, p); break;
1135 case c_substring: generate_substring(g, p); break;
1136 case c_booltest: generate_booltest(g, p); break;
1137 case c_false: generate_false(g, p); break;
1138 case c_true: break;
1139 case c_debug: generate_debug(g, p); break;
1140 default: fprintf(stderr, "%d encountered\n", p->type);
1141 exit(1);
1142 }
1143
1144 g->failure_label = a0;
1145 str_delete(g->failure_str);
1146 g->failure_str = a1;
1147 }
1148
1149 /* rustc emits warnings if variables don't match the style guide */
1150 /* (i.e. upper-case for globals, snake case for fields etc.) */
1151 /* To allow warning free compilation of generated code and */
1152 /* consistency with snowball variable namings we allow some kind of warnings here */
generate_allow_warnings(struct generator * g)1153 static void generate_allow_warnings(struct generator * g) {
1154
1155 w(g, "#![allow(non_upper_case_globals)]~N");
1156 w(g, "#![allow(non_snake_case)]~N");
1157 w(g, "#![allow(unused_variables)]~N");
1158 w(g, "#![allow(unused_mut)]~N");
1159 }
1160
generate_class_begin(struct generator * g)1161 static void generate_class_begin(struct generator * g) {
1162
1163 w(g, "use snowball::SnowballEnv;~N");
1164 if (g->analyser->among_count > 0) {
1165 w(g, "use snowball::Among;~N~N");
1166 }
1167 }
1168
generate_among_table(struct generator * g,struct among * x)1169 static void generate_among_table(struct generator * g, struct among * x) {
1170
1171 struct amongvec * v = x->b;
1172
1173 g->I[0] = x->number;
1174 g->I[1] = x->literalstring_count;
1175
1176 w(g, "~Mstatic A_~I0: &'static [Among<Context>; ~I1] = &[~N~+");
1177 {
1178 int i;
1179 for (i = 0; i < x->literalstring_count; i++) {
1180 g->I[0] = v->i;
1181 g->I[1] = v->result;
1182 g->L[0] = v->b;
1183 g->S[0] = ",";
1184
1185 w(g, "~MAmong(~L0, ~I0, ~I1, ");
1186 if (v->function != 0) {
1187 w(g, "Some(&");
1188 write_varname(g, v->function);
1189 w(g, ")");
1190 } else {
1191 w(g, "None");
1192 }
1193 w(g, ")~S0~N");
1194 v++;
1195 }
1196 }
1197 w(g, "~-~M];~N~N");
1198 }
1199
generate_amongs(struct generator * g)1200 static void generate_amongs(struct generator * g) {
1201 struct among * x;
1202 for (x = g->analyser->amongs; x; x = x->next) {
1203 generate_among_table(g, x);
1204 }
1205 }
1206
set_bit(symbol * b,int i)1207 static void set_bit(symbol * b, int i) { b[i/8] |= 1 << i%8; }
1208
generate_grouping_table(struct generator * g,struct grouping * q)1209 static void generate_grouping_table(struct generator * g, struct grouping * q) {
1210
1211 int range = q->largest_ch - q->smallest_ch + 1;
1212 int size = (range + 7)/ 8; /* assume 8 bits per symbol */
1213 symbol * b = q->b;
1214 symbol * map = create_b(size);
1215 int i;
1216 for (i = 0; i < size; i++) map[i] = 0;
1217
1218 for (i = 0; i < SIZE(b); i++) set_bit(map, b[i] - q->smallest_ch);
1219
1220 g->V[0] = q->name;
1221 g->I[0] = size;
1222 w(g, "~Mstatic ~W0: &'static [u8; ~I0] = &[");
1223 for (i = 0; i < size; i++) {
1224 write_int(g, map[i]);
1225 if (i < size - 1) w(g, ", ");
1226 }
1227 w(g, "];~N~N");
1228 lose_b(map);
1229 }
1230
generate_groupings(struct generator * g)1231 static void generate_groupings(struct generator * g) {
1232 struct grouping * q;
1233 for (q = g->analyser->groupings; q; q = q->next) {
1234 if (q->name->used)
1235 generate_grouping_table(g, q);
1236 }
1237 }
1238
1239
generate_members(struct generator * g)1240 static void generate_members(struct generator * g) {
1241
1242 struct name * q;
1243 w(g, "#[derive(Clone)]~N");
1244 w(g, "struct Context {~+~N");
1245 for (q = g->analyser->names; q; q = q->next) {
1246 g->V[0] = q;
1247 switch (q->type) {
1248 case t_string:
1249 w(g, "~M~W0: String,~N");
1250 break;
1251 case t_integer:
1252 w(g, "~M~W0: i32,~N");
1253 break;
1254 case t_boolean:
1255 w(g, "~M~W0: bool,~N");
1256 break;
1257 }
1258 }
1259 w(g, "~-}~N");
1260 }
1261
generate_methods(struct generator * g)1262 static void generate_methods(struct generator * g) {
1263
1264 struct node * p = g->analyser->program;
1265 while (p != 0) {
1266 generate(g, p);
1267 g->unreachable = false;
1268 p = p->right;
1269 }
1270 }
1271
generate_program_rust(struct generator * g)1272 extern void generate_program_rust(struct generator * g) {
1273
1274 g->outbuf = str_new();
1275 g->failure_str = str_new();
1276
1277 write_start_comment(g, "//! ", NULL);
1278 generate_allow_warnings(g);
1279 if (g->analyser->int_limits_used) {
1280 /* std::i32 is used in the code generated for i32::MAX and i32::MIN */
1281 w(g, "use std::i32;~N~N");
1282 }
1283 generate_class_begin(g);
1284
1285 generate_amongs(g);
1286 generate_groupings(g);
1287
1288 generate_members(g);
1289 generate_methods(g);
1290
1291 output_str(g->options->output_src, g->outbuf);
1292 str_delete(g->failure_str);
1293 str_delete(g->outbuf);
1294 }
1295