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

« back to all changes in this revision

Viewing changes to snowball/compiler/generator.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 <stdio.h>   /* for fprintf etc */
 
3
#include <stdlib.h>  /* free etc */
 
4
#include "header.h"
 
5
 
 
6
/* recursive use: */
 
7
 
 
8
static void generate(struct generator * g, struct node * p);
 
9
 
 
10
enum special_labels {
 
11
 
 
12
    x_return = -1
 
13
 
 
14
};
 
15
 
 
16
static int new_label(struct generator * g)
 
17
{   return g->next_label++;
 
18
}
 
19
 
 
20
/* Output routines */
 
21
static void output_str(FILE * outfile, struct str * str)
 
22
{
 
23
    char * s = b_to_s(str_data(str));
 
24
    fprintf(outfile, "%s", s);
 
25
    free(s);
 
26
}
 
27
 
 
28
static void wch(struct generator * g, int ch)
 
29
{   str_append_ch(g->outbuf, ch); /* character */
 
30
}
 
31
 
 
32
static void wnl(struct generator * g)
 
33
{   str_append_ch(g->outbuf, '\n'); /* newline */
 
34
    g->line_count++;
 
35
}
 
36
 
 
37
static void ws(struct generator * g, char * s)
 
38
{   str_append_string(g->outbuf, s); /* string */
 
39
}
 
40
 
 
41
static void wi(struct generator * g, int i)
 
42
{   str_append_int(g->outbuf, i); /* integer */
 
43
}
 
44
 
 
45
static void wi3(struct generator * g, int i)
 
46
{   if (i < 100) wch(g, ' ');
 
47
    if (i < 10)  wch(g, ' ');
 
48
    wi(g, i); /* integer (width 3) */
 
49
}
 
50
 
 
51
static void wvn(struct generator * g, struct name * p)  /* variable name */
 
52
{
 
53
    int ch = "SBIrxg"[p->type];
 
54
    switch (p->type)
 
55
    {   case t_string:
 
56
        case t_boolean:
 
57
        case t_integer:
 
58
            wch(g, ch); wch(g, '['); wi(g, p->count); wch(g, ']'); return;
 
59
        case t_external:
 
60
            ws(g, g->options->externals_prefix); break;
 
61
        default:
 
62
            wch(g, ch); wch(g, '_');
 
63
    }
 
64
    str_append_b(g->outbuf, p->b);
 
65
}
 
66
 
 
67
static void wv(struct generator * g, struct name * p)  /* reference to variable */
 
68
{   if (p->type < t_routine) ws(g, "z->");
 
69
    wvn(g, p);
 
70
}
 
71
 
 
72
static void wlitarray(struct generator * g, symbol * p)  /* write literal array */
 
73
{
 
74
    ws(g, "{ ");
 
75
    {   int i;
 
76
        for (i = 0; i < SIZE(p); i++)
 
77
        {   int ch = p[i];
 
78
            if (32 <= ch && ch <= 127)
 
79
            {   wch(g, '\'');
 
80
                switch (ch)
 
81
                {   case '\'':
 
82
                    case '\\': wch(g, '\\');
 
83
                    default:   wch(g, ch);
 
84
                }
 
85
                wch(g, '\'');
 
86
            }  else wi(g, ch);
 
87
            if (i < SIZE(p) - 1) ws(g, ", ");
 
88
        }
 
89
    }
 
90
    ws(g, " }");
 
91
}
 
92
 
 
93
static void wlitref(struct generator * g, symbol * p)  /* write ref to literal array */
 
94
{
 
95
    if (SIZE(p) == 0) ws(g, "0"); else
 
96
    {
 
97
        struct str * s = g->outbuf;
 
98
        g->outbuf = g->declarations;
 
99
        ws(g, "static symbol s_"); wi(g, g->literalstring_count); ws(g, "[] = ");
 
100
        wlitarray(g, p);
 
101
        ws(g, ";\n");
 
102
        g->outbuf = s;
 
103
        ws(g, "s_"); wi(g, g->literalstring_count);
 
104
        g->literalstring_count++;
 
105
    }
 
106
}
 
107
 
 
108
 
 
109
static void wm(struct generator * g)       /* margin */
 
110
{   int i;
 
111
    for (i = 0; i < g->margin; i++) ws(g, "    ");
 
112
}
 
113
 
 
114
static void wc(struct generator * g, struct node * p) /* comment */
 
115
{
 
116
    ws(g, " /* ");
 
117
    ws(g, (char *) name_of_token(p->type));
 
118
    unless (p->name == 0)
 
119
    {   ws(g, " ");
 
120
        str_append_b(g->outbuf, p->name->b);
 
121
    }
 
122
    ws(g, ", line "); wi(g, p->line_number); ws(g, " */");
 
123
    wnl(g);
 
124
}
 
125
 
 
126
static void wms(struct generator * g, char * s)
 
127
{   wm(g); ws(g, s);   } /* margin + string */
 
128
 
 
129
static void wbs(struct generator * g) /* block start */
 
130
{   wms(g, "{   ");
 
131
    g->margin++;
 
132
}
 
133
 
 
134
static void wbe(struct generator * g)    /* block end */
 
135
{
 
136
    if (g->line_labelled == g->line_count) { wms(g, ";"); wnl(g); }
 
137
    g->margin--;
 
138
    wms(g, "}"); wnl(g);
 
139
}
 
140
 
 
141
static void wk(struct generator * g, struct node * p)     /* keep c */
 
142
{   ws(g, p->mode == m_forward ? "int c = z->c;" :
 
143
                                 "int m = z->l - z->c;");
 
144
}
 
145
 
 
146
static char * restore_string(struct generator * g, struct node * p)
 
147
{   return p->mode == m_forward ? "z->c = c;" :
 
148
                                  "z->c = z->l - m;";
 
149
}
 
150
 
 
151
static void wr(struct generator * g, struct node * p)     /* restore c */
 
152
{   ws(g, restore_string(g, p));
 
153
}
 
154
 
 
155
static void winc(struct generator * g, struct node * p)     /* increment c */
 
156
{   ws(g, p->mode == m_forward ? "z->c++;" :
 
157
                                 "z->c--;");
 
158
}
 
