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

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