mittens 0.1.1 → 0.3.0

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 (100) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +8 -0
  3. data/LICENSE.txt +1 -1
  4. data/README.md +4 -4
  5. data/lib/mittens/version.rb +1 -1
  6. data/mittens.gemspec +1 -1
  7. data/vendor/snowball/.github/workflows/ci.yml +216 -0
  8. data/vendor/snowball/CONTRIBUTING.rst +111 -62
  9. data/vendor/snowball/GNUmakefile +194 -136
  10. data/vendor/snowball/NEWS +798 -3
  11. data/vendor/snowball/README.rst +50 -1
  12. data/vendor/snowball/ada/src/stemmer.adb +25 -13
  13. data/vendor/snowball/ada/src/stemmer.ads +9 -9
  14. data/vendor/snowball/ada/stemmer_config.gpr +7 -7
  15. data/vendor/snowball/algorithms/basque.sbl +4 -19
  16. data/vendor/snowball/algorithms/catalan.sbl +2 -9
  17. data/vendor/snowball/algorithms/danish.sbl +1 -1
  18. data/vendor/snowball/algorithms/dutch.sbl +284 -122
  19. data/vendor/snowball/algorithms/dutch_porter.sbl +178 -0
  20. data/vendor/snowball/algorithms/english.sbl +52 -37
  21. data/vendor/snowball/algorithms/esperanto.sbl +157 -0
  22. data/vendor/snowball/algorithms/estonian.sbl +269 -0
  23. data/vendor/snowball/algorithms/finnish.sbl +2 -3
  24. data/vendor/snowball/algorithms/french.sbl +42 -16
  25. data/vendor/snowball/algorithms/german.sbl +35 -14
  26. data/vendor/snowball/algorithms/greek.sbl +76 -76
  27. data/vendor/snowball/algorithms/hungarian.sbl +8 -6
  28. data/vendor/snowball/algorithms/indonesian.sbl +14 -8
  29. data/vendor/snowball/algorithms/italian.sbl +11 -21
  30. data/vendor/snowball/algorithms/lithuanian.sbl +36 -37
  31. data/vendor/snowball/algorithms/lovins.sbl +0 -1
  32. data/vendor/snowball/algorithms/nepali.sbl +138 -37
  33. data/vendor/snowball/algorithms/norwegian.sbl +19 -5
  34. data/vendor/snowball/algorithms/porter.sbl +2 -2
  35. data/vendor/snowball/algorithms/portuguese.sbl +9 -13
  36. data/vendor/snowball/algorithms/romanian.sbl +17 -4
  37. data/vendor/snowball/algorithms/serbian.sbl +467 -468
  38. data/vendor/snowball/algorithms/spanish.sbl +5 -7
  39. data/vendor/snowball/algorithms/swedish.sbl +60 -6
  40. data/vendor/snowball/algorithms/tamil.sbl +207 -176
  41. data/vendor/snowball/algorithms/turkish.sbl +461 -445
  42. data/vendor/snowball/algorithms/yiddish.sbl +36 -38
  43. data/vendor/snowball/compiler/analyser.c +445 -192
  44. data/vendor/snowball/compiler/driver.c +109 -101
  45. data/vendor/snowball/compiler/generator.c +853 -464
  46. data/vendor/snowball/compiler/generator_ada.c +404 -366
  47. data/vendor/snowball/compiler/generator_csharp.c +297 -260
  48. data/vendor/snowball/compiler/generator_go.c +323 -254
  49. data/vendor/snowball/compiler/generator_java.c +326 -252
  50. data/vendor/snowball/compiler/generator_js.c +362 -252
  51. data/vendor/snowball/compiler/generator_pascal.c +349 -197
  52. data/vendor/snowball/compiler/generator_python.c +257 -240
  53. data/vendor/snowball/compiler/generator_rust.c +423 -251
  54. data/vendor/snowball/compiler/header.h +117 -71
  55. data/vendor/snowball/compiler/space.c +137 -68
  56. data/vendor/snowball/compiler/syswords.h +2 -2
  57. data/vendor/snowball/compiler/tokeniser.c +125 -107
  58. data/vendor/snowball/csharp/Snowball/Among.cs +14 -14
  59. data/vendor/snowball/csharp/Snowball/AssemblyInfo.cs +7 -7
  60. data/vendor/snowball/csharp/Snowball/Stemmer.cs +57 -37
  61. data/vendor/snowball/csharp/Stemwords/App.config +2 -2
  62. data/vendor/snowball/csharp/Stemwords/Program.cs +16 -12
  63. data/vendor/snowball/doc/libstemmer_c_README +7 -4
  64. data/vendor/snowball/doc/libstemmer_csharp_README +4 -1
  65. data/vendor/snowball/doc/libstemmer_java_README +12 -1
  66. data/vendor/snowball/doc/libstemmer_js_README +6 -4
  67. data/vendor/snowball/doc/libstemmer_python_README +9 -4
  68. data/vendor/snowball/examples/stemwords.c +12 -12
  69. data/vendor/snowball/go/env.go +107 -31
  70. data/vendor/snowball/go/util.go +0 -4
  71. data/vendor/snowball/include/libstemmer.h +4 -0
  72. data/vendor/snowball/java/org/tartarus/snowball/Among.java +32 -15
  73. data/vendor/snowball/java/org/tartarus/snowball/SnowballProgram.java +347 -261
  74. data/vendor/snowball/java/org/tartarus/snowball/SnowballStemmer.java +3 -0
  75. data/vendor/snowball/java/org/tartarus/snowball/TestApp.java +52 -37
  76. data/vendor/snowball/javascript/base-stemmer.js +186 -2
  77. data/vendor/snowball/javascript/stemwords.js +3 -6
  78. data/vendor/snowball/libstemmer/libstemmer_c.in +1 -1
  79. data/vendor/snowball/libstemmer/mkalgorithms.pl +6 -6
  80. data/vendor/snowball/libstemmer/mkmodules.pl +2 -2
  81. data/vendor/snowball/libstemmer/modules.txt +13 -10
  82. data/vendor/snowball/libstemmer/test.c +1 -1
  83. data/vendor/snowball/pascal/SnowballProgram.pas +84 -2
  84. data/vendor/snowball/pascal/generate.pl +13 -13
  85. data/vendor/snowball/python/create_init.py +4 -1
  86. data/vendor/snowball/python/setup.cfg +0 -3
  87. data/vendor/snowball/python/setup.py +8 -3
  88. data/vendor/snowball/python/snowballstemmer/basestemmer.py +20 -54
  89. data/vendor/snowball/python/stemwords.py +8 -12
  90. data/vendor/snowball/runtime/api.c +10 -5
  91. data/vendor/snowball/runtime/header.h +10 -9
  92. data/vendor/snowball/runtime/utilities.c +9 -9
  93. data/vendor/snowball/rust/build.rs +1 -1
  94. data/vendor/snowball/rust/src/snowball/snowball_env.rs +83 -5
  95. data/vendor/snowball/tests/stemtest.c +7 -4
  96. metadata +8 -12
  97. data/vendor/snowball/.travis.yml +0 -112
  98. data/vendor/snowball/algorithms/german2.sbl +0 -145
  99. data/vendor/snowball/algorithms/kraaij_pohlmann.sbl +0 -240
  100. data/vendor/snowball/compiler/syswords2.h +0 -13
@@ -1,5 +1,4 @@
1
-
2
- #include <limits.h> /* for INT_MAX */
1
+ #include <assert.h>
3
2
  #include <stdio.h> /* for fprintf etc */
4
3
  #include <stdlib.h> /* for free etc */
5
4
  #include <string.h> /* for strlen */
@@ -11,32 +10,33 @@
11
10
  /* recursive use: */
12
11
 
13
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);
14
15
 
15
16
  static int new_label(struct generator * g) {
16
17
  return g->next_label++;
17
18
  }
18
19
 
