~snowball-yiddish-dev/snowball-yiddish/trunk

« back to all changes in this revision

Viewing changes to snowball/compiler/generator_java.c

  • Committer: richard
  • Date: 2003-03-30 12:08:09 UTC
  • Revision ID: svn-v4:633ccae0-01f4-0310-8c99-d3591da6f01f:trunk:216
This module will contain only the code and build system, and documentation
for building and running the stemming library.
All sample data will be in a separate module, and the website will be in
its own module too.

Show diffs side-by-side

added added

removed removed

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