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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/Gemfile +2 -1
- data/README.md +2 -2
- data/Rakefile +12 -5
- data/ext/mittens/extconf.rb +3 -1
- data/lib/mittens/version.rb +1 -1
- data/vendor/snowball/.github/workflows/ci.yml +144 -17
- data/vendor/snowball/.github/workflows/coverage.yml +117 -0
- data/vendor/snowball/.github/workflows/runtime-tests.yml +26 -0
- data/vendor/snowball/.gitignore +33 -7
- data/vendor/snowball/CONTRIBUTING.rst +7 -0
- data/vendor/snowball/COPYING +1 -1
- data/vendor/snowball/GNUmakefile +736 -298
- data/vendor/snowball/NEWS +1394 -7
- data/vendor/snowball/README.rst +8 -8
- data/vendor/snowball/ada/generate/generate.adb +5 -5
- data/vendor/snowball/ada/src/stemmer.adb +177 -188
- data/vendor/snowball/ada/src/stemmer.ads +86 -89
- data/vendor/snowball/ada/src/stemwords.adb +21 -5
- data/vendor/snowball/algorithms/czech.sbl +255 -0
- data/vendor/snowball/algorithms/danish.sbl +22 -10
- data/vendor/snowball/algorithms/english.sbl +7 -4
- data/vendor/snowball/algorithms/esperanto.sbl +6 -7
- data/vendor/snowball/algorithms/estonian.sbl +9 -4
- data/vendor/snowball/algorithms/finnish.sbl +33 -21
- data/vendor/snowball/algorithms/german.sbl +5 -0
- data/vendor/snowball/algorithms/indonesian.sbl +115 -96
- data/vendor/snowball/algorithms/italian.sbl +26 -1
- data/vendor/snowball/algorithms/lithuanian.sbl +13 -13
- data/vendor/snowball/algorithms/norwegian.sbl +17 -6
- data/vendor/snowball/algorithms/persian.sbl +387 -0
- data/vendor/snowball/algorithms/polish.sbl +177 -0
- data/vendor/snowball/algorithms/sesotho.sbl +115 -0
- data/vendor/snowball/algorithms/turkish.sbl +4 -4
- data/vendor/snowball/compiler/analyser.c +2002 -711
- data/vendor/snowball/compiler/driver.c +460 -298
- data/vendor/snowball/compiler/generator.c +439 -1965
- data/vendor/snowball/compiler/generator_ada.c +605 -430
- data/vendor/snowball/compiler/generator_c.c +2227 -0
- data/vendor/snowball/compiler/generator_csharp.c +365 -274
- data/vendor/snowball/compiler/generator_dart.c +1476 -0
- data/vendor/snowball/compiler/generator_go.c +348 -270
- data/vendor/snowball/compiler/generator_java.c +330 -233
- data/vendor/snowball/compiler/generator_js.c +534 -385
- data/vendor/snowball/compiler/generator_pascal.c +361 -320
- data/vendor/snowball/compiler/generator_php.c +1445 -0
- data/vendor/snowball/compiler/generator_python.c +399 -299
- data/vendor/snowball/compiler/generator_rust.c +370 -261
- data/vendor/snowball/compiler/generator_zig.c +1474 -0
- data/vendor/snowball/compiler/header.h +153 -86
- data/vendor/snowball/compiler/space.c +121 -63
- data/vendor/snowball/compiler/tokeniser.c +286 -182
- data/vendor/snowball/compiler/tokens.h +71 -0
- data/vendor/snowball/csharp/Snowball/Among.cs +14 -26
- data/vendor/snowball/csharp/Snowball/AssemblyInfo.cs +3 -3
- data/vendor/snowball/csharp/Snowball/Stemmer.cs +41 -45
- data/vendor/snowball/csharp/Stemwords/Program.cs +20 -14
- data/vendor/snowball/cxx/.gitignore +4 -0
- data/vendor/snowball/cxx/generate_algorithms.pl +87 -0
- data/vendor/snowball/cxx/stemmer.h +12 -0
- data/vendor/snowball/cxx/stemwords.cxx +176 -0
- data/vendor/snowball/cxx/utilities.cxx +2 -0
- data/vendor/snowball/dart/.gitignore +4 -0
- data/vendor/snowball/dart/analysis_options.yaml +1 -0
- data/vendor/snowball/dart/example/test_app.dart +65 -0
- data/vendor/snowball/dart/generate_algorithms.pl +21 -0
- data/vendor/snowball/dart/lib/snowball.dart +18 -0
- data/vendor/snowball/dart/lib/src/snowball.dart +339 -0
- data/vendor/snowball/dart/pubspec.yaml +17 -0
- data/vendor/snowball/doc/libstemmer_dart_README +37 -0
- data/vendor/snowball/doc/libstemmer_js_README +2 -2
- data/vendor/snowball/doc/libstemmer_php_README +38 -0
- data/vendor/snowball/doc/libstemmer_python_README +3 -3
- data/vendor/snowball/examples/stemwords.c +18 -3
- data/vendor/snowball/go/README.md +12 -4
- data/vendor/snowball/go/env.go +12 -14
- data/vendor/snowball/go/stemwords/main.go +2 -1
- data/vendor/snowball/java/org/tartarus/snowball/CharArraySequence.java +36 -0
- data/vendor/snowball/java/org/tartarus/snowball/SnowballProgram.java +17 -34
- data/vendor/snowball/java/org/tartarus/snowball/SnowballStemmer.java +0 -2
- data/vendor/snowball/javascript/base-stemmer.js +219 -252
- data/vendor/snowball/javascript/stemwords.js +86 -58
- data/vendor/snowball/libstemmer/mkmodules.pl +1 -1
- data/vendor/snowball/libstemmer/modules.txt +4 -0
- data/vendor/snowball/pascal/SnowballProgram.pas +18 -31
- data/vendor/snowball/php/base-stemmer.php +453 -0
- data/vendor/snowball/php/stemwords.php +25 -0
- data/vendor/snowball/python/create_init.py +16 -21
- data/vendor/snowball/python/pyproject.toml +3 -0
- data/vendor/snowball/python/setup.py +5 -7
- data/vendor/snowball/python/snowballstemmer/among.py +1 -2
- data/vendor/snowball/python/snowballstemmer/basestemmer.py +24 -33
- data/vendor/snowball/python/stemwords.py +72 -63
- data/vendor/snowball/runtime/api.c +11 -42
- data/vendor/snowball/runtime/api.h +11 -9
- data/vendor/snowball/runtime/snowball_runtime.h +110 -0
- data/vendor/snowball/runtime/utilities.c +282 -106
- data/vendor/snowball/rust/src/main.rs +2 -2
- data/vendor/snowball/rust/src/snowball/snowball_env.rs +7 -9
- data/vendor/snowball/tests/compilertest +62 -0
- data/vendor/snowball/tests/errors/ae-errors.sbl +53 -0
- data/vendor/snowball/tests/errors/ae-errors.stderr +8 -0
- data/vendor/snowball/tests/errors/bad-dollar.sbl +14 -0
- data/vendor/snowball/tests/errors/bad-dollar.stderr +4 -0
- data/vendor/snowball/tests/errors/bad-grouping-definition.sbl +9 -0
- data/vendor/snowball/tests/errors/bad-grouping-definition.stderr +6 -0
- data/vendor/snowball/tests/errors/missing-bra.sbl +6 -0
- data/vendor/snowball/tests/errors/missing-bra.stderr +3 -0
- data/vendor/snowball/tests/errors/missing-command.sbl +9 -0
- data/vendor/snowball/tests/errors/missing-command.stderr +1 -0
- data/vendor/snowball/tests/errors/missing-ket-backwardmode.sbl +3 -0
- data/vendor/snowball/tests/errors/missing-ket-backwardmode.stderr +1 -0
- data/vendor/snowball/tests/errors/missing-ket.sbl +7 -0
- data/vendor/snowball/tests/errors/missing-ket.stderr +6 -0
- data/vendor/snowball/tests/errors/notdefined.sbl +4 -0
- data/vendor/snowball/tests/errors/notdefined.stderr +2 -0
- data/vendor/snowball/tests/errors/string-omitted.sbl +5 -0
- data/vendor/snowball/tests/errors/string-omitted.stderr +1 -0
- data/vendor/snowball/tests/errors/undeclared.sbl +20 -0
- data/vendor/snowball/tests/errors/undeclared.stderr +9 -0
- data/vendor/snowball/tests/errors/unexpected-token.sbl +24 -0
- data/vendor/snowball/tests/errors/unexpected-token.stderr +17 -0
- data/vendor/snowball/tests/errors/wrongdirection.sbl +14 -0
- data/vendor/snowball/tests/errors/wrongdirection.stderr +1 -0
- data/vendor/snowball/tests/runtime/among.sbl +19 -0
- data/vendor/snowball/tests/runtime/arithmeticexpr.sbl +86 -0
- data/vendor/snowball/tests/runtime/attachinsert.sbl +47 -0
- data/vendor/snowball/tests/runtime/booleans.sbl +19 -0
- data/vendor/snowball/tests/runtime/externals.sbl +22 -0
- data/vendor/snowball/tests/runtime/hop.sbl +12 -0
- data/vendor/snowball/tests/runtime/integertests.sbl +60 -0
- data/vendor/snowball/tests/runtime/intlimits.sbl +25 -0
- data/vendor/snowball/tests/runtime/naming.sbl +20 -0
- data/vendor/snowball/tests/runtime/not.sbl +30 -0
- data/vendor/snowball/tests/runtime/or.sbl +17 -0
- data/vendor/snowball/tests/runtime/repeat.sbl +16 -0
- data/vendor/snowball/tests/runtime/setlimit.sbl +24 -0
- data/vendor/snowball/tests/runtime/sizelen.sbl +56 -0
- data/vendor/snowball/tests/runtime/slice.sbl +27 -0
- data/vendor/snowball/tests/runtime/stringdollar.sbl +39 -0
- data/vendor/snowball/tests/runtime/strings.sbl +66 -0
- data/vendor/snowball/tests/runtime/test.sbl +19 -0
- data/vendor/snowball/tests/stemtest.c +41 -1
- data/vendor/snowball/tests/syntax/canon.sbl +32 -0
- data/vendor/snowball/tests/syntax/canon.stderr +0 -0
- data/vendor/snowball/tests/syntax/canon.syntax +57 -0
- data/vendor/snowball/tests/syntax/emptyprogram.sbl +2 -0
- data/vendor/snowball/tests/syntax/emptyprogram.syntax +0 -0
- data/vendor/snowball/tests/syntax/groupings.sbl +11 -0
- data/vendor/snowball/tests/syntax/inline.sbl +144 -0
- data/vendor/snowball/tests/syntax/inline.stderr +0 -0
- data/vendor/snowball/tests/syntax/inline.syntax +121 -0
- data/vendor/snowball/tests/syntax/legacy.sbl +17 -0
- data/vendor/snowball/tests/syntax/legacy.stderr +5 -0
- data/vendor/snowball/tests/syntax/legacy.syntax +19 -0
- data/vendor/snowball/tests/syntax/loops.sbl +14 -0
- data/vendor/snowball/tests/syntax/loops.stderr +9 -0
- data/vendor/snowball/tests/syntax/loops.syntax +29 -0
- data/vendor/snowball/tests/syntax/noops.sbl +76 -0
- data/vendor/snowball/tests/syntax/noops.stderr +27 -0
- data/vendor/snowball/tests/syntax/noops.syntax +135 -0
- data/vendor/snowball/tests/syntax/simplifyae.sbl +21 -0
- data/vendor/snowball/tests/syntax/simplifyae.stderr +0 -0
- data/vendor/snowball/tests/syntax/simplifyae.syntax +39 -0
- data/vendor/snowball/tests/syntax/unused.sbl +18 -0
- data/vendor/snowball/tests/syntax/unused.stderr +7 -0
- data/vendor/snowball/tests/syntax/unused.syntax +3 -0
- data/vendor/snowball/zig/env.zig +599 -0
- data/vendor/snowball/zig/generate_algorithms.pl +19 -0
- data/vendor/snowball/zig/stemwords.zig +123 -0
- metadata +102 -4
- data/vendor/snowball/compiler/syswords.h +0 -86
- 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
|
-
/*
|
|
8
|
-
/* #define OPTIMISATION_WARNINGS */
|
|
7
|
+
/* Generator functions common to multiple target languages. */
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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
|
-
|
|
105
|
-
|
|
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
|
-
|
|
114
|
-
|
|
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
|
-
|
|
129
|
-
|
|
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
|
|
43
|
+
fprintf(stderr, "Unexpected type #%d in write_c_relop\n", relop);
|
|
142
44
|
exit(1);
|
|
143
45
|
}
|
|
144
46
|
}
|
|
145
47
|
|
|
146
|
-
void
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
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
|
-
|
|
273
|
-
|
|
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 (
|
|
294
|
-
int ch
|
|
295
|
-
if (
|
|
296
|
-
|
|
297
|
-
|
|
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
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
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
|
|
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
|
-
|
|
120
|
+
write_s(g, p->name->s);
|
|
121
|
+
break;
|
|
390
122
|
case c_number:
|
|
391
|
-
write_int(g, p->number);
|
|
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
|
-
|
|
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, '-');
|
|
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
|
-
|
|
408
|
-
|
|
409
|
-
write_char(g, '
|
|
410
|
-
write_string(g,
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
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
|
-
|
|
439
|
-
|
|
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
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
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
|
-
|
|
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
|
-
|
|
239
|
+
write_string(g, comment_start);
|
|
1844
240
|
write_generated_comment_content(g);
|
|
1845
241
|
if (comment_end) {
|
|
1846
|
-
|
|
242
|
+
write_string(g, comment_end);
|
|
1847
243
|
}
|
|
1848
|
-
|
|
244
|
+
write_newline(g);
|
|
245
|
+
write_newline(g);
|
|
1849
246
|
}
|
|
1850
247
|
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
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
|
-
|
|
1862
|
-
for (
|
|
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
|
-
|
|
1884
|
-
|
|
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
|
-
|
|
267
|
+
static int K_needed_(struct node * p, int call_depth);
|
|
1887
268
|
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
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
|
-
|
|
1898
|
-
|
|
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
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
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
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
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
|
-
|
|
341
|
+
return false;
|
|
1925
342
|
}
|
|
1926
343
|
|
|
1927
|
-
static
|
|
1928
|
-
|
|
1929
|
-
|
|
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
|
|
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
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
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
|
-
|
|
1964
|
-
|
|
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
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
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
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
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
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
case
|
|
1998
|
-
|
|
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
|
-
|
|
2001
|
-
case
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
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
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
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
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
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
|
-
|
|
2061
|
-
|
|
543
|
+
default:
|
|
544
|
+
return 2;
|
|
545
|
+
}
|
|
546
|
+
p = p->right;
|
|
2062
547
|
}
|
|
548
|
+
return score;
|
|
549
|
+
}
|
|
2063
550
|
|
|
2064
|
-
|
|
2065
|
-
|
|
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
|
-
/*
|
|
556
|
+
/* Language-independent write routines for simple entities */
|
|
2080
557
|
|
|
2081
|
-
|
|
2082
|
-
|
|
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
|
|
2099
|
-
|
|
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
|
-
|
|
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
|
}
|