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
@@ -4,131 +4,33 @@
4
4
  #include <string.h> /* for strlen */
5
5
  #include "header.h"
6
6
 
7
- /* Define this to get warning messages when optimisations can't be used. */
8
- /* #define OPTIMISATION_WARNINGS */
7
+ /* Generator functions common to multiple target languages. */
9
8
 
10
- /* 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
- static int new_label(struct generator * g) {
17
- return g->next_label++;
18
- }
19
-
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
- }
28
-
29
- /* Write routines for simple entities */
30
-
31
- static void wi3(struct generator * g, int i) {
32
- if (i < 100) write_char(g, ' ');
33
- if (i < 10) write_char(g, ' ');
34
- write_int(g, i); /* integer (width 3) */
35
- }
36
-
37
- /* Write routines for items from the syntax tree */
38
-
39
- static void write_varname(struct generator * g, struct name * p) {
40
- int ch = "SIIrxg"[p->type];
41
- switch (p->type) {
42
- case t_external:
43
- write_string(g, g->options->externals_prefix); break;
44
- case t_string:
45
- case t_boolean:
46
- case t_integer: {
47
- int count = p->count;
48
- if (count < 0) {
49
- p->s[SIZE(p->s)] = 0;
50
- fprintf(stderr, "Reference to optimised out variable %s attempted\n",
51
- p->s);
52
- exit(1);
53
- }
54
- if (p->type == t_boolean) {
55
- /* We use a single array for booleans and integers, with the
56
- * integers first.
57
- */
58
- count += g->analyser->name_count[t_integer];
59
- }
60
- write_char(g, ch);
61
- write_char(g, '[');
62
- write_int(g, count);
63
- write_char(g, ']');
64
- return;
65
- }
66
- default:
67
- write_char(g, ch); write_char(g, '_');
68
- }
69
- write_s(g, p->s);
70
- }
71
-
72
- static void write_varref(struct generator * g, struct name * p) { /* reference to variable */
73
- if (p->type < t_routine) write_string(g, "z->");
74
- write_varname(g, p);
75
- }
76
-
77
- static void write_hexdigit(struct generator * g, int i) {
78
- str_append_ch(g->outbuf, "0123456789ABCDEF"[i & 0xF]); /* hexchar */
79
- }
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
-
85
- static void write_hex(struct generator * g, int i) {
86
- if (i >> 4) write_hex(g, i >> 4);
87
- write_hexdigit(g, i); /* hex integer */
88
- }
89
-
90
- /* write character literal */
91
- static void wlitch(struct generator * g, int ch) {
92
- if (32 <= ch && ch < 127) {
93
- write_char(g, '\'');
94
- if (ch == '\'' || ch == '\\') {
95
- write_char(g, '\\');
96
- }
97
- write_char(g, ch);
98
- write_char(g, '\'');
99
- } else {
100
- write_string(g, "0x"); write_hex(g, ch);
101
- }
9
+ extern struct generator * create_generator(struct analyser * a, struct options * o) {
10
+ NEW(generator, g);
11
+ *g = (struct generator){0};
12
+ g->analyser = a;
13
+ g->options = o;
14
+ g->failure_label = -1;
15
+ g->varname_prefix = "v_";
16
+ g->margin_indent = " ";
17
+ return g;
102
18
  }
103
19
 
104
- static void wlitarray(struct generator * g, symbol * p) { /* write literal array */
105
- write_string(g, "{ ");
106
- for (int i = 0; i < SIZE(p); i++) {
107
- wlitch(g, p[i]);
108
- if (i < SIZE(p) - 1) write_string(g, ", ");
109
- }
110
- write_string(g, " }");
20
+ extern void close_generator(struct generator * g) {
21
+ FREE(g);
111
22
  }
112
23
 
113
- static void wlitref(struct generator * g, symbol * p) { /* write ref to literal array */
114
- if (SIZE(p) == 0) {
115
- write_char(g, '0');
116
- } else {
117
- struct str * s = g->outbuf;
118
- g->outbuf = g->declarations;
119
- write_string(g, "static const symbol s_"); write_int(g, g->literalstring_count); write_string(g, "[] = ");
120
- wlitarray(g, p);
121
- write_string(g, ";\n");
122
- g->outbuf = s;
123
- write_string(g, "s_"); write_int(g, g->literalstring_count);
124
- g->literalstring_count++;
125
- }
24
+ extern int just_return_on_fail(struct generator * g) {
25
+ return g->failure_label == x_return && str_len(g->failure_str) == 0;
126
26
  }
127
27
 
128
- static void write_margin(struct generator * g) {
129
- for (int i = 0; i < g->margin; i++) write_string(g, " ");
28
+ extern int tailcallable(struct generator * g, struct node * p) {
29
+ return just_return_on_fail(g) &&
30
+ p->right && p->right->type == c_functionend;
130
31
  }
131
32
 
33
+ // Write a C-style relational operator (also used by some other languages).
132
34
  extern void write_c_relop(struct generator * g, int relop) {
133
35
  switch (relop) {
134
36
  case c_eq: write_string(g, " == "); break;
@@ -138,1689 +40,183 @@ extern void write_c_relop(struct generator * g, int relop) {
138
40
  case c_lt: write_string(g, " < "); break;
139
41
  case c_le: write_string(g, " <= "); break;
140
42
  default:
141
- fprintf(stderr, "Unexpected type #%d in generate_integer_test\n", relop);
43
+ fprintf(stderr, "Unexpected type #%d in write_c_relop\n", relop);
142
44
  exit(1);
143
45
  }
144
46
  }
145
47
 
146
- void write_comment_content(struct generator * g, struct node * p) {
147
- switch (p->type) {
148
- case c_mathassign:
149
- case c_plusassign:
150
- case c_minusassign:
151
- case c_multiplyassign:
152
- case c_divideassign:
153
- if (p->name) {
154
- write_char(g, '$');
155
- write_s(g, p->name->s);
156
- write_char(g, ' ');
157
- }
158
- write_string(g, name_of_token(p->type));
159
- write_string(g, " <integer expression>");
160
- break;
161
- case c_eq:
162
- case c_ne:
163
- case c_gt:
164
- case c_ge:
165
- case c_lt:
166
- case c_le:
167
- write_string(g, "$(<integer expression> ");
168
- write_string(g, name_of_token(p->type));
169
- write_string(g, " <integer expression>)");
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 */
178
- default:
179
- write_string(g, name_of_token(p->type));
180
- if (p->name) {
181
- write_char(g, ' ');
182
- write_s(g, p->name->s);
48
+ static void write_comment_literalstring(struct generator * g, const symbol *s,
49
+ const char * end) {
50
+ if (end) {
51
+ // Check if the literal string contains the target language end comment
52
+ // string. Don't try to be clever here as real-world literal strings
53
+ // are unlikely to contain even partial matches.
54
+ int end_len = strlen(end);
55
+ if (end_len <= SIZE(s)) {
56
+ for (int i = 0; i <= SIZE(s) - end_len; ++i) {
57
+ for (int j = 0; j < end_len; ++j) {
58
+ if (s[i + j] != end[j]) goto next_outer;
59
+ }
60
+ write_string(g, "<literal string>");
61
+ return;
62
+ next_outer: ;
183
63
  }
64
+ }
184
65
  }
185
- write_string(g, ", line ");
186
- write_int(g, p->line_number);
187
- }
188
-
189
- static void write_comment(struct generator * g, struct node * p) {
190
- if (!g->options->comments) return;
191
- write_margin(g);
192
- write_string(g, "/* ");
193
- write_comment_content(g, p);
194
- write_string(g, " */");
195
- write_newline(g);
196
- }
197
-
198
- /* margin + string */
199
- static void wms(struct generator * g, const char * s) {
200
- write_margin(g); write_string(g, s);
201
- }
202
-
203
- static void write_block_start(struct generator * g) {
204
- w(g, "~M{~+~N");
205
- }
206
-
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");
211
- }
212
- w(g, "~-~M}~N");
213
- }
214
-
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);
221
- }
222
-
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);
234
- }
235
-
236
- static void winc(struct generator * g, struct node * p) { /* increment c */
237
- write_string(g, p->mode == m_forward ? "z->c++;" :
238
- "z->c--;");
239
- }
240
-
241
- static void wsetl(struct generator * g, int n) {
242
- g->margin--;
243
- wms(g, "lab"); write_int(g, n); write_char(g, ':'); write_newline(g);
244
- g->line_labelled = g->line_count;
245
- g->margin++;
246
- }
247
-
248
- static void wgotol(struct generator * g, int n) {
249
- wms(g, "goto lab"); write_int(g, n); write_char(g, ';'); write_newline(g);
250
- }
251
-
252
- static void write_failure(struct generator * g) {
253
- if (str_len(g->failure_str) != 0) {
254
- write_string(g, "{ ");
255
- write_str(g, g->failure_str);
256
- write_char(g, ' ');
257
- }
258
- switch (g->failure_label) {
259
- case x_return:
260
- write_string(g, "return 0;");
261
- break;
262
- default:
263
- write_string(g, "goto lab");
264
- write_int(g, g->failure_label);
265
- write_char(g, ';');
266
- g->label_used = 1;
267
- }
268
- if (str_len(g->failure_str) != 0) write_string(g, " }");
269
- }
270
66
 
271
-
272
- /* if at limit fail */
273
- static void write_check_limit(struct generator * g, struct node * p) {
274
- write_string(g, p->mode == m_forward ? "if (z->c >= z->l) " :
275
- "if (z->c <= z->lb) ");
276
- write_failure(g);
277
- }
278
-
279
- static void write_data_address(struct generator * g, struct node * p) {
280
- symbol * b = p->literalstring;
281
- if (b != NULL) {
282
- write_int(g, SIZE(b)); w(g, ", ");
283
- wlitref(g, b);
284
- } else {
285
- write_varref(g, p->name);
67
+ symbol ch_max = 0xa0;
68
+ if (g->options->encoding == ENC_SINGLEBYTE) {
69
+ ch_max = 0xff;
286
70
  }
287
- }
288
71
 
289
- /* Formatted write. */
290
- static void writef(struct generator * g, const char * input, struct node * p) {
291
72
  int i = 0;
292
-
293
- while (input[i]) {
294
- int ch = input[i++];
295
- if (ch != '~') {
296
- write_char(g, ch);
297
- continue;
73
+ write_char(g, '\'');
74
+ while (i < SIZE(s)) {
75
+ int ch;
76
+ if (g->options->encoding == ENC_UTF8) {
77
+ i += get_utf8(s + i, &ch);
78
+ } else {
79
+ ch = s[i++];
298
80
  }
299
- ch = input[i++];
300
- switch (ch) {
301
- case '~': write_char(g, '~'); continue;
302
- case 'i': winc(g, p); continue;
303
- case 'l': write_check_limit(g, p); continue;
304
- case 'f': write_failure(g); continue;
305
- case 'M': write_margin(g); continue;
306
- case 'N': write_newline(g); continue;
307
- case '{': write_block_start(g); continue;
308
- case '}': write_block_end(g); 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
- }
362
- case 'a': write_data_address(g, p); continue;
363
- case '+': g->margin++; continue;
364
- case '-': g->margin--; continue;
365
- case '$': /* insert_s, insert_v etc */
366
- write_char(g, p->literalstring == NULL ? 'v' : 's');
367
- continue;
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);
81
+ if (ch == '\'' || ch == '{') {
82
+ write_char(g, '{');
83
+ write_char(g, ch);
84
+ write_char(g, '}');
85
+ } else if (ch < 32 ||
86
+ (ch >= 127 && ch <= ch_max) ||
87
+ ch == '\\' ||
88
+ ch >= 0x590) {
89
+ // Encode characters which are problematic if emitted literally
90
+ // using Snowball-style `{U+xx}`:
91
+ //
92
+ // * Control characters.
93
+ //
94
+ // * For ENC_SINGLEBYTE we encode all non-ASCII to avoid invalid
95
+ // UTF-8 in comments (which clang warns about for C/C++ with
96
+ // option `-pedantic` or `-Winvalid-utf8`).
97
+ //
98
+ // * `\`: In Java, `\u000a` in a comment is interpreted as a
99
+ // newline and so exits the comment, while `\uq` gives
100
+ // compilation error `illegal unicode escape`. Since `\` is
101
+ // unusual in Snowball literal strings we take the simple
102
+ // approach of escaping it for all target languages.
103
+ //
104
+ // * Anything >= 0x590 as a crude way to avoid LTR characters
105
+ // affecting the rendering of source character order in confusing
106
+ // ways.
107
+ write_string(g, "{U+");
108
+ write_hex(g, ch);
109
+ write_char(g, '}');
110
+ } else {
111
+ write_wchar_as_utf8(g, ch);
377
112
  }
378
113
  }
114
+ write_char(g, '\'');
379
115
  }
380
116
 
381
- static void w(struct generator * g, const char * s) {
382
- writef(g, s, NULL);
383
- }
384
-
385
- static void generate_AE(struct generator * g, struct node * p) {
386
- const char * s;
117
+ static void write_comment_AE(struct generator * g, struct node * p) {
387
118
  switch (p->type) {
388
119
  case c_name:
389
- write_varref(g, p->name); break;
120
+ write_s(g, p->name->s);
121
+ break;
390
122
  case c_number:
391
- write_int(g, p->number); break;
392
- case c_maxint:
393
- write_string(g, "INT_MAX");
123
+ write_int(g, p->number);
394
124
  break;
125
+ case c_cursor:
126
+ case c_len:
127
+ case c_lenof:
128
+ case c_limit:
129
+ case c_maxint:
395
130
  case c_minint:
396
- write_string(g, "INT_MIN");
131
+ case c_size:
132
+ case c_sizeof:
133
+ write_string(g, name_of_token(p->type));
134
+ if (p->name) {
135
+ write_char(g, ' ');
136
+ write_s(g, p->name->s);
137
+ }
397
138
  break;
398
139
  case c_neg:
399
- write_char(g, '-'); generate_AE(g, p->right); break;
140
+ write_char(g, '-');
141
+ write_comment_AE(g, p->right);
142
+ break;
400
143
  case c_multiply:
401
- s = " * "; goto label0;
402
144
  case c_plus:
403
- s = " + "; goto label0;
404
145
  case c_minus:
405
- s = " - "; goto label0;
406
146
  case c_divide:
407
- s = " / ";
408
- label0:
409
- write_char(g, '('); generate_AE(g, p->left);
410
- write_string(g, s); generate_AE(g, p->right); write_char(g, ')'); break;
411
- case c_cursor:
412
- w(g, "z->c"); break;
413
- case c_limit:
414
- w(g, p->mode == m_forward ? "z->l" : "z->lb"); break;
415
- case c_len:
416
- if (g->options->encoding == ENC_UTF8) {
417
- w(g, "len_utf8(z->p)");
418
- break;
419
- }
420
- /* FALLTHRU */
421
- case c_size:
422
- w(g, "SIZE(z->p)");
423
- break;
424
- case c_lenof:
425
- if (g->options->encoding == ENC_UTF8) {
426
- g->V[0] = p->name;
427
- w(g, "len_utf8(~V0)");
428
- break;
429
- }
430
- /* FALLTHRU */
431
- case c_sizeof:
432
- g->V[0] = p->name;
433
- w(g, "SIZE(~V0)");
147
+ write_char(g, '(');
148
+ write_comment_AE(g, p->left);
149
+ write_char(g, ' ');
150
+ write_string(g, name_of_token(p->type));
151
+ write_char(g, ' ');
152
+ write_comment_AE(g, p->right);
153
+ write_char(g, ')');
434
154
  break;
155
+ default:
156
+ fprintf(stderr, "Unexpected type #%d in write_comment_AE\n", p->type);
157
+ exit(1);
435
158
  }
436
159
  }
437
160
 
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) {
161
+ void write_comment_content(struct generator * g, struct node * p,
162
+ const char * end) {
443
163
  switch (p->type) {
444
- case c_fail:
445
- case c_false:
446
- /* Always gives signal f. */
447
- return 0;
448
164
  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
165
  case c_plusassign:
468
166
  case c_minusassign:
469
167
  case c_multiplyassign:
470
168
  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
-
648
- /* K_needed() tests to see if we really need to keep c. Not true when the
649
- command does not touch the cursor. This and repeat_score() could be
650
- elaborated almost indefinitely.
651
- */
652
-
653
- static int K_needed_(struct node * p, int call_depth) {
654
- while (p) {
655
- switch (p->type) {
656
- case c_atlimit:
657
- case c_do:
658
- case c_dollar:
659
- case c_leftslice:
660
- case c_rightslice:
661
- case c_mathassign:
662
- case c_plusassign:
663
- case c_minusassign:
664
- case c_multiplyassign:
665
- case c_divideassign:
666
- case c_eq:
667
- case c_ne:
668
- case c_gt:
669
- case c_ge:
670
- case c_lt:
671
- case c_le:
672
- case c_sliceto:
673
- case c_booltest:
674
- case c_set:
675
- case c_unset:
676
- case c_true:
677
- case c_false:
678
- case c_debug:
679
- case c_functionend:
680
- case c_not:
681
- break;
682
-
683
- case c_call:
684
- /* Recursive functions aren't typical in snowball programs, so
685
- * make the pessimistic assumption that keep is needed if we
686
- * hit a generous limit on recursion. It's not likely to make
687
- * a difference to any real world program, but means we won't
688
- * recurse until we run out of stack for pathological cases.
689
- */
690
- if (call_depth >= 100) return true;
691
- if (K_needed_(p->name->definition, call_depth + 1))
692
- return true;
693
- break;
694
-
695
- case c_bra:
696
- if (K_needed_(p->left, call_depth)) return true;
697
- break;
698
-
699
- default: return true;
700
- }
701
- p = p->right;
702
- }
703
- return false;
704
- }
705
-
706
- extern int K_needed(struct generator * g, struct node * p) {
707
- (void)g;
708
- return K_needed_(p, 0);
709
- }
710
-
711
- static int repeat_score(struct generator * g, struct node * p, int call_depth) {
712
- int score = 0;
713
- while (p) {
714
- switch (p->type) {
715
- case c_dollar:
716
- case c_leftslice:
717
- case c_rightslice:
718
- case c_mathassign:
719
- case c_plusassign:
720
- case c_minusassign:
721
- case c_multiplyassign:
722
- case c_divideassign:
723
- case c_eq:
724
- case c_ne:
725
- case c_gt:
726
- case c_ge:
727
- case c_lt:
728
- case c_le:
729
- case c_sliceto: /* case c_not: must not be included here! */
730
- case c_debug:
731
- case c_functionend:
732
- break;
733
-
734
- case c_call:
735
- /* Recursive functions aren't typical in snowball programs, so
736
- * make the pessimistic assumption that repeat requires cursor
737
- * reinstatement if we hit a generous limit on recursion. It's
738
- * not likely to make a difference to any real world program,
739
- * but means we won't recurse until we run out of stack for
740
- * pathological cases.
741
- */
742
- if (call_depth >= 100) {
743
- return 2;
744
- }
745
- score += repeat_score(g, p->name->definition, call_depth + 1);
746
- if (score >= 2)
747
- return score;
748
- break;
749
-
750
- case c_bra:
751
- score += repeat_score(g, p->left, call_depth);
752
- if (score >= 2)
753
- return score;
754
- break;
755
-
756
- case c_name:
757
- case c_literalstring:
758
- case c_next:
759
- case c_grouping:
760
- case c_non:
761
- case c_goto_grouping:
762
- case c_gopast_grouping:
763
- case c_goto_non:
764
- case c_gopast_non:
765
- case c_hop:
766
- if (++score >= 2)
767
- return score;
768
- break;
769
-
770
- default:
771
- return 2;
772
- }
773
- p = p->right;
774
- }
775
- return score;
776
- }
777
-
778
- /* tests if an expression requires cursor reinstatement in a repeat */
779
-
780
- extern int repeat_restore(struct generator * g, struct node * p) {
781
- return repeat_score(g, p, 0) >= 2;
782
- }
783
-
784
- static void generate_bra(struct generator * g, struct node * p) {
785
- p = p->left;
786
- while (p) {
787
- generate(g, p);
788
- p = p->right;
789
- }
790
- }
791
-
792
- static void generate_and(struct generator * g, struct node * p) {
793
- struct str * savevar = NULL;
794
- if (K_needed(g, p->left)) {
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);
803
- }
804
-
805
- p = p->left;
806
- while (p) {
807
- generate(g, p);
808
- if (savevar && p->right != NULL) write_restorecursor(g, p, savevar);
809
- p = p->right;
810
- }
811
-
812
- if (savevar) {
813
- write_block_end(g);
814
- str_delete(savevar);
815
- }
816
- }
817
-
818
- static void generate_or(struct generator * g, struct node * p) {
819
- struct str * savevar = NULL;
820
- if (K_needed(g, p->left)) {
821
- savevar = vars_newname(g);
822
- }
823
-
824
- int used = g->label_used;
825
- int a0 = g->failure_label;
826
- struct str * a1 = str_copy(g->failure_str);
827
-
828
- int out_lab = new_label(g);
829
- write_comment(g, p);
830
-
831
- if (savevar) {
832
- write_block_start(g);
833
- write_savecursor(g, p, savevar);
834
- }
835
-
836
- p = p->left;
837
- str_clear(g->failure_str);
838
-
839
- while (p->right != NULL) {
840
- g->failure_label = new_label(g);
841
- g->label_used = 0;
842
- generate(g, p);
843
- wgotol(g, out_lab);
844
- if (g->label_used)
845
- wsetl(g, g->failure_label);
846
- if (savevar) write_restorecursor(g, p, savevar);
847
- p = p->right;
848
- }
849
-
850
- g->label_used = used;
851
- g->failure_label = a0;
852
- str_delete(g->failure_str);
853
- g->failure_str = a1;
854
-
855
- generate(g, p);
856
-
857
- if (savevar) {
858
- write_block_end(g);
859
- str_delete(savevar);
860
- }
861
- wsetl(g, out_lab);
862
- }
863
-
864
- static void generate_backwards(struct generator * g, struct node * p) {
865
- write_comment(g, p);
866
- writef(g, "~Mz->lb = z->c; z->c = z->l;~N", p);
867
- generate(g, p->left);
868
- w(g, "~Mz->c = z->lb;~N");
869
- }
870
-
871
-
872
- static void generate_not(struct generator * g, struct node * p) {
873
- struct str * savevar = NULL;
874
- if (K_needed(g, p->left)) {
875
- savevar = vars_newname(g);
876
- }
877
-
878
- int used = g->label_used;
879
- int a0 = g->failure_label;
880
- struct str * a1 = str_copy(g->failure_str);
881
-
882
- write_comment(g, p);
883
- if (savevar) {
884
- write_block_start(g);
885
- write_savecursor(g, p, savevar);
886
- }
887
-
888
- g->failure_label = new_label(g);
889
- str_clear(g->failure_str);
890
- g->label_used = 0;
891
- generate(g, p->left);
892
-
893
- int l = g->failure_label;
894
- int u = g->label_used;
895
-
896
- g->label_used = used;
897
- g->failure_label = a0;
898
- str_delete(g->failure_str);
899
- g->failure_str = a1;
900
-
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);
909
- }
910
- }
911
-
912
-
913
- static void generate_try(struct generator * g, struct node * p) {
914
- struct str * savevar = NULL;
915
- if (K_needed(g, p->left)) {
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);
923
- }
924
-
925
- g->failure_label = new_label(g);
926
- str_clear(g->failure_str);
927
- g->label_used = 0;
928
- if (savevar) append_restore_string(p, g->failure_str, savevar);
929
-
930
- generate(g, p->left);
931
-
932
- if (g->label_used)
933
- wsetl(g, g->failure_label);
934
-
935
- if (savevar) {
936
- write_block_end(g);
937
- str_delete(savevar);
938
- }
939
- }
940
-
941
- static void generate_set(struct generator * g, struct node * p) {
942
- write_comment(g, p);
943
- g->V[0] = p->name;
944
- writef(g, "~M~V0 = 1;~N", p);
945
- }
946
-
947
- static void generate_unset(struct generator * g, struct node * p) {
948
- write_comment(g, p);
949
- g->V[0] = p->name;
950
- writef(g, "~M~V0 = 0;~N", p);
951
- }
952
-
953
- static void generate_fail(struct generator * g, struct node * p) {
954
- write_comment(g, p);
955
- generate(g, p->left);
956
- writef(g, "~M~f~N", p);
957
- }
958
-
959
- /* generate_test() also implements 'reverse' */
960
-
961
- static void generate_test(struct generator * g, struct node * p) {
962
- struct str * savevar = NULL;
963
- if (K_needed(g, p->left)) {
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
- }
973
-
974
- generate(g, p->left);
975
-
976
- if (savevar) {
977
- write_restorecursor(g, p, savevar);
978
- write_block_end(g);
979
- str_delete(savevar);
980
- }
981
- }
982
-
983
- static void generate_do(struct generator * g, struct node * p) {
984
- struct str * savevar = NULL;
985
- if (K_needed(g, p->left)) {
986
- savevar = vars_newname(g);
987
- }
988
- if (savevar) {
989
- write_block_start(g);
990
- write_savecursor(g, p, savevar);
991
- }
992
-
993
- if (p->left->type == c_call) {
994
- /* Optimise do <call> */
995
- write_comment(g, p->left);
996
- g->V[0] = p->left->name;
997
- writef(g, "~{~Mint ret = ~V0(z);~N", p->left);
998
- w(g, "~Mif (ret < 0) return ret;~N~}");
999
- } else {
1000
- g->failure_label = new_label(g);
1001
- g->label_used = 0;
1002
- str_clear(g->failure_str);
1003
-
1004
- generate(g, p->left);
1005
-
1006
- if (g->label_used)
1007
- wsetl(g, g->failure_label);
1008
- }
1009
- if (savevar) {
1010
- write_restorecursor(g, p, savevar);
1011
- write_block_end(g);
1012
- str_delete(savevar);
1013
- }
1014
- }
1015
-
1016
- static void generate_next(struct generator * g, struct node * p) {
1017
- write_comment(g, p);
1018
- if (g->options->encoding == ENC_UTF8) {
1019
- if (p->mode == m_forward)
1020
- w(g, "~{~Mint ret = skip_utf8(z->p, z->c, z->l, 1");
1021
- else
1022
- w(g, "~{~Mint ret = skip_b_utf8(z->p, z->c, z->lb, 1");
1023
- writef(g, ");~N"
1024
- "~Mif (ret < 0) ~f~N"
1025
- "~Mz->c = ret;~N"
1026
- "~}", p);
1027
- } else
1028
- writef(g, "~M~l~N"
1029
- "~M~i~N", p);
1030
- }
1031
-
1032
- static void generate_GO_grouping(struct generator * g, struct node * p, int is_goto, int complement) {
1033
- write_comment(g, p);
1034
-
1035
- struct grouping * q = p->name->grouping;
1036
- g->S[0] = p->mode == m_forward ? "" : "_b";
1037
- g->S[1] = complement ? "in" : "out";
1038
- g->S[2] = g->options->encoding == ENC_UTF8 ? "_U" : "";
1039
- g->V[0] = p->name;
1040
- g->I[0] = q->smallest_ch;
1041
- g->I[1] = q->largest_ch;
1042
- if (is_goto) {
1043
- writef(g, "~Mif (~S1_grouping~S0~S2(z, ~V0, ~I0, ~I1, 1) < 0) ~f~N", p);
1044
- } else {
1045
- writef(g, "~{"
1046
- "~Mint ret = ~S1_grouping~S0~S2(z, ~V0, ~I0, ~I1, 1);~N"
1047
- "~Mif (ret < 0) ~f~N", p);
1048
- if (p->mode == m_forward)
1049
- w(g, "~Mz->c += ret;~N");
1050
- else
1051
- w(g, "~Mz->c -= ret;~N");
1052
- w(g, "~}");
1053
- }
1054
- }
1055
-
1056
- static void generate_GO(struct generator * g, struct node * p, int style) {
1057
- write_comment(g, p);
1058
-
1059
- int used = g->label_used;
1060
- int a0 = g->failure_label;
1061
- struct str * a1 = str_copy(g->failure_str);
1062
-
1063
- w(g, "~Mwhile (1) {~N~+");
1064
-
1065
- struct str * savevar = NULL;
1066
- if (style == 1 || repeat_restore(g, p->left)) {
1067
- savevar = vars_newname(g);
1068
- write_savecursor(g, p, savevar);
1069
- }
1070
-
1071
- g->failure_label = new_label(g);
1072
- g->label_used = 0;
1073
- str_clear(g->failure_str);
1074
- generate(g, p->left);
1075
-
1076
- if (style == 1) {
1077
- /* include for goto; omit for gopast */
1078
- write_restorecursor(g, p, savevar);
1079
- }
1080
- w(g, "~Mbreak;~N");
1081
- if (g->label_used)
1082
- wsetl(g, g->failure_label);
1083
- if (savevar) {
1084
- write_restorecursor(g, p, savevar);
1085
- str_delete(savevar);
1086
- }
1087
-
1088
- g->label_used = used;
1089
- g->failure_label = a0;
1090
- str_delete(g->failure_str);
1091
- g->failure_str = a1;
1092
-
1093
- generate_next(g, p);
1094
- w(g, "~}");
1095
- }
1096
-
1097
- static void generate_loop(struct generator * g, struct node * 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);
1102
-
1103
- generate(g, p->left);
1104
-
1105
- w(g, "~}"
1106
- "~}");
1107
- }
1108
-
1109
- static void generate_repeat_or_atleast(struct generator * g, struct node * p, struct str * loopvar) {
1110
- writef(g, "~Mwhile (1) {~+~N", p);
1111
-
1112
- struct str * savevar = NULL;
1113
- if (repeat_restore(g, p->left)) {
1114
- savevar = vars_newname(g);
1115
- write_savecursor(g, p, savevar);
1116
- }
1117
-
1118
- g->failure_label = new_label(g);
1119
- g->label_used = 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
- }
1128
- generate(g, p->left);
1129
-
1130
- if (loopvar != NULL) {
1131
- g->B[0] = str_data(loopvar);
1132
- w(g, "~M~B0--;~N");
1133
- }
1134
-
1135
- w(g, "~Mcontinue;~N");
1136
-
1137
- if (g->label_used)
1138
- wsetl(g, g->failure_label);
1139
-
1140
- if (savevar) {
1141
- write_restorecursor(g, p, savevar);
1142
- str_delete(savevar);
1143
- }
1144
-
1145
- w(g, "~Mbreak;~N~}");
1146
- }
1147
-
1148
- static void generate_repeat(struct generator * g, struct node * p) {
1149
- write_comment(g, p);
1150
- generate_repeat_or_atleast(g, p, NULL);
1151
- }
1152
-
1153
- static void generate_atleast(struct generator * g, struct node * p) {
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");
1161
- {
1162
- int used = g->label_used;
1163
- int a0 = g->failure_label;
1164
- struct str * a1 = str_copy(g->failure_str);
1165
-
1166
- generate_repeat_or_atleast(g, p, loopvar);
1167
-
1168
- g->label_used = used;
1169
- g->failure_label = a0;
1170
- str_delete(g->failure_str);
1171
- g->failure_str = a1;
1172
- }
1173
- g->B[0] = str_data(loopvar);
1174
- writef(g, "~Mif (~B0 > 0) ~f~N"
1175
- "~}", p);
1176
- str_delete(loopvar);
1177
- }
1178
-
1179
- static void generate_setmark(struct generator * g, struct node * p) {
1180
- write_comment(g, p);
1181
- g->V[0] = p->name;
1182
- writef(g, "~M~V0 = z->c;~N", p);
1183
- }
1184
-
1185
- static void generate_tomark(struct generator * g, struct node * p) {
1186
- write_comment(g, p);
1187
- g->S[0] = p->mode == m_forward ? ">" : "<";
1188
-
1189
- w(g, "~Mif (z->c ~S0 "); generate_AE(g, p->AE); writef(g, ") ~f~N", p);
1190
- w(g, "~Mz->c = "); generate_AE(g, p->AE); writef(g, ";~N", p);
1191
- }
1192
-
1193
- static void generate_atmark(struct generator * g, struct node * p) {
1194
- write_comment(g, p);
1195
- w(g, "~Mif (z->c != "); generate_AE(g, p->AE); writef(g, ") ~f~N", p);
1196
- }
1197
-
1198
- static void generate_hop(struct generator * g, struct node * p) {
1199
- write_comment(g, p);
1200
- if (g->options->encoding == ENC_UTF8) {
1201
- g->S[0] = p->mode == m_forward ? "" : "_b";
1202
- g->S[1] = p->mode == m_forward ? "z->l" : "z->lb";
1203
- w(g, "~{~Mint ret = skip~S0_utf8(z->p, z->c, ~S1, ");
1204
- generate_AE(g, p->AE);
1205
- writef(g, ");~N", p);
1206
- writef(g, "~Mif (ret < 0) ~f~N", p);
1207
- writef(g, "~Mz->c = ret;~N"
1208
- "~}", p);
1209
- } else {
1210
- // Fixed-width characters.
1211
- g->S[0] = p->mode == m_forward ? "+" : "-";
1212
- if (p->AE->type == c_number) {
1213
- // Constant distance hop.
1214
- //
1215
- // No need to check for negative hop as that's converted to false by
1216
- // the analyser.
1217
- //
1218
- // Note that if we signal f then z->c will be reset when this is
1219
- // handled - we rely on this here and unconditionally update z->c.
1220
- w(g, "z->c = z->c ~S0 ");
1221
- generate_AE(g, p->AE);
1222
- writef(g, ";~N", p);
1223
- if (p->mode == m_forward) {
1224
- writef(g, "~Mif (z->c > z->l) ~f~N", p);
1225
- } else {
1226
- writef(g, "~Mif (z->c < z->lb) ~f~N", p);
1227
- }
1228
- } else {
1229
- w(g, "~{~Mint ret = z->c ~S0 ");
1230
- generate_AE(g, p->AE);
1231
- writef(g, ";~N", p);
1232
- if (p->mode == m_forward) {
1233
- writef(g, "~Mif (ret > z->l || ret < z->c) ~f~N", p);
1234
- } else {
1235
- writef(g, "~Mif (ret < z->lb || ret > z->c) ~f~N", p);
1236
- }
1237
- writef(g, "~Mz->c = ret;~N"
1238
- "~}", p);
1239
- }
1240
- }
1241
- }
1242
-
1243
- static void generate_delete(struct generator * g, struct node * p) {
1244
- write_comment(g, p);
1245
- writef(g, "~{~Mint ret = slice_del(z);~N", p);
1246
- writef(g, "~Mif (ret < 0) return ret;~N"
1247
- "~}", p);
1248
- }
1249
-
1250
- static void generate_tolimit(struct generator * g, struct node * p) {
1251
- write_comment(g, p);
1252
- g->S[0] = p->mode == m_forward ? "" : "b";
1253
- writef(g, "~Mz->c = z->l~S0;~N", p);
1254
- }
1255
-
1256
- static void generate_atlimit(struct generator * g, struct node * p) {
1257
- write_comment(g, p);
1258
- g->S[0] = p->mode == m_forward ? "" : "b";
1259
- g->S[1] = p->mode == m_forward ? "<" : ">";
1260
- writef(g, "~Mif (z->c ~S1 z->l~S0) ~f~N", p);
1261
- }
1262
-
1263
- static void generate_leftslice(struct generator * g, struct node * p) {
1264
- write_comment(g, p);
1265
- g->S[0] = p->mode == m_forward ? "bra" : "ket";
1266
- writef(g, "~Mz->~S0 = z->c;~N", p);
1267
- }
1268
-
1269
- static void generate_rightslice(struct generator * g, struct node * p) {
1270
- write_comment(g, p);
1271
- g->S[0] = p->mode == m_forward ? "ket" : "bra";
1272
- writef(g, "~Mz->~S0 = z->c;~N", p);
1273
- }
1274
-
1275
- static void generate_assignto(struct generator * g, struct node * p) {
1276
- write_comment(g, p);
1277
- g->V[0] = p->name;
1278
- writef(g, "~M~V0 = assign_to(z, ~V0);~N"
1279
- "~Mif (~V0 == 0) return -1;~N", p);
1280
- }
1281
-
1282
- static void generate_sliceto(struct generator * g, struct node * p) {
1283
- write_comment(g, p);
1284
- g->V[0] = p->name;
1285
- writef(g, "~M~V0 = slice_to(z, ~V0);~N"
1286
- "~Mif (~V0 == 0) return -1;~N", p);
1287
- }
1288
-
1289
- static void generate_insert(struct generator * g, struct node * p, int style) {
1290
- int keep_c = style == c_attach;
1291
- write_comment(g, p);
1292
- if (p->mode == m_backward) keep_c = !keep_c;
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);
1298
- }
1299
-
1300
- static void generate_assignfrom(struct generator * g, struct node * p) {
1301
- int keep_c = p->mode == m_forward; /* like 'attach' */
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);
1310
- }
1311
-
1312
- static void generate_slicefrom(struct generator * g, struct node * 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);
1316
- }
1317
-
1318
- static void generate_setlimit(struct generator * g, struct node * p) {
1319
- struct str * varname = vars_newname(g);
1320
- write_comment(g, p);
1321
- if (p->left && p->left->type == c_tomark) {
1322
- /* Special case for:
1323
- *
1324
- * setlimit tomark AE for C
1325
- *
1326
- * All uses of setlimit in the current stemmers we ship follow this
1327
- * pattern, and by special-casing we can avoid having to save and
1328
- * restore c.
1329
- */
1330
- struct node * q = p->left;
1331
- write_comment(g, q);
1332
- assert(q->right == NULL);
1333
-
1334
- g->B[0] = str_data(varname);
1335
- writef(g, "~N~{~Mint ~B0;~N", p);
1336
-
1337
- g->S[0] = q->mode == m_forward ? ">" : "<";
1338
-
1339
- w(g, "~Mif (z->c ~S0 "); generate_AE(g, q->AE); writef(g, ") ~f~N", q);
1340
- g->B[0] = str_data(varname);
1341
- w(g, "~M~B0 = ");
1342
- if (p->mode == m_forward) {
1343
- w(g, "z->l - z->c; z->l = ");
1344
- } else {
1345
- w(g, "z->lb; z->lb = ");
1346
- }
1347
- generate_AE(g, q->AE);
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
- }
1359
- } else {
1360
- struct str * savevar = vars_newname(g);
1361
- write_savecursor(g, p, savevar);
1362
- generate(g, p->left);
1363
-
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);
1382
- }
1383
-
1384
- generate(g, p->aux);
1385
- w(g, "~M");
1386
- write_str(g, g->failure_str);
1387
- w(g, "~N"
1388
- "~}");
1389
- str_delete(varname);
1390
- }
1391
-
1392
- /* dollar sets snowball up to operate on a string variable as if it were the
1393
- * current string */
1394
- static void generate_dollar(struct generator * g, struct node * p) {
1395
- write_comment(g, p);
1396
-
1397
- int used = g->label_used;
1398
- int a0 = g->failure_label;
1399
- struct str * a1 = str_copy(g->failure_str);
1400
- g->failure_label = new_label(g);
1401
- g->label_used = 0;
1402
- str_clear(g->failure_str);
1403
-
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
1408
- g->V[0] = p->name;
1409
- /* Assume failure. */
1410
- writef(g, "~Mint failure = 1;~N"
1411
- "~Mz->p = ~V0;~N"
1412
- "~Mz->lb = z->c = 0;~N"
1413
- "~Mz->l = SIZE(z->p);~N", p);
1414
- generate(g, p->left);
1415
- /* Mark success. */
1416
- w(g, "~Mfailure = 0;~N");
1417
- if (g->label_used)
1418
- wsetl(g, g->failure_label);
1419
- g->V[0] = p->name; /* necessary */
1420
-
1421
- g->label_used = used;
1422
- g->failure_label = a0;
1423
- str_delete(g->failure_str);
1424
- g->failure_str = a1;
1425
-
1426
- g->B[0] = str_data(savevar);
1427
- writef(g, "~M~V0 = z->p;~N"
1428
- "~M* z = en~B0;~N"
1429
- "~Mif (failure) ~f~N~}", p);
1430
- str_delete(savevar);
1431
- }
1432
-
1433
- static void generate_integer_assign(struct generator * g, struct node * p, const char * s) {
1434
- write_comment(g, p);
1435
- g->V[0] = p->name;
1436
- g->S[0] = s;
1437
- w(g, "~M~V0 ~S0 "); generate_AE(g, p->AE); writef(g, ";~N", p);
1438
- }
1439
-
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
- }
1452
- generate_AE(g, p->left);
1453
- write_c_relop(g, relop);
1454
- generate_AE(g, p->AE);
1455
- if (optimise_to_return) {
1456
- writef(g, ";~N", p);
1457
- } else {
1458
- writef(g, ") ~f~N", p);
1459
- }
1460
- }
1461
-
1462
- static void generate_call(struct generator * g, struct node * p) {
1463
- int signals = check_possible_signals_list(g, p->name->definition, c_define, 0);
1464
- write_comment(g, p);
1465
- g->V[0] = p->name;
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) {
1474
- /* Combine the two tests in this special case for better optimisation
1475
- * and clearer generated code. */
1476
- writef(g, "~Mif (ret <= 0) return ret;~N", p);
1477
- } else {
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
- }
1489
- }
1490
- writef(g, "~}", p);
1491
- }
1492
-
1493
- static void generate_grouping(struct generator * g, struct node * p, int complement) {
1494
- write_comment(g, p);
1495
-
1496
- struct grouping * q = p->name->grouping;
1497
- g->S[0] = p->mode == m_forward ? "" : "_b";
1498
- g->S[1] = complement ? "out" : "in";
1499
- g->S[2] = g->options->encoding == ENC_UTF8 ? "_U" : "";
1500
- g->V[0] = p->name;
1501
- g->I[0] = q->smallest_ch;
1502
- g->I[1] = q->largest_ch;
1503
- writef(g, "~Mif (~S1_grouping~S0~S2(z, ~V0, ~I0, ~I1, 0)) ~f~N", p);
1504
- }
1505
-
1506
- static void generate_namedstring(struct generator * g, struct node * p) {
1507
- write_comment(g, p);
1508
- g->S[0] = p->mode == m_forward ? "" : "_b";
1509
- g->V[0] = p->name;
1510
- writef(g, "~Mif (!(eq_v~S0(z, ~V0))) ~f~N", p);
1511
- }
1512
-
1513
- static void generate_literalstring(struct generator * g, struct node * p) {
1514
- symbol * b = p->literalstring;
1515
- write_comment(g, p);
1516
- if (SIZE(b) == 1) {
1517
- /* It's quite common to compare with a single character literal string,
1518
- * so just inline the simpler code for this case rather than making a
1519
- * function call. In UTF-8 mode, only do this for the ASCII subset,
1520
- * since multi-byte characters are more complex to test against.
1521
- */
1522
- if (g->options->encoding == ENC_UTF8 && *b >= 128) {
1523
- printf("single byte %d\n", *b);
1524
- exit(1);
1525
- }
1526
- g->I[0] = *b;
1527
- if (p->mode == m_forward) {
1528
- writef(g, "~Mif (z->c == z->l || z->p[z->c] != ~c0) ~f~N"
1529
- "~Mz->c++;~N", p);
1530
- } else {
1531
- writef(g, "~Mif (z->c <= z->lb || z->p[z->c - 1] != ~c0) ~f~N"
1532
- "~Mz->c--;~N", p);
1533
- }
1534
- } else {
1535
- g->S[0] = p->mode == m_forward ? "" : "_b";
1536
- g->I[0] = SIZE(b);
1537
- g->L[0] = b;
1538
-
1539
- writef(g, "~Mif (!(eq_s~S0(z, ~I0, ~L0))) ~f~N", p);
1540
- }
1541
- }
1542
-
1543
- static void generate_define(struct generator * g, struct node * p) {
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
-
1550
- g->next_label = 0;
1551
- g->var_number = 0;
1552
-
1553
- g->S[0] = q->type == t_routine ? "static" : "extern";
1554
- g->V[0] = q;
1555
-
1556
- w(g, "~S0 int ~V0(struct SN_env * z) {~N~+");
1557
- if (p->amongvar_needed) w(g, "~Mint among_var;~N");
1558
- str_clear(g->failure_str);
1559
- g->failure_label = x_return;
1560
- g->label_used = 0;
1561
- int signals = check_possible_signals_list(g, p->left, c_define, 0);
1562
-
1563
- /* Generate function body. */
1564
- generate(g, p->left);
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");
1577
- }
1578
-
1579
- static void generate_substring(struct generator * g, struct node * p) {
1580
- write_comment(g, p);
1581
-
1582
- struct among * x = p->among;
1583
- int block = -1;
1584
- unsigned int bitmap = 0;
1585
- struct amongvec * among_cases = x->b;
1586
- int empty_case = -1;
1587
- int n_cases = 0;
1588
- symbol cases[2];
1589
- int shortest_size = x->shortest_size;
1590
-
1591
- g->S[0] = p->mode == m_forward ? "" : "_b";
1592
- g->I[0] = x->number;
1593
- g->I[1] = x->literalstring_count;
1594
-
1595
- /* In forward mode with non-ASCII UTF-8 characters, the first byte
1596
- * of the string will often be the same, so instead look at the last
1597
- * common byte position.
1598
- *
1599
- * In backward mode, we can't match if there are fewer characters before
1600
- * the current position than the minimum length.
1601
- */
1602
- for (int c = 0; c < x->literalstring_count; ++c) {
1603
- symbol ch;
1604
- if (among_cases[c].size == 0) {
1605
- empty_case = c;
1606
- continue;
1607
- }
1608
- if (p->mode == m_forward) {
1609
- ch = among_cases[c].b[shortest_size - 1];
1610
- } else {
1611
- ch = among_cases[c].b[among_cases[c].size - 1];
1612
- }
1613
- if (n_cases == 0) {
1614
- block = ch >> 5;
1615
- } else if (ch >> 5 != block) {
1616
- block = -1;
1617
- if (n_cases > 2) break;
1618
- }
1619
- if (block == -1) {
1620
- if (n_cases > 0 && ch == cases[0]) continue;
1621
- if (n_cases < 2) {
1622
- cases[n_cases++] = ch;
1623
- } else if (ch != cases[1]) {
1624
- ++n_cases;
1625
- break;
1626
- }
1627
- } else {
1628
- if ((bitmap & (1u << (ch & 0x1f))) == 0) {
1629
- bitmap |= 1u << (ch & 0x1f);
1630
- if (n_cases < 2)
1631
- cases[n_cases] = ch;
1632
- ++n_cases;
1633
- }
1634
- }
1635
- }
1636
-
1637
- if (block != -1 || n_cases <= 2) {
1638
- char buf[64];
1639
- g->I[2] = block;
1640
- g->I[3] = bitmap;
1641
- g->I[4] = shortest_size - 1;
1642
- if (p->mode == m_forward) {
1643
- sprintf(buf, "z->p[z->c + %d]", shortest_size - 1);
1644
- g->S[1] = buf;
1645
- if (shortest_size == 1) {
1646
- writef(g, "~Mif (z->c >= z->l", p);
1647
- } else {
1648
- writef(g, "~Mif (z->c + ~I4 >= z->l", p);
1649
- }
1650
- } else {
1651
- g->S[1] = "z->p[z->c - 1]";
1652
- if (shortest_size == 1) {
1653
- writef(g, "~Mif (z->c <= z->lb", p);
1654
- } else {
1655
- writef(g, "~Mif (z->c - ~I4 <= z->lb", p);
1656
- }
1657
- }
1658
- if (n_cases == 0) {
1659
- /* We get this for the degenerate case: among ( '' )
1660
- * This doesn't seem to be a useful construct, but it is
1661
- * syntactically valid.
1662
- */
1663
- } else if (n_cases == 1) {
1664
- g->I[4] = cases[0];
1665
- writef(g, " || ~S1 != ~I4", p);
1666
- } else if (n_cases == 2) {
1667
- g->I[4] = cases[0];
1668
- g->I[5] = cases[1];
1669
- writef(g, " || (~S1 != ~I4 && ~S1 != ~I5)", p);
1670
- } else {
1671
- writef(g, " || ~S1 >> 5 != ~I2 || !((~I3 >> (~S1 & 0x1f)) & 1)", p);
1672
- }
1673
- write_string(g, ") ");
1674
- if (empty_case != -1) {
1675
- /* If the among includes the empty string, it can never fail
1676
- * so not matching the bitmap means we match the empty string.
1677
- */
1678
- g->I[4] = among_cases[empty_case].result;
1679
- writef(g, "among_var = ~I4; else~N", p);
1680
- } else {
1681
- writef(g, "~f~N", p);
1682
- }
1683
- } else {
1684
- #ifdef OPTIMISATION_WARNINGS
1685
- printf("Couldn't shortcut among %d\n", x->number);
1686
- #endif
1687
- }
1688
-
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);
1696
- } else {
1697
- writef(g, "~Mif (!find_among~S0(z, a_~I0, ~I1)) ~f~N", p);
1698
- }
1699
- }
1700
-
1701
- static void generate_among(struct generator * g, struct node * p) {
1702
- struct among * x = p->among;
1703
-
1704
- if (x->substring == NULL) {
1705
- generate_substring(g, p);
1706
- } else {
1707
- write_comment(g, p);
1708
- }
1709
-
1710
- if (x->command_count == 1 && x->nocommand_count == 0) {
1711
- /* Only one outcome ("no match" already handled). */
1712
- generate(g, x->commands[0]);
1713
- } else if (x->command_count > 0) {
1714
- writef(g, "~Mswitch (among_var) {~N~+", p);
1715
- for (int i = 1; i <= x->command_count; i++) {
1716
- g->I[0] = i;
1717
- w(g, "~Mcase ~I0:~N~+");
1718
- generate(g, x->commands[i - 1]);
1719
- w(g, "~Mbreak;~N~-");
1720
- }
1721
- w(g, "~}");
1722
- }
1723
- }
1724
-
1725
- static void generate_booltest(struct generator * g, struct node * p) {
1726
- write_comment(g, p);
1727
- g->V[0] = p->name;
1728
- writef(g, "~Mif (!(~V0)) ~f~N", p);
1729
- }
1730
-
1731
- static void generate_false(struct generator * g, struct node * p) {
1732
- write_comment(g, p);
1733
- writef(g, "~M~f~N", p);
1734
- }
1735
-
1736
- static void generate_debug(struct generator * g, struct node * p) {
1737
- write_comment(g, p);
1738
- g->I[0] = g->debug_count++;
1739
- g->I[1] = p->line_number;
1740
- writef(g, "~Mdebug(z, ~I0, ~I1);~N", p);
1741
- }
1742
-
1743
- static void generate(struct generator * g, struct node * p) {
1744
- int used = g->label_used;
1745
- int a0 = g->failure_label;
1746
- struct str * a1 = str_copy(g->failure_str);
1747
-
1748
- switch (p->type) {
1749
- case c_define: generate_define(g, p); break;
1750
- case c_bra: generate_bra(g, p); break;
1751
- case c_and: generate_and(g, p); break;
1752
- case c_or: generate_or(g, p); break;
1753
- case c_backwards: generate_backwards(g, p); break;
1754
- case c_not: generate_not(g, p); break;
1755
- case c_set: generate_set(g, p); break;
1756
- case c_unset: generate_unset(g, p); break;
1757
- case c_try: generate_try(g, p); break;
1758
- case c_fail: generate_fail(g, p); break;
1759
- case c_reverse:
1760
- case c_test: generate_test(g, p); break;
1761
- case c_do: generate_do(g, p); break;
1762
- case c_goto: generate_GO(g, p, 1); break;
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;
1769
- case c_repeat: generate_repeat(g, p); break;
1770
- case c_loop: generate_loop(g, p); break;
1771
- case c_atleast: generate_atleast(g, p); break;
1772
- case c_setmark: generate_setmark(g, p); break;
1773
- case c_tomark: generate_tomark(g, p); break;
1774
- case c_atmark: generate_atmark(g, p); break;
1775
- case c_hop: generate_hop(g, p); break;
1776
- case c_delete: generate_delete(g, p); break;
1777
- case c_next: generate_next(g, p); break;
1778
- case c_tolimit: generate_tolimit(g, p); break;
1779
- case c_atlimit: generate_atlimit(g, p); break;
1780
- case c_leftslice: generate_leftslice(g, p); break;
1781
- case c_rightslice: generate_rightslice(g, p); break;
1782
- case c_assignto: generate_assignto(g, p); break;
1783
- case c_sliceto: generate_sliceto(g, p); break;
1784
- case c_assign: generate_assignfrom(g, p); break;
1785
- case c_insert:
1786
- case c_attach: generate_insert(g, p, p->type); break;
1787
- case c_slicefrom: generate_slicefrom(g, p); break;
1788
- case c_setlimit: generate_setlimit(g, p); break;
1789
- case c_dollar: generate_dollar(g, p); break;
1790
- case c_mathassign: generate_integer_assign(g, p, "="); break;
1791
- case c_plusassign: generate_integer_assign(g, p, "+="); break;
1792
- case c_minusassign: generate_integer_assign(g, p, "-="); break;
1793
- case c_multiplyassign:generate_integer_assign(g, p, "*="); break;
1794
- case c_divideassign: generate_integer_assign(g, p, "/="); break;
169
+ if (p->name) {
170
+ write_char(g, '$');
171
+ write_s(g, p->name->s);
172
+ write_char(g, ' ');
173
+ }
174
+ write_string(g, name_of_token(p->type));
175
+ write_char(g, ' ');
176
+ write_comment_AE(g, p->AE);
177
+ break;
1795
178
  case c_eq:
1796
179
  case c_ne:
1797
180
  case c_gt:
1798
181
  case c_ge:
1799
182
  case c_lt:
1800
183
  case c_le:
1801
- generate_integer_test(g, p);
184
+ write_string(g, "$(");
185
+ write_comment_AE(g, p->left);
186
+ write_char(g, ' ');
187
+ write_string(g, name_of_token(p->type));
188
+ write_char(g, ' ');
189
+ write_comment_AE(g, p->AE);
190
+ write_char(g, ')');
191
+ break;
192
+ case c_define:
193
+ if (p->mode == m_forward) {
194
+ write_string(g, "forwardmode define ");
195
+ } else {
196
+ write_string(g, "backwardmode define ");
197
+ }
198
+ write_s(g, p->name->s);
199
+ break;
200
+ case c_literalstring:
201
+ write_comment_literalstring(g, p->literalstring, end);
202
+ break;
203
+ case c_call:
204
+ case c_grouping:
205
+ case c_name:
206
+ write_s(g, p->name->s);
1802
207
  break;
1803
- case c_call: generate_call(g, p); break;
1804
- case c_grouping: generate_grouping(g, p, false); break;
1805
- case c_non: generate_grouping(g, p, true); break;
1806
- case c_name: generate_namedstring(g, p); break;
1807
- case c_literalstring: generate_literalstring(g, p); break;
1808
- case c_among: generate_among(g, p); break;
1809
- case c_substring: generate_substring(g, p); break;
1810
- case c_booltest: generate_booltest(g, p); break;
1811
- case c_false: generate_false(g, p); break;
1812
- case c_true: break;
1813
- case c_debug: generate_debug(g, p); break;
1814
- case c_functionend: generate_functionend(g, p); break;
1815
- default: fprintf(stderr, "%d encountered\n", p->type);
1816
- exit(1);
208
+ default:
209
+ write_string(g, name_of_token(p->type));
210
+ if (p->name) {
211
+ write_char(g, ' ');
212
+ write_s(g, p->name->s);
213
+ } else if (p->literalstring) {
214
+ write_char(g, ' ');
215
+ write_comment_literalstring(g, p->literalstring, end);
216
+ }
1817
217
  }
1818
-
1819
- if (g->failure_label != a0)
1820
- g->label_used = used;
1821
- g->failure_label = a0;
1822
- str_delete(g->failure_str);
1823
- g->failure_str = a1;
218
+ write_string(g, ", line ");
219
+ write_int(g, p->line_number);
1824
220
  }