159
 
 
160
static void wsetl(struct generator * g, int n)
 
161
{   g->margin--;
 
162
    wms(g, "lab"); wi(g, n); wch(g, ':'); wnl(g);
 
163
    g->line_labelled = g->line_count;
 
164
    g->margin++;
 
165
}
 
166
 
 
167
static void wgotol(struct generator * g, int n)
 
168
{   wms(g, "goto lab"); wi(g, n); wch(g, ';'); wnl(g);
 
169
}
 
170
 
 
171
static void wf(struct generator * g)          /* fail */
 
172
{   if (g->failure_string != 0) { ws(g, "{ "); ws(g, g->failure_string); wch(g, ' '); }
 
173
    switch (g->failure_label)
 
174
    {
 
175
        case x_return:
 
176
           ws(g, "return 0;"); break;
 
177
        default:
 
178
           ws(g, "goto lab"); wi(g, g->failure_label); wch(g, ';');
 
179
    }
 
180
    if (g->failure_string != 0) ws(g, " }");
 
181
}
 
182
 
 
183
static void wlim(struct generator * g, struct node * p)     /* if at limit fail */
 
184
{
 
185
    ws(g, p->mode == m_forward ? "if (z->c >= z->l) " :
 
186
                                 "if (z->c <= z->lb) ");
 
187
    wf(g);
 
188
}
 
189
 
 
190
static void wp(struct generator * g, char * s, struct node * p) /* formatted write */
 
191
{   int i = 0;
 
192
    int l = strlen(s);
 
193
    until (i >= l)
 
194
    {   int ch = s[i++];
 
195
        if (ch != '~') wch(g, ch); else
 
196
        switch(s[i++])
 
197
        {   default:  wch(g, s[i - 1]); continue;
 
198
            case 'C': wc(g, p); continue;
 
199
            case 'k': wk(g, p); continue;
 
200
            case 'K': /* keep for c_test */
 
201
                ws(g, p->mode == m_forward ? "int c_test = z->c;" :
 
202
                                             "int m_test = z->l - z->c;");
 
203
                continue;
 
204
            case 'r': wr(g, p); continue;
 
205
            case 'R': /* restore for c_test */
 
206
                ws(g, p->mode == m_forward ? "z->c = c_test;" :
 
207
                                             "z->c = z->l - m_test;");
 
208
                continue;
 
209
            case 'i': winc(g, p); continue;
 
210
            case 'l': wlim(g, p); continue;
 
211
            case 'f': wf(g); continue;
 
212
            case 'M': wm(g); continue;
 
213
            case 'N': wnl(g); continue;
 
214
            case '{': wbs(g); continue;
 
215
            case '}': wbe(g); continue;
 
216
            case 'S': ws(g, g->S[s[i++] - '0']); continue;
 
217
            case 'I': wi(g, g->I[s[i++] - '0']); continue;
 
218
            case 'J': wi3(g, g->I[s[i++] - '0']); continue;
 
219
            case 'V': wv(g, g->V[s[i++] - '0']); continue;
 
220
            case 'W': wvn(g, g->V[s[i++] - '0']); continue;
 
221
            case 'L': wlitref(g, g->L[s[i++] - '0']); continue;
 
222
            case 'A': wlitarray(g, g->L[s[i++] - '0']); continue;
 
223
            case '+': g->margin++; continue;
 
224
            case '-': g->margin--; continue;
 
225
            case '$': /* insert_s, insert_v etc */
 
226
                wch(g, p->literalstring == 0 ? 'v' : 's');
 
227
                continue;
 
228
            case 'p': ws(g, g->options->externals_prefix); continue;
 
229
        }
 
230
    }
 
231
}
 
232
 
 
233
static void w(struct generator * g, char * s) { wp(g, s, 0); }
 
234
 
 
235
static void generate_AE(struct generator * g, struct node * p)
 
236
{   char * s;
 
237
    switch (p->type)
 
238
    {   case c_name:
 
239
            wv(g, p->name); break;
 
240
        case c_number:
 
241
            wi(g, p->number); break;
 
242
        case c_maxint:
 
243
            ws(g, "MAXINT"); break;
 
244
        case c_minint:
 
245
            ws(g, "MININT"); break;
 
246
        case c_neg:
 
247
            wch(g, '-'); generate_AE(g, p->right); break;
 
248
        case c_multiply:
 
249
            s = " * "; goto label0;
 
250
        case c_plus:
 
251
            s = " + "; goto label0;
 
252
        case c_minus:
 
253
            s = " - "; goto label0;
 
254
        case c_divide:
 
255
            s = " / ";
 
256
        label0:
 
257
            wch(g, '('); generate_AE(g, p->left);
 
258
            ws(g, s); generate_AE(g, p->right); wch(g, ')'); break;
 
259
        case c_sizeof:
 
260
            g->V[0] = p->name;
 
261
            w(g, "SIZE(~V0)"); break;
 
262
        case c_cursor:
 
263
            w(g, "z->c"); break;
 
264
        case c_limit:
 
265
            w(g, p->mode == m_forward ? "z->l" : "z->lb"); break;
 
266
        case c_size:
 
267
            w(g, "SIZE(z->p)"); break;
 
268
    }
 
269
}
 
270
 
 
271
/* K_needed() tests to see if we really need to keep c. Not true when the
 
272
   the command does not touch the cursor. This and repeat_score() could be
 
273
   elaborated almost indefinitely.
 
274
*/
 
275
 
 
276
static int K_needed(struct generator * g, struct node * p)
 
277
{   until (p == 0)
 
278
    {   switch (p->type)
 
279
        {   case c_dollar:
 
280
            case c_leftslice:
 
281
            case c_rightslice:
 
282
            case c_mathassign:
 
283
            case c_plusassign:
 
284
            case c_minusassign:
 
285
            case c_multiplyassign:
 
286
            case c_divideassign:
 
287
            case c_eq:
 
288
            case c_ne:
 
289
            case c_gr:
 
290
            case c_ge:
 
291
            case c_ls:
 
292
            case c_le:
 
293
            case c_sliceto:
 
294
            case c_true:
 
295
            case c_false:
 
296
            case c_debug:
 
297
                break;
 
298
 
 
299
            case c_call:
 
300
                if (K_needed(g, p->name->definition)) return true;
 
301
                break;
 
302
 
 
303
            case c_bra:
 
304
                if (K_needed(g, p->left)) return true;
 
305
                break;
 
306
 
 
307
            default: return true;
 
308
        }
 
309
        p = p->right;
 
310
    }
 
311
    return false;
 
312
}
 
