mittens 0.3.0 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (174) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +8 -0
  3. data/Gemfile +2 -1
  4. data/README.md +2 -2
  5. data/Rakefile +12 -5
  6. data/ext/mittens/extconf.rb +3 -1
  7. data/lib/mittens/version.rb +1 -1
  8. data/vendor/snowball/.github/workflows/ci.yml +144 -17
  9. data/vendor/snowball/.github/workflows/coverage.yml +117 -0
  10. data/vendor/snowball/.github/workflows/runtime-tests.yml +26 -0
  11. data/vendor/snowball/.gitignore +33 -7
  12. data/vendor/snowball/CONTRIBUTING.rst +7 -0
  13. data/vendor/snowball/COPYING +1 -1
  14. data/vendor/snowball/GNUmakefile +736 -298
  15. data/vendor/snowball/NEWS +1394 -7
  16. data/vendor/snowball/README.rst +8 -8
  17. data/vendor/snowball/ada/generate/generate.adb +5 -5
  18. data/vendor/snowball/ada/src/stemmer.adb +177 -188
  19. data/vendor/snowball/ada/src/stemmer.ads +86 -89
  20. data/vendor/snowball/ada/src/stemwords.adb +21 -5
  21. data/vendor/snowball/algorithms/czech.sbl +255 -0
  22. data/vendor/snowball/algorithms/danish.sbl +22 -10
  23. data/vendor/snowball/algorithms/english.sbl +7 -4
  24. data/vendor/snowball/algorithms/esperanto.sbl +6 -7
  25. data/vendor/snowball/algorithms/estonian.sbl +9 -4
  26. data/vendor/snowball/algorithms/finnish.sbl +33 -21
  27. data/vendor/snowball/algorithms/german.sbl +5 -0
  28. data/vendor/snowball/algorithms/indonesian.sbl +115 -96
  29. data/vendor/snowball/algorithms/italian.sbl +26 -1
  30. data/vendor/snowball/algorithms/lithuanian.sbl +13 -13
  31. data/vendor/snowball/algorithms/norwegian.sbl +17 -6
  32. data/vendor/snowball/algorithms/persian.sbl +387 -0
  33. data/vendor/snowball/algorithms/polish.sbl +177 -0
  34. data/vendor/snowball/algorithms/sesotho.sbl +115 -0
  35. data/vendor/snowball/algorithms/turkish.sbl +4 -4
  36. data/vendor/snowball/compiler/analyser.c +2002 -711
  37. data/vendor/snowball/compiler/driver.c +460 -298
  38. data/vendor/snowball/compiler/generator.c +439 -1965
  39. data/vendor/snowball/compiler/generator_ada.c +605 -430
  40. data/vendor/snowball/compiler/generator_c.c +2227 -0
  41. data/vendor/snowball/compiler/generator_csharp.c +365 -274
  42. data/vendor/snowball/compiler/generator_dart.c +1476 -0
  43. data/vendor/snowball/compiler/generator_go.c +348 -270
  44. data/vendor/snowball/compiler/generator_java.c +330 -233
  45. data/vendor/snowball/compiler/generator_js.c +534 -385
  46. data/vendor/snowball/compiler/generator_pascal.c +361 -320
  47. data/vendor/snowball/compiler/generator_php.c +1445 -0
  48. data/vendor/snowball/compiler/generator_python.c +399 -299
  49. data/vendor/snowball/compiler/generator_rust.c +370 -261
  50. data/vendor/snowball/compiler/generator_zig.c +1474 -0
  51. data/vendor/snowball/compiler/header.h +153 -86
  52. data/vendor/snowball/compiler/space.c +121 -63
  53. data/vendor/snowball/compiler/tokeniser.c +286 -182
  54. data/vendor/snowball/compiler/tokens.h +71 -0
  55. data/vendor/snowball/csharp/Snowball/Among.cs +14 -26
  56. data/vendor/snowball/csharp/Snowball/AssemblyInfo.cs +3 -3
  57. data/vendor/snowball/csharp/Snowball/Stemmer.cs +41 -45
  58. data/vendor/snowball/csharp/Stemwords/Program.cs +20 -14
  59. data/vendor/snowball/cxx/.gitignore +4 -0
  60. data/vendor/snowball/cxx/generate_algorithms.pl +87 -0
  61. data/vendor/snowball/cxx/stemmer.h +12 -0
  62. data/vendor/snowball/cxx/stemwords.cxx +176 -0
  63. data/vendor/snowball/cxx/utilities.cxx +2 -0
  64. data/vendor/snowball/dart/.gitignore +4 -0
  65. data/vendor/snowball/dart/analysis_options.yaml +1 -0
  66. data/vendor/snowball/dart/example/test_app.dart +65 -0
  67. data/vendor/snowball/dart/generate_algorithms.pl +21 -0
  68. data/vendor/snowball/dart/lib/snowball.dart +18 -0
  69. data/vendor/snowball/dart/lib/src/snowball.dart +339 -0
  70. data/vendor/snowball/dart/pubspec.yaml +17 -0
  71. data/vendor/snowball/doc/libstemmer_dart_README +37 -0
  72. data/vendor/snowball/doc/libstemmer_js_README +2 -2
  73. data/vendor/snowball/doc/libstemmer_php_README +38 -0
  74. data/vendor/snowball/doc/libstemmer_python_README +3 -3
  75. data/vendor/snowball/examples/stemwords.c +18 -3
  76. data/vendor/snowball/go/README.md +12 -4
  77. data/vendor/snowball/go/env.go +12 -14
  78. data/vendor/snowball/go/stemwords/main.go +2 -1
  79. data/vendor/snowball/java/org/tartarus/snowball/CharArraySequence.java +36 -0
  80. data/vendor/snowball/java/org/tartarus/snowball/SnowballProgram.java +17 -34
  81. data/vendor/snowball/java/org/tartarus/snowball/SnowballStemmer.java +0 -2
  82. data/vendor/snowball/javascript/base-stemmer.js +219 -252
  83. data/vendor/snowball/javascript/stemwords.js +86 -58
  84. data/vendor/snowball/libstemmer/mkmodules.pl +1 -1
  85. data/vendor/snowball/libstemmer/modules.txt +4 -0
  86. data/vendor/snowball/pascal/SnowballProgram.pas +18 -31
  87. data/vendor/snowball/php/base-stemmer.php +453 -0
  88. data/vendor/snowball/php/stemwords.php +25 -0
  89. data/vendor/snowball/python/create_init.py +16 -21
  90. data/vendor/snowball/python/pyproject.toml +3 -0
  91. data/vendor/snowball/python/setup.py +5 -7
  92. data/vendor/snowball/python/snowballstemmer/among.py +1 -2
  93. data/vendor/snowball/python/snowballstemmer/basestemmer.py +24 -33
  94. data/vendor/snowball/python/stemwords.py +72 -63
  95. data/vendor/snowball/runtime/api.c +11 -42
  96. data/vendor/snowball/runtime/api.h +11 -9
  97. data/vendor/snowball/runtime/snowball_runtime.h +110 -0
  98. data/vendor/snowball/runtime/utilities.c +282 -106
  99. data/vendor/snowball/rust/src/main.rs +2 -2
  100. data/vendor/snowball/rust/src/snowball/snowball_env.rs +7 -9
  101. data/vendor/snowball/tests/compilertest +62 -0
  102. data/vendor/snowball/tests/errors/ae-errors.sbl +53 -0
  103. data/vendor/snowball/tests/errors/ae-errors.stderr +8 -0
  104. data/vendor/snowball/tests/errors/bad-dollar.sbl +14 -0
  105. data/vendor/snowball/tests/errors/bad-dollar.stderr +4 -0
  106. data/vendor/snowball/tests/errors/bad-grouping-definition.sbl +9 -0
  107. data/vendor/snowball/tests/errors/bad-grouping-definition.stderr +6 -0
  108. data/vendor/snowball/tests/errors/missing-bra.sbl +6 -0
  109. data/vendor/snowball/tests/errors/missing-bra.stderr +3 -0
  110. data/vendor/snowball/tests/errors/missing-command.sbl +9 -0
  111. data/vendor/snowball/tests/errors/missing-command.stderr +1 -0
  112. data/vendor/snowball/tests/errors/missing-ket-backwardmode.sbl +3 -0
  113. data/vendor/snowball/tests/errors/missing-ket-backwardmode.stderr +1 -0
  114. data/vendor/snowball/tests/errors/missing-ket.sbl +7 -0
  115. data/vendor/snowball/tests/errors/missing-ket.stderr +6 -0
  116. data/vendor/snowball/tests/errors/notdefined.sbl +4 -0
  117. data/vendor/snowball/tests/errors/notdefined.stderr +2 -0
  118. data/vendor/snowball/tests/errors/string-omitted.sbl +5 -0
  119. data/vendor/snowball/tests/errors/string-omitted.stderr +1 -0
  120. data/vendor/snowball/tests/errors/undeclared.sbl +20 -0
  121. data/vendor/snowball/tests/errors/undeclared.stderr +9 -0
  122. data/vendor/snowball/tests/errors/unexpected-token.sbl +24 -0
  123. data/vendor/snowball/tests/errors/unexpected-token.stderr +17 -0
  124. data/vendor/snowball/tests/errors/wrongdirection.sbl +14 -0
  125. data/vendor/snowball/tests/errors/wrongdirection.stderr +1 -0
  126. data/vendor/snowball/tests/runtime/among.sbl +19 -0
  127. data/vendor/snowball/tests/runtime/arithmeticexpr.sbl +86 -0
  128. data/vendor/snowball/tests/runtime/attachinsert.sbl +47 -0
  129. data/vendor/snowball/tests/runtime/booleans.sbl +19 -0
  130. data/vendor/snowball/tests/runtime/externals.sbl +22 -0
  131. data/vendor/snowball/tests/runtime/hop.sbl +12 -0
  132. data/vendor/snowball/tests/runtime/integertests.sbl +60 -0
  133. data/vendor/snowball/tests/runtime/intlimits.sbl +25 -0
  134. data/vendor/snowball/tests/runtime/naming.sbl +20 -0
  135. data/vendor/snowball/tests/runtime/not.sbl +30 -0
  136. data/vendor/snowball/tests/runtime/or.sbl +17 -0
  137. data/vendor/snowball/tests/runtime/repeat.sbl +16 -0
  138. data/vendor/snowball/tests/runtime/setlimit.sbl +24 -0
  139. data/vendor/snowball/tests/runtime/sizelen.sbl +56 -0
  140. data/vendor/snowball/tests/runtime/slice.sbl +27 -0
  141. data/vendor/snowball/tests/runtime/stringdollar.sbl +39 -0
  142. data/vendor/snowball/tests/runtime/strings.sbl +66 -0
  143. data/vendor/snowball/tests/runtime/test.sbl +19 -0
  144. data/vendor/snowball/tests/stemtest.c +41 -1
  145. data/vendor/snowball/tests/syntax/canon.sbl +32 -0
  146. data/vendor/snowball/tests/syntax/canon.stderr +0 -0
  147. data/vendor/snowball/tests/syntax/canon.syntax +57 -0
  148. data/vendor/snowball/tests/syntax/emptyprogram.sbl +2 -0
  149. data/vendor/snowball/tests/syntax/emptyprogram.syntax +0 -0
  150. data/vendor/snowball/tests/syntax/groupings.sbl +11 -0
  151. data/vendor/snowball/tests/syntax/inline.sbl +144 -0
  152. data/vendor/snowball/tests/syntax/inline.stderr +0 -0
  153. data/vendor/snowball/tests/syntax/inline.syntax +121 -0
  154. data/vendor/snowball/tests/syntax/legacy.sbl +17 -0
  155. data/vendor/snowball/tests/syntax/legacy.stderr +5 -0
  156. data/vendor/snowball/tests/syntax/legacy.syntax +19 -0
  157. data/vendor/snowball/tests/syntax/loops.sbl +14 -0
  158. data/vendor/snowball/tests/syntax/loops.stderr +9 -0
  159. data/vendor/snowball/tests/syntax/loops.syntax +29 -0
  160. data/vendor/snowball/tests/syntax/noops.sbl +76 -0
  161. data/vendor/snowball/tests/syntax/noops.stderr +27 -0
  162. data/vendor/snowball/tests/syntax/noops.syntax +135 -0
  163. data/vendor/snowball/tests/syntax/simplifyae.sbl +21 -0
  164. data/vendor/snowball/tests/syntax/simplifyae.stderr +0 -0
  165. data/vendor/snowball/tests/syntax/simplifyae.syntax +39 -0
  166. data/vendor/snowball/tests/syntax/unused.sbl +18 -0
  167. data/vendor/snowball/tests/syntax/unused.stderr +7 -0
  168. data/vendor/snowball/tests/syntax/unused.syntax +3 -0
  169. data/vendor/snowball/zig/env.zig +599 -0
  170. data/vendor/snowball/zig/generate_algorithms.pl +19 -0
  171. data/vendor/snowball/zig/stemwords.zig +123 -0
  172. metadata +102 -4
  173. data/vendor/snowball/compiler/syswords.h +0 -86
  174. data/vendor/snowball/runtime/header.h +0 -62
