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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/LICENSE.txt +1 -1
- data/README.md +4 -4
- data/lib/mittens/version.rb +1 -1
- data/mittens.gemspec +1 -1
- data/vendor/snowball/.github/workflows/ci.yml +216 -0
- data/vendor/snowball/CONTRIBUTING.rst +111 -62
- data/vendor/snowball/GNUmakefile +194 -136
- data/vendor/snowball/NEWS +798 -3
- data/vendor/snowball/README.rst +50 -1
- data/vendor/snowball/ada/src/stemmer.adb +25 -13
- data/vendor/snowball/ada/src/stemmer.ads +9 -9
- data/vendor/snowball/ada/stemmer_config.gpr +7 -7
- data/vendor/snowball/algorithms/basque.sbl +4 -19
- data/vendor/snowball/algorithms/catalan.sbl +2 -9
- data/vendor/snowball/algorithms/danish.sbl +1 -1
- data/vendor/snowball/algorithms/dutch.sbl +284 -122
- data/vendor/snowball/algorithms/dutch_porter.sbl +178 -0
- data/vendor/snowball/algorithms/english.sbl +52 -37
- data/vendor/snowball/algorithms/esperanto.sbl +157 -0
- data/vendor/snowball/algorithms/estonian.sbl +269 -0
- data/vendor/snowball/algorithms/finnish.sbl +2 -3
- data/vendor/snowball/algorithms/french.sbl +42 -16
- data/vendor/snowball/algorithms/german.sbl +35 -14
- data/vendor/snowball/algorithms/greek.sbl +76 -76
- data/vendor/snowball/algorithms/hungarian.sbl +8 -6
- data/vendor/snowball/algorithms/indonesian.sbl +14 -8
- data/vendor/snowball/algorithms/italian.sbl +11 -21
- data/vendor/snowball/algorithms/lithuanian.sbl +36 -37
- data/vendor/snowball/algorithms/lovins.sbl +0 -1
- data/vendor/snowball/algorithms/nepali.sbl +138 -37
- data/vendor/snowball/algorithms/norwegian.sbl +19 -5
- data/vendor/snowball/algorithms/porter.sbl +2 -2
- data/vendor/snowball/algorithms/portuguese.sbl +9 -13
- data/vendor/snowball/algorithms/romanian.sbl +17 -4
- data/vendor/snowball/algorithms/serbian.sbl +467 -468
- data/vendor/snowball/algorithms/spanish.sbl +5 -7
- data/vendor/snowball/algorithms/swedish.sbl +60 -6
- data/vendor/snowball/algorithms/tamil.sbl +207 -176
- data/vendor/snowball/algorithms/turkish.sbl +461 -445
- data/vendor/snowball/algorithms/yiddish.sbl +36 -38
- data/vendor/snowball/compiler/analyser.c +445 -192
- data/vendor/snowball/compiler/driver.c +109 -101
- data/vendor/snowball/compiler/generator.c +853 -464
- data/vendor/snowball/compiler/generator_ada.c +404 -366
- data/vendor/snowball/compiler/generator_csharp.c +297 -260
- data/vendor/snowball/compiler/generator_go.c +323 -254
- data/vendor/snowball/compiler/generator_java.c +326 -252
- data/vendor/snowball/compiler/generator_js.c +362 -252
- data/vendor/snowball/compiler/generator_pascal.c +349 -197
- data/vendor/snowball/compiler/generator_python.c +257 -240
- data/vendor/snowball/compiler/generator_rust.c +423 -251
- data/vendor/snowball/compiler/header.h +117 -71
- data/vendor/snowball/compiler/space.c +137 -68
- data/vendor/snowball/compiler/syswords.h +2 -2
- data/vendor/snowball/compiler/tokeniser.c +125 -107
- data/vendor/snowball/csharp/Snowball/Among.cs +14 -14
- data/vendor/snowball/csharp/Snowball/AssemblyInfo.cs +7 -7
- data/vendor/snowball/csharp/Snowball/Stemmer.cs +57 -37
- data/vendor/snowball/csharp/Stemwords/App.config +2 -2
- data/vendor/snowball/csharp/Stemwords/Program.cs +16 -12
- data/vendor/snowball/doc/libstemmer_c_README +7 -4
- data/vendor/snowball/doc/libstemmer_csharp_README +4 -1
- data/vendor/snowball/doc/libstemmer_java_README +12 -1
- data/vendor/snowball/doc/libstemmer_js_README +6 -4
- data/vendor/snowball/doc/libstemmer_python_README +9 -4
- data/vendor/snowball/examples/stemwords.c +12 -12
- data/vendor/snowball/go/env.go +107 -31
- data/vendor/snowball/go/util.go +0 -4
- data/vendor/snowball/include/libstemmer.h +4 -0
- data/vendor/snowball/java/org/tartarus/snowball/Among.java +32 -15
- data/vendor/snowball/java/org/tartarus/snowball/SnowballProgram.java +347 -261
- data/vendor/snowball/java/org/tartarus/snowball/SnowballStemmer.java +3 -0
- data/vendor/snowball/java/org/tartarus/snowball/TestApp.java +52 -37
- data/vendor/snowball/javascript/base-stemmer.js +186 -2
- data/vendor/snowball/javascript/stemwords.js +3 -6
- data/vendor/snowball/libstemmer/libstemmer_c.in +1 -1
- data/vendor/snowball/libstemmer/mkalgorithms.pl +6 -6
- data/vendor/snowball/libstemmer/mkmodules.pl +2 -2
- data/vendor/snowball/libstemmer/modules.txt +13 -10
- data/vendor/snowball/libstemmer/test.c +1 -1
- data/vendor/snowball/pascal/SnowballProgram.pas +84 -2
- data/vendor/snowball/pascal/generate.pl +13 -13
- data/vendor/snowball/python/create_init.py +4 -1
- data/vendor/snowball/python/setup.cfg +0 -3
- data/vendor/snowball/python/setup.py +8 -3
- data/vendor/snowball/python/snowballstemmer/basestemmer.py +20 -54
- data/vendor/snowball/python/stemwords.py +8 -12
- data/vendor/snowball/runtime/api.c +10 -5
- data/vendor/snowball/runtime/header.h +10 -9
- data/vendor/snowball/runtime/utilities.c +9 -9
- data/vendor/snowball/rust/build.rs +1 -1
- data/vendor/snowball/rust/src/snowball/snowball_env.rs +83 -5
- data/vendor/snowball/tests/stemtest.c +7 -4
- metadata +8 -12
- data/vendor/snowball/.travis.yml +0 -112
- data/vendor/snowball/algorithms/german2.sbl +0 -145
- data/vendor/snowball/algorithms/kraaij_pohlmann.sbl +0 -240
- 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
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
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
|
-
|
50
|
-
|
51
|
-
|
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
|
-
|
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
|
-
|
105
|
-
|
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
|
-
|
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
|
-
|
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
|
163
|
+
case c_gt:
|
152
164
|
case c_ge:
|
153
|
-
case
|
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
|
-
|
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
|
-
|
173
|
-
|
174
|
-
|
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);
|
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
|
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
|
195
|
-
|
196
|
-
|
197
|
-
|
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
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
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
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
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
|
258
|
-
if (g->
|
252
|
+
static void write_failure(struct generator * g) {
|
253
|
+
if (str_len(g->failure_str) != 0) {
|
259
254
|
write_string(g, "{ ");
|
260
|
-
|
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->
|
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
|
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 !=
|
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
|
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
|
-
|
311
|
-
|
312
|
-
case '
|
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
|
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':
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
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 ==
|
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,
|
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, "
|
393
|
+
write_string(g, "INT_MAX");
|
394
|
+
break;
|
354
395
|
case c_minint:
|
355
|
-
write_string(g, "
|
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
|
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
|
668
|
+
case c_gt:
|
417
669
|
case c_ge:
|
418
|
-
case
|
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_(
|
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_(
|
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
|
-
|
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
|
725
|
+
case c_gt:
|
471
726
|
case c_ge:
|
472
|
-
case
|
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
|
-
|
793
|
+
struct str * savevar = NULL;
|
534
794
|
if (K_needed(g, p->left)) {
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
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 (
|
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
|
-
|
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
|
-
|
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
|
-
|
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 (
|
561
|
-
|
562
|
-
|
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->
|
568
|
-
|
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 (
|
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->
|
852
|
+
str_delete(g->failure_str);
|
853
|
+
g->failure_str = a1;
|
583
854
|
|
584
855
|
generate(g, p);
|
585
|
-
|
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;~
|
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
|
-
|
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
|
-
|
880
|
+
struct str * a1 = str_copy(g->failure_str);
|
603
881
|
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
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
|
-
|
618
|
-
int u = g->label_used;
|
893
|
+
int l = g->failure_label;
|
894
|
+
int u = g->label_used;
|
619
895
|
|
620
|
-
|
621
|
-
|
622
|
-
|
896
|
+
g->label_used = used;
|
897
|
+
g->failure_label = a0;
|
898
|
+
str_delete(g->failure_str);
|
899
|
+
g->failure_str = a1;
|
623
900
|
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
if (
|
629
|
-
|
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
|
-
|
914
|
+
struct str * savevar = NULL;
|
636
915
|
if (K_needed(g, p->left)) {
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
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 (
|
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
|
-
|
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
|
-
|
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~
|
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
|
-
|
962
|
+
struct str * savevar = NULL;
|
671
963
|
if (K_needed(g, p->left)) {
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
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 (
|
684
|
-
|
685
|
-
|
686
|
-
|
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
|
-
|
984
|
+
struct str * savevar = NULL;
|
693
985
|
if (K_needed(g, p->left)) {
|
694
|
-
|
695
|
-
|
696
|
-
|
697
|
-
|
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, "~{
|
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->
|
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 (
|
715
|
-
|
716
|
-
|
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, "~{
|
1020
|
+
w(g, "~{~Mint ret = skip_utf8(z->p, z->c, z->l, 1");
|
724
1021
|
else
|
725
|
-
w(g, "~{
|
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;~
|
1025
|
+
"~Mz->c = ret;~N"
|
729
1026
|
"~}", p);
|
730
1027
|
} else
|
731
1028
|
writef(g, "~M~l~N"
|
732
|
-
"~M~i~
|
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~
|
1043
|
+
writef(g, "~Mif (~S1_grouping~S0~S2(z, ~V0, ~I0, ~I1, 1) < 0) ~f~N", p);
|
746
1044
|
} else {
|
747
|
-
writef(g, "~{
|
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
|
-
|
1057
|
+
write_comment(g, p);
|
760
1058
|
|
761
1059
|
int used = g->label_used;
|
762
1060
|
int a0 = g->failure_label;
|
763
|
-
|
1061
|
+
struct str * a1 = str_copy(g->failure_str);
|
764
1062
|
|
765
|
-
|
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
|
-
|
783
|
-
|
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->
|
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
|
-
|
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 (
|
799
|
-
|
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->
|
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
|
-
|
812
|
-
|
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,
|
821
|
-
|
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
|
-
|
830
|
-
|
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->
|
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 (
|
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 (
|
845
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
1164
|
+
struct str * a1 = str_copy(g->failure_str);
|
862
1165
|
|
863
|
-
generate_repeat_or_atleast(g, p,
|
1166
|
+
generate_repeat_or_atleast(g, p, loopvar);
|
864
1167
|
|
865
1168
|
g->label_used = used;
|
866
1169
|
g->failure_label = a0;
|
867
|
-
g->
|
1170
|
+
str_delete(g->failure_str);
|
1171
|
+
g->failure_str = a1;
|
868
1172
|
}
|
869
|
-
|
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;~
|
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, ";~
|
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~
|
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, "~{
|
1203
|
+
w(g, "~{~Mint ret = skip~S0_utf8(z->p, z->c, ~S1, ");
|
895
1204
|
generate_AE(g, p->AE);
|
896
|
-
writef(g, ");~
|
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
|
-
|
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, "~{
|
1229
|
+
w(g, "~{~Mint ret = z->c ~S0 ");
|
921
1230
|
generate_AE(g, p->AE);
|
922
|
-
writef(g, ";~
|
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
|
-
|
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;~
|
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~
|
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;~
|
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;~
|
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);~
|
964
|
-
"~Mif (~V0 == 0) return -1;~
|
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);~
|
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, "~{
|
978
|
-
if (keep_c) w(g, "~
|
979
|
-
writef(g, "~
|
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
|
-
|
989
|
-
|
990
|
-
|
991
|
-
|
992
|
-
|
993
|
-
writef(g, "~
|
994
|
-
|
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
|
-
|
999
|
-
writef(g, "~
|
1000
|
-
|
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
|
-
|
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
|
-
|
1017
|
-
writef(g, "~N~{
|
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
|
-
|
1026
|
-
|
1340
|
+
g->B[0] = str_data(varname);
|
1341
|
+
w(g, "~M~B0 = ");
|
1027
1342
|
if (p->mode == m_forward) {
|
1028
|
-
w(g, "
|
1343
|
+
w(g, "z->l - z->c; z->l = ");
|
1029
1344
|
} else {
|
1030
|
-
w(g, "
|
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
|
-
|
1036
|
-
|
1360
|
+
struct str * savevar = vars_newname(g);
|
1361
|
+
write_savecursor(g, p, savevar);
|
1037
1362
|
generate(g, p->left);
|
1038
1363
|
|
1039
|
-
|
1040
|
-
|
1041
|
-
|
1042
|
-
|
1043
|
-
|
1044
|
-
|
1045
|
-
|
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
|
-
|
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
|
-
|
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->
|
1402
|
+
str_clear(g->failure_str);
|
1067
1403
|
|
1068
|
-
|
1069
|
-
g->
|
1070
|
-
writef(g, "~{
|
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->
|
1423
|
+
str_delete(g->failure_str);
|
1424
|
+
g->failure_str = a1;
|
1087
1425
|
|
1088
|
-
g->
|
1426
|
+
g->B[0] = str_data(savevar);
|
1089
1427
|
writef(g, "~M~V0 = z->p;~N"
|
1090
|
-
"~M* z =
|
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, ";~
|
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
|
1102
|
-
|
1103
|
-
|
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
|
-
|
1106
|
-
write_string(g, s);
|
1107
|
-
write_char(g, ' ');
|
1453
|
+
write_c_relop(g, relop);
|
1108
1454
|
generate_AE(g, p->AE);
|
1109
|
-
|
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
|
-
|
1116
|
-
|
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
|
1476
|
+
writef(g, "~Mif (ret <= 0) return ret;~N", p);
|
1120
1477
|
} else {
|
1121
|
-
|
1122
|
-
|
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~
|
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~
|
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~
|
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~
|
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~
|
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, "~
|
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->
|
1558
|
+
str_clear(g->failure_str);
|
1188
1559
|
g->failure_label = x_return;
|
1189
1560
|
g->label_used = 0;
|
1190
|
-
g->
|
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
|
-
|
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 =
|
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~
|
1679
|
+
writef(g, "among_var = ~I4; else~N", p);
|
1304
1680
|
} else {
|
1305
|
-
writef(g, "~f~
|
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 (
|
1315
|
-
writef(g, "~
|
1316
|
-
|
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, "~
|
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 ==
|
1329
|
-
|
1330
|
-
|
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
|
-
|
1337
|
-
|
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~
|
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~
|
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);~
|
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
|
-
|
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:
|
1416
|
-
case c_ne:
|
1417
|
-
case
|
1418
|
-
case c_ge:
|
1419
|
-
case
|
1420
|
-
case c_le:
|
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->
|
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
|
-
|
1444
|
-
|
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
|
-
|
1500
|
-
|
1501
|
-
|
1502
|
-
|
1503
|
-
g
|
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, "~
|
1898
|
+
w(g, "~Mstatic const struct among a_~I0[~I1] = {~N");
|
1512
1899
|
|
1513
|
-
|
1514
|
-
|
1515
|
-
|
1516
|
-
|
1517
|
-
|
1518
|
-
|
1519
|
-
|
1520
|
-
|
1521
|
-
g
|
1522
|
-
|
1523
|
-
|
1524
|
-
|
1525
|
-
|
1526
|
-
|
1527
|
-
|
1528
|
-
|
1529
|
-
|
1530
|
-
|
1531
|
-
|
1532
|
-
|
1533
|
-
|
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 <
|
1941
|
+
for (int i = 0; i < size; i++) map[i] = 0;
|
1564
1942
|
|
1565
|
-
|
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
|
-
|
1633
|
-
|
1634
|
-
|
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
|
-
|
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
|
-
|
1683
|
-
|
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
|
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
|
}
|