313
 
 
314
static int repeat_score(struct generator * g, struct node * p)
 
315
{   int score = 0;
 
316
    until (p == 0)
 
317
    {
 
318
        switch (p->type)
 
319
        {   case c_dollar:
 
320
            case c_leftslice:
 
321
            case c_rightslice:
 
322
            case c_mathassign:
 
323
            case c_plusassign:
 
324
            case c_minusassign:
 
325
            case c_multiplyassign:
 
326
            case c_divideassign:
 
327
            case c_eq:
 
328
            case c_ne:
 
329
            case c_gr:
 
330
            case c_ge:
 
331
            case c_ls:
 
332
            case c_le:
 
333
            case c_sliceto:   /* case c_not: must not be included here! */
 
334
            case c_debug:
 
335
                break;
 
336
 
 
337
            case c_call:
 
338
                score += repeat_score(g, p->name->definition);
 
339
                break;
 
340
 
 
341
            case c_bra:
 
342
                score += repeat_score(g, p->left);
 
343
                break;
 
344
 
 
345
            case c_name:
 
346
            case c_literalstring:
 
347
            case c_next:
 
348
            case c_grouping:
 
349
            case c_non:
 
350
            case c_hop:
 
351
                score = score + 1; break;
 
352
 
 
353
            default: score = 2; break;
 
354
        }
 
355
        p = p->right;
 
356
    }
 
357
    return score;
 
358
}
 
359
 
 
360
/* tests if an expression requires cursor reinstatement in a repeat */
 
361
 
 
362
static int repeat_restore(struct generator * g, struct node * p)
 
363
{   return repeat_score(g, p) >= 2;
 
364
}
 
365
 
 
366
static void generate_bra(struct generator * g, struct node * p)
 
367
{   p = p->left;
 
368
    until (p == 0) { generate(g, p); p = p->right; }
 
369
}
 
370
 
 
371
static void generate_and(struct generator * g, struct node * p)
 
372
{   int keep_c = K_needed(g, p->left);
 
373
    if (keep_c) wp(g, "~{~k~C", p);
 
374
           else wp(g, "~M~C", p);
 
375
    p = p->left;
 
376
    until (p == 0)
 
377
    {   generate(g, p);
 
378
        if (keep_c && p->right != 0) wp(g, "~M~r~N", p);
 
379
        p = p->right;
 
380
    }
 
381
    if (keep_c) w(g, "~}");
 
382
}
 
383
 
 
384
static void generate_or(struct generator * g, struct node * p)
 
385
{   int keep_c = K_needed(g, p->left);
 
386
 
 
387
    int a0 = g->failure_label;
 
388
    char * a1 = g->failure_string;
 
389
 
 
390
    int out_lab = new_label(g);
 
391
 
 
392
    if (keep_c) wp(g, "~{~k~C", p);
 
393
           else wp(g, "~M~C", p);
 
394
    p = p->left;
 
395
    g->failure_string = 0;
 
396
    until (p == 0)
 
397
    {   if (p->right != 0)
 
398
        {
 
399
            g->failure_label = new_label(g);
 
400
            generate(g, p);
 
401
            wgotol(g, out_lab);
 
402
            wsetl(g, g->failure_label);
 
403
            if (keep_c) wp(g, "~M~r~N", p);
 
404
        } else
 
405
        {
 
406
            g->failure_label = a0;
 
407
            g->failure_string = a1;
 
408
 
 
409
            generate(g, p);
 
410
            if (keep_c) w(g, "~}");
 
411
            wsetl(g, out_lab);
 
412
        }
 
413
        p = p->right;
 
414
    }
 
415
}
 
416
 
 
417
static void generate_backwards(struct generator * g, struct node * p)
 
418
{
 
419
    wp(g,"~Mz->lb = z->c; z->c = z->l;~C~N", p);
 
420
    generate(g, p->left);
 
421
    w(g, "~Mz->c = z->lb;~N");
 
422
}
 
423
 
 
424
 
 
425
static void generate_not(struct generator * g, struct node * p)
 
426
{   int keep_c = K_needed(g, p->left);
 
427
 
 
428
    int a0 = g->failure_label;
 
429
    char * a1 = g->failure_string;
 
430
 
 
431
    if (keep_c) wp(g, "~{~k~C", p);
 
432
           else wp(g, "~M~C", p);
 
433
 
 
434
    g->failure_label = new_label(g);
 
435
    g->failure_string = 0;
 
436
    generate(g, p->left);
 
437
 
 
438
    {   int l = g->failure_label;
 
439
 
 
440
        g->failure_label = a0;
 
441
        g->failure_string = a1;
 
442
 
 
443
        w(g, "~M~f~N");
 
444
        wsetl(g, l);
 
445
    }
 
446
    if (keep_c) wp(g, "~M~r~N"
 
447
                   "~}", p);
 
448
}
 
449
 
 
450
 
 
451
static void generate_try(struct generator * g, struct node * p)
 
452
{   int keep_c = K_needed(g, p->left);
 
453
 
 
454
    if (keep_c) wp(g, "~{~k~C", p);
 
455
           else wp(g, "~M~C", p);
 
456
 
 
457
    g->failure_label = new_label(g);
 
458
    g->failure_string = keep_c ? restore_string(g, p) : 0;
 
459
    generate(g, p->left);
 
460
 
 
461
    wsetl(g, g->failure_label);
 
462
 
 
463
    if (keep_c) w(g, "~}");
 
464
}
 
465
 
 
466
static void generate_set(struct generator * g, struct node * p)
 
467
{   g->V[0] = p->name; wp(g, "~M~V0 = 1;~C", p);
 
468
}
 
469
 
 
470
static void generate_unset(struct generator * g, struct node * p)
 
471
{   g->V[0] = p->name; wp(g, "~M~V0 = 0;~C", p);
 
472
}
 
473
 
 
474
static void generate_fail(struct generator * g, struct node * p)
 