@@ -0,0 +1,2227 @@
1
+ #include <assert.h>
2
+ #include <stdio.h> /* for fprintf etc */
3
+ #include <stdlib.h> /* for exit */
4
+ #include <string.h> /* for strlen */
5
+ #include "header.h"
6
+
7
+ /* Define this to get warning messages when optimisations can't be used. */
8
+ /* #define OPTIMISATION_WARNINGS */
9
+
10
+ /* prototype functions for recursive use: */
11
+
12
+ static void generate(struct generator * g, struct node * p);
13
+ static void w(struct generator * g, const char * s);
14
+ static void writef(struct generator * g, const char * s, struct node * p);
15
+
16
+ /* Write routines for items from the syntax tree */
17
+
18
+ static void write_relop(struct generator * g, int relop) {
19
+ write_c_relop(g, relop);
20
+ }
21
+
22
+ static void write_varname(struct generator * g, struct name * p) {
23
+ if (p->type == t_external) {
24
+ if (g->options->target_lang == LANG_CPLUSPLUS) {
25
+ write_string(g, g->options->package);
26
+ write_string(g, "::");
27
+ write_s(g, g->options->name);
28
+ write_string(g, "::");
29
+ }
30
+ if (g->options->externals_prefix) {
31
+ write_string(g, g->options->externals_prefix);
32
+ }
33
+ } else {
34
+ /* Name variables using their Snowball name prefixed by s_, b_ or i_
35
+ * depending on their type.
36
+ *
37
+ * We use the same naming scheme for both global and local variables.
38
+ */
39
+ write_char(g, "sbirxg"[p->type]);
40
+ write_char(g, '_');
41
+ }
42
+ write_s(g, p->s);
43
+ }
44
+
45
+ /* Reference to variable, e.g. when assigning to or using in an expression. */
46
+ static void write_varref(struct generator * g, struct name * p) {
47
+ if (p->type < t_routine && p->local_to == NULL) {
48
+ write_string(g, "((SN_local *)z)->");
49
+ }
50
+ write_varname(g, p);
51
+ }
52
+
53
+ /* write character literal */
54
+ static void wlitch(struct generator * g, int ch) {
55
+ if (32 <= ch && ch < 127) {
56
+ write_char(g, '\'');
57
+ if (ch == '\'' || ch == '\\') {
58
+ write_char(g, '\\');
59
+ }
60
+ write_char(g, ch);
61
+ write_char(g, '\'');
62
+ } else {
63
+ write_string(g, "0x");
64
+ write_hex(g, ch);
65
+ }
66
+ }
67
+
68
+ static void wlitarray(struct generator * g, symbol * p) { /* write literal array */
69
+ write_string(g, "{ ");
70
+ for (int i = 0; i < SIZE(p); i++) {
71
+ if (i) write_string(g, ", ");
72
+ wlitch(g, p[i]);
73
+ }
74
+ write_string(g, " }");
75
+ }
76
+
77
+ static void wlitref(struct generator * g, symbol * p) { /* write ref to literal array */
78
+ if (SIZE(p) == 0) {
79
+ write_char(g, '0');
80
+ } else {
81
+ struct str * s = g->outbuf;
82
+ g->outbuf = g->declarations;
83
+ write_string(g, "static const symbol s_"); write_int(g, g->literalstring_count); write_string(g, "[] = ");
84
+ wlitarray(g, p);
85
+ write_string(g, ";\n");
86
+ g->outbuf = s;
87
+ write_string(g, "s_"); write_int(g, g->literalstring_count);
88
+ g->literalstring_count++;
89
+ }
90
+ }
91
+
92
+ static void write_comment(struct generator * g, struct node * p) {
93
+ if (!g->options->comments) return;
94
+ write_margin(g);
95
+ write_string(g, "/* ");
96
+ write_comment_content(g, p, "*/");
97
+ write_string(g, " */");
98
+ write_newline(g);
99
+ }
100
+
101
+ static void write_block_start(struct generator * g) {
102
+ w(g, "~M{~+~N");
103
+ }
104
+
105
+ static void write_block_end(struct generator * g) {
106
+ if (g->line_labelled == g->line_count) {
107
+ // Before C23, `;` is required between a label and the block end.
108
+ w(g, "~M;~N");
109
+ }
110
+ w(g, "~-~M}~N");
111
+ }
112
+
113
+ static void write_savecursor(struct generator * g, struct node * p,
114
+ struct str * savevar) {
115
+ g->B[0] = str_data(savevar);
116
+ g->S[1] = "";
117
+ if (p->mode != m_forward) g->S[1] = "z->l - ";
118
+ writef(g, "~Mint ~B0 = ~S1z->c;~N", p);
119
+ }
120
+
121
+ static void append_restore_string(struct node * p, struct str * out, struct str * savevar) {
122
+ str_append_string(out, "z->c = ");
123
+ if (p->mode != m_forward) str_append_string(out, "z->l - ");
124
+ str_append(out, savevar);
125
+ str_append_ch(out, ';');
126
+ }
127
+
128
+ static void write_restorecursor(struct generator * g, struct node * p, struct str * savevar) {
129
+ write_margin(g);
130
+ append_restore_string(p, g->outbuf, savevar);
131
+ write_newline(g);
132
+ }
133
+
134
+ static void winc(struct generator * g, struct node * p) { /* increment c */
135
+ write_string(g, p->mode == m_forward ? "z->c++;" :
136
+ "z->c--;");
137
+ }
138
+
139
+ static void wsetl(struct generator * g, int n) {
140
+ g->margin--;
141
+ write_margin(g);
142
+ write_string(g, "lab");
143
+ write_int(g, n);
144
+ write_char(g, ':');
145
+ write_newline(g);
146
+ g->line_labelled = g->line_count;
147
+ g->margin++;
148
+ }
149
+
150
+ static void write_failure(struct generator * g) {
151
+ if (str_len(g->failure_str) != 0) {
152
+ write_string(g, "{ ");
153
+ write_str(g, g->failure_str);
154
+ write_char(g, ' ');
155
+ }
156
+ switch (g->failure_label) {
157
+ case x_return:
158
+ write_string(g, "return 0;");
159
+ break;
160
+ default:
161
+ write_string(g, "goto lab");
162
+ write_int(g, g->failure_label);
163
+ write_char(g, ';');
164
+ g->label_used = 1;
165
+ }
166
+ if (str_len(g->failure_str) != 0) write_string(g, " }");
167
+ }
168
+
169
+ /* if at limit fail */
170
+ static void write_check_limit(struct generator * g, struct node * p) {
171
+ if (p->mode == m_forward) {
172
+ write_string(g, "if (z->c >= z->l) ");
173
+ } else {
174
+ write_string(g, "if (z->c <= z->lb) ");
175
+ }
176
+ write_failure(g);
177
+ }
178
+
179
+ static void write_data_address(struct generator * g, struct node * p) {
180
+ symbol * b = p->literalstring;
181
+ if (b != NULL) {
182
+ write_int(g, SIZE(b)); w(g, ", ");
183
+ wlitref(g, b);
184
+ } else {
185
+ write_varref(g, p->name);
186
+ }
187
+ }
188
+
189
+ /* Formatted write. */
190
+ static void writef(struct generator * g, const char * input, struct node * p) {
191
+ int i = 0;
192
+
193
+ while (input[i]) {
194
+ int ch = input[i++];
195
+ if (ch != '~') {
196
+ write_char(g, ch);
197
+ continue;
198
+ }
199
+ ch = input[i++];
200
+ switch (ch) {
201
+ case '~': write_char(g, '~'); continue;
202
+ case 'f': write_failure(g); continue;
203
+ case 'M': write_margin(g); continue;
204
+ case 'N': write_newline(g); continue;
205
+ case '{': write_block_start(g); continue;
206
+ case '}': write_block_end(g); continue;
207
+ case 'S': {
208
+ int j = input[i++] - '0';
209
+ if (j < 0 || j > (int)(sizeof(g->S) / sizeof(g->S[0]))) {
210
+ printf("Invalid escape sequence ~%c%c in writef(g, \"%s\", p)\n",
211
+ ch, input[i - 1], input);
212
+ exit(1);
213
+ }
214
+ write_string(g, g->S[j]);
215
+ continue;
216
+ }
217
+ case 'B': {
218
+ int j = input[i++] - '0';
219
+ if (j < 0 || j > (int)(sizeof(g->B) / sizeof(g->B[0])))
220
+ goto invalid_escape2;
221
+ write_s(g, g->B[j]);
222
+ continue;
223
+ }
224
+ case 'F': { // Among function dispatcher.
225
+ struct among * x = p->among;
226
+ if (x->function_count == 0) {
227
+ write_char(g, '0');
228
+ continue;
229
+ }
230
+
231
+ if (x->function_count == 1) {
232
+ // Only one different function used in this among.
233
+ struct amongvec * v = x->b;
234
+ for (int j = 0; j < x->literalstring_count; j++) {
235
+ if (v[j].function) {
236
+ write_varref(g, v[j].function);
237
+ goto continue_outer_loop;
238
+ }
239
+ }
240
+ fprintf(stderr, "function_count == 1 but no among functions\n");
241
+ exit(1);
242
+ continue_outer_loop:
243
+ continue;
244
+ }
245
+
246
+ w(g, "af_");
247
+ write_int(g, x->number);
248
+ continue;
249
+ }
250
+ case 'I':
251
+ case 'J':
252
+ case 'c': {
253
+ int j = input[i++] - '0';
254
+ if (j < 0 || j > (int)(sizeof(g->I) / sizeof(g->I[0])))
255
+ goto invalid_escape2;
256
+ if (ch == 'I')
257
+ write_int(g, g->I[j]);
258
+ else if (ch == 'J')
259
+ wi3(g, g->I[j]);
260
+ else
261
+ wlitch(g, g->I[j]);
262
+ continue;
263
+ }
264
+ case 'V':
265
+ write_varref(g, p->name);
266
+ continue;
267
+ case 'W':
268
+ write_varname(g, p->name);
269
+ continue;
270
+ case 'L':
271
+ wlitref(g, p->literalstring);
272
+ continue;
273
+ case 's':
274
+ write_int(g, SIZE(p->literalstring));
275
+ continue;
276
+ case 'a': write_data_address(g, p); continue;
277
+ case '+': g->margin++; continue;
278
+ case '-': g->margin--; continue;
279
+ case 'n': write_s(g, g->options->name); continue;
280
+ case '$': /* insert_s, insert_v etc */
281
+ write_char(g, p->literalstring == NULL ? 'v' : 's');
282
+ continue;
283
+ case 'p':
284
+ if (g->options->externals_prefix)
285
+ write_string(g, g->options->externals_prefix);
286
+ continue;
287
+ default:
288
+ printf("Invalid escape sequence ~%c in writef(g, \"%s\", p)\n",
289
+ ch, input);
290
+ exit(1);
291
+ invalid_escape2:
292
+ printf("Invalid escape sequence ~%c%c in writef(g, \"%s\", p)\n",
293
+ ch, input[i - 1], input);
294
+ exit(1);
295
+ }
296
+ }
297
+ }
298
+
299
+ static void w(struct generator * g, const char * s) {
300
+ writef(g, s, NULL);
301
+ }
302
+
303
+ /* Write out a statement with additional code to propagate a negative return
304
+ * value which indicates an error.
305
+ *
306
+ * When generating C++, such errors throw exceptions so we don't need to
307
+ * check for negative return values.
308
+ */
309
+ static void write_propagating_error(struct generator * g, const char * s,
310
+ int keep_c,
311
+ struct node *p) {
312
+ if (g->options->target_lang == LANG_CPLUSPLUS) {
313
+ if (keep_c) {
314
+ write_block_start(g);
315
+ w(g, "~Mint saved_c = z->c;~N");
316
+ }
317
+ write_margin(g);
318
+ writef(g, s, p);
319
+ w(g, ";~N");
320
+ if (keep_c) {
321
+ w(g, "~Mz->c = saved_c;~N");
322
+ write_block_end(g);
323
+ }
324
+ } else {
325
+ write_block_start(g);
326
+ if (keep_c) {
327
+ w(g, "~Mint saved_c = z->c;~N");
328
+ }
329
+ w(g, "~Mint ret = ");
330
+ writef(g, s, p);
331
+ w(g, ";~N");
332
+ if (keep_c) {
333
+ w(g, "~Mz->c = saved_c;~N");
334
+ }
335
+ w(g, "~Mif (ret < 0) return ret;~N");
336
+ write_block_end(g);
337
+ }
338
+ }
339
+
340
+ static void generate_AE(struct generator * g, struct node * p) {
341
+ const char * s;
342
+ switch (p->type) {
343
+ case c_name:
344
+ write_varref(g, p->name);
345
+ break;
346
+ case c_number:
347
+ write_int(g, p->number);
348
+ break;
349
+ case c_maxint:
350
+ write_string(g, "INT_MAX");
351
+ break;
352
+ case c_minint:
353
+ write_string(g, "INT_MIN");
354
+ break;
355
+ case c_neg:
356
+ write_char(g, '-');
357
+ generate_AE(g, p->right);
358
+ break;
359
+ case c_multiply:
360
+ s = " * ";
361
+ goto label0;
362
+ case c_divide:
363
+ s = " / ";
364
+ goto label0;
365
+ case c_plus:
366
+ s = " + ";
367
+ goto label0;
368
+ case c_minus:
369
+ s = " - ";
370
+ label0:
371
+ write_char(g, '(');
372
+ generate_AE(g, p->left);
373
+ write_string(g, s);
374
+ generate_AE(g, p->right);
375
+ write_char(g, ')');
376
+ break;
377
+ case c_cursor:
378
+ w(g, "z->c");
379
+ break;
380
+ case c_limit:
381
+ w(g, p->mode == m_forward ? "z->l" : "z->lb");
382
+ break;
383
+ case c_len:
384
+ if (g->options->encoding == ENC_UTF8) {
385
+ w(g, "len_utf8(z->p)");
386
+ break;
387
+ }
388
+ /* FALLTHRU */
389
+ case c_size:
390
+ w(g, "SIZE(z->p)");
391
+ break;
392
+ case c_lenof:
393
+ if (g->options->encoding == ENC_UTF8) {
394
+ writef(g, "len_utf8(~V)", p);
395
+ break;
396
+ }
397
+ /* FALLTHRU */
398
+ case c_sizeof:
399
+ writef(g, "SIZE(~V)", p);
400
+ break;
401
+ }
402
+ }
403
+
404
+ static void generate_bra(struct generator * g, struct node * p) {
405
+ write_comment(g, p);
406
+ p = p->left;
407
+ while (p) {
408
+ generate(g, p);
409
+ p = p->right;
410
+ }
411
+ }
412
+
413
+ static void generate_and(struct generator * g, struct node * p) {
414
+ struct str * savevar = NULL;
415
+ if (K_needed_for_and(p->left)) {
416
+ savevar = vars_newname(g);
417
+ }
418
+
419
+ write_comment(g, p);
420
+
421
+ if (savevar) {
422
+ write_block_start(g);
423
+ write_savecursor(g, p, savevar);
424
+ }
425
+
426
+ p = p->left;
427
+ while (p) {
428
+ generate(g, p);
429
+ if (savevar && p->right != NULL) write_restorecursor(g, p, savevar);
430
+ p = p->right;
431
+ }
432
+
433
+ if (savevar) {
434
+ write_block_end(g);
435
+ str_delete(savevar);
436
+ }
437
+ }
438
+
439
+ static void generate_or(struct generator * g, struct node * p) {
440
+ struct str * savevar = NULL;
441
+ if (K_needed_for_or(p->left)) {
442
+ savevar = vars_newname(g);
443
+ }
444
+
445
+ int used = g->label_used;
446
+ int a0 = g->failure_label;
447
+ struct str * a1 = str_copy(g->failure_str);
448
+
449
+ write_comment(g, p);
450
+ w(g, "~Mdo {~N~+");
451
+
452
+ if (savevar) {
453
+ write_savecursor(g, p, savevar);
454
+ }
455
+
456
+ p = p->left;
457
+ str_clear(g->failure_str);
458
+
459
+ if (p == NULL) {
460
+ /* p should never be NULL after an or: there should be at least two
461
+ * sub nodes. */
462
+ fprintf(stderr, "Error: \"or\" node without children nodes.");
463
+ exit(1);
464
+ }
465
+ while (p->right != NULL) {
466
+ int label = new_label(g);
467
+ g->failure_label = label;
468
+ g->label_used = 0;
469
+ generate(g, p);
470
+ w(g, "~Mbreak;~N");
471
+
472
+ if (g->label_used)
473
+ wsetl(g, g->failure_label);
474
+ if (savevar && K_needed_node_on_f(p)) {
475
+ write_restorecursor(g, p, savevar);
476
+ }
477
+ p = p->right;
478
+ }
479
+
480
+ g->label_used = used;
481
+ g->failure_label = a0;
482
+ str_delete(g->failure_str);
483
+ g->failure_str = a1;
484
+
485
+ generate(g, p);
486
+
487
+ write_block_end(g);
488
+ if (str_back(g->outbuf) == '\n') {
489
+ str_pop(g->outbuf);
490
+ }
491
+ w(g, " while (0);~N");
492
+
493
+ if (savevar) {
494
+ str_delete(savevar);
495
+ }
496
+ }
497
+
498
+ static void generate_backwards(struct generator * g, struct node * p) {
499
+ write_comment(g, p);
500
+ writef(g, "~Mz->lb = z->c; z->c = z->l;~N", p);
501
+ generate(g, p->left);
502
+ w(g, "~Mz->c = z->lb;~N");
503
+ }
504
+
505
+ static void generate_not(struct generator * g, struct node * p) {
506
+ struct str * savevar = NULL;
507
+ if (K_needed_node_on_f(p->left)) {
508
+ savevar = vars_newname(g);
509
+ }
510
+
511
+ int used = g->label_used;
512
+ int a0 = g->failure_label;
513
+ struct str * a1 = str_copy(g->failure_str);
514
+
515
+ write_comment(g, p);
516
+ if (savevar) {
517
+ write_block_start(g);
518
+ write_savecursor(g, p, savevar);
519
+ }
520
+
521
+ int label = new_label(g);
522
+ g->failure_label = label;
523
+ str_clear(g->failure_str);
524
+ g->label_used = 0;
525
+ generate(g, p->left);
526
+
527
+ int l = g->failure_label;
528
+ int u = g->label_used;
529
+
530
+ g->label_used = used;
531
+ g->failure_label = a0;
532
+ str_delete(g->failure_str);
533
+ g->failure_str = a1;
534
+
535
+ writef(g, "~M~f~N", p);
536
+ if (u)
537
+ wsetl(g, l);
538
+
539
+ if (savevar) {
540
+ write_restorecursor(g, p, savevar);
541
+ write_block_end(g);
542
+ str_delete(savevar);
543
+ }
544
+ }
545
+
546
+ static void generate_try(struct generator * g, struct node * p) {
547
+ struct str * savevar = NULL;
548
+ if (K_needed(p->left)) {
549
+ savevar = vars_newname(g);
550
+ }
551
+
552
+ write_comment(g, p);
553
+ if (savevar) {
554
+ write_block_start(g);
555
+ write_savecursor(g, p, savevar);
556
+ }
557
+
558
+ int label = new_label(g);
559
+ g->failure_label = label;
560
+ str_clear(g->failure_str);
561
+ g->label_used = 0;
562
+ if (savevar) {
563
+ append_restore_string(p, g->failure_str, savevar);
564
+ }
565
+
566
+ generate(g, p->left);
567
+
568
+ if (g->label_used)
569
+ wsetl(g, g->failure_label);
570
+
571
+ if (savevar) {
572
+ write_block_end(g);
573
+ str_delete(savevar);
574
+ }
575
+ }
576
+
577
+ static void generate_set(struct generator * g, struct node * p) {
578
+ write_comment(g, p);
579
+ if (g->options->target_lang == LANG_CPLUSPLUS) {
580
+ writef(g, "~M~V = true;~N", p);
581
+ } else {
582
+ writef(g, "~M~V = 1;~N", p);
583
+ }
584
+ }
585
+
586
+ static void generate_unset(struct generator * g, struct node * p) {
587
+ write_comment(g, p);
588
+ if (g->options->target_lang == LANG_CPLUSPLUS) {
589
+ writef(g, "~M~V = false;~N", p);
590
+ } else {
591
+ writef(g, "~M~V = 0;~N", p);
592
+ }
593
+ }
594
+
595
+ static void generate_fail(struct generator * g, struct node * p) {
596
+ write_comment(g, p);
597
+ generate(g, p->left);
598
+ writef(g, "~M~f~N", p);
599
+ }
600
+
601
+ /* generate_test() also implements 'reverse' */
602
+ static void generate_test(struct generator * g, struct node * p) {
603
+ struct str * savevar = NULL;
604
+ if (K_needed(p->left)) {
605
+ savevar = vars_newname(g);
606
+ }
607
+
608
+ write_comment(g, p);
609
+
610
+ if (savevar) {
611
+ write_block_start(g);
612
+ write_savecursor(g, p, savevar);
613
+ }
614
+
615
+ generate(g, p->left);
616
+
617
+ if (savevar) {
618
+ write_restorecursor(g, p, savevar);
619
+ write_block_end(g);
620
+ str_delete(savevar);
621
+ }
622
+ }
623
+
624
+ static void generate_do(struct generator * g, struct node * p) {
625
+ struct str * savevar = NULL;
626
+ if (K_needed(p->left)) {
627
+ savevar = vars_newname(g);
628
+ }
629
+
630
+ write_comment(g, p);
631
+ if (savevar) {
632
+ write_block_start(g);
633
+ write_savecursor(g, p, savevar);
634
+ }
635
+
636
+ if (p->left->type == c_call) {
637
+ /* Optimise do <call> */
638
+ write_comment(g, p->left);
639
+ write_propagating_error(g, "~V(z)", false, p->left);
640
+ } else {
641
+ int label = new_label(g);
642
+ g->failure_label = label;
643
+ g->label_used = 0;
644
+ str_clear(g->failure_str);
645
+
646
+ generate(g, p->left);
647
+
648
+ if (g->label_used)
649
+ wsetl(g, g->failure_label);
650
+ }
651
+
652
+ if (savevar) {
653
+ write_restorecursor(g, p, savevar);
654
+ write_block_end(g);
655
+ str_delete(savevar);
656
+ }
657
+ }
658
+
659
+ static void generate_next(struct generator * g, struct node * p) {
660
+ write_comment(g, p);
661
+ if (g->options->encoding == ENC_UTF8) {
662
+ if (p->mode == m_forward)
663
+ w(g, "~{~Mint ret = skip_utf8(z->p, z->c, z->l, 1");
664
+ else
665
+ w(g, "~{~Mint ret = skip_b_utf8(z->p, z->c, z->lb, 1");
666
+ writef(g, ");~N"
667
+ "~Mif (ret < 0) ~f~N"
668
+ "~Mz->c = ret;~N"
669
+ "~}", p);
670
+ } else {
671
+ write_margin(g);
672
+ write_check_limit(g, p);
673
+ write_newline(g);
674
+ write_margin(g);
675
+ winc(g, p);
676
+ write_newline(g);
677
+ }
678
+ }
679
+
680
+ static void generate_GO_grouping(struct generator * g, struct node * p, int is_goto, int complement) {
681
+ write_comment(g, p);
682
+
683
+ struct grouping * q = p->name->grouping;
684
+ g->S[0] = p->mode == m_forward ? "" : "_b";
685
+ g->S[1] = complement ? "in" : "out";
686
+ g->S[2] = g->options->encoding == ENC_UTF8 ? "_U" : "";
687
+ g->I[0] = q->smallest_ch;
688
+ g->I[1] = q->largest_ch;
689
+ if (is_goto) {
690
+ writef(g, "~Mif (~S1_grouping~S0~S2(z, ~V, ~I0, ~I1, 1) < 0) ~f~N", p);
691
+ } else {
692
+ writef(g, "~{"
693
+ "~Mint ret = ~S1_grouping~S0~S2(z, ~V, ~I0, ~I1, 1);~N"
694
+ "~Mif (ret < 0) ~f~N", p);
695
+
696
+ if (p->mode == m_forward)
697
+ w(g, "~Mz->c += ret;~N");
698
+ else
699
+ w(g, "~Mz->c -= ret;~N");
700
+ w(g, "~}");
701
+ }
702
+ }
703
+
704
+ static void generate_GO(struct generator * g, struct node * p, int is_goto) {
705
+ write_comment(g, p);
706
+
707
+ int used = g->label_used;
708
+ int a0 = g->failure_label;
709
+ struct str * a1 = str_copy(g->failure_str);
710
+
711
+ w(g, "~Mwhile (1) {~N~+");
712
+
713
+ struct str * savevar = NULL;
714
+ if (is_goto || repeat_restore(p->left)) {
715
+ savevar = vars_newname(g);
716
+ write_savecursor(g, p, savevar);
717
+ }
718
+
719
+ int label = new_label(g);
720
+ g->failure_label = label;
721
+ g->label_used = 0;
722
+ str_clear(g->failure_str);
723
+ generate(g, p->left);
724
+
725
+ /* include for goto; omit for gopast */
726
+ if (is_goto) write_restorecursor(g, p, savevar);
727
+ w(g, "~Mbreak;~N");
728
+
729
+ if (g->label_used)
730
+ wsetl(g, g->failure_label);
731
+ if (savevar) {
732
+ write_restorecursor(g, p, savevar);
733
+ str_delete(savevar);
734
+ }
735
+
736
+ g->label_used = used;
737
+ g->failure_label = a0;
738
+ str_delete(g->failure_str);
739
+ g->failure_str = a1;
740
+
741
+ generate_next(g, p);
742
+
743
+ w(g, "~}");
744
+ }
745
+
746
+ static void generate_loop(struct generator * g, struct node * p) {
747
+ write_comment(g, p);
748
+ if (g->options->target_lang == LANG_C) {
749
+ w(g, "~{~Mint i; for (i = ");
750
+ } else {
751
+ w(g, "~Mfor (int i = ");
752
+ }
753
+ generate_AE(g, p->AE);
754
+ writef(g, "; i > 0; i--) {~N~+", p);
755
+
756
+ generate(g, p->left);
757
+
758
+ w(g, "~}");
759
+ if (g->options->target_lang == LANG_C) {
760
+ w(g, "~}");
761
+ }
762
+ }
763
+
764
+ static void generate_repeat_or_atleast(struct generator * g, struct node * p, struct str * loopvar) {
765
+ writef(g, "~Mwhile (1) {~+~N", p);
766
+
767
+ struct str * savevar = NULL;
768
+ if (repeat_restore(p->left)) {
769
+ savevar = vars_newname(g);
770
+ write_savecursor(g, p, savevar);
771
+ }
772
+
773
+ int label = new_label(g);
774
+ g->failure_label = label;
775
+ g->label_used = 0;
776
+ str_clear(g->failure_str);
777
+
778
+ generate(g, p->left);
779
+
780
+ if (loopvar != NULL) {
781
+ g->B[0] = str_data(loopvar);
782
+ w(g, "~M~B0--;~N");
783
+ }
784
+
785
+ w(g, "~Mcontinue;~N");
786
+
787
+ if (g->label_used)
788
+ wsetl(g, g->failure_label);
789
+
790
+ if (savevar) {
791
+ write_restorecursor(g, p, savevar);
792
+ str_delete(savevar);
793
+ }
794
+
795
+ w(g, "~Mbreak;~N~}");
796
+ }
797
+
798
+ static void generate_repeat(struct generator * g, struct node * p) {
799
+ write_comment(g, p);
800
+ generate_repeat_or_atleast(g, p, NULL);
801
+ }
802
+
803
+ static void generate_atleast(struct generator * g, struct node * p) {
804
+ write_comment(g, p);
805
+
806
+ struct str * loopvar = vars_newname(g);
807
+ g->B[0] = str_data(loopvar);
808
+ w(g, "~{~Mint ~B0 = ");
809
+ generate_AE(g, p->AE);
810
+ w(g, ";~N");
811
+ {
812
+ int used = g->label_used;
813
+ int a0 = g->failure_label;
814
+ struct str * a1 = str_copy(g->failure_str);
815
+
816
+ generate_repeat_or_atleast(g, p, loopvar);
817
+
818
+ g->label_used = used;
819
+ g->failure_label = a0;
820
+ str_delete(g->failure_str);
821
+ g->failure_str = a1;
822
+ }
823
+ g->B[0] = str_data(loopvar);
824
+ writef(g, "~Mif (~B0 > 0) ~f~N", p);
825
+ w(g, "~}");
826
+ str_delete(loopvar);
827
+ }
828
+
829
+ static void generate_tomark(struct generator * g, struct node * p) {
830
+ write_comment(g, p);
831
+ g->S[0] = p->mode == m_forward ? ">" : "<";
832
+
833
+ w(g, "~Mif (z->c ~S0 "); generate_AE(g, p->AE); writef(g, ") ~f~N", p);
834
+ w(g, "~Mz->c = "); generate_AE(g, p->AE); writef(g, ";~N", p);
835
+ }
836
+
837
+ static void generate_hop(struct generator * g, struct node * p) {
838
+ write_comment(g, p);
839
+ if (g->options->encoding == ENC_UTF8) {
840
+ g->S[0] = p->mode == m_forward ? "" : "_b";
841
+ g->S[1] = p->mode == m_forward ? "z->l" : "z->lb";
842
+ w(g, "~{");
843
+ if (p->AE->type == c_number) {
844
+ // Constant distance hop.
845
+ //
846
+ // No need to check for negative hop as that's converted to false by
847
+ // the analyser.
848
+ g->I[0] = p->AE->number;
849
+ w(g, "~Mint ret = skip~S0_utf8(z->p, z->c, ~S1, ~I0);~N");
850
+ } else {
851
+ w(g, "~Mint ae = ");
852
+ generate_AE(g, p->AE);
853
+ w(g, ";~N");
854
+ w(g, "~Mint ret = ae >= 0 ? skip~S0_utf8(z->p, z->c, ~S1, ae) : -1;~N");
855
+ }
856
+ w(g, "~Mif (ret < 0) ~f~N");
857
+ w(g, "~Mz->c = ret;~N");
858
+ w(g, "~}");
859
+ } else {
860
+ // Fixed-width characters.
861
+ g->S[0] = p->mode == m_forward ? "+" : "-";
862
+ if (p->AE->type == c_number) {
863
+ // Constant distance hop.
864
+ //
865
+ // No need to check for negative hop as that's converted to false by
866
+ // the analyser.
867
+ g->I[0] = p->AE->number;
868
+ if (p->mode == m_forward) {
869
+ writef(g, "~Mif (z->c ~S0 ~I0 > z->l) ~f~N", p);
870
+ } else {
871
+ writef(g, "~Mif (z->c ~S0 ~I0 < z->lb) ~f~N", p);
872
+ }
873
+ writef(g, "~Mz->c ~S0= ~I0;~N", p);
874
+ } else {
875
+ w(g, "~{~Mint ret = z->c ~S0 ");
876
+ generate_AE(g, p->AE);
877
+ writef(g, ";~N", p);
878
+ if (p->mode == m_forward) {
879
+ writef(g, "~Mif (ret > z->l || ret < z->c) ~f~N", p);
880
+ } else {
881
+ writef(g, "~Mif (ret < z->lb || ret > z->c) ~f~N", p);
882
+ }
883
+ writef(g, "~Mz->c = ret;~N"
884
+ "~}", p);
885
+ }
886
+ }
887
+ }
888
+
889
+ static void generate_tolimit(struct generator * g, struct node * p) {
890
+ write_comment(g, p);
891
+ g->S[0] = p->mode == m_forward ? "" : "b";
892
+ writef(g, "~Mz->c = z->l~S0;~N", p);
893
+ }
894
+
895
+ static void generate_leftslice(struct generator * g, struct node * p) {
896
+ write_comment(g, p);
897
+ g->S[0] = p->mode == m_forward ? "bra" : "ket";
898
+ writef(g, "~Mz->~S0 = z->c;~N", p);
899
+ }
900
+
901
+ static void generate_rightslice(struct generator * g, struct node * p) {
902
+ write_comment(g, p);
903
+ g->S[0] = p->mode == m_forward ? "ket" : "bra";
904
+ writef(g, "~Mz->~S0 = z->c;~N", p);
905
+ }
906
+
907
+ static void generate_assignto(struct generator * g, struct node * p) {
908
+ write_comment(g, p);
909
+ write_propagating_error(g, "assign_to(z, &~V)", false, p);
910
+ }
911
+
912
+ static void generate_sliceto(struct generator * g, struct node * p) {
913
+ write_comment(g, p);
914
+ write_propagating_error(g, "slice_to(z, &~V)", false, p);
915
+ }
916
+
917
+ static void generate_insert(struct generator * g, struct node * p, int style) {
918
+ write_comment(g, p);
919
+ int keep_c = style == c_attach;
920
+ if (p->mode == m_backward) keep_c = !keep_c;
921
+ write_propagating_error(g, "insert_~$(z, z->c, z->c, ~a)", keep_c, p);
922
+ }
923
+
924
+ static void generate_stringassign(struct generator * g, struct node * p) {
925
+ write_comment(g, p);
926
+ if (p->mode == m_forward) {
927
+ /* like 'attach' */
928
+ write_propagating_error(g, "insert_~$(z, z->c, z->l, ~a)", true, p);
929
+ } else {
930
+ write_propagating_error(g, "insert_~$(z, z->lb, z->c, ~a)", false, p);
931
+ }
932
+ }
933
+
934
+ static void generate_slicefrom(struct generator * g, struct node * p) {
935
+ write_comment(g, p);
936
+ if (p->literalstring && SIZE(p->literalstring) == 0) {
937
+ write_propagating_error(g, "slice_del(z)", false, p);
938
+ return;
939
+ }
940
+ write_propagating_error(g, "slice_from_~$(z, ~a)", false, p);
941
+ }
942
+
943
+ static void generate_setlimit(struct generator * g, struct node * p) {
944
+ write_comment(g, p);
945
+ struct str * varname = vars_newname(g);
946
+
947
+ bool extra_block = false;
948
+ if (p->left && p->left->type == c_tomark) {
949
+ /* Special case for:
950
+ *
951
+ * setlimit tomark AE for C
952
+ *
953
+ * All uses of setlimit in the current stemmers we ship follow this
954
+ * pattern, and by special-casing we can avoid having to save and
955
+ * restore c.
956
+ */
957
+ struct node * q = p->left;
958
+ write_comment(g, q);
959
+ assert(q->right == NULL);
960
+
961
+ g->B[0] = str_data(varname);
962
+ writef(g, "~{~Mint ~B0;~N", p);
963
+
964
+ g->S[0] = q->mode == m_forward ? ">" : "<";
965
+ w(g, "~Mif (z->c ~S0 "); generate_AE(g, q->AE); writef(g, ") ~f~N", q);
966
+
967
+ g->B[0] = str_data(varname);
968
+ if (p->mode == m_forward) {
969
+ w(g, "~M~B0 = z->l; z->l = ");
970
+ generate_AE(g, q->AE);
971
+ w(g, "; ~B0 -= z->l;~N");
972
+ } else {
973
+ w(g, "~M~B0 = z->lb; z->lb = ");
974
+ generate_AE(g, q->AE);
975
+ w(g, ";~N");
976
+ }
977
+
978
+ if (p->mode == m_forward) {
979
+ str_assign(g->failure_str, "z->l += ");
980
+ str_append(g->failure_str, varname);
981
+ str_append_ch(g->failure_str, ';');
982
+ } else {
983
+ str_assign(g->failure_str, "z->lb = ");
984
+ str_append(g->failure_str, varname);
985
+ str_append_ch(g->failure_str, ';');
986
+ }
987
+ } else {
988
+ write_block_start(g);
989
+ extra_block = true;
990
+ struct str * savevar = vars_newname(g);
991
+ write_savecursor(g, p, savevar);
992
+
993
+ generate(g, p->left);
994
+
995
+ g->B[0] = str_data(varname);
996
+ if (p->mode == m_forward) {
997
+ w(g, "~{~Mint ~B0 = z->l - z->c; z->l = z->c;~N");
998
+ } else {
999
+ w(g, "~{~Mint ~B0 = z->lb; z->lb = z->c;~N");
1000
+ }
1001
+ write_restorecursor(g, p, savevar);
1002
+
1003
+ if (p->mode == m_forward) {
1004
+ str_assign(g->failure_str, "z->l += ");
1005
+ str_append(g->failure_str, varname);
1006
+ str_append_ch(g->failure_str, ';');
1007
+ } else {
1008
+ str_assign(g->failure_str, "z->lb = ");
1009
+ str_append(g->failure_str, varname);
1010
+ str_append_ch(g->failure_str, ';');
1011
+ }
1012
+ str_delete(savevar);
1013
+ }
1014
+
1015
+ generate(g, p->aux);
1016
+
1017
+ write_margin(g);
1018
+ write_str(g, g->failure_str);
1019
+ w(g, "~N"
1020
+ "~}");
1021
+ if (extra_block) {
1022
+ write_block_end(g);
1023
+ }
1024
+
1025
+ str_delete(varname);
1026
+ }
1027
+
1028
+ /* dollar sets snowball up to operate on a string variable as if it were the
1029
+ * current string */
1030
+ static void generate_dollar(struct generator * g, struct node * p) {
1031
+ write_comment(g, p);
1032
+
1033
+ int used = g->label_used;
1034
+ int a0 = g->failure_label;
1035
+ struct str * a1 = str_copy(g->failure_str);
1036
+ int label = new_label(g);
1037
+ g->failure_label = label;
1038
+ g->label_used = 0;
1039
+ str_clear(g->failure_str);
1040
+
1041
+ struct str * savevar = vars_newname(g);
1042
+ g->B[0] = str_data(savevar);
1043
+
1044
+ // We only want to save and restore SN_env, not the variables.
1045
+ writef(g, "~{~Mstruct SN_env en~B0 = *z;~N", p);
1046
+ if (p->left->possible_signals == -1) {
1047
+ /* Assume failure. */
1048
+ w(g, "~Mint ~B0_f = 1;~N");
1049
+ }
1050
+ writef(g, "~Mz->p = ~V;~N"
1051
+ "~Mz->lb = z->c = 0;~N"
1052
+ "~Mz->l = SIZE(z->p);~N", p);
1053
+
1054
+ generate(g, p->left);
1055
+
1056
+ if (p->left->possible_signals == -1) {
1057
+ /* Mark success. */
1058
+ g->B[0] = str_data(savevar);
1059
+ w(g, "~M~B0_f = 0;~N");
1060
+ }
1061
+
1062
+ if (g->label_used)
1063
+ wsetl(g, g->failure_label);
1064
+
1065
+ g->label_used = used;
1066
+ g->failure_label = a0;
1067
+ str_delete(g->failure_str);
1068
+ g->failure_str = a1;
1069
+
1070
+ g->B[0] = str_data(savevar);
1071
+ writef(g, "~M~V = z->p;~N"
1072
+ "~M*z = en~B0;~N", p);
1073
+
1074
+ if (p->left->possible_signals == 0) {
1075
+ // p->left always signals f.
1076
+ w(g, "~M~f~N");
1077
+ } else if (p->left->possible_signals == -1) {
1078
+ w(g, "~Mif (~B0_f) ~f~N");
1079
+ }
1080
+ w(g, "~}");
1081
+
1082
+ str_delete(savevar);
1083
+ }
1084
+
1085
+ static void generate_integer_assign(struct generator * g, struct node * p, const char * s) {
1086
+ write_comment(g, p);
1087
+ g->S[0] = s;
1088
+ writef(g, "~M~V ~S0 ", p);
1089
+ generate_AE(g, p->AE);
1090
+ w(g, ";~N");
1091
+ }
1092
+
1093
+ static void generate_integer_test(struct generator * g, struct node * p) {
1094
+ write_comment(g, p);
1095
+ int relop = p->type;
1096
+ int optimise_to_return = tailcallable(g, p);
1097
+ if (optimise_to_return) {
1098
+ w(g, "~Mreturn ");
1099
+ p->right = NULL;
1100
+ } else {
1101
+ w(g, "~Mif (");
1102
+ // We want the inverse of the snowball test here.
1103
+ relop ^= 1;
1104
+ }
1105
+ generate_AE(g, p->left);
1106
+ write_relop(g, relop);
1107
+ generate_AE(g, p->AE);
1108
+ if (optimise_to_return) {
1109
+ writef(g, ";~N", p);
1110
+ } else {
1111
+ writef(g, ") ~f~N", p);
1112
+ }
1113
+ }
1114
+
1115
+ static void generate_call(struct generator * g, struct node * p) {
1116
+ int signals = p->name->definition->possible_signals;
1117
+ write_comment(g, p);
1118
+ if (tailcallable(g, p)) {
1119
+ /* Tail call. */
1120
+ writef(g, "~Mreturn ~V(z);~N", p);
1121
+ p->right = NULL;
1122
+ return;
1123
+ }
1124
+ if (just_return_on_fail(g) && signals == 0) {
1125
+ /* Always fails. */
1126
+ writef(g, "~Mreturn ~V(z);~N", p);
1127
+ return;
1128
+ }
1129
+ if (just_return_on_fail(g)) {
1130
+ write_block_start(g);
1131
+ writef(g, "~Mint ret = ~V(z);~N", p);
1132
+ if (g->options->target_lang == LANG_CPLUSPLUS) {
1133
+ writef(g, "~Mif (ret == 0) return ret;~N", p);
1134
+ } else {
1135
+ /* For C, we need to propagate both failures and runtime errors so
1136
+ * we do a combined test for better optimisation and clearer
1137
+ * generated code. */
1138
+ writef(g, "~Mif (ret <= 0) return ret;~N", p);
1139
+ }
1140
+ write_block_end(g);
1141
+ } else {
1142
+ if (signals == 1) {
1143
+ /* Always succeeds - just need to handle runtime errors. */
1144
+ write_propagating_error(g, "~V(z)", false, p);
1145
+ } else if (signals == 0) {
1146
+ /* Always fails. */
1147
+ write_propagating_error(g, "~V(z)", false, p);
1148
+ writef(g, "~M~f~N", p);
1149
+ } else {
1150
+ if (g->options->target_lang == LANG_CPLUSPLUS) {
1151
+ writef(g, "~Mif (!~V(z)) ~f~N", p);
1152
+ } else {
1153
+ write_block_start(g);
1154
+ writef(g, "~Mint ret = ~V(z);~N", p);
1155
+ writef(g, "~Mif (ret == 0) ~f~N", p);
1156
+ writef(g, "~Mif (ret < 0) return ret;~N", p);
1157
+ write_block_end(g);
1158
+ }
1159
+ }
1160
+ }
1161
+ }
1162
+
1163
+ static void generate_grouping(struct generator * g, struct node * p, int complement) {
1164
+ write_comment(g, p);
1165
+
1166
+ struct grouping * q = p->name->grouping;
1167
+ g->S[0] = p->mode == m_forward ? "" : "_b";
1168
+ g->S[1] = complement ? "out" : "in";
1169
+ g->S[2] = g->options->encoding == ENC_UTF8 ? "_U" : "";
1170
+ g->I[0] = q->smallest_ch;
1171
+ g->I[1] = q->largest_ch;
1172
+ if (tailcallable(g, p)) {
1173
+ writef(g, "~Mreturn !~S1_grouping~S0~S2(z, ~V, ~I0, ~I1, 0);~N", p);
1174
+ p->right = NULL;
1175
+ } else {
1176
+ writef(g, "~Mif (~S1_grouping~S0~S2(z, ~V, ~I0, ~I1, 0)) ~f~N", p);
1177
+ }
1178
+ }
1179
+
1180
+ static void generate_namedstring(struct generator * g, struct node * p) {
1181
+ write_comment(g, p);
1182
+ g->S[0] = p->mode == m_forward ? "" : "_b";
1183
+ if (tailcallable(g, p)) {
1184
+ writef(g, "~Mreturn eq_v~S0(z, ~V);~N", p);
1185
+ p->right = NULL;
1186
+ } else {
1187
+ writef(g, "~Mif (!(eq_v~S0(z, ~V))) ~f~N", p);
1188
+ }
1189
+ }
1190
+
1191
+ static void generate_literalstring(struct generator * g, struct node * p) {
1192
+ write_comment(g, p);
1193
+ symbol * b = p->literalstring;
1194
+ if (SIZE(b) == 1) {
1195
+ /* It's quite common to compare with a single character literal string,
1196
+ * so just inline the simpler code for this case rather than making a
1197
+ * function call. In UTF-8 mode, only do this for the ASCII subset,
1198
+ * since multi-byte characters are more complex to test against.
1199
+ */
1200
+ if (g->options->encoding == ENC_UTF8 && *b >= 128) {
1201
+ printf("single byte %d\n", *b);
1202
+ exit(1);
1203
+ }
1204
+ g->I[0] = *b;
1205
+ if (p->mode == m_forward) {
1206
+ writef(g, "~Mif (z->c == z->l || z->p[z->c] != ~c0) ~f~N"
1207
+ "~Mz->c++;~N", p);
1208
+ } else {
1209
+ writef(g, "~Mif (z->c <= z->lb || z->p[z->c - 1] != ~c0) ~f~N"
1210
+ "~Mz->c--;~N", p);
1211
+ }
1212
+ return;
1213
+ }
1214
+
1215
+ g->S[0] = p->mode == m_forward ? "" : "_b";
1216
+ if (tailcallable(g, p)) {
1217
+ writef(g, "~Mreturn eq_s~S0(z, ~s, ~L);~N", p);
1218
+ p->right = NULL;
1219
+ } else {
1220
+ writef(g, "~Mif (!(eq_s~S0(z, ~s, ~L))) ~f~N", p);
1221
+ }
1222
+ }
1223
+
1224
+ static void generate_define(struct generator * g, struct node * p) {
1225
+ struct name * q = p->name;
1226
+
1227
+ write_newline(g);
1228
+ write_comment(g, p);
1229
+
1230
+ if (q->type == t_routine) {
1231
+ write_string(g, "static ");
1232
+ } else if (g->options->target_lang == LANG_C) {
1233
+ write_string(g, "extern ");
1234
+ }
1235
+ writef(g, "int ~V(struct SN_env * z) {~N~+", p);
1236
+
1237
+ if (q->amongvar_needed) {
1238
+ w(g, "~Mint among_var;~N");
1239
+ }
1240
+
1241
+ /* Declare localised variables. */
1242
+ for (struct name * name = g->analyser->names; name; name = name->next) {
1243
+ if (name->local_to == q) {
1244
+ switch (name->type) {
1245
+ case t_string:
1246
+ assert(0);
1247
+ break;
1248
+ case t_integer:
1249
+ w(g, "~Mint ");
1250
+ write_varname(g, name);
1251
+ w(g, ";~N");
1252
+ break;
1253
+ case t_boolean:
1254
+ if (g->options->target_lang == LANG_CPLUSPLUS) {
1255
+ w(g, "~Mbool ");
1256
+ } else {
1257
+ w(g, "~Mint ");
1258
+ }
1259
+ write_varname(g, name);
1260
+ w(g, ";~N");
1261
+ break;
1262
+ }
1263
+ }
1264
+ }
1265
+
1266
+ g->next_label = 0;
1267
+ g->var_number = 0;
1268
+
1269
+ str_clear(g->failure_str);
1270
+ g->failure_label = x_return;
1271
+ g->label_used = 0;
1272
+
1273
+ /* Generate function body. */
1274
+ generate(g, p->left);
1275
+ if (p->left->right) {
1276
+ assert(p->left->right->type == c_functionend);
1277
+ if (p->left->possible_signals) {
1278
+ generate(g, p->left->right);
1279
+ }
1280
+ }
1281
+ w(g, "~}");
1282
+ }
1283
+
1284
+ static void generate_functionend(struct generator * g, struct node * p) {
1285
+ (void)p;
1286
+ w(g, "~Mreturn 1;~N");
1287
+ }
1288
+
1289
+ static void generate_substring(struct generator * g, struct node * p) {
1290
+ write_comment(g, p);
1291
+
1292
+ struct among * x = p->among;
1293
+ int block = -1;
1294
+ unsigned int bitmap = 0;
1295
+ struct amongvec * among_cases = x->b;
1296
+ int empty_case = -1;
1297
+ int n_cases = 0;
1298
+ symbol cases[2];
1299
+ int shortest_size = x->shortest_size;
1300
+
1301
+ g->S[0] = p->mode == m_forward ? "" : "_b";
1302
+ g->I[0] = x->number;
1303
+ g->I[1] = x->literalstring_count;
1304
+
1305
+ /* In forward mode with non-ASCII UTF-8 characters, the first byte
1306
+ * of the string will often be the same, so instead look at the last
1307
+ * common byte position.
1308
+ *
1309
+ * In backward mode, we can't match if there are fewer characters before
1310
+ * the current position than the minimum length.
1311
+ */
1312
+ for (int c = 0; c < x->literalstring_count; ++c) {
1313
+ symbol ch;
1314
+ if (among_cases[c].size == 0) {
1315
+ empty_case = c;
1316
+ continue;
1317
+ }
1318
+ if (p->mode == m_forward) {
1319
+ ch = among_cases[c].b[shortest_size - 1];
1320
+ } else {
1321
+ ch = among_cases[c].b[among_cases[c].size - 1];
1322
+ }
1323
+ if (n_cases == 0) {
1324
+ block = ch >> 5;
1325
+ } else if (ch >> 5 != block) {
1326
+ block = -1;
1327
+ if (n_cases > 2) break;
1328
+ }
1329
+ if (block == -1) {
1330
+ if (n_cases > 0 && ch == cases[0]) continue;
1331
+ if (n_cases < 2) {
1332
+ cases[n_cases++] = ch;
1333
+ } else if (ch != cases[1]) {
1334
+ ++n_cases;
1335
+ break;
1336
+ }
1337
+ } else {
1338
+ if ((bitmap & (1u << (ch & 0x1f))) == 0) {
1339
+ bitmap |= 1u << (ch & 0x1f);
1340
+ if (n_cases < 2)
1341
+ cases[n_cases] = ch;
1342
+ ++n_cases;
1343
+ }
1344
+ }
1345
+ }
1346
+
1347
+ bool pre_check = (block != -1 || n_cases <= 2);
1348
+ if (g->options->coverage) {
1349
+ // Don't shortcut if generating coverage.
1350
+ pre_check = false;
1351
+ }
1352
+ if (pre_check) {
1353
+ char buf[64];
1354
+ g->I[2] = block;
1355
+ g->I[3] = bitmap;
1356
+ g->I[4] = shortest_size - 1;
1357
+ if (p->mode == m_forward) {
1358
+ checked_snprintf(buf, sizeof(buf),
1359
+ "z->p[z->c + %d]", shortest_size - 1);
1360
+ g->S[1] = buf;
1361
+ if (shortest_size == 1) {
1362
+ writef(g, "~Mif (z->c >= z->l", p);
1363
+ } else {
1364
+ writef(g, "~Mif (z->c + ~I4 >= z->l", p);
1365
+ }
1366
+ } else {
1367
+ g->S[1] = "z->p[z->c - 1]";
1368
+ if (shortest_size == 1) {
1369
+ writef(g, "~Mif (z->c <= z->lb", p);
1370
+ } else {
1371
+ writef(g, "~Mif (z->c - ~I4 <= z->lb", p);
1372
+ }
1373
+ }
1374
+ assert(n_cases > 0);
1375
+ if (n_cases == 1) {
1376
+ g->I[4] = cases[0];
1377
+ writef(g, " || ~S1 != ~I4", p);
1378
+ } else if (n_cases == 2) {
1379
+ g->I[4] = cases[0];
1380
+ g->I[5] = cases[1];
1381
+ writef(g, " || (~S1 != ~I4 && ~S1 != ~I5)", p);
1382
+ } else {
1383
+ writef(g, " || ~S1 >> 5 != ~I2 || !((~I3 >> (~S1 & 0x1f)) & 1)", p);
1384
+ }
1385
+ write_string(g, ") ");
1386
+ if (empty_case != -1 && !among_cases[empty_case].function) {
1387
+ /* If the among includes the ungated empty string, it can never
1388
+ * fail so not matching the bitmap means we match the empty string.
1389
+ */
1390
+ g->I[4] = among_cases[empty_case].result;
1391
+ writef(g, "among_var = ~I4; else~N", p);
1392
+ } else {
1393
+ writef(g, "~f~N", p);
1394
+ }
1395
+ } else {
1396
+ #ifdef OPTIMISATION_WARNINGS
1397
+ printf("Couldn't shortcut among %d\n", x->number);
1398
+ #endif
1399
+ }
1400
+
1401
+ if (x->amongvar_needed) {
1402
+ writef(g, "~Mamong_var = find_among~S0(z, a_~I0, ~I1, ~F);~N", p);
1403
+ if (!x->always_matches) {
1404
+ writef(g, "~Mif (!among_var) ~f~N", p);
1405
+ }
1406
+ return;
1407
+ }
1408
+
1409
+ if (pre_check && !x->function_count) {
1410
+ // If all cases are one symbol long (so one byte of UTF-8, one
1411
+ // character long in fixed-width encodings) then we don't need to call
1412
+ // the helper and can just inc/dec the cursor by 1.
1413
+ if (x->longest_size == 1 && !x->always_matches) {
1414
+ write_margin(g);
1415
+ winc(g, p);
1416
+ write_newline(g);
1417
+ // Suppress generating table for this among.
1418
+ x->used = false;
1419
+ return;
1420
+ }
1421
+ }
1422
+
1423
+ if (x->always_matches) {
1424
+ writef(g, "~Mfind_among~S0(z, a_~I0, ~I1, ~F);~N", p);
1425
+ } else if (x->command_count == 0 && tailcallable(g, p)) {
1426
+ writef(g, "~Mreturn find_among~S0(z, a_~I0, ~I1, ~F) != 0;~N", p);
1427
+ x->node->right = NULL;
1428
+ } else {
1429
+ writef(g, "~Mif (!find_among~S0(z, a_~I0, ~I1, ~F)) ~f~N", p);
1430
+ }
1431
+ }
1432
+
1433
+ static void generate_among(struct generator * g, struct node * p) {
1434
+ struct among * x = p->among;
1435
+
1436
+ if (x->substring == NULL) {
1437
+ generate_substring(g, p);
1438
+ } else {
1439
+ write_comment(g, p);
1440
+ }
1441
+
1442
+ if (x->command_count == 1 && x->nocommand_count == 0) {
1443
+ /* Only one outcome ("no match" already handled). */
1444
+ generate(g, x->commands[0]);
1445
+ } else if (x->command_count > 0) {
1446
+ writef(g, "~Mswitch (among_var) {~N~+", p);
1447
+ for (int i = 1; i <= x->command_count; i++) {
1448
+ g->I[0] = i;
1449
+ w(g, "~Mcase ~I0:~N~+");
1450
+ generate(g, x->commands[i - 1]);
1451
+ w(g, "~Mbreak;~N~-");
1452
+ }
1453
+ w(g, "~}");
1454
+ }
1455
+ }
1456
+
1457
+ static void generate_booltest(struct generator * g, struct node * p, int inverted) {
1458
+ write_comment(g, p);
1459
+ if (tailcallable(g, p)) {
1460
+ // Optimise at end of function.
1461
+ if (inverted) {
1462
+ writef(g, "~Mreturn !~V;~N", p);
1463
+ } else {
1464
+ writef(g, "~Mreturn ~V;~N", p);
1465
+ }
1466
+ p->right = NULL;
1467
+ return;
1468
+ }
1469
+ if (inverted) {
1470
+ writef(g, "~Mif (~V) ~f~N", p);
1471
+ } else {
1472
+ writef(g, "~Mif (!~V) ~f~N", p);
1473
+ }
1474
+ }
1475
+
1476
+ static void generate_false(struct generator * g, struct node * p) {
1477
+ write_comment(g, p);
1478
+ writef(g, "~M~f~N", p);
1479
+ }
1480
+
1481
+ static void generate_debug(struct generator * g, struct node * p) {
1482
+ write_comment(g, p);
1483
+ g->I[0] = g->debug_count++;
1484
+ g->I[1] = p->line_number;
1485
+ writef(g, "~Mdebug(z, ~I0, ~I1);~N", p);
1486
+ }
1487
+
1488
+ static void generate(struct generator * g, struct node * p) {
1489
+ int used = g->label_used;
1490
+ int a0 = g->failure_label;
1491
+ struct str * a1 = str_copy(g->failure_str);
1492
+
1493
+ switch (p->type) {
1494
+ case c_define: generate_define(g, p); break;
1495
+ case c_bra: generate_bra(g, p); break;
1496
+ case c_and: generate_and(g, p); break;
1497
+ case c_or: generate_or(g, p); break;
1498
+ case c_backwards: generate_backwards(g, p); break;
1499
+ case c_not: generate_not(g, p); break;
1500
+ case c_set: generate_set(g, p); break;
1501
+ case c_unset: generate_unset(g, p); break;
1502
+ case c_try: generate_try(g, p); break;
1503
+ case c_fail: generate_fail(g, p); break;
1504
+ case c_reverse:
1505
+ case c_test: generate_test(g, p); break;
1506
+ case c_do: generate_do(g, p); break;
1507
+ case c_goto: generate_GO(g, p, 1); break;
1508
+ case c_gopast: generate_GO(g, p, 0); break;
1509
+ case c_goto_grouping: generate_GO_grouping(g, p, 1, 0); break;
1510
+ case c_gopast_grouping:
1511
+ generate_GO_grouping(g, p, 0, 0); break;
1512
+ case c_goto_non: generate_GO_grouping(g, p, 1, 1); break;
1513
+ case c_gopast_non: generate_GO_grouping(g, p, 0, 1); break;
1514
+ case c_repeat: generate_repeat(g, p); break;
1515
+ case c_loop: generate_loop(g, p); break;
1516
+ case c_atleast: generate_atleast(g, p); break;
1517
+ case c_tomark: generate_tomark(g, p); break;
1518
+ case c_hop: generate_hop(g, p); break;
1519
+ case c_next: generate_next(g, p); break;
1520
+ case c_tolimit: generate_tolimit(g, p); break;
1521
+ case c_leftslice: generate_leftslice(g, p); break;
1522
+ case c_rightslice: generate_rightslice(g, p); break;
1523
+ case c_assignto: generate_assignto(g, p); break;
1524
+ case c_sliceto: generate_sliceto(g, p); break;
1525
+ case c_stringassign: generate_stringassign(g, p); break;
1526
+ case c_insert:
1527
+ case c_attach: generate_insert(g, p, p->type); break;
1528
+ case c_slicefrom: generate_slicefrom(g, p); break;
1529
+ case c_setlimit: generate_setlimit(g, p); break;
1530
+ case c_dollar: generate_dollar(g, p); break;
1531
+ case c_assign: generate_integer_assign(g, p, "="); break;
1532
+ case c_plusassign: generate_integer_assign(g, p, "+="); break;
1533
+ case c_minusassign: generate_integer_assign(g, p, "-="); break;
1534
+ case c_multiplyassign:generate_integer_assign(g, p, "*="); break;
1535
+ case c_divideassign: generate_integer_assign(g, p, "/="); break;
1536
+ case c_eq:
1537
+ case c_ne:
1538
+ case c_gt:
1539
+ case c_ge:
1540
+ case c_lt:
1541
+ case c_le:
1542
+ generate_integer_test(g, p);
1543
+ break;
1544
+ case c_call: generate_call(g, p); break;
1545
+ case c_grouping: generate_grouping(g, p, false); break;
1546
+ case c_non: generate_grouping(g, p, true); break;
1547
+ case c_name: generate_namedstring(g, p); break;
1548
+ case c_literalstring: generate_literalstring(g, p); break;
1549
+ case c_among: generate_among(g, p); break;
1550
+ case c_substring: generate_substring(g, p); break;
1551
+ case c_booltest: generate_booltest(g, p, false); break;
1552
+ case c_not_booltest: generate_booltest(g, p, true); break;
1553
+ case c_false: generate_false(g, p); break;
1554
+ case c_true: break;
1555
+ case c_debug: generate_debug(g, p); break;
1556
+ case c_functionend: generate_functionend(g, p); break;
1557
+ default: fprintf(stderr, "%d encountered\n", p->type);
1558
+ exit(1);
1559
+ }
1560
+
1561
+ if (g->failure_label != a0)
1562
+ g->label_used = used;
1563
+
1564
+ g->failure_label = a0;
1565
+ str_delete(g->failure_str);
1566
+ g->failure_str = a1;
1567
+ }
1568
+
1569
+ static void generate_head(struct generator * g) {
1570
+ struct options * o = g->options;
1571
+ if (o->cheader) {
1572
+ int quoted = (o->cheader[0] == '<' || o->cheader[0] == '"');
1573
+ w(g, "#include ");
1574
+ if (!quoted) write_char(g, '<');
1575
+ write_string(g, o->cheader);
1576
+ if (!quoted) write_char(g, '>');
1577
+ write_newline(g);
1578
+ write_newline(g);
1579
+ }
1580
+
1581
+ if (o->target_lang == LANG_CPLUSPLUS) {
1582
+ w(g, "#define SNOWBALL_RUNTIME_THROW_EXCEPTIONS~N");
1583
+ }
1584
+ if (g->analyser->debug_used) {
1585
+ w(g, "#define SNOWBALL_DEBUG_COMMAND_USED~N");
1586
+ }
1587
+
1588
+ w(g, "#include \"");
1589
+ write_s(g, o->output_leaf);
1590
+ w(g, ".h\"~N~N");
1591
+
1592
+ if (g->analyser->int_limits_used) {
1593
+ w(g, "#include <limits.h>~N");
1594
+ }
1595
+ w(g, "#include <stddef.h>~N~N");
1596
+
1597
+ if (o->target_lang == LANG_CPLUSPLUS) {
1598
+ w(g, "~Mtypedef ");
1599
+ write_string(g, o->package);
1600
+ w(g, "::~n::SN_local SN_local;~N~N");
1601
+ return;
1602
+ }
1603
+
1604
+ w(g, "#include \"");
1605
+ if (o->runtime_path) {
1606
+ write_string(g, o->runtime_path);
1607
+ if (o->runtime_path[strlen(o->runtime_path) - 1] != '/')
1608
+ write_char(g, '/');
1609
+ }
1610
+
1611
+ w(g, "snowball_runtime.h\"~N~N");
1612
+
1613
+ if (g->analyser->variable_count > 0) {
1614
+ // Generate the struct SN_local definition, which embeds a struct
1615
+ // SN_env and also holds non-localised variables. We group variables
1616
+ // by type to try to produce more efficient struct packing.
1617
+ w(g, "struct SN_local {~N~+"
1618
+ "~Mstruct SN_env z;~N");
1619
+
1620
+ for (struct name * name = g->analyser->names; name; name = name->next) {
1621
+ if (!name->local_to && name->type == t_integer) {
1622
+ w(g, "~Mint ");
1623
+ write_varname(g, name);
1624
+ w(g, ";~N");
1625
+ }
1626
+ }
1627
+
1628
+ for (struct name * name = g->analyser->names; name; name = name->next) {
1629
+ if (!name->local_to && name->type == t_boolean) {
1630
+ if (g->options->target_lang == LANG_CPLUSPLUS) {
1631
+ w(g, "~Mbool ");
1632
+ } else {
1633
+ w(g, "~Munsigned char ");
1634
+ }
1635
+ write_varname(g, name);
1636
+ w(g, ";~N");
1637
+ }
1638
+ }
1639
+
1640
+ for (struct name * name = g->analyser->names; name; name = name->next) {
1641
+ if (!name->local_to && name->type == t_string) {
1642
+ w(g, "~Msymbol * ");
1643
+ write_varname(g, name);
1644
+ w(g, ";~N");
1645
+ }
1646
+ }
1647
+
1648
+ w(g, "~-~M};~N~N");
1649
+
1650
+ if (g->options->target_lang == LANG_C) {
1651
+ w(g, "typedef struct SN_local SN_local;~N~N");
1652
+ }
1653
+ }
1654
+
1655
+ const char * vp = g->options->variables_prefix;
1656
+ if (vp) {
1657
+ for (struct name * q = g->analyser->names; q; q = q->next) {
1658
+ if (q->local_to) continue;
1659
+ switch (q->type) {
1660
+ case t_string:
1661
+ w(g, "extern const symbol * ");
1662
+ write_string(g, vp);
1663
+ write_s(g, q->s);
1664
+ w(g, "(struct SN_env * z) {~N~+");
1665
+ w(g, "~Msymbol * p = ");
1666
+ write_varref(g, q);
1667
+ w(g, ";~N"
1668
+ "~Mp[SIZE(p)] = 0;~N"
1669
+ "~Mreturn p;~N~-"
1670
+ "}~N~N");
1671
+ break;
1672
+ case t_integer:
1673
+ w(g, "extern int ");
1674
+ write_string(g, vp);
1675
+ write_s(g, q->s);
1676
+ w(g, "(struct SN_env * z) {~N~+"
1677
+ "~Mreturn ");
1678
+ write_varref(g, q);
1679
+ w(g, ";~N~-"
1680
+ "}~N~N");
1681
+ break;
1682
+ case t_boolean:
1683
+ if (g->options->target_lang == LANG_CPLUSPLUS) {
1684
+ w(g, "extern bool ");
1685
+ } else {
1686
+ w(g, "extern int ");
1687
+ }
1688
+ write_string(g, vp);
1689
+ write_s(g, q->s);
1690
+ w(g, "(struct SN_env * z) {~N~+"
1691
+ "~Mreturn ");
1692
+ write_varref(g, q);
1693
+ w(g, ";~N~-"
1694
+ "}~N~N");
1695
+ break;
1696
+ }
1697
+ }
1698
+ }
1699
+ }
1700
+
1701
+ static void generate_routine_declarations(struct generator * g) {
1702
+ if (g->options->target_lang == LANG_C) {
1703
+ w(g, "#ifdef __cplusplus~N"
1704
+ "extern \"C\" {~N"
1705
+ "#endif~N");
1706
+ for (struct name * q = g->analyser->names; q; q = q->next) {
1707
+ if (q->type == t_external) {
1708
+ w(g, "extern int ");
1709
+ write_varname(g, q);
1710
+ w(g, "(struct SN_env * z);~N");
1711
+ }
1712
+ }
1713
+ w(g, "#ifdef __cplusplus~N"
1714
+ "}~N"
1715
+ "#endif~N~N");
1716
+ }
1717
+
1718
+ if (g->analyser->name_count[t_routine]) {
1719
+ for (struct name * q = g->analyser->names; q; q = q->next) {
1720
+ if (q->type == t_routine) {
1721
+ w(g, "static int ");
1722
+ write_varname(g, q);
1723
+ w(g, "(struct SN_env * z);~N");
1724
+ }
1725
+ }
1726
+ write_newline(g);
1727
+ }
1728
+ }
1729
+
1730
+ static void generate_among_table(struct generator * g, struct among * x) {
1731
+ write_newline(g);
1732
+ write_comment(g, x->node);
1733
+
1734
+ struct amongvec * v = x->b;
1735
+
1736
+ g->I[0] = x->number;
1737
+ for (int i = 0; i < x->literalstring_count; i++) {
1738
+ if (v[i].size) {
1739
+ g->I[1] = i;
1740
+ g->I[2] = v[i].size;
1741
+ w(g, "static const symbol s_~I0_~I1[~I2] = ");
1742
+ wlitarray(g, v[i].b);
1743
+ w(g, ";~N");
1744
+ }
1745
+ }
1746
+
1747
+ g->I[1] = x->literalstring_count;
1748
+ if (g->options->coverage) {
1749
+ g->I[1] = g->I[1] * 2 + 1;
1750
+ }
1751
+ w(g, "~Mstatic const struct among a_~I0[~I1] = {~N");
1752
+
1753
+ for (int i = 0; i < x->literalstring_count; i++) {
1754
+ if (i) w(g, ",~N");
1755
+ g->I[1] = i;
1756
+ g->I[2] = v[i].size;
1757
+ g->I[3] = (v[i].i >= 0 ? v[i].i - i : 0);
1758
+ g->I[4] = v[i].result;
1759
+ g->I[5] = v[i].function_index;
1760
+
1761
+ if (g->options->comments) {
1762
+ w(g, "/*~J1 */ ");
1763
+ }
1764
+ w(g, "{ ~I2, ");
1765
+ if (v[i].size == 0) {
1766
+ w(g, "0,");
1767
+ } else {
1768
+ w(g, "s_~I0_~I1,");
1769
+ }
1770
+ w(g, " ~I3, ~I4, ~I5}");
1771
+ }
1772
+ if (g->options->coverage) {
1773
+ w(g, ",~N");
1774
+ g->S[1] = g->analyser->tokeniser->file;
1775
+ for (int i = 0; i < x->literalstring_count; i++) {
1776
+ if (g->options->comments) {
1777
+ w(g, "/* coverage */ ");
1778
+ }
1779
+ g->I[1] = x->b[i].line_number;
1780
+ g->I[2] = x->b[i].string_index;
1781
+ w(g, "{ ~I0, (const symbol*)\"~S1:~I1\", 0, ~I2, 0 },~N");
1782
+ }
1783
+ if (x->always_matches) {
1784
+ g->I[0] = -1;
1785
+ }
1786
+ if (g->options->comments) {
1787
+ w(g, "/* coverage */ ");
1788
+ }
1789
+ g->I[1] = x->node->line_number;
1790
+ w(g, "{ ~I0, (const symbol*)\"~S1:~I1\", 0, 0, 0 },~N");
1791
+ }
1792
+ w(g, "~N};~N");
1793
+
1794
+ if (x->function_count <= 1) return;
1795
+
1796
+ w(g, "~N~Mstatic int af_~I0(struct SN_env * z) {~N~+");
1797
+ w(g, "~Mswitch (z->af) {~N~+");
1798
+ for (int n = 1; n <= x->function_count; n++) {
1799
+ w(g, "~Mcase ");
1800
+ write_int(g, n);
1801
+ w(g, ": return ");
1802
+ for (int i = 0; i < x->literalstring_count; i++) {
1803
+ if (v[i].function_index == n) {
1804
+ write_varref(g, v[i].function);
1805
+ w(g, "(z);~N");
1806
+ break;
1807
+ }
1808
+ }
1809
+ }
1810
+ w(g, "~-~M}~N");
1811
+ w(g, "~Mreturn -1;~N");
1812
+ w(g, "~-~M}~N");
1813
+ }
1814
+
1815
+ static void generate_amongs(struct generator * g) {
1816
+ struct str * s = g->outbuf;
1817
+ g->outbuf = g->declarations;
1818
+ for (struct among * x = g->analyser->amongs; x; x = x->next) {
1819
+ if (x->used) generate_among_table(g, x);
1820
+ }
1821
+ g->outbuf = s;
1822
+ }
1823
+
1824
+ static void set_bit(symbol * b, int i) { b[i >> 3] |= 1 << (i & 7); }
1825
+
1826
+ static void generate_grouping_table(struct generator * g, struct grouping * q) {
1827
+ int range = q->largest_ch - q->smallest_ch + 1;
1828
+ int size = (range + 7) / 8; /* assume 8 bits per symbol */
1829
+ symbol * b = q->b;
1830
+ symbol * map = create_b(size);
1831
+
1832
+ for (int i = 0; i < size; i++) map[i] = 0;
1833
+
1834
+ for (int i = 0; i < SIZE(b); i++) set_bit(map, b[i] - q->smallest_ch);
1835
+
1836
+ w(g, "~Nstatic const unsigned char ");
1837
+ write_varname(g, q->name);
1838
+ w(g, "[] = { ");
1839
+ for (int i = 0; i < size; i++) {
1840
+ if (i) w(g, ", ");
1841
+ write_int(g, map[i]);
1842
+ }
1843
+ if (g->options->coverage) {
1844
+ int grouping_number = q->name->count;
1845
+ if (grouping_number > 255) grouping_number = 255;
1846
+ w(g, ", ");
1847
+ wlitch(g, grouping_number);
1848
+
1849
+ char buf[1024];
1850
+ checked_snprintf(buf, sizeof(buf), "%s:%d: grouping %.*s",
1851
+ g->analyser->tokeniser->file, q->line_number,
1852
+ SIZE(q->name->s), q->name->s);
1853
+
1854
+ for (const char * p = buf; *p; ++p) {
1855
+ w(g, ", ");
1856
+ wlitch(g, (int)*p);
1857
+ }
1858
+ w(g, ", '\\0'");
1859
+ }
1860
+ w(g, " };~N");
1861
+
1862
+ lose_b(map);
1863
+ }
1864
+
1865
+ static void generate_groupings(struct generator * g) {
1866
+ struct str * s = g->outbuf;
1867
+ g->outbuf = g->declarations;
1868
+ for (struct grouping * q = g->analyser->groupings; q; q = q->next) {
1869
+ generate_grouping_table(g, q);
1870
+ }
1871
+ g->outbuf = s;
1872
+ }
1873
+
1874
+ static void generate_create(struct generator * g) {
1875
+ w(g, "~N"
1876
+ "extern struct SN_env * ~pcreate_env(void) {~N~+");
1877
+
1878
+ if (g->analyser->variable_count == 0) {
1879
+ w(g, "~Mreturn SN_new_env(sizeof(struct SN_env));~N");
1880
+ } else {
1881
+ w(g, "~Mstruct SN_env * z = SN_new_env(sizeof(SN_local));~N"
1882
+ "~Mif (z) {~N~+");
1883
+
1884
+ for (struct name * name = g->analyser->names; name; name = name->next) {
1885
+ if (!name->local_to) {
1886
+ switch (name->type) {
1887
+ case t_string:
1888
+ w(g, "~M");
1889
+ write_varref(g, name);
1890
+ w(g, " = NULL;~N");
1891
+ break;
1892
+ case t_integer:
1893
+ w(g, "~M");
1894
+ write_varref(g, name);
1895
+ w(g, " = 0;~N");
1896
+ break;
1897
+ case t_boolean:
1898
+ w(g, "~M");
1899
+ write_varref(g, name);
1900
+ if (g->options->target_lang == LANG_CPLUSPLUS) {
1901
+ w(g, " = false;~N");
1902
+ } else {
1903
+ w(g, " = 0;~N");
1904
+ }
1905
+ break;
1906
+ }
1907
+ }
1908
+ }
1909
+
1910
+ if (g->analyser->name_count[t_string] > 0) {
1911
+ write_newline(g);
1912
+
1913
+ // To simplify error handling, we initialise all strings to NULL
1914
+ // above, then try to allocate them in a second pass.
1915
+ for (struct name * name = g->analyser->names; name; name = name->next) {
1916
+ if (!name->local_to) {
1917
+ switch (name->type) {
1918
+ case t_string:
1919
+ w(g, "~Mif ((");
1920
+ write_varref(g, name);
1921
+ w(g, " = create_s()) == NULL) {~N~+"
1922
+ "~M~pclose_env(z);~N"
1923
+ "~Mreturn NULL;~N~-"
1924
+ "~M}~N");
1925
+ break;
1926
+ }
1927
+ }
1928
+ }
1929
+ }
1930
+
1931
+ w(g, "~-~M}~N"
1932
+ "~Mreturn z;~N");
1933
+ }
1934
+
1935
+ w(g, "~-}~N");
1936
+ }
1937
+
1938
+ static void generate_close(struct generator * g) {
1939
+ w(g, "~Nextern void ~pclose_env(struct SN_env * z) {~N~+");
1940
+
1941
+ if (g->analyser->name_count[t_string] > 0) {
1942
+ w(g, "~Mif (!z) return;~N");
1943
+
1944
+ for (struct name * name = g->analyser->names; name; name = name->next) {
1945
+ if (!name->local_to && name->type == t_string) {
1946
+ w(g, "~Mlose_s(");
1947
+ write_varref(g, name);
1948
+ w(g, ");~N");
1949
+ }
1950
+ }
1951
+ }
1952
+
1953
+ // Note: SN_delete_env() no-ops if z is NULL so we don't to gate this call.
1954
+ w(g, "~MSN_delete_env(z);~N"
1955
+ "~-}~N~N");
1956
+ }
1957
+
1958
+ static void generate_header_file(struct generator * g) {
1959
+ struct options * o = g->options;
1960
+ if (o->hheader) {
1961
+ int quoted = (o->hheader[0] == '<' || o->hheader[0] == '"');
1962
+ w(g, "#include ");
1963
+ if (!quoted) write_char(g, '<');
1964
+ write_string(g, o->hheader);
1965
+ if (!quoted) write_char(g, '>');
1966
+ write_newline(g);
1967
+ write_newline(g);
1968
+ }
1969
+
1970
+ if (o->target_lang == LANG_CPLUSPLUS) {
1971
+ w(g, "#define SNOWBALL_RUNTIME_THROW_EXCEPTIONS~N"
1972
+ "#include \"");
1973
+ if (o->runtime_path) {
1974
+ write_string(g, o->runtime_path);
1975
+ if (o->runtime_path[strlen(o->runtime_path) - 1] != '/')
1976
+ write_char(g, '/');
1977
+ }
1978
+ w(g, "snowball_runtime.h\"~N~N");
1979
+
1980
+ w(g, "namespace ");
1981
+ write_string(g, o->package);
1982
+ w(g, " {~N~N");
1983
+
1984
+ w(g, "class ~n : public ");
1985
+ write_string(g, o->parent_class_name);
1986
+ w(g, " {~N"
1987
+ " public:~N~+");
1988
+ }
1989
+
1990
+ if (o->target_lang == LANG_C) {
1991
+ w(g, "#ifdef __cplusplus~N"
1992
+ "extern \"C\" {~N"
1993
+ "#endif~N"); /* for C++ */
1994
+
1995
+ w(g, "~N"
1996
+ "extern struct SN_env * ~pcreate_env(void);~N"
1997
+ "extern void ~pclose_env(struct SN_env * z);~N"
1998
+ "~N");
1999
+ }
2000
+
2001
+ const char * vp = o->variables_prefix;
2002
+ if (vp) {
2003
+ for (struct name * q = g->analyser->names; q; q = q->next) {
2004
+ if (q->local_to) continue;
2005
+ switch (q->type) {
2006
+ case t_string:
2007
+ if (o->target_lang == LANG_CPLUSPLUS) {
2008
+ w(g, "~Mconst symbol * ");
2009
+ } else {
2010
+ w(g, "extern const symbol * ");
2011
+ }
2012
+ write_string(g, vp);
2013
+ write_s(g, q->s);
2014
+ if (o->target_lang == LANG_CPLUSPLUS) {
2015
+ w(g, "() {~N~+"
2016
+ "~Mstruct SN_env * z = &(zlocal.z);~N"
2017
+ "~Msymbol * p = ");
2018
+ write_varref(g, q);
2019
+ w(g, ";~N"
2020
+ "~Mp[SIZE(p)] = 0;~N"
2021
+ "~Mreturn p;~N~-"
2022
+ "~M}~N~N");
2023
+ } else {
2024
+ w(g, "(struct SN_env * z);~N");
2025
+ }
2026
+ break;
2027
+ case t_integer:
2028
+ if (o->target_lang == LANG_CPLUSPLUS) {
2029
+ w(g, "~Mint ");
2030
+ } else {
2031
+ w(g, "extern int ");
2032
+ }
2033
+ write_string(g, vp);
2034
+ write_s(g, q->s);
2035
+ if (o->target_lang == LANG_CPLUSPLUS) {
2036
+ w(g, "() {~N~+"
2037
+ "~Mstruct SN_env * z = &(zlocal.z);~N"
2038
+ "~Mreturn ");
2039
+ write_varref(g, q);
2040
+ w(g, ";~N~-"
2041
+ "~M}~N~N");
2042
+ } else {
2043
+ w(g, "(struct SN_env * z);~N");
2044
+ }
2045
+ break;
2046
+ case t_boolean:
2047
+ if (o->target_lang == LANG_CPLUSPLUS) {
2048
+ w(g, "~Mbool ");
2049
+ } else {
2050
+ w(g, "extern int ");
2051
+ }
2052
+ write_string(g, vp);
2053
+ write_s(g, q->s);
2054
+ if (o->target_lang == LANG_CPLUSPLUS) {
2055
+ w(g, "() {~N~+"
2056
+ "~Mstruct SN_env * z = &(zlocal.z);~N"
2057
+ "~Mreturn ");
2058
+ write_varref(g, q);
2059
+ w(g, ";~N~-"
2060
+ "~M}~N~N");
2061
+ } else {
2062
+ w(g, "(struct SN_env * z);~N");
2063
+ }
2064
+ break;
2065
+ }
2066
+ }
2067
+ }
2068
+
2069
+ if (o->target_lang == LANG_C) {
2070
+ for (struct name * q = g->analyser->names; q; q = q->next) {
2071
+ if (q->type == t_external) {
2072
+ w(g, "extern int ");
2073
+ write_varname(g, q);
2074
+ w(g, "(struct SN_env * z);~N");
2075
+ }
2076
+ }
2077
+
2078
+ w(g, "~N"
2079
+ "#ifdef __cplusplus~N"
2080
+ "}~N"
2081
+ "#endif~N"); /* for C++ */
2082
+ }
2083
+
2084
+ if (o->target_lang == LANG_CPLUSPLUS) {
2085
+ // Generate the struct SN_local definition, which embeds a struct
2086
+ // SN_env and also holds any non-localised variables. We group
2087
+ // variables by type to try to produce more efficient struct packing.
2088
+ w(g, "~Mstruct SN_local {~N~+"
2089
+ "~Mstruct SN_env z;~N");
2090
+
2091
+ for (struct name * name = g->analyser->names; name; name = name->next) {
2092
+ if (!name->local_to && name->type == t_integer) {
2093
+ w(g, "~Mint ");
2094
+ write_varname(g, name);
2095
+ w(g, ";~N");
2096
+ }
2097
+ }
2098
+
2099
+ for (struct name * name = g->analyser->names; name; name = name->next) {
2100
+ if (!name->local_to && name->type == t_boolean) {
2101
+ if (g->options->target_lang == LANG_CPLUSPLUS) {
2102
+ w(g, "~Mbool ");
2103
+ } else {
2104
+ w(g, "~Munsigned char ");
2105
+ }
2106
+ write_varname(g, name);
2107
+ w(g, ";~N");
2108
+ }
2109
+ }
2110
+
2111
+ for (struct name * name = g->analyser->names; name; name = name->next) {
2112
+ if (!name->local_to && name->type == t_string) {
2113
+ w(g, "~Msymbol * ");
2114
+ write_varname(g, name);
2115
+ w(g, ";~N");
2116
+ }
2117
+ }
2118
+
2119
+ w(g, "~-~M};~N"
2120
+ "~N");
2121
+
2122
+ w(g, "~- private:~N~+"
2123
+ "~MSN_local zlocal = {};~N"
2124
+ "~N"
2125
+ "~Mvoid close_env() {~N~+"
2126
+ "~Mstruct SN_env * z = &(zlocal.z);~N");
2127
+ if (g->analyser->name_count[t_string] > 0) {
2128
+ for (struct name * name = g->analyser->names; name; name = name->next) {
2129
+ if (!name->local_to && name->type == t_string) {
2130
+ w(g, "~Mlose_s(");
2131
+ write_varref(g, name);
2132
+ w(g, ");~N");
2133
+ }
2134
+ }
2135
+ }
2136
+ w(g, "~Mlose_s(z->p);~N"
2137
+ "~-~M}~N~N");
2138
+
2139
+ for (struct name * q = g->analyser->names; q; q = q->next) {
2140
+ if (!q->local_to && q->type == t_external) {
2141
+ w(g, "~Mstatic int ");
2142
+ if (g->options->externals_prefix) {
2143
+ write_string(g, g->options->externals_prefix);
2144
+ }
2145
+ write_s(g, q->s);
2146
+ w(g, "(struct SN_env * z);~N~N");
2147
+ }
2148
+ }
2149
+
2150
+ w(g, "~- public:~N~+"
2151
+ "~M~n() {~N~+"
2152
+ "~Mstruct SN_env * z = &(zlocal.z);~N"
2153
+ "~Mz->p = create_s();~N");
2154
+ if (g->analyser->name_count[t_string] > 0) {
2155
+ w(g, "~Mtry {~N~+");
2156
+ for (struct name * name = g->analyser->names; name; name = name->next) {
2157
+ if (!name->local_to && name->type == t_string) {
2158
+ write_margin(g);
2159
+ write_varref(g, name);
2160
+ w(g, " = create_s();~N");
2161
+ }
2162
+ }
2163
+ w(g, "~-~M} catch (...) {~N~+"
2164
+ "~Mclose_env();~N"
2165
+ "~Mthrow;~N"
2166
+ "~-~M}~N");
2167
+ }
2168
+ w(g, "~-~M}~N~N"
2169
+ "~M~~~n() {~N~+"
2170
+ "~Mclose_env();~N"
2171
+ "~-~M}~N~N"
2172
+ "~Mstd::string operator()(const std::string& word) override {~N~+"
2173
+ "~Mstruct SN_env* z = &(zlocal.z);~N"
2174
+ "~Mconst symbol* s = reinterpret_cast<const symbol*>(word.data());~N"
2175
+ "~Mint s_size = word.size() > INT_MAX ? INT_MAX : word.size();~N"
2176
+ "~Mreplace_s(z, 0, z->l, s_size, s);~N"
2177
+ "~Mz->c = 0;~N"
2178
+ "~M");
2179
+ write_string(g, o->package);
2180
+ write_string(g, "::");
2181
+ write_s(g, o->name);
2182
+ write_string(g, "::");
2183
+ if (g->options->externals_prefix) {
2184
+ write_string(g, g->options->externals_prefix);
2185
+ }
2186
+ w(g, "stem(z);~N"
2187
+ "~Mreturn std::string(reinterpret_cast<const char*>(z->p), SIZE(z->p));~N"
2188
+ "~-~M}~N"
2189
+ "~-~M};~N~N");
2190
+
2191
+ w(g, "}~N");
2192
+ }
2193
+ }
2194
+
2195
+ extern void generate_program_c(struct generator * g) {
2196
+ g->outbuf = str_new();
2197
+ g->failure_str = str_new();
2198
+ write_start_comment(g, "/* ", " */");
2199
+ generate_head(g);
2200
+ generate_routine_declarations(g);
2201
+ g->declarations = g->outbuf;
2202
+ g->outbuf = str_new();
2203
+ g->literalstring_count = 0;
2204
+
2205
+ for (struct node * p = g->analyser->program; p; p = p->right) {
2206
+ generate(g, p);
2207
+ }
2208
+
2209
+ generate_amongs(g);
2210
+ generate_groupings(g);
2211
+
2212
+ if (g->options->target_lang != LANG_CPLUSPLUS) {
2213
+ generate_create(g);
2214
+ generate_close(g);
2215
+ }
2216
+
2217
+ output_str(g->options->output_src, g->declarations);
2218
+ str_delete(g->declarations);
2219
+ output_str(g->options->output_src, g->outbuf);
2220
+ str_clear(g->outbuf);
2221
+
2222
+ write_start_comment(g, "/* ", " */");
2223
+ generate_header_file(g);
2224
+ output_str(g->options->output_h, g->outbuf);
2225
+ str_delete(g->outbuf);
2226
+ str_delete(g->failure_str);
2227
+ }