19
- /* Write routines for simple entities */
20
-
21
- /* Write a space if the preceding character was not whitespace */
22
- static void ws_opt_space(struct generator * g, const char * s) {
23
- int ch = str_back(g->outbuf);
24
- if (ch != ' ' && ch != '\n' && ch != '\t' && ch != -1)
25
- write_char(g, ' ');
26
- write_string(g, s);
20
+ static struct str * vars_newname(struct generator * g) {
21
+ struct str * output;
22
+ g->var_number++;
23
+ output = str_new();
24
+ str_append_string(output, "v_");
25
+ str_append_int(output, g->var_number);
26
+ return output;
27
27
  }
28
28
 
29
+ /* Write routines for simple entities */
30
+
29
31
  static void wi3(struct generator * g, int i) {
30
32
  if (i < 100) write_char(g, ' ');
31
33
  if (i < 10) write_char(g, ' ');
32
34
  write_int(g, i); /* integer (width 3) */
33
35
  }
34
36
 
35
-
36
37
  /* Write routines for items from the syntax tree */
37
38
 
38
39
  static void write_varname(struct generator * g, struct name * p) {
39
-
40
40
  int ch = "SIIrxg"[p->type];
41
41
  switch (p->type) {
42
42
  case t_external:
@@ -46,9 +46,9 @@ static void write_varname(struct generator * g, struct name * p) {
46
46
  case t_integer: {
47
47
  int count = p->count;
48
48
  if (count < 0) {
49
- fprintf(stderr, "Reference to optimised out variable ");
50
- report_b(stderr, p->b);
51
- fprintf(stderr, " attempted\n");
49
+ p->s[SIZE(p->s)] = 0;
50
+ fprintf(stderr, "Reference to optimised out variable %s attempted\n",
51
+ p->s);
52
52
  exit(1);
53
53
  }
54
54
  if (p->type == t_boolean) {
@@ -66,7 +66,7 @@ static void write_varname(struct generator * g, struct name * p) {
66
66
  default:
67
67
  write_char(g, ch); write_char(g, '_');
68
68
  }
69
- write_b(g, p->b);
69
+ write_s(g, p->s);
70
70
  }
71
71
 
72
72
  static void write_varref(struct generator * g, struct name * p) { /* reference to variable */
@@ -78,6 +78,10 @@ static void write_hexdigit(struct generator * g, int i) {
78
78
  str_append_ch(g->outbuf, "0123456789ABCDEF"[i & 0xF]); /* hexchar */
79
79
  }
80
80
 
81
+ extern void write_hex4(struct generator * g, int ch) {
82
+ for (int i = 12; i >= 0; i -= 4) write_hexdigit(g, ch >> i);
83
+ }
84
+
81
85
  static void write_hex(struct generator * g, int i) {
82
86
  if (i >> 4) write_hex(g, i >> 4);
83
87
  write_hexdigit(g, i); /* hex integer */
@@ -98,20 +102,15 @@ static void wlitch(struct generator * g, int ch) {
98
102
  }
99
103
 
100
104
  static void wlitarray(struct generator * g, symbol * p) { /* write literal array */
101
-
102
105
  write_string(g, "{ ");
103
- {
104
- int i;
105
- for (i = 0; i < SIZE(p); i++) {
106
- wlitch(g, p[i]);
107
- if (i < SIZE(p) - 1) write_string(g, ", ");
108
- }
106
+ for (int i = 0; i < SIZE(p); i++) {
107
+ wlitch(g, p[i]);
108
+ if (i < SIZE(p) - 1) write_string(g, ", ");
109
109
  }
110
110
  write_string(g, " }");
111
111
  }
112
112
 
113
113
  static void wlitref(struct generator * g, symbol * p) { /* write ref to literal array */
114
-
115
114
  if (SIZE(p) == 0) {
116
115
  write_char(g, '0');
117
116
  } else {
@@ -127,8 +126,21 @@ static void wlitref(struct generator * g, symbol * p) { /* write ref to literal
127
126
  }
128
127
 
129
128
  static void write_margin(struct generator * g) {
130
- int i;
131
- for (i = 0; i < g->margin; i++) write_string(g, " ");
129
+ for (int i = 0; i < g->margin; i++) write_string(g, " ");
130
+ }
131
+
132
+ extern void write_c_relop(struct generator * g, int relop) {
133
+ switch (relop) {
134
+ case c_eq: write_string(g, " == "); break;
135
+ case c_ne: write_string(g, " != "); break;
136
+ case c_gt: write_string(g, " > "); break;
137
+ case c_ge: write_string(g, " >= "); break;
138
+ case c_lt: write_string(g, " < "); break;
139
+ case c_le: write_string(g, " <= "); break;
140
+ default:
141
+ fprintf(stderr, "Unexpected type #%d in generate_integer_test\n", relop);
142
+ exit(1);
143
+ }
132
144
  }
133
145
 
134
146
  void write_comment_content(struct generator * g, struct node * p) {
@@ -140,7 +152,7 @@ void write_comment_content(struct generator * g, struct node * p) {
140
152
  case c_divideassign:
141
153
  if (p->name) {
142
154
  write_char(g, '$');
143
- write_b(g, p->name->b);
155
+ write_s(g, p->name->s);
144
156
  write_char(g, ' ');
145
157
  }
146
158
  write_string(g, name_of_token(p->type));
@@ -148,19 +160,26 @@ void write_comment_content(struct generator * g, struct node * p) {
148
160
  break;
149
161
  case c_eq:
150
162
  case c_ne:
151
- case c_gr:
163
+ case c_gt:
152
164
  case c_ge:
153
- case c_ls:
165
+ case c_lt:
154
166
  case c_le:
155
167
  write_string(g, "$(<integer expression> ");
156
168
  write_string(g, name_of_token(p->type));
157
169
  write_string(g, " <integer expression>)");
158
170
  break;
171
+ case c_define:
172
+ if (p->mode == m_forward) {
173
+ write_string(g, "forwardmode ");
174
+ } else {
175
+ write_string(g, "backwardmode ");
176
+ }
177
+ /* FALLTHRU */
159
178
  default:
160
179
  write_string(g, name_of_token(p->type));
161
180
  if (p->name) {
162
181
  write_char(g, ' ');
163
- write_b(g, p->name->b);
182
+ write_s(g, p->name->s);
164
183
  }
165
184
  }
166
185
  write_string(g, ", line ");
@@ -168,73 +187,50 @@ void write_comment_content(struct generator * g, struct node * p) {
168
187
  }
169
188
 
170
189
  static void write_comment(struct generator * g, struct node * p) {
171
- if (g->options->comments) {
172
- ws_opt_space(g, "/* ");
173
- write_comment_content(g, p);
174
- write_string(g, " */");
175
- }
190
+ if (!g->options->comments) return;
191
+ write_margin(g);
192
+ write_string(g, "/* ");
193
+ write_comment_content(g, p);
194
+ write_string(g, " */");
176
195
  write_newline(g);
177
196
  }
178
197
 
198
+ /* margin + string */
179
199
  static void wms(struct generator * g, const char * s) {
180
- write_margin(g); write_string(g, s); } /* margin + string */
181
-
182
- static void write_block_start(struct generator * g) { /* block start */
183
- wms(g, "{ ");
184
- g->margin++;
200
+ write_margin(g); write_string(g, s);
185
201
  }
186
202
 
187
- static void write_block_end(struct generator * g) { /* block end */
188
-
189
- if (g->line_labelled == g->line_count) { wms(g, ";"); write_newline(g); }
190
- g->margin--;
191
- wms(g, "}"); write_newline(g);
203
+ static void write_block_start(struct generator * g) {
204
+ w(g, "~M{~+~N");
192
205
  }
193
206
 
194
- static void w(struct generator * g, const char * s);
195
-
196
- /* keep c */
197
- static void wk(struct generator * g, struct node * p, int keep_limit) {
198
- ++g->keep_count;
199
- if (p->mode == m_forward) {
200
- write_string(g, "int c");
201
- write_int(g, g->keep_count);
202
- write_string(g, " = z->c");
203
- if (keep_limit) {
204
- write_string(g, ", mlimit");
205
- write_int(g, g->keep_count);
206
- }
207
- write_char(g, ';');
208
- } else {
209
- write_string(g, "int m");
210
- write_int(g, g->keep_count);
211
- write_string(g, " = z->l - z->c");
212
- if (keep_limit) {
213
- write_string(g, ", mlimit");
214
- write_int(g, g->keep_count);
215
- }
216
- write_string(g, "; (void)m");
217
- write_int(g, g->keep_count);
218
- write_char(g, ';');
207
+ static void write_block_end(struct generator * g) {
208
+ if (g->line_labelled == g->line_count) {
209
+ // Before C23, `;` is required between a label and the block end.
210
+ w(g, "~M;~N");
219
211
  }
212
+ w(g, "~-~M}~N");
220
213
  }
221
214
 
222
- static void wrestore(struct generator * g, struct node * p, int keep_token) { /* restore c */
223
- if (p->mode == m_forward) {
224
- write_string(g, "z->c = c");
225
- } else {
226
- write_string(g, "z->c = z->l - m");
227
- }
228
- write_int(g, keep_token); write_char(g, ';');
215
+ static void write_savecursor(struct generator * g, struct node * p,
216
+ struct str * savevar) {
217
+ g->B[0] = str_data(savevar);
218
+ g->S[1] = "";
219
+ if (p->mode != m_forward) g->S[1] = "z->l - ";
220
+ writef(g, "~Mint ~B0 = ~S1z->c;~N", p);
229
221
  }
230
222
 
231
- static void wrestorelimit(struct generator * g, struct node * p, int keep_token) { /* restore limit */
232
- if (p->mode == m_forward) {
233
- w(g, "z->l += mlimit");
234
- } else {
235
- w(g, "z->lb = mlimit");
236
- }
237
- write_int(g, keep_token); write_string(g, ";");
223
+ static void append_restore_string(struct node * p, struct str * out, struct str * savevar) {
224
+ str_append_string(out, "z->c = ");
225
+ if (p->mode != m_forward) str_append_string(out, "z->l - ");
226
+ str_append(out, savevar);
227
+ str_append_string(out, ";");
228
+ }
229
+
230
+ static void write_restorecursor(struct generator * g, struct node * p, struct str * savevar) {
231
+ write_margin(g);
232
+ append_restore_string(p, g->outbuf, savevar);
233
+ write_newline(g);
238
234
  }
239
235
 
240
236
  static void winc(struct generator * g, struct node * p) { /* increment c */
@@ -243,7 +239,6 @@ static void winc(struct generator * g, struct node * p) { /* increment c */
243
239
  }
244
240
 
245
241
  static void wsetl(struct generator * g, int n) {
246
-
247
242
  g->margin--;
248
243
  wms(g, "lab"); write_int(g, n); write_char(g, ':'); write_newline(g);
249
244
  g->line_labelled = g->line_count;
@@ -254,14 +249,10 @@ static void wgotol(struct generator * g, int n) {
254
249
  wms(g, "goto lab"); write_int(g, n); write_char(g, ';'); write_newline(g);
255
250
  }
256
251
 
257
- static void write_failure(struct generator * g, struct node * p) { /* fail */
258
- if (g->failure_keep_count != 0) {
252
+ static void write_failure(struct generator * g) {
253
+ if (str_len(g->failure_str) != 0) {
259
254
  write_string(g, "{ ");
260
- if (g->failure_keep_count > 0) {
261
- wrestore(g, p, g->failure_keep_count);
262
- } else {
263
- wrestorelimit(g, p, -g->failure_keep_count);
264
- }
255
+ write_str(g, g->failure_str);
265
256
  write_char(g, ' ');
266
257
  }
267
258
  switch (g->failure_label) {
@@ -274,21 +265,20 @@ static void write_failure(struct generator * g, struct node * p) { /* f
274
265
  write_char(g, ';');
275
266
  g->label_used = 1;
276
267
  }
277
- if (g->failure_keep_count != 0) write_string(g, " }");
268
+ if (str_len(g->failure_str) != 0) write_string(g, " }");
278
269
  }
279
270
 
280
271
 
281
272
  /* if at limit fail */
282
273
  static void write_check_limit(struct generator * g, struct node * p) {
283
-
284
274
  write_string(g, p->mode == m_forward ? "if (z->c >= z->l) " :
285
275
  "if (z->c <= z->lb) ");
286
- write_failure(g, p);
276
+ write_failure(g);
287
277
  }
288
278
 
289
279
  static void write_data_address(struct generator * g, struct node * p) {
290
280
  symbol * b = p->literalstring;
291
- if (b != 0) {
281
+ if (b != NULL) {
292
282
  write_int(g, SIZE(b)); w(g, ", ");
293
283
  wlitref(g, b);
294
284
  } else {
@@ -299,47 +289,97 @@ static void write_data_address(struct generator * g, struct node * p) {
299
289
  /* Formatted write. */
300
290
  static void writef(struct generator * g, const char * input, struct node * p) {
301
291
  int i = 0;
302
- int l = strlen(input);
303
292
 
304
- while (i < l) {
293
+ while (input[i]) {
305
294
  int ch = input[i++];
306
295
  if (ch != '~') {
307
296
  write_char(g, ch);
308
297
  continue;
309
298
  }
310
- switch (input[i++]) {
311
- default: write_char(g, input[i - 1]); continue;
312
- case 'C': write_comment(g, p); continue;
313
- case 'k': wk(g, p, false); continue;
314
- case 'K': wk(g, p, true); continue;
299
+ ch = input[i++];
300
+ switch (ch) {
301
+ case '~': write_char(g, '~'); continue;
315
302
  case 'i': winc(g, p); continue;
316
303
  case 'l': write_check_limit(g, p); continue;
317
- case 'f': write_failure(g, p); continue;
304
+ case 'f': write_failure(g); continue;
318
305
  case 'M': write_margin(g); continue;
319
306
  case 'N': write_newline(g); continue;
320
307
  case '{': write_block_start(g); continue;
321
308
  case '}': write_block_end(g); continue;
322
- case 'S': write_string(g, g->S[input[i++] - '0']); continue;
323
- case 'I': write_int(g, g->I[input[i++] - '0']); continue;
324
- case 'J': wi3(g, g->I[input[i++] - '0']); continue;
325
- case 'V': write_varref(g, g->V[input[i++] - '0']); continue;
326
- case 'W': write_varname(g, g->V[input[i++] - '0']); continue;
327
- case 'L': wlitref(g, g->L[input[i++] - '0']); continue;
328
- case 'A': wlitarray(g, g->L[input[i++] - '0']); continue;
329
- case 'c': wlitch(g, g->I[input[i++] - '0']); continue;
309
+ case 'S': {
310
+ int j = input[i++] - '0';
311
+ if (j < 0 || j > (int)(sizeof(g->S) / sizeof(g->S[0]))) {
312
+ printf("Invalid escape sequence ~%c%c in writef(g, \"%s\", p)\n",
313
+ ch, input[i - 1], input);
314
+ exit(1);
315
+ }
316
+ write_string(g, g->S[j]);
317
+ continue;
318
+ }
319
+ case 'B': {
320
+ int j = input[i++] - '0';
321
+ if (j < 0 || j > (int)(sizeof(g->B) / sizeof(g->B[0])))
322
+ goto invalid_escape2;
323
+ write_s(g, g->B[j]);
324
+ continue;
325
+ }
326
+ case 'I':
327
+ case 'J':
328
+ case 'c': {
329
+ int j = input[i++] - '0';
330
+ if (j < 0 || j > (int)(sizeof(g->I) / sizeof(g->I[0])))
331
+ goto invalid_escape2;
332
+ if (ch == 'I')
333
+ write_int(g, g->I[j]);
334
+ else if (ch == 'J')
335
+ wi3(g, g->I[j]);
336
+ else
337
+ wlitch(g, g->I[j]);
338
+ continue;
339
+ }
340
+ case 'V':
341
+ case 'W': {
342
+ int j = input[i++] - '0';
343
+ if (j < 0 || j > (int)(sizeof(g->V) / sizeof(g->V[0])))
344
+ goto invalid_escape2;
345
+ if (ch == 'V')
346
+ write_varref(g, g->V[j]);
347
+ else
348
+ write_varname(g, g->V[j]);
349
+ continue;
350
+ }
351
+ case 'L':
352
+ case 'A': {
353
+ int j = input[i++] - '0';
354
+ if (j < 0 || j > (int)(sizeof(g->L) / sizeof(g->L[0])))
355
+ goto invalid_escape2;
356
+ if (ch == 'L')
357
+ wlitref(g, g->L[j]);
358
+ else
359
+ wlitarray(g, g->L[j]);
360
+ continue;
361
+ }
330
362
  case 'a': write_data_address(g, p); continue;
331
363
  case '+': g->margin++; continue;
332
364
  case '-': g->margin--; continue;
333
365
  case '$': /* insert_s, insert_v etc */
334
- write_char(g, p->literalstring == 0 ? 'v' : 's');
366
+ write_char(g, p->literalstring == NULL ? 'v' : 's');
335
367
  continue;
336
368
  case 'p': write_string(g, g->options->externals_prefix); continue;
369
+ default:
370
+ printf("Invalid escape sequence ~%c in writef(g, \"%s\", p)\n",
371
+ ch, input);
372
+ exit(1);
373
+ invalid_escape2:
374
+ printf("Invalid escape sequence ~%c%c in writef(g, \"%s\", p)\n",
375
+ ch, input[i - 1], input);
376
+ exit(1);
337
377
  }
338
378
  }
339
379
  }
340
380
 
341
381
  static void w(struct generator * g, const char * s) {
342
- writef(g, s, 0);
382
+ writef(g, s, NULL);
343
383
  }
344
384
 
345
385
  static void generate_AE(struct generator * g, struct node * p) {
@@ -350,9 +390,11 @@ static void generate_AE(struct generator * g, struct node * p) {
350
390
  case c_number:
351
391
  write_int(g, p->number); break;
352
392
  case c_maxint:
353
- write_string(g, "MAXINT"); break;
393
+ write_string(g, "INT_MAX");
394
+ break;
354
395
  case c_minint:
355
- write_string(g, "MININT"); break;
396
+ write_string(g, "INT_MIN");
397
+ break;
356
398
  case c_neg:
357
399
  write_char(g, '-'); generate_AE(g, p->right); break;
358
400
  case c_multiply:
@@ -393,12 +435,222 @@ static void generate_AE(struct generator * g, struct node * p) {
393
435
  }
394
436
  }
395
437
 
438
+ // Return 0 for always f.
439
+ // Return 1 for always t.
440
+ // Return -1 for don't know (or can raise t or f).
441
+ static int check_possible_signals(struct generator * g,
442
+ struct node * p, int call_depth) {
443
+ switch (p->type) {
444
+ case c_fail:
445
+ case c_false:
446
+ /* Always gives signal f. */
447
+ return 0;
448
+ case c_assign:
449
+ case c_attach:
450
+ case c_debug:
451
+ case c_delete:
452
+ case c_do:
453
+ case c_insert:
454
+ case c_leftslice:
455
+ case c_repeat:
456
+ case c_rightslice:
457
+ case c_set:
458
+ case c_setmark:
459
+ case c_slicefrom:
460
+ case c_sliceto:
461
+ case c_tolimit:
462
+ case c_tomark:
463
+ case c_true:
464
+ case c_try:
465
+ case c_unset:
466
+ case c_mathassign:
467
+ case c_plusassign:
468
+ case c_minusassign:
469
+ case c_multiplyassign:
470
+ case c_divideassign:
471
+ case c_functionend:
472
+ /* Always gives signal t. */
473
+ return 1;
474
+ case c_not: {
475
+ int res = check_possible_signals(g, p->left, call_depth);
476
+ if (res >= 0)
477
+ res = !res;
478
+ if (res == 0 && p->right) {
479
+ if (p->right->type != c_functionend) {
480
+ fprintf(stderr, "%s:%d: warning: 'not' always signals f so following commands are unreachable\n",
481
+ g->analyser->tokeniser->file, p->line_number);
482
+ }
483
+ p->right = NULL;
484
+ }
485
+ return res;
486
+ }
487
+ case c_setlimit: {
488
+ /* If p->left signals f, setlimit does. */
489
+ int res = check_possible_signals(g, p->left, call_depth);
490
+ if (res == 0) {
491
+ return res;
492
+ }
493
+ /* Otherwise gives same signal as p->aux. */
494
+ int res2 = check_possible_signals(g, p->aux, call_depth);
495
+ if (res2 <= 0)
496
+ return res2;
497
+ return res;
498
+ }
499
+ case c_and:
500
+ case c_bra:
501
+ /* Gives same signal as list p->left. */
502
+ return check_possible_signals_list(g, p->left, p->type, call_depth);
503
+ case c_atleast:
504
+ case c_backwards:
505
+ case c_loop:
506
+ case c_reverse:
507
+ case c_test:
508
+ /* Give same signal as p->left. */
509
+ return check_possible_signals(g, p->left, call_depth);
510
+ case c_call:
511
+ if (call_depth >= 100) {
512
+ /* Recursive functions aren't typical in snowball programs,
513
+ * so make the pessimistic assumption that both t and f are
514
+ * possible if we hit a generous limit on recursion. It's
515
+ * not likely to make a difference to any real world
516
+ * program, but means we won't recurse until we run out of
517
+ * stack for pathological cases.
518
+ */
519
+ return -1;
520
+ }
521
+ return check_possible_signals_list(g, p->name->definition, c_define,
522
+ call_depth + 1);
523
+ case c_gopast:
524
+ case c_goto:
525
+ case c_goto_grouping:
526
+ case c_gopast_grouping:
527
+ case c_goto_non:
528
+ case c_gopast_non:
529
+ /* FIXME: unless we can prove that c is either definitely atlimit
530
+ * or definitely not atlimit... */
531
+ return -1;
532
+ case c_atlimit:
533
+ case c_atmark:
534
+ case c_booltest:
535
+ case c_hop:
536
+ case c_literalstring:
537
+ case c_next:
538
+ case c_eq:
539
+ case c_ne:
540
+ case c_gt:
541
+ case c_ge:
542
+ case c_lt:
543
+ case c_le:
544
+ case c_grouping:
545
+ case c_non:
546
+ case c_name:
547
+ /* FIXME: unless we can prove... */
548
+ return -1;
549
+ case c_substring: {
550
+ struct among * x = p->among;
551
+ if (x->always_matches) {
552
+ return 1;
553
+ }
554
+ return -1;
555
+ }
556
+ case c_among: {
557
+ struct among * x = p->among;
558
+ int r = 1;
559
+
560
+ if (x->substring == NULL) {
561
+ if (!x->always_matches) {
562
+ r = -1;
563
+ }
564
+ }
565
+
566
+ if (x->command_count > 0) {
567
+ int trues = (x->nocommand_count > 0);
568
+ int falses = false;
569
+ for (int i = 1; i <= x->command_count; i++) {
570
+ int res = check_possible_signals(g, x->commands[i - 1],
571
+ call_depth);
572
+ if (res == 0) {
573
+ falses = true;
574
+ } else if (res > 0) {
575
+ trues = true;
576
+ } else {
577
+ falses = trues = true;
578
+ }
579
+ if (falses && trues) break;
580
+ }
581
+ if (!trues) {
582
+ // All commands in among always fail.
583
+ return 0;
584
+ }
585
+ if (falses) {
586
+ // Commands in among can succeed or fail.
587
+ return -1;
588
+ }
589
+ }
590
+ return r;
591
+ }
592
+ case c_or: {
593
+ int r = 0;
594
+ for (struct node * q = p->left; q; q = q->right) {
595
+ // Just check this node - q->right is a separate clause of
596
+ // the OR.
597
+ int res = check_possible_signals(g, q, call_depth);
598
+ if (res > 0) {
599
+ // If any clause of the OR always signals t, then the OR
600
+ // always signals t.
601
+ if (q->right) {
602
+ if (q->right->type != c_functionend) {
603
+ fprintf(stderr, "%s:%d: warning: command always signals t here so rest of 'or' is unreachable\n",
604
+ g->analyser->tokeniser->file,
605
+ q->line_number);
606
+ }
607
+ q->right = NULL;
608
+ }
609
+ return 1;
610
+ }
611
+ if (res < 0) {
612
+ r = res;
613
+ }
614
+ }
615
+ return r;
616
+ }
617
+ default:
618
+ return -1;
619
+ }
620
+ }
621
+
622
+ // Return 0 for always f.
623
+ // Return 1 for always t.
624
+ // Return -1 for don't know (or can raise t or f).
625
+ int check_possible_signals_list(struct generator * g, struct node * p,
626
+ int type, int call_depth) {
627
+ int r = 1;
628
+ while (p) {
629
+ int res = check_possible_signals(g, p, call_depth);
630
+ if (res == 0) {
631
+ // If any command always signals f, then the list always signals f.
632
+ if (p->right) {
633
+ if (p->right->type != c_functionend) {
634
+ fprintf(stderr, "%s:%d: warning: command always signals f here so rest of %s is unreachable\n",
635
+ g->analyser->tokeniser->file, p->line_number,
636
+ (type == c_and ? "'and'" : "command list"));
637
+ }
638
+ p->right = NULL;
639
+ }
640
+ return res;
641
+ }
642
+ if (res < 0) r = res;
643
+ p = p->right;
644
+ }
645
+ return r;
646
+ }
647
+
396
648
  /* K_needed() tests to see if we really need to keep c. Not true when the
397
649
  command does not touch the cursor. This and repeat_score() could be
398
650
  elaborated almost indefinitely.
399
651
  */
400
652
 
401
- static int K_needed_(struct generator * g, struct node * p, int call_depth) {
653
+ static int K_needed_(struct node * p, int call_depth) {
402
654
  while (p) {
403
655
  switch (p->type) {
404
656
  case c_atlimit:
@@ -413,9 +665,9 @@ static int K_needed_(struct generator * g, struct node * p, int call_depth) {
413
665
  case c_divideassign:
414
666
  case c_eq:
415
667
  case c_ne:
416
- case c_gr:
668
+ case c_gt:
417
669
  case c_ge:
418
- case c_ls:
670
+ case c_lt:
419
671
  case c_le:
420
672
  case c_sliceto:
421
673
  case c_booltest:
@@ -424,6 +676,8 @@ static int K_needed_(struct generator * g, struct node * p, int call_depth) {
424
676
  case c_true:
425
677
  case c_false:
426
678
  case c_debug:
679
+ case c_functionend:
680
+ case c_not:
427
681
  break;
428
682
 
429
683
  case c_call:
@@ -434,12 +688,12 @@ static int K_needed_(struct generator * g, struct node * p, int call_depth) {
434
688
  * recurse until we run out of stack for pathological cases.
435
689
  */
436
690
  if (call_depth >= 100) return true;
437
- if (K_needed_(g, p->name->definition, call_depth + 1))
691
+ if (K_needed_(p->name->definition, call_depth + 1))
438
692
  return true;
439
693
  break;
440
694
 
441
695
  case c_bra:
442
- if (K_needed_(g, p->left, call_depth)) return true;
696
+ if (K_needed_(p->left, call_depth)) return true;
443
697
  break;
444
698
 
445
699
  default: return true;
@@ -450,7 +704,8 @@ static int K_needed_(struct generator * g, struct node * p, int call_depth) {
450
704
  }
451
705
 
452
706
  extern int K_needed(struct generator * g, struct node * p) {
453
- return K_needed_(g, p, 0);
707
+ (void)g;
708
+ return K_needed_(p, 0);
454
709
  }
455
710
 
456
711
  static int repeat_score(struct generator * g, struct node * p, int call_depth) {
@@ -467,12 +722,13 @@ static int repeat_score(struct generator * g, struct node * p, int call_depth) {
467
722
  case c_divideassign:
468
723
  case c_eq:
469
724
  case c_ne:
470
- case c_gr:
725
+ case c_gt:
471
726
  case c_ge:
472
- case c_ls:
727
+ case c_lt:
473
728
  case c_le:
474
729
  case c_sliceto: /* case c_not: must not be included here! */
475
730
  case c_debug:
731
+ case c_functionend:
476
732
  break;
477
733
 
478
734
  case c_call:
@@ -502,6 +758,10 @@ static int repeat_score(struct generator * g, struct node * p, int call_depth) {
502
758
  case c_next:
503
759
  case c_grouping:
504
760
  case c_non:
761
+ case c_goto_grouping:
762
+ case c_gopast_grouping:
763
+ case c_goto_non:
764
+ case c_gopast_non:
505
765
  case c_hop:
506
766
  if (++score >= 2)
507
767
  return score;
@@ -530,209 +790,247 @@ static void generate_bra(struct generator * g, struct node * p) {
530
790
  }
531
791
 
532
792
  static void generate_and(struct generator * g, struct node * p) {
533
- int keep_c = 0;
793
+ struct str * savevar = NULL;
534
794
  if (K_needed(g, p->left)) {
535
- writef(g, "~{~k~C", p);
536
- keep_c = g->keep_count;
537
- } else {
538
- writef(g, "~M~C", p);
795
+ savevar = vars_newname(g);
796
+ }
797
+
798
+ write_comment(g, p);
799
+
800
+ if (savevar) {
801
+ write_block_start(g);
802
+ write_savecursor(g, p, savevar);
539
803
  }
804
+
540
805
  p = p->left;
541
806
  while (p) {
542
807
  generate(g, p);
543
- if (keep_c && p->right != 0) {
544
- w(g, "~M"); wrestore(g, p, keep_c); w(g, "~N");
545
- }
808
+ if (savevar && p->right != NULL) write_restorecursor(g, p, savevar);
546
809
  p = p->right;
547
810
  }
548
- if (keep_c) w(g, "~}");
811
+
812
+ if (savevar) {
813
+ write_block_end(g);
814
+ str_delete(savevar);
815
+ }
549
816
  }
550
817
 
551
818
  static void generate_or(struct generator * g, struct node * p) {
552
- int keep_c = 0;
819
+ struct str * savevar = NULL;
820
+ if (K_needed(g, p->left)) {
821
+ savevar = vars_newname(g);
822
+ }
553
823
 
554
824
  int used = g->label_used;
555
825
  int a0 = g->failure_label;
556
- int a1 = g->failure_keep_count;
826
+ struct str * a1 = str_copy(g->failure_str);
557
827
 
558
828
  int out_lab = new_label(g);
829
+ write_comment(g, p);
559
830
 
560
- if (K_needed(g, p->left)) {
561
- writef(g, "~{~k~C", p);
562
- keep_c = g->keep_count;
563
- } else {
564
- writef(g, "~M~C", p);
831
+ if (savevar) {
832
+ write_block_start(g);
833
+ write_savecursor(g, p, savevar);
565
834
  }
835
+
566
836
  p = p->left;
567
- g->failure_keep_count = 0;
568
- while (p->right) {
837
+ str_clear(g->failure_str);
838
+
839
+ while (p->right != NULL) {
569
840
  g->failure_label = new_label(g);
570
841
  g->label_used = 0;
571
842
  generate(g, p);
572
843
  wgotol(g, out_lab);
573
844
  if (g->label_used)
574
845
  wsetl(g, g->failure_label);
575
- if (keep_c) {
576
- w(g, "~M"); wrestore(g, p, keep_c); w(g, "~N");
577
- }
846
+ if (savevar) write_restorecursor(g, p, savevar);
578
847
  p = p->right;
579
848
  }
849
+
580
850
  g->label_used = used;
581
851
  g->failure_label = a0;
582
- g->failure_keep_count = a1;
852
+ str_delete(g->failure_str);
853
+ g->failure_str = a1;
583
854
 
584
855
  generate(g, p);
585
- if (keep_c) w(g, "~}");
856
+
857
+ if (savevar) {
858
+ write_block_end(g);
859
+ str_delete(savevar);
860
+ }
586
861
  wsetl(g, out_lab);
587
862
  }
588
863
 
589
864
  static void generate_backwards(struct generator * g, struct node * p) {
590
-
591
- writef(g, "~Mz->lb = z->c; z->c = z->l;~C~N", p);
865
+ write_comment(g, p);
866
+ writef(g, "~Mz->lb = z->c; z->c = z->l;~N", p);
592
867
  generate(g, p->left);
593
868
  w(g, "~Mz->c = z->lb;~N");
594
869
  }
595
870
 
596
871
 
597
872
  static void generate_not(struct generator * g, struct node * p) {
598
- int keep_c = 0;
873
+ struct str * savevar = NULL;
874
+ if (K_needed(g, p->left)) {
875
+ savevar = vars_newname(g);
876
+ }
599
877
 
600
878
  int used = g->label_used;
601
879
  int a0 = g->failure_label;
602
- int a1 = g->failure_keep_count;
880
+ struct str * a1 = str_copy(g->failure_str);
603
881
 
604
- if (K_needed(g, p->left)) {
605
- writef(g, "~{~k~C", p);
606
- keep_c = g->keep_count;
607
- } else {
608
- writef(g, "~M~C", p);
882
+ write_comment(g, p);
883
+ if (savevar) {
884
+ write_block_start(g);
885
+ write_savecursor(g, p, savevar);
609
886
  }
610
887
 
611
888
  g->failure_label = new_label(g);
889
+ str_clear(g->failure_str);
612
890
  g->label_used = 0;
613
- g->failure_keep_count = 0;
614
891
  generate(g, p->left);
615
892
 
616
- {
617
- int l = g->failure_label;
618
- int u = g->label_used;
893
+ int l = g->failure_label;
894
+ int u = g->label_used;
619
895
 
620
- g->label_used = used;
621
- g->failure_label = a0;
622
- g->failure_keep_count = a1;
896
+ g->label_used = used;
897
+ g->failure_label = a0;
898
+ str_delete(g->failure_str);
899
+ g->failure_str = a1;
623
900
 
624
- writef(g, "~M~f~N", p);
625
- if (u)
626
- wsetl(g, l);
627
- }
628
- if (keep_c) {
629
- w(g, "~M"); wrestore(g, p, keep_c); w(g, "~N~}");
901
+ writef(g, "~M~f~N", p);
902
+ if (u)
903
+ wsetl(g, l);
904
+
905
+ if (savevar) {
906
+ write_restorecursor(g, p, savevar);
907
+ write_block_end(g);
908
+ str_delete(savevar);
630
909
  }
631
910
  }
632
911
 
633
912
 
634
913
  static void generate_try(struct generator * g, struct node * p) {
635
- int keep_c = 0;
914
+ struct str * savevar = NULL;
636
915
  if (K_needed(g, p->left)) {
637
- writef(g, "~{~k~C", p);
638
- keep_c = g->keep_count;
639
- } else {
640
- writef(g, "~M~C", p);
916
+ savevar = vars_newname(g);
917
+ }
918
+
919
+ write_comment(g, p);
920
+ if (savevar) {
921
+ write_block_start(g);
922
+ write_savecursor(g, p, savevar);
641
923
  }
642
- g->failure_keep_count = keep_c;
643
924
 
644
925
  g->failure_label = new_label(g);
926
+ str_clear(g->failure_str);
645
927
  g->label_used = 0;
928
+ if (savevar) append_restore_string(p, g->failure_str, savevar);
929
+
646
930
  generate(g, p->left);
647
931
 
648
932
  if (g->label_used)
649
933
  wsetl(g, g->failure_label);
650
934
 
651
- if (keep_c) w(g, "~}");
935
+ if (savevar) {
936
+ write_block_end(g);
937
+ str_delete(savevar);
938
+ }
652
939
  }
653
940
 
654
941
  static void generate_set(struct generator * g, struct node * p) {
655
- g->V[0] = p->name; writef(g, "~M~V0 = 1;~C", p);
942
+ write_comment(g, p);
943
+ g->V[0] = p->name;
944
+ writef(g, "~M~V0 = 1;~N", p);
656
945
  }
657
946
 
658
947
  static void generate_unset(struct generator * g, struct node * p) {
659
- g->V[0] = p->name; writef(g, "~M~V0 = 0;~C", p);
948
+ write_comment(g, p);
949
+ g->V[0] = p->name;
950
+ writef(g, "~M~V0 = 0;~N", p);
660
951
  }
661
952
 
662
953
  static void generate_fail(struct generator * g, struct node * p) {
954
+ write_comment(g, p);
663
955
  generate(g, p->left);
664
- writef(g, "~M~f~C", p);
956
+ writef(g, "~M~f~N", p);
665
957
  }
666
958
 
667
959
  /* generate_test() also implements 'reverse' */
668
960
 
669
961
  static void generate_test(struct generator * g, struct node * p) {
670
- int keep_c = 0;
962
+ struct str * savevar = NULL;
671
963
  if (K_needed(g, p->left)) {
672
- keep_c = ++g->keep_count;
673
- w(g, p->mode == m_forward ? "~{int c_test" :
674
- "~{int m_test");
675
- write_int(g, keep_c);
676
- w(g, p->mode == m_forward ? " = z->c;" :
677
- " = z->l - z->c;");
678
- writef(g, "~C", p);
679
- } else writef(g, "~M~C", p);
964
+ savevar = vars_newname(g);
965
+ }
966
+
967
+ write_comment(g, p);
968
+
969
+ if (savevar) {
970
+ write_block_start(g);
971
+ write_savecursor(g, p, savevar);
972
+ }
680
973
 
681
974
  generate(g, p->left);
682
975
 
683
- if (keep_c) {
684
- w(g, p->mode == m_forward ? "~Mz->c = c_test" :
685
- "~Mz->c = z->l - m_test");
686
- write_int(g, keep_c);
687
- writef(g, ";~N~}", p);
976
+ if (savevar) {
977
+ write_restorecursor(g, p, savevar);
978
+ write_block_end(g);
979
+ str_delete(savevar);
688
980
  }
689
981
  }
690
982
 
691
983
  static void generate_do(struct generator * g, struct node * p) {
692
- int keep_c = 0;
984
+ struct str * savevar = NULL;
693
985
  if (K_needed(g, p->left)) {
694
- writef(g, "~{~k~C", p);
695
- keep_c = g->keep_count;
696
- } else {
697
- writef(g, "~M~C", p);
986
+ savevar = vars_newname(g);
987
+ }
988
+ if (savevar) {
989
+ write_block_start(g);
990
+ write_savecursor(g, p, savevar);
698
991
  }
699
992
 
700
993
  if (p->left->type == c_call) {
701
994
  /* Optimise do <call> */
995
+ write_comment(g, p->left);
702
996
  g->V[0] = p->left->name;
703
- writef(g, "~{int ret = ~V0(z);~C", p->left);
997
+ writef(g, "~{~Mint ret = ~V0(z);~N", p->left);
704
998
  w(g, "~Mif (ret < 0) return ret;~N~}");
705
999
  } else {
706
1000
  g->failure_label = new_label(g);
707
1001
  g->label_used = 0;
708
- g->failure_keep_count = 0;
1002
+ str_clear(g->failure_str);
1003
+
709
1004
  generate(g, p->left);
710
1005
 
711
1006
  if (g->label_used)
712
1007
  wsetl(g, g->failure_label);
713
1008
  }
714
- if (keep_c) {
715
- w(g, "~M"); wrestore(g, p, keep_c);
716
- w(g, "~N~}");
1009
+ if (savevar) {
1010
+ write_restorecursor(g, p, savevar);
1011
+ write_block_end(g);
1012
+ str_delete(savevar);
717
1013
  }
718
1014
  }
719
1015
 
720
1016
  static void generate_next(struct generator * g, struct node * p) {
1017
+ write_comment(g, p);
721
1018
  if (g->options->encoding == ENC_UTF8) {
722
1019
  if (p->mode == m_forward)
723
- w(g, "~{int ret = skip_utf8(z->p, z->c, z->l, 1");
1020
+ w(g, "~{~Mint ret = skip_utf8(z->p, z->c, z->l, 1");
724
1021
  else
725
- w(g, "~{int ret = skip_b_utf8(z->p, z->c, z->lb, 1");
1022
+ w(g, "~{~Mint ret = skip_b_utf8(z->p, z->c, z->lb, 1");
726
1023
  writef(g, ");~N"
727
1024
  "~Mif (ret < 0) ~f~N"
728
- "~Mz->c = ret;~C"
1025
+ "~Mz->c = ret;~N"
729
1026
  "~}", p);
730
1027
  } else
731
1028
  writef(g, "~M~l~N"
732
- "~M~i~C", p);
1029
+ "~M~i~N", p);
733
1030
  }
734
1031
 
735
1032
  static void generate_GO_grouping(struct generator * g, struct node * p, int is_goto, int complement) {
1033
+ write_comment(g, p);
736
1034
 
737
1035
  struct grouping * q = p->name->grouping;
738
1036
  g->S[0] = p->mode == m_forward ? "" : "_b";
@@ -742,9 +1040,9 @@ static void generate_GO_grouping(struct generator * g, struct node * p, int is_g
742
1040
  g->I[0] = q->smallest_ch;
743
1041
  g->I[1] = q->largest_ch;
744
1042
  if (is_goto) {
745
- writef(g, "~Mif (~S1_grouping~S0~S2(z, ~V0, ~I0, ~I1, 1) < 0) ~f~C", p);
1043
+ writef(g, "~Mif (~S1_grouping~S0~S2(z, ~V0, ~I0, ~I1, 1) < 0) ~f~N", p);
746
1044
  } else {
747
- writef(g, "~{~C"
1045
+ writef(g, "~{"
748
1046
  "~Mint ret = ~S1_grouping~S0~S2(z, ~V0, ~I0, ~I1, 1);~N"
749
1047
  "~Mif (ret < 0) ~f~N", p);
750
1048
  if (p->mode == m_forward)
@@ -756,60 +1054,51 @@ static void generate_GO_grouping(struct generator * g, struct node * p, int is_g
756
1054
  }
757
1055
 
758
1056
  static void generate_GO(struct generator * g, struct node * p, int style) {
759
- int keep_c = 0;
1057
+ write_comment(g, p);
760
1058
 
761
1059
  int used = g->label_used;
762
1060
  int a0 = g->failure_label;
763
- int a1 = g->failure_keep_count;
1061
+ struct str * a1 = str_copy(g->failure_str);
764
1062
 
765
- if (p->left->type == c_grouping || p->left->type == c_non) {
766
- /* Special case for "goto" or "gopast" when used on a grouping or an
767
- * inverted grouping - the movement of c by the matching action is
768
- * exactly what we want! */
769
- #ifdef OPTIMISATION_WARNINGS
770
- printf("Optimising %s %s\n", style ? "goto" : "gopast", p->left->type == c_non ? "non" : "grouping");
771
- #endif
772
- if (g->options->comments) {
773
- writef(g, "~M~C", p);
774
- }
775
- generate_GO_grouping(g, p->left, style, p->left->type == c_non);
776
- return;
777
- }
778
-
779
- w(g, "~Mwhile(1) {"); writef(g, "~C~+", p);
1063
+ w(g, "~Mwhile (1) {~N~+");
780
1064
 
1065
+ struct str * savevar = NULL;
781
1066
  if (style == 1 || repeat_restore(g, p->left)) {
782
- writef(g, "~M~k~N", p);
783
- keep_c = g->keep_count;
1067
+ savevar = vars_newname(g);
1068
+ write_savecursor(g, p, savevar);
784
1069
  }
785
1070
 
786
1071
  g->failure_label = new_label(g);
787
1072
  g->label_used = 0;
788
- g->failure_keep_count = 0;
1073
+ str_clear(g->failure_str);
789
1074
  generate(g, p->left);
790
1075
 
791
1076
  if (style == 1) {
792
1077
  /* include for goto; omit for gopast */
793
- w(g, "~M"); wrestore(g, p, keep_c); w(g, "~N");
1078
+ write_restorecursor(g, p, savevar);
794
1079
  }
795
1080
  w(g, "~Mbreak;~N");
796
1081
  if (g->label_used)
797
1082
  wsetl(g, g->failure_label);
798
- if (keep_c) {
799
- w(g, "~M"); wrestore(g, p, keep_c); w(g, "~N");
1083
+ if (savevar) {
1084
+ write_restorecursor(g, p, savevar);
1085
+ str_delete(savevar);
800
1086
  }
801
1087
 
802
1088
  g->label_used = used;
803
1089
  g->failure_label = a0;
804
- g->failure_keep_count = a1;
1090
+ str_delete(g->failure_str);
1091
+ g->failure_str = a1;
805
1092
 
806
1093
  generate_next(g, p);
807
1094
  w(g, "~}");
808
1095
  }
809
1096
 
810
1097
  static void generate_loop(struct generator * g, struct node * p) {
811
- w(g, "~{int i; for (i = "); generate_AE(g, p->AE); writef(g, "; i > 0; i--)~C"
812
- "~{", p);
1098
+ write_comment(g, p);
1099
+ w(g, "~{~Mint i; for (i = ");
1100
+ generate_AE(g, p->AE);
1101
+ writef(g, "; i > 0; i--) {~N~+", p);
813
1102
 
814
1103
  generate(g, p->left);
815
1104
 
@@ -817,83 +1106,103 @@ static void generate_loop(struct generator * g, struct node * p) {
817
1106
  "~}");
818
1107
  }
819
1108
 
820
- static void generate_repeat_or_atleast(struct generator * g, struct node * p, int atleast_case) {
821
- int keep_c = 0;
822
- if (atleast_case) {
823
- writef(g, "~Mwhile(1) {~+~N", p);
824
- } else {
825
- writef(g, "~Mwhile(1) {~+~C", p);
826
- }
1109
+ static void generate_repeat_or_atleast(struct generator * g, struct node * p, struct str * loopvar) {
1110
+ writef(g, "~Mwhile (1) {~+~N", p);
827
1111
 
1112
+ struct str * savevar = NULL;
828
1113
  if (repeat_restore(g, p->left)) {
829
- writef(g, "~M~k~N", p);
830
- keep_c = g->keep_count;
1114
+ savevar = vars_newname(g);
1115
+ write_savecursor(g, p, savevar);
831
1116
  }
832
1117
 
833
1118
  g->failure_label = new_label(g);
834
1119
  g->label_used = 0;
835
- g->failure_keep_count = 0;
1120
+ str_clear(g->failure_str);
1121
+
1122
+ int possible_signals = check_possible_signals_list(g, p->left, p->type, 0);
1123
+ if (possible_signals != -1) {
1124
+ fprintf(stderr, "%s:%d: warning: body of '%s' always signals '%c'\n",
1125
+ g->analyser->tokeniser->file, p->line_number,
1126
+ loopvar ? "atleast" : "repeat", possible_signals ? 't' : 'f');
1127
+ }
836
1128
  generate(g, p->left);
837
1129
 
838
- if (atleast_case) w(g, "~Mi--;~N");
1130
+ if (loopvar != NULL) {
1131
+ g->B[0] = str_data(loopvar);
1132
+ w(g, "~M~B0--;~N");
1133
+ }
839
1134
 
840
1135
  w(g, "~Mcontinue;~N");
1136
+
841
1137
  if (g->label_used)
842
1138
  wsetl(g, g->failure_label);
843
1139
 
844
- if (keep_c) {
845
- w(g, "~M"); wrestore(g, p, keep_c); w(g, "~N");
1140
+ if (savevar) {
1141
+ write_restorecursor(g, p, savevar);
1142
+ str_delete(savevar);
846
1143
  }
847
1144
 
848
- w(g, "~Mbreak;~N"
849
- "~}");
1145
+ w(g, "~Mbreak;~N~}");
850
1146
  }
851
1147
 
852
1148
  static void generate_repeat(struct generator * g, struct node * p) {
853
- generate_repeat_or_atleast(g, p, false);
1149
+ write_comment(g, p);
1150
+ generate_repeat_or_atleast(g, p, NULL);
854
1151
  }
855
1152
 
856
1153
  static void generate_atleast(struct generator * g, struct node * p) {
857
- w(g, "~{int i = "); generate_AE(g, p->AE); w(g, ";~C");
1154
+ struct str * loopvar = vars_newname(g);
1155
+
1156
+ write_comment(g, p);
1157
+ g->B[0] = str_data(loopvar);
1158
+ w(g, "~{~Mint ~B0 = ");
1159
+ generate_AE(g, p->AE);
1160
+ w(g, ";~N");
858
1161
  {
859
1162
  int used = g->label_used;
860
1163
  int a0 = g->failure_label;
861
- int a1 = g->failure_keep_count;
1164
+ struct str * a1 = str_copy(g->failure_str);
862
1165
 
863
- generate_repeat_or_atleast(g, p, true);
1166
+ generate_repeat_or_atleast(g, p, loopvar);
864
1167
 
865
1168
  g->label_used = used;
866
1169
  g->failure_label = a0;
867
- g->failure_keep_count = a1;
1170
+ str_delete(g->failure_str);
1171
+ g->failure_str = a1;
868
1172
  }
869
- writef(g, "~Mif (i > 0) ~f~N"
1173
+ g->B[0] = str_data(loopvar);
1174
+ writef(g, "~Mif (~B0 > 0) ~f~N"
870
1175
  "~}", p);
1176
+ str_delete(loopvar);
871
1177
  }
872
1178
 
873
1179
  static void generate_setmark(struct generator * g, struct node * p) {
1180
+ write_comment(g, p);
874
1181
  g->V[0] = p->name;
875
- writef(g, "~M~V0 = z->c;~C", p);
1182
+ writef(g, "~M~V0 = z->c;~N", p);
876
1183
  }
877
1184
 
878
1185
  static void generate_tomark(struct generator * g, struct node * p) {
1186
+ write_comment(g, p);
879
1187
  g->S[0] = p->mode == m_forward ? ">" : "<";
880
1188
 
881
1189
  w(g, "~Mif (z->c ~S0 "); generate_AE(g, p->AE); writef(g, ") ~f~N", p);
882
- w(g, "~Mz->c = "); generate_AE(g, p->AE); writef(g, ";~C", p);
1190
+ w(g, "~Mz->c = "); generate_AE(g, p->AE); writef(g, ";~N", p);
883
1191
  }
884
1192
 
885
1193
  static void generate_atmark(struct generator * g, struct node * p) {
886
-
887
- w(g, "~Mif (z->c != "); generate_AE(g, p->AE); writef(g, ") ~f~C", p);
1194
+ write_comment(g, p);
1195
+ w(g, "~Mif (z->c != "); generate_AE(g, p->AE); writef(g, ") ~f~N", p);
888
1196
  }
889
1197
 
890
1198
  static void generate_hop(struct generator * g, struct node * p) {
1199
+ write_comment(g, p);
891
1200
  if (g->options->encoding == ENC_UTF8) {
892
1201
  g->S[0] = p->mode == m_forward ? "" : "_b";
893
1202
  g->S[1] = p->mode == m_forward ? "z->l" : "z->lb";
894
- w(g, "~{int ret = skip~S0_utf8(z->p, z->c, ~S1, ");
1203
+ w(g, "~{~Mint ret = skip~S0_utf8(z->p, z->c, ~S1, ");
895
1204
  generate_AE(g, p->AE);
896
- writef(g, ");~C", p);
1205
+ writef(g, ");~N", p);
897
1206
  writef(g, "~Mif (ret < 0) ~f~N", p);
898
1207
  writef(g, "~Mz->c = ret;~N"
899
1208
  "~}", p);
@@ -910,16 +1219,16 @@ static void generate_hop(struct generator * g, struct node * p) {
910
1219
  // handled - we rely on this here and unconditionally update z->c.
911
1220
  w(g, "z->c = z->c ~S0 ");
912
1221
  generate_AE(g, p->AE);
913
- w(g, ";~C");
1222
+ writef(g, ";~N", p);
914
1223
  if (p->mode == m_forward) {
915
1224
  writef(g, "~Mif (z->c > z->l) ~f~N", p);
916
1225
  } else {
917
1226
  writef(g, "~Mif (z->c < z->lb) ~f~N", p);
918
1227
  }
919
1228
  } else {
920
- w(g, "~{int ret = z->c ~S0 ");
1229
+ w(g, "~{~Mint ret = z->c ~S0 ");
921
1230
  generate_AE(g, p->AE);
922
- writef(g, ";~C", p);
1231
+ writef(g, ";~N", p);
923
1232
  if (p->mode == m_forward) {
924
1233
  writef(g, "~Mif (ret > z->l || ret < z->c) ~f~N", p);
925
1234
  } else {
@@ -932,76 +1241,83 @@ static void generate_hop(struct generator * g, struct node * p) {
932
1241
  }
933
1242
 
934
1243
  static void generate_delete(struct generator * g, struct node * p) {
935
- writef(g, "~{int ret = slice_del(z);~C", p);
1244
+ write_comment(g, p);
1245
+ writef(g, "~{~Mint ret = slice_del(z);~N", p);
936
1246
  writef(g, "~Mif (ret < 0) return ret;~N"
937
1247
  "~}", p);
938
1248
  }
939
1249
 
940
1250
  static void generate_tolimit(struct generator * g, struct node * p) {
1251
+ write_comment(g, p);
941
1252
  g->S[0] = p->mode == m_forward ? "" : "b";
942
- writef(g, "~Mz->c = z->l~S0;~C", p);
1253
+ writef(g, "~Mz->c = z->l~S0;~N", p);
943
1254
  }
944
1255
 
945
1256
  static void generate_atlimit(struct generator * g, struct node * p) {
1257
+ write_comment(g, p);
946
1258
  g->S[0] = p->mode == m_forward ? "" : "b";
947
1259
  g->S[1] = p->mode == m_forward ? "<" : ">";
948
- writef(g, "~Mif (z->c ~S1 z->l~S0) ~f~C", p);
1260
+ writef(g, "~Mif (z->c ~S1 z->l~S0) ~f~N", p);
949
1261
  }
950
1262
 
951
1263
  static void generate_leftslice(struct generator * g, struct node * p) {
1264
+ write_comment(g, p);
952
1265
  g->S[0] = p->mode == m_forward ? "bra" : "ket";
953
- writef(g, "~Mz->~S0 = z->c;~C", p);
1266
+ writef(g, "~Mz->~S0 = z->c;~N", p);
954
1267
  }
955
1268
 
956
1269
  static void generate_rightslice(struct generator * g, struct node * p) {
1270
+ write_comment(g, p);
957
1271
  g->S[0] = p->mode == m_forward ? "ket" : "bra";
958
- writef(g, "~Mz->~S0 = z->c;~C", p);
1272
+ writef(g, "~Mz->~S0 = z->c;~N", p);
959
1273
  }
960
1274
 
961
1275
  static void generate_assignto(struct generator * g, struct node * p) {
1276
+ write_comment(g, p);
962
1277
  g->V[0] = p->name;
963
- writef(g, "~M~V0 = assign_to(z, ~V0);~C"
964
- "~Mif (~V0 == 0) return -1;~C", p);
1278
+ writef(g, "~M~V0 = assign_to(z, ~V0);~N"
1279
+ "~Mif (~V0 == 0) return -1;~N", p);
965
1280
  }
966
1281
 
967
1282
  static void generate_sliceto(struct generator * g, struct node * p) {
1283
+ write_comment(g, p);
968
1284
  g->V[0] = p->name;
969
- writef(g, "~M~V0 = slice_to(z, ~V0);~C"
1285
+ writef(g, "~M~V0 = slice_to(z, ~V0);~N"
970
1286
  "~Mif (~V0 == 0) return -1;~N", p);
971
1287
  }
972
1288
 
973
1289
  static void generate_insert(struct generator * g, struct node * p, int style) {
974
-
975
1290
  int keep_c = style == c_attach;
1291
+ write_comment(g, p);
976
1292
  if (p->mode == m_backward) keep_c = !keep_c;
977
- writef(g, "~{int ret;~N", p);
978
- if (keep_c) w(g, "~{int saved_c = z->c;~N");
979
- writef(g, "~Mret = insert_~$(z, z->c, z->c, ~a);~C", p);
980
- if (keep_c) w(g, "~Mz->c = saved_c;~N~}");
981
- writef(g, "~Mif (ret < 0) return ret;~N"
982
- "~}", p);
1293
+ writef(g, "~{", p);
1294
+ if (keep_c) w(g, "~Mint saved_c = z->c;~N");
1295
+ writef(g, "~Mint ret = insert_~$(z, z->c, z->c, ~a);~N", p);
1296
+ if (keep_c) w(g, "~Mz->c = saved_c;~N");
1297
+ writef(g, "~Mif (ret < 0) return ret;~N~}", p);
983
1298
  }
984
1299
 
985
1300
  static void generate_assignfrom(struct generator * g, struct node * p) {
986
-
987
1301
  int keep_c = p->mode == m_forward; /* like 'attach' */
988
- writef(g, "~{int ret;~N", p);
989
- if (keep_c) writef(g, "~{int saved_c = z->c;~N", p);
990
- w(g, "~Mret = ");
991
- writef(g, keep_c ? "insert_~$(z, z->c, z->l, ~a);~C" : "insert_~$(z, z->lb, z->c, ~a);~C", p);
992
- if (keep_c) w(g, "~Mz->c = saved_c;~N~}");
993
- writef(g, "~Mif (ret < 0) return ret;~N"
994
- "~}", p);
1302
+
1303
+ write_comment(g, p);
1304
+ writef(g, "~{", p);
1305
+ if (keep_c) w(g, "~Mint saved_c = z->c;~N");
1306
+ w(g, "~Mint ret = ");
1307
+ writef(g, keep_c ? "insert_~$(z, z->c, z->l, ~a);~N" : "insert_~$(z, z->lb, z->c, ~a);~N", p);
1308
+ if (keep_c) w(g, "~Mz->c = saved_c;~N");
1309
+ writef(g, "~Mif (ret < 0) return ret;~N~}", p);
995
1310
  }
996
1311
 
997
1312
  static void generate_slicefrom(struct generator * g, struct node * p) {
998
- writef(g, "~{int ret = slice_from_~$(z, ~a);~C", p);
999
- writef(g, "~Mif (ret < 0) return ret;~N"
1000
- "~}", p);
1313
+ write_comment(g, p);
1314
+ writef(g, "~{~Mint ret = slice_from_~$(z, ~a);~N", p);
1315
+ writef(g, "~Mif (ret < 0) return ret;~N~}", p);
1001
1316
  }
1002
1317
 
1003
1318
  static void generate_setlimit(struct generator * g, struct node * p) {
1004
- int keep_c;
1319
+ struct str * varname = vars_newname(g);
1320
+ write_comment(g, p);
1005
1321
  if (p->left && p->left->type == c_tomark) {
1006
1322
  /* Special case for:
1007
1323
  *
@@ -1012,62 +1328,83 @@ static void generate_setlimit(struct generator * g, struct node * p) {
1012
1328
  * restore c.
1013
1329
  */
1014
1330
  struct node * q = p->left;
1331
+ write_comment(g, q);
1332
+ assert(q->right == NULL);
1015
1333
 
1016
- ++g->keep_count;
1017
- writef(g, "~N~{int mlimit", p);
1018
- write_int(g, g->keep_count);
1019
- writef(g, ";~C", p);
1020
- keep_c = g->keep_count;
1334
+ g->B[0] = str_data(varname);
1335
+ writef(g, "~N~{~Mint ~B0;~N", p);
1021
1336
 
1022
1337
  g->S[0] = q->mode == m_forward ? ">" : "<";
1023
1338
 
1024
1339
  w(g, "~Mif (z->c ~S0 "); generate_AE(g, q->AE); writef(g, ") ~f~N", q);
1025
- w(g, "~Mmlimit");
1026
- write_int(g, keep_c);
1340
+ g->B[0] = str_data(varname);
1341
+ w(g, "~M~B0 = ");
1027
1342
  if (p->mode == m_forward) {
1028
- w(g, " = z->l - z->c; z->l = ");
1343
+ w(g, "z->l - z->c; z->l = ");
1029
1344
  } else {
1030
- w(g, " = z->lb; z->lb = ");
1345
+ w(g, "z->lb; z->lb = ");
1031
1346
  }
1032
1347
  generate_AE(g, q->AE);
1033
1348
  w(g, ";~N");
1349
+
1350
+ if (p->mode == m_forward) {
1351
+ str_assign(g->failure_str, "z->l += ");
1352
+ str_append(g->failure_str, varname);
1353
+ str_append_ch(g->failure_str, ';');
1354
+ } else {
1355
+ str_assign(g->failure_str, "z->lb = ");
1356
+ str_append(g->failure_str, varname);
1357
+ str_append_ch(g->failure_str, ';');
1358
+ }
1034
1359
  } else {
1035
- writef(g, "~{~K~C", p);
1036
- keep_c = g->keep_count;
1360
+ struct str * savevar = vars_newname(g);
1361
+ write_savecursor(g, p, savevar);
1037
1362
  generate(g, p->left);
1038
1363
 
1039
- w(g, "~Mmlimit");
1040
- write_int(g, keep_c);
1041
- if (p->mode == m_forward)
1042
- w(g, " = z->l - z->c; z->l = z->c;~N");
1043
- else
1044
- w(g, " = z->lb; z->lb = z->c;~N");
1045
- w(g, "~M"); wrestore(g, p, keep_c); w(g, "~N");
1364
+ g->B[0] = str_data(varname);
1365
+ if (p->mode == m_forward) {
1366
+ w(g, "~Mint ~B0 = z->l - z->c; z->l = z->c;~N");
1367
+ } else {
1368
+ w(g, "~Mint ~B0 = z->lb; z->lb = z->c;~N");
1369
+ }
1370
+ write_restorecursor(g, p, savevar);
1371
+
1372
+ if (p->mode == m_forward) {
1373
+ str_assign(g->failure_str, "z->l += ");
1374
+ str_append(g->failure_str, varname);
1375
+ str_append_ch(g->failure_str, ';');
1376
+ } else {
1377
+ str_assign(g->failure_str, "z->lb = ");
1378
+ str_append(g->failure_str, varname);
1379
+ str_append_ch(g->failure_str, ';');
1380
+ }
1381
+ str_delete(savevar);
1046
1382
  }
1047
1383
 
1048
- g->failure_keep_count = -keep_c;
1049
1384
  generate(g, p->aux);
1050
1385
  w(g, "~M");
1051
- wrestorelimit(g, p, -g->failure_keep_count);
1386
+ write_str(g, g->failure_str);
1052
1387
  w(g, "~N"
1053
1388
  "~}");
1389
+ str_delete(varname);
1054
1390
  }
1055
1391
 
1056
1392
  /* dollar sets snowball up to operate on a string variable as if it were the
1057
1393
  * current string */
1058
1394
  static void generate_dollar(struct generator * g, struct node * p) {
1395
+ write_comment(g, p);
1059
1396
 
1060
1397
  int used = g->label_used;
1061
1398
  int a0 = g->failure_label;
1062
- int a1 = g->failure_keep_count;
1063
- int keep_token;
1399
+ struct str * a1 = str_copy(g->failure_str);
1064
1400
  g->failure_label = new_label(g);
1065
1401
  g->label_used = 0;
1066
- g->failure_keep_count = 0;
1402
+ str_clear(g->failure_str);
1067
1403
 
1068
- keep_token = ++g->keep_count;
1069
- g->I[0] = keep_token;
1070
- writef(g, "~{struct SN_env env~I0 = * z;~C", p);
1404
+ struct str * savevar = vars_newname(g);
1405
+ g->B[0] = str_data(savevar);
1406
+ writef(g, "~{~Mstruct SN_env en~B0 = * z;~N", p);
1407
+ // only copy start - we don't need to copy variables
1071
1408
  g->V[0] = p->name;
1072
1409
  /* Assume failure. */
1073
1410
  writef(g, "~Mint failure = 1;~N"
@@ -1083,47 +1420,78 @@ static void generate_dollar(struct generator * g, struct node * p) {
1083
1420
 
1084
1421
  g->label_used = used;
1085
1422
  g->failure_label = a0;
1086
- g->failure_keep_count = a1;
1423
+ str_delete(g->failure_str);
1424
+ g->failure_str = a1;
1087
1425
 
1088
- g->I[0] = keep_token;
1426
+ g->B[0] = str_data(savevar);
1089
1427
  writef(g, "~M~V0 = z->p;~N"
1090
- "~M* z = env~I0;~N"
1428
+ "~M* z = en~B0;~N"
1091
1429
  "~Mif (failure) ~f~N~}", p);
1430
+ str_delete(savevar);
1092
1431
  }
1093
1432
 
1094
- static void generate_integer_assign(struct generator * g, struct node * p, char * s) {
1095
-
1433
+ static void generate_integer_assign(struct generator * g, struct node * p, const char * s) {
1434
+ write_comment(g, p);
1096
1435
  g->V[0] = p->name;
1097
1436
  g->S[0] = s;
1098
- w(g, "~M~V0 ~S0 "); generate_AE(g, p->AE); writef(g, ";~C", p);
1437
+ w(g, "~M~V0 ~S0 "); generate_AE(g, p->AE); writef(g, ";~N", p);
1099
1438
  }
1100
1439
 
1101
- static void generate_integer_test(struct generator * g, struct node * p, char * s) {
1102
-
1103
- w(g, "~Mif (!(");
1440
+ static void generate_integer_test(struct generator * g, struct node * p) {
1441
+ write_comment(g, p);
1442
+ int relop = p->type;
1443
+ int optimise_to_return = (g->failure_label == x_return && p->right && p->right->type == c_functionend);
1444
+ if (optimise_to_return) {
1445
+ w(g, "~Mreturn ");
1446
+ p->right = NULL;
1447
+ } else {
1448
+ w(g, "~Mif (");
1449
+ // We want the inverse of the snowball test here.
1450
+ relop ^= 1;
1451
+ }
1104
1452
  generate_AE(g, p->left);
1105
- write_char(g, ' ');
1106
- write_string(g, s);
1107
- write_char(g, ' ');
1453
+ write_c_relop(g, relop);
1108
1454
  generate_AE(g, p->AE);
1109
- writef(g, ")) ~f~C", p);
1455
+ if (optimise_to_return) {
1456
+ writef(g, ";~N", p);
1457
+ } else {
1458
+ writef(g, ") ~f~N", p);
1459
+ }
1110
1460
  }
1111
1461
 
1112
1462
  static void generate_call(struct generator * g, struct node * p) {
1113
-
1463
+ int signals = check_possible_signals_list(g, p->name->definition, c_define, 0);
1464
+ write_comment(g, p);
1114
1465
  g->V[0] = p->name;
1115
- writef(g, "~{int ret = ~V0(z);~C", p);
1116
- if (g->failure_keep_count == 0 && g->failure_label == x_return) {
1466
+ if (str_len(g->failure_str) == 0 && g->failure_label == x_return &&
1467
+ (signals == 0 || (p->right && p->right->type == c_functionend))) {
1468
+ /* Always fails or tail call. */
1469
+ writef(g, "~Mreturn ~V0(z);~N", p);
1470
+ return;
1471
+ }
1472
+ writef(g, "~{~Mint ret = ~V0(z);~N", p);
1473
+ if (str_len(g->failure_str) == 0 && g->failure_label == x_return) {
1117
1474
  /* Combine the two tests in this special case for better optimisation
1118
1475
  * and clearer generated code. */
1119
- writef(g, "~Mif (ret <= 0) return ret;~N~}", p);
1476
+ writef(g, "~Mif (ret <= 0) return ret;~N", p);
1120
1477
  } else {
1121
- writef(g, "~Mif (ret == 0) ~f~N"
1122
- "~Mif (ret < 0) return ret;~N~}", p);
1478
+ if (signals == 1) {
1479
+ /* Always succeeds - just need to handle runtime errors. */
1480
+ writef(g, "~Mif (ret < 0) return ret;~N", p);
1481
+ } else if (signals == 0) {
1482
+ /* Always fails. */
1483
+ writef(g, "~Mif (ret < 0) return ret;~N", p);
1484
+ writef(g, "~M~f~N", p);
1485
+ } else {
1486
+ writef(g, "~Mif (ret == 0) ~f~N", p);
1487
+ writef(g, "~Mif (ret < 0) return ret;~N", p);
1488
+ }
1123
1489
  }
1490
+ writef(g, "~}", p);
1124
1491
  }
1125
1492
 
1126
1493
  static void generate_grouping(struct generator * g, struct node * p, int complement) {
1494
+ write_comment(g, p);
1127
1495
 
1128
1496
  struct grouping * q = p->name->grouping;
1129
1497
  g->S[0] = p->mode == m_forward ? "" : "_b";
@@ -1132,18 +1500,19 @@ static void generate_grouping(struct generator * g, struct node * p, int complem
1132
1500
  g->V[0] = p->name;
1133
1501
  g->I[0] = q->smallest_ch;
1134
1502
  g->I[1] = q->largest_ch;
1135
- writef(g, "~Mif (~S1_grouping~S0~S2(z, ~V0, ~I0, ~I1, 0)) ~f~C", p);
1503
+ writef(g, "~Mif (~S1_grouping~S0~S2(z, ~V0, ~I0, ~I1, 0)) ~f~N", p);
1136
1504
  }
1137
1505
 
1138
1506
  static void generate_namedstring(struct generator * g, struct node * p) {
1139
-
1507
+ write_comment(g, p);
1140
1508
  g->S[0] = p->mode == m_forward ? "" : "_b";
1141
1509
  g->V[0] = p->name;
1142
- writef(g, "~Mif (!(eq_v~S0(z, ~V0))) ~f~C", p);
1510
+ writef(g, "~Mif (!(eq_v~S0(z, ~V0))) ~f~N", p);
1143
1511
  }
1144
1512
 
1145
1513
  static void generate_literalstring(struct generator * g, struct node * p) {
1146
1514
  symbol * b = p->literalstring;
1515
+ write_comment(g, p);
1147
1516
  if (SIZE(b) == 1) {
1148
1517
  /* It's quite common to compare with a single character literal string,
1149
1518
  * so just inline the simpler code for this case rather than making a
@@ -1156,10 +1525,10 @@ static void generate_literalstring(struct generator * g, struct node * p) {
1156
1525
  }
1157
1526
  g->I[0] = *b;
1158
1527
  if (p->mode == m_forward) {
1159
- writef(g, "~Mif (z->c == z->l || z->p[z->c] != ~c0) ~f~C"
1528
+ writef(g, "~Mif (z->c == z->l || z->p[z->c] != ~c0) ~f~N"
1160
1529
  "~Mz->c++;~N", p);
1161
1530
  } else {
1162
- writef(g, "~Mif (z->c <= z->lb || z->p[z->c - 1] != ~c0) ~f~C"
1531
+ writef(g, "~Mif (z->c <= z->lb || z->p[z->c - 1] != ~c0) ~f~N"
1163
1532
  "~Mz->c--;~N", p);
1164
1533
  }
1165
1534
  } else {
@@ -1167,43 +1536,57 @@ static void generate_literalstring(struct generator * g, struct node * p) {
1167
1536
  g->I[0] = SIZE(b);
1168
1537
  g->L[0] = b;
1169
1538
 
1170
- writef(g, "~Mif (!(eq_s~S0(z, ~I0, ~L0))) ~f~C", p);
1539
+ writef(g, "~Mif (!(eq_s~S0(z, ~I0, ~L0))) ~f~N", p);
1171
1540
  }
1172
1541
  }
1173
1542
 
1174
1543
  static void generate_define(struct generator * g, struct node * p) {
1175
1544
  struct name * q = p->name;
1545
+ if (q->type == t_routine && !q->used) return;
1546
+
1547
+ write_newline(g);
1548
+ write_comment(g, p);
1549
+
1176
1550
  g->next_label = 0;
1551
+ g->var_number = 0;
1177
1552
 
1178
1553
  g->S[0] = q->type == t_routine ? "static" : "extern";
1179
1554
  g->V[0] = q;
1180
1555
 
1181
- w(g, "~N~S0 int ~V0(struct SN_env * z) {");
1182
- if (g->options->comments) {
1183
- write_string(g, p->mode == m_forward ? " /* forwardmode */" : " /* backwardmode */");
1184
- }
1185
- w(g, "~N~+");
1556
+ w(g, "~S0 int ~V0(struct SN_env * z) {~N~+");
1186
1557
  if (p->amongvar_needed) w(g, "~Mint among_var;~N");
1187
- g->failure_keep_count = 0;
1558
+ str_clear(g->failure_str);
1188
1559
  g->failure_label = x_return;
1189
1560
  g->label_used = 0;
1190
- g->keep_count = 0;
1561
+ int signals = check_possible_signals_list(g, p->left, c_define, 0);
1562
+
1563
+ /* Generate function body. */
1191
1564
  generate(g, p->left);
1192
- w(g, "~Mreturn 1;~N~}");
1565
+ if (p->left->right) {
1566
+ assert(p->left->right->type == c_functionend);
1567
+ if (signals) {
1568
+ generate(g, p->left->right);
1569
+ }
1570
+ }
1571
+ w(g, "~}");
1572
+ }
1573
+
1574
+ static void generate_functionend(struct generator * g, struct node * p) {
1575
+ (void)p;
1576
+ w(g, "~Mreturn 1;~N");
1193
1577
  }
1194
1578
 
1195
1579
  static void generate_substring(struct generator * g, struct node * p) {
1580
+ write_comment(g, p);
1196
1581
 
1197
1582
  struct among * x = p->among;
1198
1583
  int block = -1;
1199
1584
  unsigned int bitmap = 0;
1200
1585
  struct amongvec * among_cases = x->b;
1201
- int c;
1202
1586
  int empty_case = -1;
1203
1587
  int n_cases = 0;
1204
1588
  symbol cases[2];
1205
- int shortest_size = INT_MAX;
1206
- int shown_comment = 0;
1589
+ int shortest_size = x->shortest_size;
1207
1590
 
1208
1591
  g->S[0] = p->mode == m_forward ? "" : "_b";
1209
1592
  g->I[0] = x->number;
@@ -1216,14 +1599,7 @@ static void generate_substring(struct generator * g, struct node * p) {
1216
1599
  * In backward mode, we can't match if there are fewer characters before
1217
1600
  * the current position than the minimum length.
1218
1601
  */
1219
- for (c = 0; c < x->literalstring_count; ++c) {
1220
- int size = among_cases[c].size;
1221
- if (size != 0 && size < shortest_size) {
1222
- shortest_size = size;
1223
- }
1224
- }
1225
-
1226
- for (c = 0; c < x->literalstring_count; ++c) {
1602
+ for (int c = 0; c < x->literalstring_count; ++c) {
1227
1603
  symbol ch;
1228
1604
  if (among_cases[c].size == 0) {
1229
1605
  empty_case = c;
@@ -1300,42 +1676,43 @@ static void generate_substring(struct generator * g, struct node * p) {
1300
1676
  * so not matching the bitmap means we match the empty string.
1301
1677
  */
1302
1678
  g->I[4] = among_cases[empty_case].result;
1303
- writef(g, "among_var = ~I4; else~C", p);
1679
+ writef(g, "among_var = ~I4; else~N", p);
1304
1680
  } else {
1305
- writef(g, "~f~C", p);
1681
+ writef(g, "~f~N", p);
1306
1682
  }
1307
- shown_comment = 1;
1308
1683
  } else {
1309
1684
  #ifdef OPTIMISATION_WARNINGS
1310
1685
  printf("Couldn't shortcut among %d\n", x->number);
1311
1686
  #endif
1312
1687
  }
1313
1688
 
1314
- if (!x->amongvar_needed) {
1315
- writef(g, "~Mif (!(find_among~S0(z, a_~I0, ~I1))) ~f", p);
1316
- writef(g, shown_comment ? "~N" : "~C", p);
1689
+ if (x->amongvar_needed) {
1690
+ writef(g, "~Mamong_var = find_among~S0(z, a_~I0, ~I1);~N", p);
1691
+ if (!x->always_matches) {
1692
+ writef(g, "~Mif (!among_var) ~f~N", p);
1693
+ }
1694
+ } else if (x->always_matches) {
1695
+ writef(g, "~Mfind_among~S0(z, a_~I0, ~I1);~N", p);
1317
1696
  } else {
1318
- writef(g, "~Mamong_var = find_among~S0(z, a_~I0, ~I1);", p);
1319
- writef(g, shown_comment ? "~N" : "~C", p);
1320
- writef(g, "~Mif (!(among_var)) ~f~N", p);
1697
+ writef(g, "~Mif (!find_among~S0(z, a_~I0, ~I1)) ~f~N", p);
1321
1698
  }
1322
1699
  }
1323
1700
 
1324
1701
  static void generate_among(struct generator * g, struct node * p) {
1325
-
1326
1702
  struct among * x = p->among;
1327
1703
 
1328
- if (x->substring == 0) generate_substring(g, p);
1329
-
1330
- if (x->starter != 0) generate(g, x->starter);
1704
+ if (x->substring == NULL) {
1705
+ generate_substring(g, p);
1706
+ } else {
1707
+ write_comment(g, p);
1708
+ }
1331
1709
 
1332
1710
  if (x->command_count == 1 && x->nocommand_count == 0) {
1333
1711
  /* Only one outcome ("no match" already handled). */
1334
1712
  generate(g, x->commands[0]);
1335
1713
  } else if (x->command_count > 0) {
1336
- int i;
1337
- writef(g, "~Mswitch (among_var) {~C~+", p);
1338
- for (i = 1; i <= x->command_count; i++) {
1714
+ writef(g, "~Mswitch (among_var) {~N~+", p);
1715
+ for (int i = 1; i <= x->command_count; i++) {
1339
1716
  g->I[0] = i;
1340
1717
  w(g, "~Mcase ~I0:~N~+");
1341
1718
  generate(g, x->commands[i - 1]);
@@ -1346,29 +1723,27 @@ static void generate_among(struct generator * g, struct node * p) {
1346
1723
  }
1347
1724
 
1348
1725
  static void generate_booltest(struct generator * g, struct node * p) {
1349
-
1726
+ write_comment(g, p);
1350
1727
  g->V[0] = p->name;
1351
- writef(g, "~Mif (!(~V0)) ~f~C", p);
1728
+ writef(g, "~Mif (!(~V0)) ~f~N", p);
1352
1729
  }
1353
1730
 
1354
1731
  static void generate_false(struct generator * g, struct node * p) {
1355
-
1356
- writef(g, "~M~f~C", p);
1732
+ write_comment(g, p);
1733
+ writef(g, "~M~f~N", p);
1357
1734
  }
1358
1735
 
1359
1736
  static void generate_debug(struct generator * g, struct node * p) {
1360
-
1737
+ write_comment(g, p);
1361
1738
  g->I[0] = g->debug_count++;
1362
1739
  g->I[1] = p->line_number;
1363
- writef(g, "~Mdebug(z, ~I0, ~I1);~C", p);
1364
-
1740
+ writef(g, "~Mdebug(z, ~I0, ~I1);~N", p);
1365
1741
  }
1366
1742
 
1367
1743
  static void generate(struct generator * g, struct node * p) {
1368
-
1369
1744
  int used = g->label_used;
1370
1745
  int a0 = g->failure_label;
1371
- int a1 = g->failure_keep_count;
1746
+ struct str * a1 = str_copy(g->failure_str);
1372
1747
 
1373
1748
  switch (p->type) {
1374
1749
  case c_define: generate_define(g, p); break;
@@ -1386,6 +1761,11 @@ static void generate(struct generator * g, struct node * p) {
1386
1761
  case c_do: generate_do(g, p); break;
1387
1762
  case c_goto: generate_GO(g, p, 1); break;
1388
1763
  case c_gopast: generate_GO(g, p, 0); break;
1764
+ case c_goto_grouping: generate_GO_grouping(g, p, 1, 0); break;
1765
+ case c_gopast_grouping:
1766
+ generate_GO_grouping(g, p, 0, 0); break;
1767
+ case c_goto_non: generate_GO_grouping(g, p, 1, 1); break;
1768
+ case c_gopast_non: generate_GO_grouping(g, p, 0, 1); break;
1389
1769
  case c_repeat: generate_repeat(g, p); break;
1390
1770
  case c_loop: generate_loop(g, p); break;
1391
1771
  case c_atleast: generate_atleast(g, p); break;
@@ -1412,12 +1792,14 @@ static void generate(struct generator * g, struct node * p) {
1412
1792
  case c_minusassign: generate_integer_assign(g, p, "-="); break;
1413
1793
  case c_multiplyassign:generate_integer_assign(g, p, "*="); break;
1414
1794
  case c_divideassign: generate_integer_assign(g, p, "/="); break;
1415
- case c_eq: generate_integer_test(g, p, "=="); break;
1416
- case c_ne: generate_integer_test(g, p, "!="); break;
1417
- case c_gr: generate_integer_test(g, p, ">"); break;
1418
- case c_ge: generate_integer_test(g, p, ">="); break;
1419
- case c_ls: generate_integer_test(g, p, "<"); break;
1420
- case c_le: generate_integer_test(g, p, "<="); break;
1795
+ case c_eq:
1796
+ case c_ne:
1797
+ case c_gt:
1798
+ case c_ge:
1799
+ case c_lt:
1800
+ case c_le:
1801
+ generate_integer_test(g, p);
1802
+ break;
1421
1803
  case c_call: generate_call(g, p); break;
1422
1804
  case c_grouping: generate_grouping(g, p, false); break;
1423
1805
  case c_non: generate_grouping(g, p, true); break;
@@ -1429,6 +1811,7 @@ static void generate(struct generator * g, struct node * p) {
1429
1811
  case c_false: generate_false(g, p); break;
1430
1812
  case c_true: break;
1431
1813
  case c_debug: generate_debug(g, p); break;
1814
+ case c_functionend: generate_functionend(g, p); break;
1432
1815
  default: fprintf(stderr, "%d encountered\n", p->type);
1433
1816
  exit(1);
1434
1817
  }
@@ -1436,12 +1819,21 @@ static void generate(struct generator * g, struct node * p) {
1436
1819
  if (g->failure_label != a0)
1437
1820
  g->label_used = used;
1438
1821
  g->failure_label = a0;
1439
- g->failure_keep_count = a1;
1822
+ str_delete(g->failure_str);
1823
+ g->failure_str = a1;
1440
1824
  }
1441
1825
 
1442
1826
  void write_generated_comment_content(struct generator * g) {
1443
- w(g, "Generated by Snowball " SNOWBALL_VERSION
1444
- " - https://snowballstem.org/");
1827
+ // Report only the leafname of the Snowball source file to make output
1828
+ // reproducible even if an absolute path to the source file is specified.
1829
+ write_string(g, "Generated from ");
1830
+ const char * leaf = g->analyser->tokeniser->file;
1831
+ const char * p = strrchr(leaf, '/');
1832
+ if (p) leaf = p + 1;
1833
+ p = strrchr(leaf, '\\');
1834
+ if (p) leaf = p + 1;
1835
+ write_string(g, leaf);
1836
+ write_string(g, " by Snowball " SNOWBALL_VERSION " - https://snowballstem.org/");
1445
1837
  }
1446
1838
 
1447
1839
  void write_start_comment(struct generator * g,
@@ -1457,7 +1849,6 @@ void write_start_comment(struct generator * g,
1457
1849
  }
1458
1850
 
1459
1851
  static void generate_head(struct generator * g) {
1460
-
1461
1852
  w(g, "#include \"");
1462
1853
  if (g->options->runtime_path) {
1463
1854
  write_string(g, g->options->runtime_path);
@@ -1468,8 +1859,7 @@ static void generate_head(struct generator * g) {
1468
1859
  }
1469
1860
 
1470
1861
  static void generate_routine_headers(struct generator * g) {
1471
- struct name * q;
1472
- for (q = g->analyser->names; q; q = q->next) {
1862
+ for (struct name * q = g->analyser->names; q; q = q->next) {
1473
1863
  g->V[0] = q;
1474
1864
  switch (q->type) {
1475
1865
  case t_routine:
@@ -1491,60 +1881,51 @@ static void generate_routine_headers(struct generator * g) {
1491
1881
  }
1492
1882
 
1493
1883
  static void generate_among_table(struct generator * g, struct among * x) {
1884
+ write_comment(g, x->node);
1494
1885
 
1495
1886
  struct amongvec * v = x->b;
1496
1887
 
1497
1888
  g->I[0] = x->number;
1498
- {
1499
- int i;
1500
- for (i = 0; i < x->literalstring_count; i++) {
1501
- g->I[1] = i;
1502
- g->I[2] = v->size;
1503
- g->L[0] = v->b;
1504
- if (v->size)
1505
- w(g, "static const symbol s_~I0_~I1[~I2] = ~A0;~N");
1506
- v++;
1507
- }
1889
+ for (int i = 0; i < x->literalstring_count; i++) {
1890
+ g->I[1] = i;
1891
+ g->I[2] = v[i].size;
1892
+ g->L[0] = v[i].b;
1893
+ if (v[i].size)
1894
+ w(g, "static const symbol s_~I0_~I1[~I2] = ~A0;~N");
1508
1895
  }
1509
1896
 
1510
1897
  g->I[1] = x->literalstring_count;
1511
- w(g, "~N~Mstatic const struct among a_~I0[~I1] =~N{~N");
1898
+ w(g, "~Mstatic const struct among a_~I0[~I1] = {~N");
1512
1899
 
1513
- v = x->b;
1514
- {
1515
- int i;
1516
- for (i = 0; i < x->literalstring_count; i++) {
1517
- g->I[1] = i;
1518
- g->I[2] = v->size;
1519
- g->I[3] = v->i;
1520
- g->I[4] = v->result;
1521
- g->S[0] = i < x->literalstring_count - 1 ? "," : "";
1522
-
1523
- if (g->options->comments) {
1524
- w(g, "/*~J1 */ ");
1525
- }
1526
- w(g, "{ ~I2, ");
1527
- if (v->size == 0) {
1528
- w(g, "0,");
1529
- } else {
1530
- w(g, "s_~I0_~I1,");
1531
- }
1532
- w(g, " ~I3, ~I4, ");
1533
- if (v->function == 0) {
1534
- write_char(g, '0');
1535
- } else {
1536
- write_varname(g, v->function);
1537
- }
1538
- w(g, "}~S0~N");
1539
- v++;
1900
+ for (int i = 0; i < x->literalstring_count; i++) {
1901
+ g->I[1] = i;
1902
+ g->I[2] = v[i].size;
1903
+ g->I[3] = (v[i].i >= 0 ? v[i].i - i : 0);
1904
+ g->I[4] = v[i].result;
1905
+ g->S[0] = i < x->literalstring_count - 1 ? "," : "";
1906
+
1907
+ if (g->options->comments) {
1908
+ w(g, "/*~J1 */ ");
1909
+ }
1910
+ w(g, "{ ~I2, ");
1911
+ if (v[i].size == 0) {
1912
+ w(g, "0,");
1913
+ } else {
1914
+ w(g, "s_~I0_~I1,");
1915
+ }
1916
+ w(g, " ~I3, ~I4, ");
1917
+ if (v[i].function == NULL) {
1918
+ write_char(g, '0');
1919
+ } else {
1920
+ write_varname(g, v[i].function);
1540
1921
  }
1922
+ w(g, "}~S0~N");
1541
1923
  }
1542
1924
  w(g, "};~N~N");
1543
1925
  }
1544
1926
 
1545
1927
  static void generate_amongs(struct generator * g) {
1546
- struct among * x;
1547
- for (x = g->analyser->amongs; x; x = x->next) {
1928
+ for (struct among * x = g->analyser->amongs; x; x = x->next) {
1548
1929
  generate_among_table(g, x);
1549
1930
  }
1550
1931
  }
@@ -1552,37 +1933,34 @@ static void generate_amongs(struct generator * g) {
1552
1933
  static void set_bit(symbol * b, int i) { b[i/8] |= 1 << i%8; }
1553
1934
 
1554
1935
  static void generate_grouping_table(struct generator * g, struct grouping * q) {
1555
-
1556
1936
  int range = q->largest_ch - q->smallest_ch + 1;
1557
1937
  int size = (range + 7)/ 8; /* assume 8 bits per symbol */
1558
1938
  symbol * b = q->b;
1559
1939
  symbol * map = create_b(size);
1560
- int i;
1561
- for (i = 0; i < size; i++) map[i] = 0;
1562
1940
 
1563
- for (i = 0; i < SIZE(b); i++) set_bit(map, b[i] - q->smallest_ch);
1941
+ for (int i = 0; i < size; i++) map[i] = 0;
1564
1942
 
1565
- g->V[0] = q->name;
1943
+ for (int i = 0; i < SIZE(b); i++) set_bit(map, b[i] - q->smallest_ch);
1566
1944
 
1945
+ g->V[0] = q->name;
1567
1946
  w(g, "static const unsigned char ~V0[] = { ");
1568
- for (i = 0; i < size; i++) {
1947
+ for (int i = 0; i < size; i++) {
1569
1948
  write_int(g, map[i]);
1570
1949
  if (i < size - 1) w(g, ", ");
1571
1950
  }
1572
1951
  w(g, " };~N~N");
1952
+
1573
1953
  lose_b(map);
1574
1954
  }
1575
1955
 
1576
1956
  static void generate_groupings(struct generator * g) {
1577
- struct grouping * q;
1578
- for (q = g->analyser->groupings; q; q = q->next) {
1957
+ for (struct grouping * q = g->analyser->groupings; q; q = q->next) {
1579
1958
  if (q->name->used)
1580
1959
  generate_grouping_table(g, q);
1581
1960
  }
1582
1961
  }
1583
1962
 
1584
1963
  static void generate_create(struct generator * g) {
1585
-
1586
1964
  int * p = g->analyser->name_count;
1587
1965
  g->I[0] = p[t_string];
1588
1966
  g->I[1] = p[t_integer] + p[t_boolean];
@@ -1592,7 +1970,6 @@ static void generate_create(struct generator * g) {
1592
1970
  }
1593
1971
 
1594
1972
  static void generate_close(struct generator * g) {
1595
-
1596
1973
  int * p = g->analyser->name_count;
1597
1974
  g->I[0] = p[t_string];
1598
1975
  w(g, "~Nextern void ~pclose_env(struct SN_env * z) { SN_close_env(z, ~I0); }~N~N");
@@ -1606,8 +1983,6 @@ static void generate_create_and_close_templates(struct generator * g) {
1606
1983
  }
1607
1984
 
1608
1985
  static void generate_header_file(struct generator * g) {
1609
-
1610
- struct name * q;
1611
1986
  const char * vp = g->options->variables_prefix;
1612
1987
  g->S[0] = vp;
1613
1988
 
@@ -1616,7 +1991,7 @@ static void generate_header_file(struct generator * g) {
1616
1991
  "#endif~N"); /* for C++ */
1617
1992
 
1618
1993
  generate_create_and_close_templates(g);
1619
- for (q = g->analyser->names; q; q = q->next) {
1994
+ for (struct name * q = g->analyser->names; q; q = q->next) {
1620
1995
  g->V[0] = q;
1621
1996
  switch (q->type) {
1622
1997
  case t_external:
@@ -1629,9 +2004,9 @@ static void generate_header_file(struct generator * g) {
1629
2004
  int count = q->count;
1630
2005
  if (count < 0) {
1631
2006
  /* Unused variables should get removed from `names`. */
1632
- fprintf(stderr, "Optimised out variable ");
1633
- report_b(stderr, q->b);
1634
- fprintf(stderr, " still in names list\n");
2007
+ q->s[SIZE(q->s)] = 0;
2008
+ fprintf(stderr, "Optimised out variable %s still in names list\n",
2009
+ q->s);
1635
2010
  exit(1);
1636
2011
  }
1637
2012
  if (q->type == t_boolean) {
@@ -1643,7 +2018,7 @@ static void generate_header_file(struct generator * g) {
1643
2018
  g->I[0] = count;
1644
2019
  g->I[1] = "SIIrxg"[q->type];
1645
2020
  w(g, "#define ~S0");
1646
- write_b(g, q->b);
2021
+ write_s(g, q->s);
1647
2022
  w(g, " (~c1[~I0])~N");
1648
2023
  }
1649
2024
  break;
@@ -1659,9 +2034,12 @@ static void generate_header_file(struct generator * g) {
1659
2034
  }
1660
2035
 
1661
2036
  extern void generate_program_c(struct generator * g) {
1662
-
1663
2037
  g->outbuf = str_new();
2038
+ g->failure_str = str_new();
1664
2039
  write_start_comment(g, "/* ", " */");
2040
+ if (g->analyser->int_limits_used) {
2041
+ w(g, "#include <limits.h>~N");
2042
+ }
1665
2043
  generate_head(g);
1666
2044
  generate_routine_headers(g);
1667
2045
  w(g, "#ifdef __cplusplus~N"
@@ -1678,12 +2056,14 @@ extern void generate_program_c(struct generator * g) {
1678
2056
  g->declarations = g->outbuf;
1679
2057
  g->outbuf = str_new();
1680
2058
  g->literalstring_count = 0;
1681
- {
1682
- struct node * p = g->analyser->program;
1683
- while (p) { generate(g, p); p = p->right; }
2059
+
2060
+ for (struct node * p = g->analyser->program; p; p = p->right) {
2061
+ generate(g, p);
1684
2062
  }
2063
+
1685
2064
  generate_create(g);
1686
2065
  generate_close(g);
2066
+
1687
2067
  output_str(g->options->output_src, g->declarations);
1688
2068
  str_delete(g->declarations);
1689
2069
  output_str(g->options->output_src, g->outbuf);
@@ -1693,6 +2073,7 @@ extern void generate_program_c(struct generator * g) {
1693
2073
  generate_header_file(g);
1694
2074
  output_str(g->options->output_h, g->outbuf);
1695
2075
  str_delete(g->outbuf);
2076
+ str_delete(g->failure_str);
1696
2077
  }
1697
2078
 
1698
2079
  /* Generator functions common to multiple languages. */
@@ -1725,6 +2106,12 @@ extern void write_char(struct generator * g, int ch) {
1725
2106
  }
1726
2107
 
1727
2108
  extern void write_newline(struct generator * g) {
2109
+ /* Avoid generating trailing whitespace. */
2110
+ while (true) {
2111
+ int ch = str_back(g->outbuf);
2112
+ if (ch != ' ' && ch != '\t') break;
2113
+ str_pop(g->outbuf);
2114
+ }
1728
2115
  str_append_ch(g->outbuf, '\n'); /* newline */
1729
2116
  g->line_count++;
1730
2117
  }
@@ -1733,16 +2120,18 @@ extern void write_string(struct generator * g, const char * s) {
1733
2120
  str_append_string(g->outbuf, s);
1734
2121
  }
1735
2122
 
2123
+ extern void write_wchar_as_utf8(struct generator * g, symbol ch) {
2124
+ str_append_wchar_as_utf8(g->outbuf, ch);
2125
+ }
2126
+
1736
2127
  extern void write_int(struct generator * g, int i) {
1737
2128
  str_append_int(g->outbuf, i);
1738
2129
  }
1739
2130
 
1740
- extern void write_b(struct generator * g, symbol * b) {
1741
-
1742
- str_append_b(g->outbuf, b);
2131
+ extern void write_s(struct generator * g, const byte * s) {
2132
+ str_append_s(g->outbuf, s);
1743
2133
  }
1744
2134
 
1745
2135
  extern void write_str(struct generator * g, struct str * str) {
1746
-
1747
2136
  str_append(g->outbuf, str);
1748
2137
  }