475
{   generate(g, p->left);
 
476
    wp(g, "~M~f~C", p);
 
477
}
 
478
 
 
479
/* generate_test() also implements 'reverse' */
 
480
 
 
481
static void generate_test(struct generator * g, struct node * p)
 
482
{   int keep_c = K_needed(g, p->left);
 
483
    if (keep_c) wp(g, "~{~K~C", p);
 
484
           else wp(g, "~M~C", p);
 
485
 
 
486
    generate(g, p->left);
 
487
 
 
488
    if (keep_c) wp(g, "~M~R~N"
 
489
                   "~}", p);
 
490
}
 
491
 
 
492
static void generate_do(struct generator * g, struct node * p)
 
493
{   int keep_c = K_needed(g, p->left);
 
494
    if (keep_c) wp(g, "~{~k~C", p);
 
495
           else wp(g, "~M~C", p);
 
496
 
 
497
    g->failure_label = new_label(g);
 
498
    g->failure_string = 0;
 
499
    generate(g, p->left);
 
500
 
 
501
    wsetl(g, g->failure_label);
 
502
    if (keep_c) wp(g, "~M~r~N"
 
503
                   "~}", p);
 
504
}
 
505
 
 
506
static void generate_GO(struct generator * g, struct node * p, int style)
 
507
{   int keep_c = style == 1 || repeat_restore(g, p->left);
 
508
 
 
509
    int a0 = g->failure_label;
 
510
    char * a1 = g->failure_string;
 
511
 
 
512
    w(g, "~Mwhile(1) {"); wp(g, "~C~+", p);
 
513
 
 
514
    if (keep_c) wp(g, "~M~k~N", p);
 
515
 
 
516
    g->failure_label = new_label(g);
 
517
    generate(g, p->left);
 
518
 
 
519
    if (style == 1) wp(g, "~M~r~N", p);  /* include for goto; omit for gopast */
 
520
    w(g, "~Mbreak;~N");
 
521
    wsetl(g, g->failure_label);
 
522
    if (keep_c) wp(g, "~M~r~N", p);
 
523
 
 
524
    g->failure_label = a0;
 
525
    g->failure_string = a1;
 
526
 
 
527
    wp(g, "~M~l~N"
 
528
          "~M~i~N"
 
529
       "~}", p);
 
530
}
 
531
 
 
532
static void generate_loop(struct generator * g, struct node * p)
 
533
{   w(g, "~{int i; for (i = "); generate_AE(g, p->AE); wp(g, "; i > 0; i--)~C"
 
534
            "~{", p);
 
535
 
 
536
    generate(g, p->left);
 
537
 
 
538
    w(g,    "~}"
 
539
         "~}");
 
540
}
 
541
 
 
542
static void generate_repeat(struct generator * g, struct node * p, int atleast_case)
 
543
{   int keep_c = repeat_restore(g, p->left);
 
544
    wp(g, "~Mwhile(1) {~C~+", p);
 
545
 
 
546
    if (keep_c) wp(g, "~M~k~N", p);
 
547
 
 
548
    g->failure_label = new_label(g);
 
549
    g->failure_string = 0;
 
550
    generate(g, p->left);
 
551
 
 
552
    if (atleast_case) w(g, "~Mi--;~N");
 
553
 
 
554
    w(g, "~Mcontinue;~N");
 
555
    wsetl(g, g->failure_label);
 
556
 
 
557
    if (keep_c) wp(g, "~M~r~N", p);
 
558
 
 
559
    w(g, "~Mbreak;~N"
 
560
      "~}");
 
561
}
 
562
 
 
563
static void generate_atleast(struct generator * g, struct node * p)
 
564
{   w(g, "~{int i = "); generate_AE(g, p->AE); w(g, ";~N");
 
565
    {
 
566
        int a0 = g->failure_label;
 
567
        char * a1 = g->failure_string;
 
568
 
 
569
        generate_repeat(g, p, true);
 
570
 
 
571
        g->failure_label = a0;
 
572
        g->failure_string = a1;
 
573
    }
 
574
    w(g, "~Mif (i > 0) ~f~N"
 
575
      "~}");
 
576
}
 
577
 
 
578
static void generate_setmark(struct generator * g, struct node * p)
 
579
{   g->V[0] = p->name;
 
580
    wp(g, "~M~V0 = z->c;~C", p);
 
581
}
 
582
 
 
583
static void generate_tomark(struct generator * g, struct node * p)
 
584
{   g->S[0] = p->mode == m_forward ? ">" : "<";
 
585
 
 
586
    w(g, "~Mif (z->c ~S0 "); generate_AE(g, p->AE); w(g, ") ~f~N");
 
587
    w(g, "~Mz->c = "); generate_AE(g, p->AE); wp(g, ";~C", p);
 
588
}
 
589
 
 
590
static void generate_atmark(struct generator * g, struct node * p)
 
591
{
 
592
    w(g, "~Mif (z->c != "); generate_AE(g, p->AE); wp(g, ") ~f~C", p);
 
593
}
 
594
 
 
595
 
 
596
static void generate_hop(struct generator * g, struct node * p)
 
597
{   g->S[0] = p->mode == m_forward ? "+" : "-";
 
598
 
 
599
    w(g, "~{int c = z->c ~S0 "); generate_AE(g, p->AE); w(g, ";~N");
 
600
 
 
601
    g->S[0] = p->mode == m_forward ? "0" : "z->lb";
 
602
 
 
603
    wp(g, "~Mif (~S0 > c || c > z->l) ~f~N"
 
604
          "~Mz->c = c;~C"
 
605
          "~}", p);
 
606
}
 
607
 
 
608
static void generate_delete(struct generator * g, struct node * p)
 
609
{   wp(g, "~Mslice_del(z);~C", p);
 
610
}
 
611
 
 
612
 
 
613
static void generate_next(struct generator * g, struct node * p)
 
614
{   wp(g, "~M~l~N"
 
615
          "~M~i~C", p);
 
616
}
 
617
 
 
618
static void generate_tolimit(struct generator * g, struct node * p)
 
619
{   g->S[0] = p->mode == m_forward ? "" : "b";
 
620
    wp(g, "~Mz->c = z->l~S0;~C", p);
 
621
}
 
