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