1825
221
 
1826
222
  void write_generated_comment_content(struct generator * g) {
@@ -1840,266 +236,337 @@ void write_start_comment(struct generator * g,
1840
236
  const char * comment_start,
1841
237
  const char * comment_end) {
1842
238
  write_margin(g);
1843
- w(g, comment_start);
239
+ write_string(g, comment_start);
1844
240
  write_generated_comment_content(g);
1845
241
  if (comment_end) {
1846
- w(g, comment_end);
242
+ write_string(g, comment_end);
1847
243
  }
1848
- w(g, "~N~N");
244
+ write_newline(g);
245
+ write_newline(g);
1849
246
  }
1850
247
 
1851
- static void generate_head(struct generator * g) {
1852
- w(g, "#include \"");
1853
- if (g->options->runtime_path) {
1854
- write_string(g, g->options->runtime_path);
1855
- if (g->options->runtime_path[strlen(g->options->runtime_path) - 1] != '/')
1856
- write_char(g, '/');
1857
- }
1858
- w(g, "header.h\"~N~N");
248
+ extern struct str * vars_newname(struct generator * g) {
249
+ struct str * output;
250
+ g->var_number++;
251
+ output = str_new();
252
+ str_append_string(output, g->varname_prefix);
253
+ str_append_int(output, g->var_number);
254
+ return output;
1859
255
  }
1860
256
 
1861
- static void generate_routine_headers(struct generator * g) {
1862
- for (struct name * q = g->analyser->names; q; q = q->next) {
1863
- g->V[0] = q;
1864
- switch (q->type) {
1865
- case t_routine:
1866
- w(g, "static int ~W0(struct SN_env * z);~N");
1867
- break;
1868
- case t_external:
1869
- w(g,
1870
- "#ifdef __cplusplus~N"
1871
- "extern \"C\" {~N"
1872
- "#endif~N"
1873
- "extern int ~W0(struct SN_env * z);~N"
1874
- "#ifdef __cplusplus~N"
1875
- "}~N"
1876
- "#endif~N"
1877
- );
1878
- break;
1879
- }
1880
- }
257
+ extern void write_margin(struct generator * g) {
258
+ for (int i = 0; i < g->margin; i++) write_string(g, g->margin_indent);
1881
259
  }
1882
260
 
1883
- static void generate_among_table(struct generator * g, struct among * x) {
1884
- write_comment(g, x->node);
261
+ /* K_needed() tests to see if we really need to keep c. Not true when the
262
+ command does not touch the cursor (and in backwardmode, also does not
263
+ change the limit by inserting, deleting, or replacing text in the string).
264
+ This and repeat_score() could be elaborated almost indefinitely.
265
+ */
1885
266
 
1886
- struct amongvec * v = x->b;
267
+ static int K_needed_(struct node * p, int call_depth);
1887
268
 
1888
- g->I[0] = x->number;
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");
1895
- }
269
+ static int K_needed_node(struct node * p, int call_depth) {
270
+ switch (p->type) {
271
+ case c_assignto:
272
+ case c_do:
273
+ case c_dollar:
274
+ case c_leftslice:
275
+ case c_rightslice:
276
+ case c_assign:
277
+ case c_plusassign:
278
+ case c_minusassign:
279
+ case c_multiplyassign:
280
+ case c_divideassign:
281
+ case c_eq:
282
+ case c_ne:
283
+ case c_gt:
284
+ case c_ge:
285
+ case c_lt:
286
+ case c_le:
287
+ case c_sliceto:
288
+ case c_booltest:
289
+ case c_not_booltest:
290
+ case c_set:
291
+ case c_unset:
292
+ case c_true:
293
+ case c_false:
294
+ case c_debug:
295
+ case c_functionend:
296
+ // Doesn't change the cursor or always restores it.
297
+ break;
1896
298
 
1897
- g->I[1] = x->literalstring_count;
1898
- w(g, "~Mstatic const struct among a_~I0[~I1] = {~N");
299
+ case c_stringassign:
300
+ // Doesn't change the cursor in forwards mode; in backwards
301
+ // mode the cursor and forwards limit move in step.
302
+ break;
1899
303
 
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 ? "," : "";
304
+ case c_attach:
305
+ // Cursor modified in backwardmode.
306
+ if (p->mode == m_backward) return true;
307
+ break;
1906
308
 
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);
1921
- }
1922
- w(g, "}~S0~N");
309
+ case c_insert:
310
+ // Cursor modified in forwards mode.
311
+ if (p->mode == m_forward) return true;
312
+ break;
313
+
314
+ case c_call:
315
+ /* Recursive functions aren't typical in snowball programs, so
316
+ * make the pessimistic assumption that keep is needed if we
317
+ * hit a generous limit on recursion. It's not likely to make
318
+ * a difference to any real world program, but means we won't
319
+ * recurse until we run out of stack for pathological cases.
320
+ */
321
+ if (call_depth >= 100) return true;
322
+ if (K_needed_(p->name->definition->left, call_depth + 1))
323
+ return true;
324
+ break;
325
+
326
+ case c_bra:
327
+ case c_loop:
328
+ case c_fail:
329
+ if (K_needed_(p->left, call_depth)) return true;
330
+ break;
331
+
332
+ case c_backwards:
333
+ case c_reverse:
334
+ case c_test:
335
+ if (p->possible_signals != 1) return true;
336
+ // Restores cursor on t and the subcommand can't fail.
337
+ break;
338
+
339
+ default: return true;
1923
340
  }
1924
- w(g, "};~N~N");
341
+ return false;
1925
342
  }
1926
343
 
1927
- static void generate_amongs(struct generator * g) {
1928
- for (struct among * x = g->analyser->amongs; x; x = x->next) {
1929
- generate_among_table(g, x);
344
+ static int K_needed_(struct node * p, int call_depth) {
345
+ while (p) {
346
+ if (K_needed_node(p, call_depth)) return true;
347
+ p = p->right;
1930
348
  }
349
+ return false;
350
+ }
351
+
352
+ extern int K_needed(struct node * p) {
353
+ return K_needed_(p, 0);
1931
354
  }
1932
355
 
1933
- static void set_bit(symbol * b, int i) { b[i/8] |= 1 << i%8; }
356
+ static int K_needed_node_on_f_(struct node * p, int call_depth) {
357
+ switch (p->type) {
358
+ case c_assignto:
359
+ case c_do:
360
+ case c_dollar:
361
+ case c_leftslice:
362
+ case c_rightslice:
363
+ case c_assign:
364
+ case c_plusassign:
365
+ case c_minusassign:
366
+ case c_multiplyassign:
367
+ case c_divideassign:
368
+ case c_eq:
369
+ case c_ne:
370
+ case c_gt:
371
+ case c_ge:
372
+ case c_lt:
373
+ case c_le:
374
+ case c_sliceto:
375
+ case c_booltest:
376
+ case c_not_booltest:
377
+ case c_set:
378
+ case c_unset:
379
+ case c_true:
380
+ case c_false:
381
+ case c_debug:
382
+ case c_functionend:
383
+ // Doesn't change the cursor or always restores it.
384
+ break;
385
+
386
+ case c_grouping:
387
+ case c_literalstring:
388
+ case c_name:
389
+ case c_non:
390
+ case c_hop:
391
+ case c_next:
392
+ case c_substring:
393
+ case c_tomark:
394
+ // Doesn't modify the cursor on failure.
395
+ break;
396
+
397
+ case c_repeat:
398
+ case c_slicefrom:
399
+ case c_tolimit:
400
+ case c_attach:
401
+ case c_insert:
402
+ // Can't fail, so can't modify the cursor on failure.
403
+ break;
1934
404
 
1935
- static void generate_grouping_table(struct generator * g, struct grouping * q) {
1936
- int range = q->largest_ch - q->smallest_ch + 1;
1937
- int size = (range + 7)/ 8; /* assume 8 bits per symbol */
1938
- symbol * b = q->b;
1939
- symbol * map = create_b(size);
405
+ case c_goto:
406
+ case c_try:
407
+ // Restores the cursor on failure.
408
+ break;
1940
409
 
1941
- for (int i = 0; i < size; i++) map[i] = 0;
410
+ case c_gopast:
411
+ // Restores the cursor on failure if repeat_restore() is true.
412
+ if (!repeat_restore(p->left)) return true;
413
+ break;
1942
414
 
1943
- for (int i = 0; i < SIZE(b); i++) set_bit(map, b[i] - q->smallest_ch);
415
+ case c_call:
416
+ /* Recursive functions aren't typical in snowball programs, so
417
+ * make the pessimistic assumption that keep is needed if we
418
+ * hit a generous limit on recursion. It's not likely to make
419
+ * a difference to any real world program, but means we won't
420
+ * recurse until we run out of stack for pathological cases.
421
+ */
422
+ if (call_depth >= 100) return true;
423
+ if (K_needed_(p->name->definition->left, call_depth + 1))
424
+ return true;
425
+ break;
1944
426
 
1945
- g->V[0] = q->name;
1946
- w(g, "static const unsigned char ~V0[] = { ");
1947
- for (int i = 0; i < size; i++) {
1948
- write_int(g, map[i]);
1949
- if (i < size - 1) w(g, ", ");
1950
- }
1951
- w(g, " };~N~N");
427
+ case c_bra:
428
+ case c_loop:
429
+ case c_fail:
430
+ if (K_needed_(p->left, call_depth)) return true;
431
+ break;
1952
432
 
1953
- lose_b(map);
1954
- }
433
+ case c_backwards:
434
+ case c_reverse:
435
+ case c_test:
436
+ if (p->possible_signals != 1) return true;
437
+ // Restores cursor on t and the subcommand can't fail.
438
+ break;
1955
439
 
1956
- static void generate_groupings(struct generator * g) {
1957
- for (struct grouping * q = g->analyser->groupings; q; q = q->next) {
1958
- if (q->name->used)
1959
- generate_grouping_table(g, q);
440
+ default:
441
+ // FIXME: Can we handle c_or c_and c_among c_atleast c_setlimit
442
+ // better?
443
+ return true;
1960
444
  }
445
+ return false;
1961
446
  }
1962
447
 
1963
- static void generate_create(struct generator * g) {
1964
- int * p = g->analyser->name_count;
1965
- g->I[0] = p[t_string];
1966
- g->I[1] = p[t_integer] + p[t_boolean];
1967
- w(g, "~N"
1968
- "extern struct SN_env * ~pcreate_env(void) { return SN_create_env(~I0, ~I1); }"
1969
- "~N");
448
+ extern int K_needed_node_on_f(struct node * p) {
449
+ return K_needed_node_on_f_(p, 0);
1970
450
  }
1971
451
 
1972
- static void generate_close(struct generator * g) {
1973
- int * p = g->analyser->name_count;
1974
- g->I[0] = p[t_string];
1975
- w(g, "~Nextern void ~pclose_env(struct SN_env * z) { SN_close_env(z, ~I0); }~N~N");
452
+ // Like K_needed(), but for the sub-node chain of c_or. We only restore on
453
+ // signal f, and the cursor only needs to be restored between nodes so we don't
454
+ // need to check the final node in the chain.
455
+ extern int K_needed_for_or(struct node * p) {
456
+ while (p->right) {
457
+ if (K_needed_node_on_f(p)) return true;
458
+ p = p->right;
459
+ }
460
+ return false;
1976
461
  }
1977
462
 
1978
- static void generate_create_and_close_templates(struct generator * g) {
1979
- w(g, "~N"
1980
- "extern struct SN_env * ~pcreate_env(void);~N"
1981
- "extern void ~pclose_env(struct SN_env * z);~N"
1982
- "~N");
463
+ // Like K_needed(), but for the sub-node chain of c_and. The cursor only needs
464
+ // to be restored between nodes so we don't need to check the final node in the
465
+ // chain.
466
+ extern int K_needed_for_and(struct node * p) {
467
+ while (p->right) {
468
+ if (K_needed_node(p, 0)) return true;
469
+ p = p->right;
470
+ }
471
+ return false;
1983
472
  }
1984
473
 
1985
- static void generate_header_file(struct generator * g) {
1986
- const char * vp = g->options->variables_prefix;
1987
- g->S[0] = vp;
1988
-
1989
- w(g, "#ifdef __cplusplus~N"
1990
- "extern \"C\" {~N"
1991
- "#endif~N"); /* for C++ */
1992
-
1993
- generate_create_and_close_templates(g);
1994
- for (struct name * q = g->analyser->names; q; q = q->next) {
1995
- g->V[0] = q;
1996
- switch (q->type) {
1997
- case t_external:
1998
- w(g, "extern int ~W0(struct SN_env * z);~N");
474
+ static int repeat_score(struct node * p, int call_depth) {
475
+ int score = 0;
476
+ while (p) {
477
+ switch (p->type) {
478
+ case c_dollar:
479
+ case c_leftslice:
480
+ case c_rightslice:
481
+ case c_assign:
482
+ case c_plusassign:
483
+ case c_minusassign:
484
+ case c_multiplyassign:
485
+ case c_divideassign:
486
+ case c_eq:
487
+ case c_ne:
488
+ case c_gt:
489
+ case c_ge:
490
+ case c_lt:
491
+ case c_le:
492
+ case c_sliceto: /* case c_not: must not be included here! */
493
+ case c_booltest:
494
+ case c_not_booltest:
495
+ case c_set:
496
+ case c_unset:
497
+ case c_true:
498
+ case c_false:
499
+ case c_debug:
500
+ case c_functionend:
1999
501
  break;
2000
- case t_string:
2001
- case t_integer:
2002
- case t_boolean:
2003
- if (vp) {
2004
- int count = q->count;
2005
- if (count < 0) {
2006
- /* Unused variables should get removed from `names`. */
2007
- q->s[SIZE(q->s)] = 0;
2008
- fprintf(stderr, "Optimised out variable %s still in names list\n",
2009
- q->s);
2010
- exit(1);
2011
- }
2012
- if (q->type == t_boolean) {
2013
- /* We use a single array for booleans and integers,
2014
- * with the integers first.
2015
- */
2016
- count += g->analyser->name_count[t_integer];
2017
- }
2018
- g->I[0] = count;
2019
- g->I[1] = "SIIrxg"[q->type];
2020
- w(g, "#define ~S0");
2021
- write_s(g, q->s);
2022
- w(g, " (~c1[~I0])~N");
502
+
503
+ case c_call:
504
+ /* Recursive functions aren't typical in snowball programs, so
505
+ * make the pessimistic assumption that repeat requires cursor
506
+ * reinstatement if we hit a generous limit on recursion. It's
507
+ * not likely to make a difference to any real world program,
508
+ * but means we won't recurse until we run out of stack for
509
+ * pathological cases.
510
+ */
511
+ if (call_depth >= 100) {
512
+ return 2;
2023
513
  }
514
+ score += repeat_score(p->name->definition->left, call_depth + 1);
515
+ if (score >= 2)
516
+ return score;
2024
517
  break;
2025
- }
2026
- }
2027
518
 
2028
- w(g, "~N"
2029
- "#ifdef __cplusplus~N"
2030
- "}~N"
2031
- "#endif~N"); /* for C++ */
2032
-
2033
- w(g, "~N");
2034
- }
519
+ case c_bra:
520
+ score += repeat_score(p->left, call_depth);
521
+ if (score >= 2)
522
+ return score;
523
+ break;
2035
524
 
2036
- extern void generate_program_c(struct generator * g) {
2037
- g->outbuf = str_new();
2038
- g->failure_str = str_new();
2039
- write_start_comment(g, "/* ", " */");
2040
- if (g->analyser->int_limits_used) {
2041
- w(g, "#include <limits.h>~N");
2042
- }
2043
- generate_head(g);
2044
- generate_routine_headers(g);
2045
- w(g, "#ifdef __cplusplus~N"
2046
- "extern \"C\" {~N"
2047
- "#endif~N"
2048
- "~N");
2049
- generate_create_and_close_templates(g);
2050
- w(g, "~N"
2051
- "#ifdef __cplusplus~N"
2052
- "}~N"
2053
- "#endif~N");
2054
- generate_amongs(g);
2055
- generate_groupings(g);
2056
- g->declarations = g->outbuf;
2057
- g->outbuf = str_new();
2058
- g->literalstring_count = 0;
525
+ case c_name:
526
+ case c_literalstring:
527
+ case c_next:
528
+ case c_grouping:
529
+ case c_non:
530
+ #if 0
531
+ // These could be here if the target-language helpers all preserved
532
+ // the cursor on failure:
533
+ case c_goto_grouping:
534
+ case c_gopast_grouping:
535
+ case c_goto_non:
536
+ case c_gopast_non:
537
+ #endif
538
+ case c_hop:
539
+ if (++score >= 2)
540
+ return score;
541
+ break;
2059
542
 
2060
- for (struct node * p = g->analyser->program; p; p = p->right) {
2061
- generate(g, p);
543
+ default:
544
+ return 2;
545
+ }
546
+ p = p->right;
2062
547
  }
548
+ return score;
549
+ }
2063
550
 
2064
- generate_create(g);
2065
- generate_close(g);
2066
-
2067
- output_str(g->options->output_src, g->declarations);
2068
- str_delete(g->declarations);
2069
- output_str(g->options->output_src, g->outbuf);
2070
- str_clear(g->outbuf);
2071
-
2072
- write_start_comment(g, "/* ", " */");
2073
- generate_header_file(g);
2074
- output_str(g->options->output_h, g->outbuf);
2075
- str_delete(g->outbuf);
2076
- str_delete(g->failure_str);
551
+ /* tests if an expression requires cursor reinstatement in a repeat */
552
+ extern int repeat_restore(struct node * p) {
553
+ return repeat_score(p, 0) >= 2;
2077
554
  }
2078
555
 
2079
- /* Generator functions common to multiple languages. */
556
+ /* Language-independent write routines for simple entities */
2080
557
 
2081
- extern struct generator * create_generator(struct analyser * a, struct options * o) {
2082
- NEW(generator, g);
2083
- g->analyser = a;
2084
- g->options = o;
2085
- g->margin = 0;
2086
- g->debug_count = 0;
2087
- g->copy_from_count = 0;
2088
- g->line_count = 0;
2089
- g->line_labelled = 0;
2090
- g->failure_label = -1;
2091
- g->unreachable = false;
2092
- #ifndef DISABLE_PYTHON
2093
- g->max_label = 0;
2094
- #endif
2095
- return g;
558
+ static void write_hexdigit(struct generator * g, unsigned i) {
559
+ str_append_ch(g->outbuf, "0123456789ABCDEF"[i & 0xF]); /* hexchar */
2096
560
  }
2097
561
 
2098
- extern void close_generator(struct generator * g) {
2099
- FREE(g);
562
+ extern void write_hex4(struct generator * g, unsigned ch) {
563
+ for (int i = 12; i >= 0; i -= 4) write_hexdigit(g, ch >> i);
2100
564
  }
2101
565
 
2102
- /* Write routines for simple entities */
566
+ extern void write_hex(struct generator * g, unsigned i) {
567
+ if (i >> 4) write_hex(g, i >> 4);
568
+ write_hexdigit(g, i); /* hex integer */
569
+ }
2103
570
 
2104
571
  extern void write_char(struct generator * g, int ch) {
2105
572
  str_append_ch(g->outbuf, ch); /* character */
@@ -2128,6 +595,13 @@ extern void write_int(struct generator * g, int i) {
2128
595
  str_append_int(g->outbuf, i);
2129
596
  }
2130
597
 
598
+ // Write an integer, left-padded to width 3 with spaces.
599
+ extern void wi3(struct generator * g, int i) {
600
+ if (i < 100) write_char(g, ' ');
601
+ if (i < 10) write_char(g, ' ');
602
+ write_int(g, i);
603
+ }
604
+
2131
605
  extern void write_s(struct generator * g, const byte * s) {
2132
606
  str_append_s(g->outbuf, s);
2133
607
  }