622
 
 
623
static void generate_atlimit(struct generator * g, struct node * p)
 
624
{   g->S[0] = p->mode == m_forward ? "" : "b";
 
625
    g->S[1] = p->mode == m_forward ? "<" : ">";
 
626
    wp(g, "~Mif (z->c ~S1 z->l~S0) ~f~C", p);
 
627
}
 
628
 
 
629
static void generate_leftslice(struct generator * g, struct node * p)
 
630
{   g->S[0] = p->mode == m_forward ? "bra" : "ket";
 
631
    wp(g, "~Mz->~S0 = z->c;~C", p);
 
632
}
 
633
 
 
634
static void generate_rightslice(struct generator * g, struct node * p)
 
635
{   g->S[0] = p->mode == m_forward ? "ket" : "bra";
 
636
    wp(g, "~Mz->~S0 = z->c;~C", p);
 
637
}
 
638
 
 
639
static void generate_assignto(struct generator * g, struct node * p)
 
640
{   g->V[0] = p->name;
 
641
    wp(g, "~M~V0 = assign_to(z, ~V0);~C", p);
 
642
}
 
643
 
 
644
static void generate_sliceto(struct generator * g, struct node * p)
 
645
{   g->V[0] = p->name;
 
646
    wp(g, "~M~V0 = slice_to(z, ~V0);~C", p);
 
647
}
 
648
 
 
649
static void generate_data_address(struct generator * g, struct node * p)
 
650
{
 
651
    symbol * b = p->literalstring;
 
652
    if (b != 0)
 
653
    {   wi(g, SIZE(b)); w(g, ", ");
 
654
        wlitref(g, b);
 
655
    } else
 
656
        wv(g, p->name);
 
657
}
 
658
 
 
659
static void generate_insert(struct generator * g, struct node * p, int style)
 
660
{
 
661
    int keep_c = style == c_attach;
 
662
    if (p->mode == m_backward) keep_c = !keep_c;
 
663
    if (keep_c) w(g, "~{int c = z->c;~N");
 
664
    wp(g, "~Minsert_~$(z, z->c, z->c, ", p);
 
665
    generate_data_address(g, p);
 
666
    wp(g, ");~C", p);
 
667
    if (keep_c) w(g, "~Mz->c = c;~N~}");
 
668
}
 
669
 
 
670
static void generate_assignfrom(struct generator * g, struct node * p)
 
671
{
 
672
    int keep_c = p->mode == m_forward; /* like 'attach' */
 
673
    if (keep_c) wp(g, "~{int c = z->c;~N"
 
674
                   "~Minsert_~$(z, z->c, z->l, ", p);
 
675
                else wp(g, "~Minsert_~$(z, z->lb, z->c, ", p);
 
676
    generate_data_address(g, p);
 
677
    wp(g, ");~C", p);
 
678
    if (keep_c) w(g, "~Mz->c = c;~N~}");
 
679
}
 
680
 
 
681
/* bugs marked <======= fixed 22/7/02. Similar fixes required for Java */
 
682
 
 
683
static void generate_slicefrom(struct generator * g, struct node * p)
 
684
{
 
685
/*  w(g, "~Mslice_from_s(z, ");   <============= bug! should be: */
 
686
    wp(g, "~Mslice_from_~$(z, ", p);
 
687
    generate_data_address(g, p);
 
688
    wp(g, ");~C", p);
 
689
}
 
690
 
 
691
static void generate_setlimit(struct generator * g, struct node * p)
 
692
{   wp(g, "~{~k~C"
 
693
              "~Mint m3;~N", p);
 
694
    generate(g, p->left);
 
695
    if (p->mode == m_forward) w(g, "~Mm3 = z->l - z->c; z->l = z->c;~N");
 
696
                         else w(g, "~Mm3 = z->lb; z->lb = z->c;~N");
 
697
    wp(g, "~M~r~N", p);
 
698
    {
 
699
        g->failure_string = p->mode == m_forward ? "z->l += m3;" :
 
700
                                                   "z->lb = m3;";
 
701
        generate(g, p->aux);
 
702
        wms(g, g->failure_string);
 
703
        w(g, "~N"
 
704
          "~}");
 
705
    }
 
706
}
 
707
 
 
708
/* There are bugs in this version
 
709
--static void generate_dollar(struct generator * g, struct node * p)
 
710
--{
 
711
--    g->V[0] = p->name;
 
712
--    g->failure_string = "* z = env;";
 
713
--    wp(g, "~{struct SN_env env = * z;~C"
 
714
--             "~Mz->p = ~V0;~N"
 
715
--             "~Mz->c = 0;~N"   <====== z->lb ought to be set to 0 as well
 
716
--             "~Mz->l = SIZE(z->p);~N", p);
 
717
--    generate(g, p->left);
 
718
--    wms(g, g->failure_string); <====== but string p->name may have a new address
 
719
--    w(g, "~N"
 
720
--      "~}");
 
721
--}
 
722
*/
 
723
 
 
724
static void generate_dollar(struct generator * g, struct node * p)
 
725
{
 
726
    int a0 = g->failure_label;
 
727
    char * a1 = g->failure_string;
 
728
    g->failure_label = new_label(g);
 
729
    g->failure_string = 0;
 
730
 
 
731
    g->V[0] = p->name;
 
732
    wp(g, "~{struct SN_env env = * z;~C"
 
733
             "~Mint failure = 1; /* assume failure */~N"
 
734
             "~Mz->p = ~V0;~N"
 
735
             "~Mz->lb = z->c = 0;~N"
 
736
             "~Mz->l = SIZE(z->p);~N", p);
 
737
    generate(g, p->left);
 
738
    w(g, "~Mfailure = 0; /* mark success */~N");
 
739
    wsetl(g, g->failure_label);
 
740
    g->V[0] = p->name; /* necessary */
 
741
 
 
742
    g->failure_label = a0;
 
743
    g->failure_string = a1;
 
744
 
 
745
    w(g, "~M~V0 = z->p;~N"
 
746
         "~M* z = env;~N"
 
747
         "~Mif (failure) ~f~N~}");
 
748
}
 
749
 
 
750
static void generate_integer_assign(struct generator * g, struct node * p, char * s)
 
751
{
 
752
    g->V[0] = p->name;
 
753
    g->S[0] = s;
 
754
    w(g, "~M~V0 ~S0 "); generate_AE(g, p->AE); w(g, ";~N");
 
755
}
 
756
 
 
757
static void generate_integer_test(struct generator * g, struct node * p, char * s)
 
758
{
 
759
    g->V[0] = p->name;
 
760
    g->S[0] = s;
 
761
    w(g, "~Mif (!(~V0 ~S0 "); generate_AE(g, p->AE); w(g, ")) ~f~N");
 
762
}
 
763
 
 
764
static void generate_call(struct generator * g, struct node * p)
 
765
{
 
766
    g->V[0] = p->name;
 
767
    wp(g, "~Mif (!~V0(z)) ~f~C", p);
 
768
}
 
769
 
 
770
static void generate_grouping(struct generator * g, struct node * p, int complement)
 
771
{
 
772
    struct grouping * q = p->name->grouping;
 
773
    g->S[0] = p->mode == m_forward ? "" : "_b";
 
774
    g->S[1] = complement ? "out" : "in";
 
775
    g->V[0] = p->name;
 
776
    g->I[0] = q->smallest_ch;
 
777
    g->I[1] = q->largest_ch;
 
778
    if (q->no_gaps)
 
779
        w(g, "~Mif (!(~S1_range~S0(z, ~I0, ~I1))) ~f~N");
 
780
    else
 
781
        w(g, "~Mif (!(~S1_grouping~S0(z, ~V0, ~I0, ~I1))) ~f~N");
 
782
}
 
783
 
 
784
static void generate_namedstring(struct generator * g, struct node * p)
 
785
{
 
786
    g->S[0] = p->mode == m_forward ? "" : "_b";
 
787
    g->V[0] = p->name;
 
788
    wp(g, "~Mif (!(eq_v~S0(z, ~V0))) ~f~C", p);
 
789
}
 
790
 
 
791
static void generate_literalstring(struct generator * g, struct node * p)
 
792
{   symbol * b = p->literalstring;
 
793
    g->S[0] = p->mode == m_forward ? "" : "_b";
 
794
    g->I[0] = SIZE(b);
 
795
    g->L[0] = b;
 
796
 
 
797
    w(g, "~Mif (!(eq_s~S0(z, ~I0, ~L0))) ~f~N");
 
798
}
 
799
 
 
800
static void generate_define(struct generator * g, struct node * p)
 
801
{   struct name * q = p->name;
 
802
    g->next_label = 0;
 
803
 
 
804
    g->S[0] = q->type == t_routine ? "static" : "extern";
 
805
    g->V[0] = q;
 
806
 
 
807
    w(g, "~N~S0 int ~V0(struct SN_env * z) {~N~+");
 
808
    if (p->amongvar_needed) w(g, "~Mint among_var;~N");
 
809
    g->failure_string = 0;
 
810
    g->failure_label = x_return;
 
811
    generate(g, p->left);
 
812
    w(g, "~Mreturn 1;~N~}");
 
813
}
 
814
 
 
815
static void generate_substring(struct generator * g, struct node * p)
 
816
{
 
817
    struct among * x = p->among;
 
818
 
 
819
    g->S[0] = p->mode == m_forward ? "" : "_b";
 
820
    g->I[0] = x->number;
 
821
    g->I[1] = x->literalstring_count;
 
822
 
 
823
    if (x->command_count == 0 && x->starter == 0)
 
824
        wp(g, "~Mif (!(find_among~S0(z, a_~I0, ~I1))) ~f~C", p);
 
825
    else
 
826
        wp(g, "~Mamong_var = find_among~S0(z, a_~I0, ~I1);~C"
 
827
              "~Mif (!(among_var)) ~f~N", p);
 
828
}
 
829
 
 
830
static void generate_among(struct generator * g, struct node * p)
 
831
{
 
832
    struct among * x = p->among;
 
833
    int case_number = 1;
 
834
 
 
835
    if (x->substring == 0) generate_substring(g, p);
 
836
    if (x->command_count == 0 && x->starter == 0) return;
 
837
 
 
838
    unless (x->starter == 0) generate(g, x->starter);
 
839
 
 
840
    p = p->left;
 
841
    if (p != 0 && p->type != c_literalstring) p = p->right;
 
842
    w(g, "~Mswitch(among_var) {~N~+"
 
843
             "~Mcase 0: ~f~N");
 
844
 
 
845
    until (p == 0)
 
846
    {    if (p->type == c_bra && p->left != 0)
 
847
         {   g->I[0] = case_number++;
 
848
             w(g, "~Mcase ~I0:~N~+"); generate(g, p); w(g, "~Mbreak;~N~-");
 
849
         }
 
850
         p = p->right;
 
851
    }
 
852
    w(g, "~}");
 
853
}
 
854
 
 
855
static void generate_booltest(struct generator * g, struct node * p)
 
856
{
 
857
    g->V[0] = p->name;
 
858
    wp(g, "~Mif (!(~V0)) ~f~C", p);
 
859
}
 
860
 
 
861
static void generate_false(struct generator * g, struct node * p)
 
862
{
 
863
    wp(g, "~M~f~C", p);
 
864
}
 
865
 
 
866
static void generate_debug(struct generator * g, struct node * p)
 
867
{
 
868
    g->I[0] = g->debug_count++;
 
869
    g->I[1] = p->line_number;
 
870
    wp(g, "~Mdebug(z, ~I0, ~I1);~C", p);
 
871
 
 
872
}
 
873
 
 
874
static void generate(struct generator * g, struct node * p)
 
875
{
 
876
    int a0 = g->failure_label;
 
877
    char * a1 = g->failure_string;
 
878
 
 
879
    switch (p->type)
 
880
    {
 
881
        case c_define:        generate_define(g, p); break;
 
882
        case c_bra:           generate_bra(g, p); break;
 
883
        case c_and:           generate_and(g, p); break;
 
884
        case c_or:            generate_or(g, p); break;
 
885
        case c_backwards:     generate_backwards(g, p); break;
 
886
        case c_not:           generate_not(g, p); break;
 
887
        case c_set:           generate_set(g, p); break;
 
888
        case c_unset:         generate_unset(g, p); break;
 
889
        case c_try:           generate_try(g, p); break;
 
890
        case c_fail:          generate_fail(g, p); break;
 
891
        case c_reverse:
 
892
        case c_test:          generate_test(g, p); break;
 
893
        case c_do:            generate_do(g, p); break;
 
894
        case c_goto:          generate_GO(g, p, 1); break;
 
895
        case c_gopast:        generate_GO(g, p, 0); break;
 
896
        case c_repeat:        generate_repeat(g, p, false); break;
 
897
        case c_loop:          generate_loop(g, p); break;
 
898
        case c_atleast:       generate_atleast(g, p); break;
 
899
        case c_setmark:       generate_setmark(g, p); break;
 
900
        case c_tomark:        generate_tomark(g, p); break;
 
901
        case c_atmark:        generate_atmark(g, p); break;
 
902
        case c_hop:           generate_hop(g, p); break;
 
903
        case c_delete:        generate_delete(g, p); break;
 
904
        case c_next:          generate_next(g, p); break;
 
905
        case c_tolimit:       generate_tolimit(g, p); break;
 
906
        case c_atlimit:       generate_atlimit(g, p); break;
 
907
        case c_leftslice:     generate_leftslice(g, p); break;
 
908
        case c_rightslice:    generate_rightslice(g, p); break;
 
909
        case c_assignto:      generate_assignto(g, p); break;
 
910
        case c_sliceto:       generate_sliceto(g, p); break;
 
911
        case c_assign:        generate_assignfrom(g, p); break;
 
912
        case c_insert:
 
913
        case c_attach:        generate_insert(g, p, p->type); break;
 
914
        case c_slicefrom:     generate_slicefrom(g, p); break;
 
915
        case c_setlimit:      generate_setlimit(g, p); break;
 
916
        case c_dollar:        generate_dollar(g, p); break;
 
917
        case c_mathassign:    generate_integer_assign(g, p, "="); break;
 
918
        case c_plusassign:    generate_integer_assign(g, p, "+="); break;
 
919
        case c_minusassign:   generate_integer_assign(g, p, "-="); break;
 
920
        case c_multiplyassign:generate_integer_assign(g, p, "*="); break;
 
921
        case c_divideassign:  generate_integer_assign(g, p, "/="); break;
 
922
        case c_eq:            generate_integer_test(g, p, "=="); break;
 
923
        case c_ne:            generate_integer_test(g, p, "!="); break;
 
924
        case c_gr:            generate_integer_test(g, p, ">"); break;
 
925
        case c_ge:            generate_integer_test(g, p, ">="); break;
 
926
        case c_ls:            generate_integer_test(g, p, "<"); break;
 
927
        case c_le:            generate_integer_test(g, p, "<="); break;
 
928
        case c_call:          generate_call(g, p); break;
 
929
        case c_grouping:      generate_grouping(g, p, false); break;
 
930
        case c_non:           generate_grouping(g, p, true); break;
 
931
        case c_name:          generate_namedstring(g, p); break;
 
932
        case c_literalstring: generate_literalstring(g, p); break;
 
933
        case c_among:         generate_among(g, p); break;
 
934
        case c_substring:     generate_substring(g, p); break;
 
935
        case c_booltest:      generate_booltest(g, p); break;
 
936
        case c_false:         generate_false(g, p); break;
 
937
        case c_true:          break;
 
938
        case c_debug:         generate_debug(g, p); break;
 
939
        default: fprintf(stderr, "%d encountered\n", p->type);
 
940
                 exit(1);
 
941
    }
 
942
 
 
943
    g->failure_label = a0;
 
944
    g->failure_string = a1;
 
945
 
 
946
}
 
947
 
 
948
static void generate_start_comment(struct generator * g)
 
949
{
 
950
    w(g, "~N/* This file was generated automatically by the Snowball to ANSI C compiler */~N");
 
951
}
 
952
 
 
953
static void generate_head(struct generator * g)
 
954
{
 
955
    w(g, "~N#include \"header.h\"~N~N");
 
956
}
 
957
 
 
958
static void generate_routine_headers(struct generator * g)
 
959
{   struct name * q = g->analyser->names;
 
960
    until (q == 0)
 
961
    {   g->V[0] = q;
 
962
        switch (q->type)
 
963
        {   case t_routine:  g->S[0] = "static"; goto label0;
 
964
            case t_external: g->S[0] = "extern";
 
965
            label0:
 
966
                w(g, "~S0 int ~W0(struct SN_env * z);~N");
 
967
        }
 
968
        q = q->next;
 
969
    }
 
970
}
 
971
 
 
972
static void generate_among_table(struct generator * g, struct among * x)
 
973
{
 
974
    struct amongvec * v = x->b;
 
975
 
 
976
    g->I[0] = x->number;
 
977
 
 
978
    {   int i;
 
979
        for (i = 0; i < x->literalstring_count; i++)
 
980
 
 
981
        {   g->I[1] = i;
 
982
            g->I[2] = v->size;
 
983
            g->L[0] = v->b;
 
984
            unless (v->size == 0)
 
985
                w(g, "static symbol s_~I0_~I1[~I2] = ~A0;~N");
 
986
            v++;
 
987
        }
 
988
    }
 
989
 
 
990
    g->I[1] = x->literalstring_count;
 
991
    w(g, "~N~Mstatic struct among a_~I0[~I1] =~N{~N");
 
992
 
 
993
    v = x->b;
 
994
    {   int i;
 
995
        for (i = 0; i < x->literalstring_count; i++)
 
996
 
 
997
        {   g->I[1] = i;
 
998
            g->I[2] = v->size;
 
999
            g->I[3] = v->i;
 
1000
            g->I[4] = v->result;
 
1001
            g->S[0] = i < x->literalstring_count - 1 ? "," : "";
 
1002
 
 
1003
            w(g, "/*~J1 */ { ~I2, ");
 
1004
            if (v->size == 0) w(g, "0,");
 
1005
                         else w(g, "s_~I0_~I1,");
 
1006
            w(g, " ~I3, ~I4, ");
 
1007
            if (v->function == 0) w(g, "0"); else
 
1008
                                  wvn(g, v->function);
 
1009
            w(g, "}~S0~N");
 
1010
            v++;
 
1011
        }
 
1012
    }
 
1013
    w(g, "};~N~N");
 
1014
}
 
1015
 
 
1016
static void generate_amongs(struct generator * g)
 
1017
{   struct among * x = g->analyser->amongs;
 
1018
    until (x == 0)
 
1019
    {   generate_among_table(g, x);
 
1020
        x = x->next;
 
1021
    }
 
1022
}
 
1023
 
 
1024
static void set_bit(symbol * b, int i) { b[i/8] |= 1 << i%8; }
 
1025
 
 
1026
static int bit_is_set(symbol * b, int i) { return b[i/8] & 1 << i%8; }
 
1027
 
 
1028
static void generate_grouping_table(struct generator * g, struct grouping * q)
 
1029
{
 
1030
    int range = q->largest_ch - q->smallest_ch + 1;
 
1031
    int size = (range + 7)/ 8;  /* assume 8 bits per symbol */
 
1032
    symbol * b = q->b;
 
1033
    symbol * map = create_b(size);
 
1034
    int i;
 
1035
    for (i = 0; i < size; i++) map[i] = 0;
 
1036
 
 
1037
    for (i = 0; i < SIZE(b); i++) set_bit(map, b[i] - q->smallest_ch);
 
1038
 
 
1039
    q->no_gaps = true;
 
1040
    for (i = 0; i < range; i++) unless (bit_is_set(map, i)) q->no_gaps = false;
 
1041
 
 
1042
    unless (q->no_gaps)
 
1043
    {   g->V[0] = q->name;
 
1044
 
 
1045
        w(g, "static unsigned char ~V0[] = { ");
 
1046
        for (i = 0; i < size; i++)
 
1047
        {    wi(g, map[i]);
 
1048
             if (i < size - 1) w(g, ", ");
 
1049
        }
 
1050
        w(g, " };~N~N");
 
1051
    }
 
1052
    lose_b(map);
 
1053
}
 
1054
 
 
1055
static void generate_groupings(struct generator * g)
 
1056
{   struct grouping * q = g->analyser->groupings;
 
1057
    until (q == 0)
 
1058
    {   generate_grouping_table(g, q);
 
1059
        q = q->next;
 
1060
    }
 
1061
}
 
1062
 
 
1063
static void generate_create(struct generator * g)
 
1064
{
 
1065
    int * p = g->analyser->name_count;
 
1066
    g->I[0] = p[t_string];
 
1067
    g->I[1] = p[t_integer];
 
1068
    g->I[2] = p[t_boolean];
 
1069
    w(g, "~N"
 
1070
         "extern struct SN_env * ~pcreate_env(void) { return SN_create_env(~I0, ~I1, ~I2); }"
 
1071
         "~N");
 
1072
}
 
1073
 
 
1074
static void generate_close(struct generator * g)
 
1075
{
 
1076
    w(g, "~Nextern void ~pclose_env(struct SN_env * z) { SN_close_env(z); }~N~N");
 
1077
}
 
1078
 
 
1079
static void generate_create_and_close_templates(struct generator * g) {
 
1080
    w(g, "~N"
 
1081
         "extern struct SN_env * ~pcreate_env(void);~N"
 
1082
         "extern void ~pclose_env(struct SN_env * z);~N~N");
 
1083
}
 
1084
 
 
1085
static void generate_header_file(struct generator * g)
 
1086
{
 
1087
    struct name * q = g->analyser->names;
 
1088
    char * vp = g->options->variables_prefix;
 
1089
    g->S[0] = vp;
 
1090
    generate_create_and_close_templates(g);
 
1091
    until (q == 0)
 
1092
    {   g->V[0] = q;
 
1093
        switch (q->type)
 
1094
        {
 
1095
            case t_external:
 
1096
                w(g, "extern int ~W0(struct SN_env * z);~N");
 
1097
                break;
 
1098
            case t_string:  g->S[1] = "S"; goto label0;
 
1099
            case t_integer: g->S[1] = "I"; goto label0;
 
1100
            case t_boolean: g->S[1] = "B";
 
1101
            label0:
 
1102
                if (vp)
 
1103
                {   g->I[0] = q->count;
 
1104
                    w(g, "#define ~S0");
 
1105
                    str_append_b(g->outbuf, q->b);
 
1106
                    w(g, " (~S1[~I0])~N");
 
1107
                }
 
1108
                break;
 
1109
        }
 
1110
        q = q->next;
 
1111
    }
 
1112
    w(g, "~N");
 
1113
}
 
1114
 
 
1115
extern void generate_program_c(struct generator * g)
 
1116
{
 
1117
    g->outbuf = str_new();
 
1118
    generate_start_comment(g);
 
1119
    generate_head(g);
 
1120
    generate_routine_headers(g);
 
1121
    generate_create_and_close_templates(g);
 
1122
    generate_amongs(g);
 
1123
    generate_groupings(g);
 
1124
    g->declarations = g->outbuf;
 
1125
    g->outbuf = str_new();
 
1126
    g->literalstring_count = 0;
 
1127
    {   struct node * p = g->analyser->program;
 
1128
        until (p == 0) { generate(g, p); p = p->right; }
 
1129
    }
 
1130
    generate_create(g);
 
1131
    generate_close(g);
 
1132
    output_str(g->options->output_c, g->declarations);
 
1133
    str_delete(g->declarations);
 
1134
    output_str(g->options->output_c, g->outbuf);
 
1135
    str_clear(g->outbuf);
 
1136
 
 
1137
    generate_start_comment(g);
 
1138
    generate_header_file(g);
 
1139
    output_str(g->options->output_h, g->outbuf);
 
1140
    str_delete(g->outbuf);
 
1141
}
 
1142
 
 
1143
extern struct generator * create_generator_c(struct analyser * a, struct options * o)
 
1144
{   NEW(generator, g);
 
1145
    g->analyser = a;
 
1146
    g->options = o;
 
1147
    g->margin = 0;
 
1148
    g->debug_count = 0;
 
1149
    g->line_count = 0;
 
1150
    return g;
 
1151
}
 
1152
 
 
1153
extern void close_generator_c(struct generator * g)
 
1154
{
 
1155
    FREE(g);
 
1156
}
 
1157