mittens 0.3.0 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (174) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +8 -0
  3. data/Gemfile +2 -1
  4. data/README.md +2 -2
  5. data/Rakefile +12 -5
  6. data/ext/mittens/extconf.rb +3 -1
  7. data/lib/mittens/version.rb +1 -1
  8. data/vendor/snowball/.github/workflows/ci.yml +144 -17
  9. data/vendor/snowball/.github/workflows/coverage.yml +117 -0
  10. data/vendor/snowball/.github/workflows/runtime-tests.yml +26 -0
  11. data/vendor/snowball/.gitignore +33 -7
  12. data/vendor/snowball/CONTRIBUTING.rst +7 -0
  13. data/vendor/snowball/COPYING +1 -1
  14. data/vendor/snowball/GNUmakefile +736 -298
  15. data/vendor/snowball/NEWS +1394 -7
  16. data/vendor/snowball/README.rst +8 -8
  17. data/vendor/snowball/ada/generate/generate.adb +5 -5
  18. data/vendor/snowball/ada/src/stemmer.adb +177 -188
  19. data/vendor/snowball/ada/src/stemmer.ads +86 -89
  20. data/vendor/snowball/ada/src/stemwords.adb +21 -5
  21. data/vendor/snowball/algorithms/czech.sbl +255 -0
  22. data/vendor/snowball/algorithms/danish.sbl +22 -10
  23. data/vendor/snowball/algorithms/english.sbl +7 -4
  24. data/vendor/snowball/algorithms/esperanto.sbl +6 -7
  25. data/vendor/snowball/algorithms/estonian.sbl +9 -4
  26. data/vendor/snowball/algorithms/finnish.sbl +33 -21
  27. data/vendor/snowball/algorithms/german.sbl +5 -0
  28. data/vendor/snowball/algorithms/indonesian.sbl +115 -96
  29. data/vendor/snowball/algorithms/italian.sbl +26 -1
  30. data/vendor/snowball/algorithms/lithuanian.sbl +13 -13
  31. data/vendor/snowball/algorithms/norwegian.sbl +17 -6
  32. data/vendor/snowball/algorithms/persian.sbl +387 -0
  33. data/vendor/snowball/algorithms/polish.sbl +177 -0
  34. data/vendor/snowball/algorithms/sesotho.sbl +115 -0
  35. data/vendor/snowball/algorithms/turkish.sbl +4 -4
  36. data/vendor/snowball/compiler/analyser.c +2002 -711
  37. data/vendor/snowball/compiler/driver.c +460 -298
  38. data/vendor/snowball/compiler/generator.c +439 -1965
  39. data/vendor/snowball/compiler/generator_ada.c +605 -430
  40. data/vendor/snowball/compiler/generator_c.c +2227 -0
  41. data/vendor/snowball/compiler/generator_csharp.c +365 -274
  42. data/vendor/snowball/compiler/generator_dart.c +1476 -0
  43. data/vendor/snowball/compiler/generator_go.c +348 -270
  44. data/vendor/snowball/compiler/generator_java.c +330 -233
  45. data/vendor/snowball/compiler/generator_js.c +534 -385
  46. data/vendor/snowball/compiler/generator_pascal.c +361 -320
  47. data/vendor/snowball/compiler/generator_php.c +1445 -0
  48. data/vendor/snowball/compiler/generator_python.c +399 -299
  49. data/vendor/snowball/compiler/generator_rust.c +370 -261
  50. data/vendor/snowball/compiler/generator_zig.c +1474 -0
  51. data/vendor/snowball/compiler/header.h +153 -86
  52. data/vendor/snowball/compiler/space.c +121 -63
  53. data/vendor/snowball/compiler/tokeniser.c +286 -182
  54. data/vendor/snowball/compiler/tokens.h +71 -0
  55. data/vendor/snowball/csharp/Snowball/Among.cs +14 -26
  56. data/vendor/snowball/csharp/Snowball/AssemblyInfo.cs +3 -3
  57. data/vendor/snowball/csharp/Snowball/Stemmer.cs +41 -45
  58. data/vendor/snowball/csharp/Stemwords/Program.cs +20 -14
  59. data/vendor/snowball/cxx/.gitignore +4 -0
  60. data/vendor/snowball/cxx/generate_algorithms.pl +87 -0
  61. data/vendor/snowball/cxx/stemmer.h +12 -0
  62. data/vendor/snowball/cxx/stemwords.cxx +176 -0
  63. data/vendor/snowball/cxx/utilities.cxx +2 -0
  64. data/vendor/snowball/dart/.gitignore +4 -0
  65. data/vendor/snowball/dart/analysis_options.yaml +1 -0
  66. data/vendor/snowball/dart/example/test_app.dart +65 -0
  67. data/vendor/snowball/dart/generate_algorithms.pl +21 -0
  68. data/vendor/snowball/dart/lib/snowball.dart +18 -0
  69. data/vendor/snowball/dart/lib/src/snowball.dart +339 -0
  70. data/vendor/snowball/dart/pubspec.yaml +17 -0
  71. data/vendor/snowball/doc/libstemmer_dart_README +37 -0
  72. data/vendor/snowball/doc/libstemmer_js_README +2 -2
  73. data/vendor/snowball/doc/libstemmer_php_README +38 -0
  74. data/vendor/snowball/doc/libstemmer_python_README +3 -3
  75. data/vendor/snowball/examples/stemwords.c +18 -3
  76. data/vendor/snowball/go/README.md +12 -4
  77. data/vendor/snowball/go/env.go +12 -14
  78. data/vendor/snowball/go/stemwords/main.go +2 -1
  79. data/vendor/snowball/java/org/tartarus/snowball/CharArraySequence.java +36 -0
  80. data/vendor/snowball/java/org/tartarus/snowball/SnowballProgram.java +17 -34
  81. data/vendor/snowball/java/org/tartarus/snowball/SnowballStemmer.java +0 -2
  82. data/vendor/snowball/javascript/base-stemmer.js +219 -252
  83. data/vendor/snowball/javascript/stemwords.js +86 -58
  84. data/vendor/snowball/libstemmer/mkmodules.pl +1 -1
  85. data/vendor/snowball/libstemmer/modules.txt +4 -0
  86. data/vendor/snowball/pascal/SnowballProgram.pas +18 -31
  87. data/vendor/snowball/php/base-stemmer.php +453 -0
  88. data/vendor/snowball/php/stemwords.php +25 -0
  89. data/vendor/snowball/python/create_init.py +16 -21
  90. data/vendor/snowball/python/pyproject.toml +3 -0
  91. data/vendor/snowball/python/setup.py +5 -7
  92. data/vendor/snowball/python/snowballstemmer/among.py +1 -2
  93. data/vendor/snowball/python/snowballstemmer/basestemmer.py +24 -33
  94. data/vendor/snowball/python/stemwords.py +72 -63
  95. data/vendor/snowball/runtime/api.c +11 -42
  96. data/vendor/snowball/runtime/api.h +11 -9
  97. data/vendor/snowball/runtime/snowball_runtime.h +110 -0
  98. data/vendor/snowball/runtime/utilities.c +282 -106
  99. data/vendor/snowball/rust/src/main.rs +2 -2
  100. data/vendor/snowball/rust/src/snowball/snowball_env.rs +7 -9
  101. data/vendor/snowball/tests/compilertest +62 -0
  102. data/vendor/snowball/tests/errors/ae-errors.sbl +53 -0
  103. data/vendor/snowball/tests/errors/ae-errors.stderr +8 -0
  104. data/vendor/snowball/tests/errors/bad-dollar.sbl +14 -0
  105. data/vendor/snowball/tests/errors/bad-dollar.stderr +4 -0
  106. data/vendor/snowball/tests/errors/bad-grouping-definition.sbl +9 -0
  107. data/vendor/snowball/tests/errors/bad-grouping-definition.stderr +6 -0
  108. data/vendor/snowball/tests/errors/missing-bra.sbl +6 -0
  109. data/vendor/snowball/tests/errors/missing-bra.stderr +3 -0
  110. data/vendor/snowball/tests/errors/missing-command.sbl +9 -0
  111. data/vendor/snowball/tests/errors/missing-command.stderr +1 -0
  112. data/vendor/snowball/tests/errors/missing-ket-backwardmode.sbl +3 -0
  113. data/vendor/snowball/tests/errors/missing-ket-backwardmode.stderr +1 -0
  114. data/vendor/snowball/tests/errors/missing-ket.sbl +7 -0
  115. data/vendor/snowball/tests/errors/missing-ket.stderr +6 -0
  116. data/vendor/snowball/tests/errors/notdefined.sbl +4 -0
  117. data/vendor/snowball/tests/errors/notdefined.stderr +2 -0
  118. data/vendor/snowball/tests/errors/string-omitted.sbl +5 -0
  119. data/vendor/snowball/tests/errors/string-omitted.stderr +1 -0
  120. data/vendor/snowball/tests/errors/undeclared.sbl +20 -0
  121. data/vendor/snowball/tests/errors/undeclared.stderr +9 -0
  122. data/vendor/snowball/tests/errors/unexpected-token.sbl +24 -0
  123. data/vendor/snowball/tests/errors/unexpected-token.stderr +17 -0
  124. data/vendor/snowball/tests/errors/wrongdirection.sbl +14 -0
  125. data/vendor/snowball/tests/errors/wrongdirection.stderr +1 -0
  126. data/vendor/snowball/tests/runtime/among.sbl +19 -0
  127. data/vendor/snowball/tests/runtime/arithmeticexpr.sbl +86 -0
  128. data/vendor/snowball/tests/runtime/attachinsert.sbl +47 -0
  129. data/vendor/snowball/tests/runtime/booleans.sbl +19 -0
  130. data/vendor/snowball/tests/runtime/externals.sbl +22 -0
  131. data/vendor/snowball/tests/runtime/hop.sbl +12 -0
  132. data/vendor/snowball/tests/runtime/integertests.sbl +60 -0
  133. data/vendor/snowball/tests/runtime/intlimits.sbl +25 -0
  134. data/vendor/snowball/tests/runtime/naming.sbl +20 -0
  135. data/vendor/snowball/tests/runtime/not.sbl +30 -0
  136. data/vendor/snowball/tests/runtime/or.sbl +17 -0
  137. data/vendor/snowball/tests/runtime/repeat.sbl +16 -0
  138. data/vendor/snowball/tests/runtime/setlimit.sbl +24 -0
  139. data/vendor/snowball/tests/runtime/sizelen.sbl +56 -0
  140. data/vendor/snowball/tests/runtime/slice.sbl +27 -0
  141. data/vendor/snowball/tests/runtime/stringdollar.sbl +39 -0
  142. data/vendor/snowball/tests/runtime/strings.sbl +66 -0
  143. data/vendor/snowball/tests/runtime/test.sbl +19 -0
  144. data/vendor/snowball/tests/stemtest.c +41 -1
  145. data/vendor/snowball/tests/syntax/canon.sbl +32 -0
  146. data/vendor/snowball/tests/syntax/canon.stderr +0 -0
  147. data/vendor/snowball/tests/syntax/canon.syntax +57 -0
  148. data/vendor/snowball/tests/syntax/emptyprogram.sbl +2 -0
  149. data/vendor/snowball/tests/syntax/emptyprogram.syntax +0 -0
  150. data/vendor/snowball/tests/syntax/groupings.sbl +11 -0
  151. data/vendor/snowball/tests/syntax/inline.sbl +144 -0
  152. data/vendor/snowball/tests/syntax/inline.stderr +0 -0
  153. data/vendor/snowball/tests/syntax/inline.syntax +121 -0
  154. data/vendor/snowball/tests/syntax/legacy.sbl +17 -0
  155. data/vendor/snowball/tests/syntax/legacy.stderr +5 -0
  156. data/vendor/snowball/tests/syntax/legacy.syntax +19 -0
  157. data/vendor/snowball/tests/syntax/loops.sbl +14 -0
  158. data/vendor/snowball/tests/syntax/loops.stderr +9 -0
  159. data/vendor/snowball/tests/syntax/loops.syntax +29 -0
  160. data/vendor/snowball/tests/syntax/noops.sbl +76 -0
  161. data/vendor/snowball/tests/syntax/noops.stderr +27 -0
  162. data/vendor/snowball/tests/syntax/noops.syntax +135 -0
  163. data/vendor/snowball/tests/syntax/simplifyae.sbl +21 -0
  164. data/vendor/snowball/tests/syntax/simplifyae.stderr +0 -0
  165. data/vendor/snowball/tests/syntax/simplifyae.syntax +39 -0
  166. data/vendor/snowball/tests/syntax/unused.sbl +18 -0
  167. data/vendor/snowball/tests/syntax/unused.stderr +7 -0
  168. data/vendor/snowball/tests/syntax/unused.syntax +3 -0
  169. data/vendor/snowball/zig/env.zig +599 -0
  170. data/vendor/snowball/zig/generate_algorithms.pl +19 -0
  171. data/vendor/snowball/zig/stemwords.zig +123 -0
  172. metadata +102 -4
  173. data/vendor/snowball/compiler/syswords.h +0 -86
  174. data/vendor/snowball/runtime/header.h +0 -62
@@ -1,34 +1,67 @@
1
1
  #include <assert.h>
2
+ #include <ctype.h>
3
+ #include <stdio.h> /* for fprintf etc */
2
4
  #include <stdlib.h> /* for exit */
3
5
  #include <string.h> /* for strlen */
4
- #include <stdio.h> /* for fprintf etc */
5
- #include <ctype.h>
6
6
  #include "header.h"
7
7
 
8
- /* prototypes */
8
+ /* prototype functions for recursive use: */
9
9
 
10
10
  static void generate(struct generator * g, struct node * p);
11
11
  static void w(struct generator * g, const char * s);
12
12
  static void writef(struct generator * g, const char * s, struct node * p);
13
13
 
14
- static int new_label(struct generator * g) {
15
- return g->next_label++;
16
- }
14
+ /* Write routines for items from the syntax tree */
17
15
 
18
- static struct str * vars_newname(struct generator * g) {
19
- struct str * output;
20
- g->var_number++;
21
- output = str_new();
22
- str_append_string(output, "v_");
23
- str_append_int(output, g->var_number);
24
- return output;
16
+ static void write_relop(struct generator * g, int relop) {
17
+ // Relational operators are the same as C, save for (in-)equality.
18
+ switch (relop) {
19
+ case c_eq: write_string(g, " = "); break;
20
+ case c_ne: write_string(g, " /= "); break;
21
+ default: write_c_relop(g, relop);
22
+ }
25
23
  }
26
24
 
27
- /* Write routines for items from the syntax tree */
28
-
29
25
  static void write_varname(struct generator * g, struct name * p) {
30
- if (p->type != t_external) {
26
+ int ends_in_underscore = (p->s[SIZE(p->s) - 1] == '_');
27
+ if (p->type == t_external) {
28
+ if (g->options->externals_prefix) {
29
+ write_string(g, g->options->externals_prefix);
30
+ }
31
+ } else {
32
+ /* Ada identifiers are case-insensitive but Snowball identifiers
33
+ * should be case-sensitive. To address this, if any groups of
34
+ * identifiers of the same type have the same case, we insert a counter
35
+ * after the type-code for all but one of them. This count is unique
36
+ * within each type of variable so this avoid collisions while being
37
+ * minimally intrusive on the readability of the generated code.
38
+ *
39
+ * Ada also doesn't allow identifiers to end in an underscore,
40
+ * so we append a `E` to such identifiers. To avoid potential
41
+ * collisions from doing so, we also insert the counter after
42
+ * the type-code in this case (which may not be necessary, but this
43
+ * case seems more of a theoretical concern, whereas identifiers
44
+ * differing only by case has been seen in real-world Snowball code).
45
+ *
46
+ * So for example (noting that we upper-case the first character of
47
+ * the Snowball name below):
48
+ *
49
+ * Snowball integer `i` -> Ada `I_I`
50
+ * Snowball integer `I` -> Ada `I2_I`
51
+ * Snowball integer `i_` -> Ada `I3_I_E`
52
+ * Snowball integer `i_e` -> Ada `I_I_e`
53
+ *
54
+ * We don't try to solve this problem for external identifiers - it
55
+ * seems more helpful to leave those alone and encourage snowball
56
+ * program authors to avoid naming externals which only differ by
57
+ * case.
58
+ *
59
+ * We use the same naming scheme for both global and local variables.
60
+ */
31
61
  write_char(g, "SBIRXG"[p->type]);
62
+ if (ends_in_underscore || p->case_collision) {
63
+ write_int(g, p->count);
64
+ }
32
65
  write_char(g, '_');
33
66
  }
34
67
 
@@ -39,52 +72,61 @@ static void write_varname(struct generator * g, struct name * p) {
39
72
  p->s[0] = save_initial;
40
73
  }
41
74
 
42
- if (p->s[SIZE(p->s) - 1] == '_') {
43
- write_char(g, 'E');
44
- }
75
+ if (ends_in_underscore) write_char(g, 'E');
45
76
  }
46
77
 
47
- static void write_varref(struct generator * g, struct name * p) { /* reference to variable */
48
- if (p->type < t_routine) write_string(g, "Z.");
78
+ /* Reference to variable, e.g. when assigning to or using in an expression. */
79
+ static void write_varref(struct generator * g, struct name * p) {
80
+ if (p->type < t_routine && p->local_to == NULL) {
81
+ write_string(g, "Z.");
82
+ }
49
83
  write_varname(g, p);
50
84
  }
51
85
 
52
86
  static void write_literal_string(struct generator * g, symbol * p) {
87
+ if (SIZE(p) == 0) {
88
+ write_string(g, "\"\"");
89
+ return;
90
+ }
53
91
  // Ada supports UTF-8 literal strings, we only need to escape the quote and
54
92
  // special characters.
55
- write_char(g, '"');
56
- for (int i = 0; i < SIZE(p); i++) {
57
- int ch = p[i];
58
- if (ch == '"') {
59
- write_string(g, "\"\"");
60
- } else if (ch < 32 || ch == 127) {
61
- printf("In write_literal_string, can't handle non-graphic character 0x%02x currently\n", (int)p[i]);
62
- exit(1);
63
- } else if (ch <= 255) {
64
- write_char(g, ch);
93
+ bool in_quotes = false;
94
+ int i = 0;
95
+ while (i < SIZE(p)) {
96
+ int ch;
97
+ int w = get_utf8(p + i, &ch);
98
+ // Write out ASCII and lower Unicode printables as literal characters.
99
+ // Use escapes for anything over 0x590 as a crude way to avoid LTR
100
+ // characters affecting the rendering of source character order in
101
+ // confusing ways.
102
+ if ((32 <= ch && ch < 127) || (0xa0 < ch && ch < 0x590)) {
103
+ if (!in_quotes) {
104
+ if (i > 0) {
105
+ write_string(g, " & ");
106
+ }
107
+ write_char(g, '"');
108
+ in_quotes = true;
109
+ }
110
+ if (ch == '"') write_char(g, '\\');
111
+ write_wchar_as_utf8(g, ch);
65
112
  } else {
66
- printf("In write_literal_string, can't convert p[%d] to char because it's 0x%02x\n", i, (int)p[i]);
67
- exit(1);
113
+ if (in_quotes) {
114
+ write_char(g, '"');
115
+ in_quotes = false;
116
+ }
117
+ for (int j = i; j < i + w; ++j) {
118
+ if (j > 0) {
119
+ write_string(g, " & ");
120
+ }
121
+ write_string(g, "Character'Val(");
122
+ write_int(g, (int)p[j]);
123
+ write_string(g, ")");
124
+ }
68
125
  }
126
+ i += w;
69
127
  }
70
- write_char(g, '"');
71
- }
72
-
73
- static void write_margin(struct generator * g) {
74
- for (int i = 0; i < g->margin; i++) write_string(g, " ");
75
- }
76
-
77
- static void write_relop(struct generator * g, int relop) {
78
- switch (relop) {
79
- case c_eq: write_string(g, " = "); break;
80
- case c_ne: write_string(g, " /= "); break;
81
- case c_gt: write_string(g, " > "); break;
82
- case c_ge: write_string(g, " >= "); break;
83
- case c_lt: write_string(g, " < "); break;
84
- case c_le: write_string(g, " <= "); break;
85
- default:
86
- fprintf(stderr, "Unexpected type #%d in generate_integer_test\n", relop);
87
- exit(1);
128
+ if (in_quotes) {
129
+ write_char(g, '"');
88
130
  }
89
131
  }
90
132
 
@@ -96,7 +138,7 @@ static void write_declare(struct generator * g,
96
138
  g->outbuf = g->declarations;
97
139
  write_string(g, " ");
98
140
  writef(g, declaration, p);
99
- write_string(g, ";");
141
+ write_char(g, ';');
100
142
  write_newline(g);
101
143
  g->outbuf = temp;
102
144
  }
@@ -105,7 +147,7 @@ static void write_comment(struct generator * g, struct node * p) {
105
147
  if (!g->options->comments) return;
106
148
  write_margin(g);
107
149
  write_string(g, "-- ");
108
- write_comment_content(g, p);
150
+ write_comment_content(g, p, NULL);
109
151
  write_newline(g);
110
152
  }
111
153
 
@@ -130,7 +172,7 @@ static void append_restore_string(struct node * p, struct str * out, struct str
130
172
  str_append_string(out, "Z.C := ");
131
173
  if (p->mode != m_forward) str_append_string(out, "Z.L - ");
132
174
  str_append(out, savevar);
133
- str_append_string(out, ";");
175
+ str_append_ch(out, ';');
134
176
  }
135
177
 
136
178
  static void write_restorecursor(struct generator * g, struct node * p, struct str * savevar) {
@@ -146,15 +188,6 @@ static void wsetl(struct generator * g, int n) {
146
188
  write_int(g, n);
147
189
  write_string(g, ">>");
148
190
  write_newline(g);
149
- g->line_labelled = g->line_count;
150
- }
151
-
152
- static void wgotol(struct generator * g, int n) {
153
- write_margin(g);
154
- write_string(g, "goto lab");
155
- write_int(g, n);
156
- write_string(g, ";");
157
- write_newline(g);
158
191
  }
159
192
 
160
193
  static void write_failure(struct generator * g) {
@@ -174,7 +207,7 @@ static void write_failure(struct generator * g) {
174
207
  default:
175
208
  write_string(g, "goto lab");
176
209
  write_int(g, g->failure_label);
177
- write_string(g, ";");
210
+ write_char(g, ';');
178
211
  g->label_used = 1;
179
212
  }
180
213
  write_newline(g);
@@ -190,18 +223,8 @@ static void write_failure_if(struct generator * g, const char * s, struct node *
190
223
  g->unreachable = false;
191
224
  }
192
225
 
193
- /* if at limit fail */
194
- static void write_check_limit(struct generator * g, struct node * p) {
195
- if (p->mode == m_forward) {
196
- write_failure_if(g, "Z.C >= Z.L", p);
197
- } else {
198
- write_failure_if(g, "Z.C <= Z.Lb", p);
199
- }
200
- }
201
-
202
226
  /* Formatted write. */
203
227
  static void writef(struct generator * g, const char * input, struct node * p) {
204
- (void)p;
205
228
  int i = 0;
206
229
 
207
230
  while (input[i]) {
@@ -246,26 +269,17 @@ static void writef(struct generator * g, const char * input, struct node * p) {
246
269
  continue;
247
270
  }
248
271
  case 'V':
249
- case 'W': {
250
- int j = input[i++] - '0';
251
- if (j < 0 || j > (int)(sizeof(g->V) / sizeof(g->V[0])))
252
- goto invalid_escape2;
253
- if (ch == 'V')
254
- write_varref(g, g->V[j]);
255
- else
256
- write_varname(g, g->V[j]);
272
+ write_varref(g, p->name);
257
273
  continue;
258
- }
259
- case 'L': {
260
- int j = input[i++] - '0';
261
- if (j < 0 || j > (int)(sizeof(g->L) / sizeof(g->L[0])))
262
- goto invalid_escape2;
263
- write_literal_string(g, g->L[j]);
274
+ case 'W':
275
+ write_varname(g, p->name);
276
+ continue;
277
+ case 'L':
278
+ write_literal_string(g, p->literalstring);
264
279
  continue;
265
- }
266
280
  case '+': g->margin++; continue;
267
281
  case '-': g->margin--; continue;
268
- case 'n': write_string(g, g->options->name); continue;
282
+ case 'n': write_s(g, g->options->name); continue;
269
283
  default:
270
284
  printf("Invalid escape sequence ~%c in writef(g, \"%s\", p)\n",
271
285
  ch, input);
@@ -302,7 +316,8 @@ static void generate_AE(struct generator * g, struct node * p) {
302
316
  const char * s;
303
317
  switch (p->type) {
304
318
  case c_name:
305
- write_varref(g, p->name); break;
319
+ write_varref(g, p->name);
320
+ break;
306
321
  case c_number:
307
322
  // Avoid `parentheses required for unary minus` error from gnat.
308
323
  if (p->number < 0)
@@ -312,41 +327,51 @@ static void generate_AE(struct generator * g, struct node * p) {
312
327
  write_char(g, ')');
313
328
  break;
314
329
  case c_maxint:
315
- write_string(g, "Integer'Last"); break;
330
+ write_string(g, "Integer'Last");
331
+ break;
316
332
  case c_minint:
317
- write_string(g, "Integer'First"); break;
333
+ write_string(g, "Integer'First");
334
+ break;
318
335
  case c_neg:
319
- write_string(g, "(-"); generate_AE(g, p->right); write_char(g, ')'); break;
336
+ write_string(g, "(-");
337
+ generate_AE(g, p->right);
338
+ write_char(g, ')');
339
+ break;
320
340
  case c_multiply:
321
- s = " * "; goto label0;
322
- case c_plus:
323
- s = " + "; goto label0;
324
- case c_minus:
325
- s = " - "; goto label0;
341
+ s = " * ";
342
+ goto label0;
326
343
  case c_divide:
327
344
  s = " / ";
345
+ goto label0;
346
+ case c_plus:
347
+ s = " + ";
348
+ goto label0;
349
+ case c_minus:
350
+ s = " - ";
328
351
  label0:
329
- write_char(g, '('); generate_AE(g, p->left);
330
- write_string(g, s); generate_AE(g, p->right); write_char(g, ')'); break;
352
+ write_char(g, '(');
353
+ generate_AE(g, p->left);
354
+ write_string(g, s);
355
+ generate_AE(g, p->right);
356
+ write_char(g, ')');
357
+ break;
331
358
  case c_cursor:
332
- w(g, "Z.C"); break;
359
+ w(g, "Z.C");
360
+ break;
333
361
  case c_limit:
334
- w(g, p->mode == m_forward ? "Z.L" : "Z.Lb"); break;
362
+ w(g, p->mode == m_forward ? "Z.L" : "Z.Lb");
363
+ break;
335
364
  case c_len:
336
- w(g, "Length_Utf8 (Z)");
365
+ w(g, "Length_Utf8 (Z.P, Z.Len)");
337
366
  break;
338
367
  case c_size:
339
368
  w(g, "Z.Len");
340
369
  break;
341
370
  case c_lenof:
342
- g->V[0] = p->name;
343
- w(g, "Length_Utf8 (Ada.Strings.Unbounded.To_String (~V0))");
371
+ writef(g, "Length_Utf8 (~V, Z.L~W)", p);
344
372
  break;
345
373
  case c_sizeof:
346
- g->V[0] = p->name;
347
- w(g, "Ada.Strings.Unbounded.Length (~V0)");
348
- break;
349
- default:
374
+ writef(g, "Z.L~W", p);
350
375
  break;
351
376
  }
352
377
  }
@@ -362,13 +387,15 @@ static void generate_bra(struct generator * g, struct node * p) {
362
387
 
363
388
  static void generate_and(struct generator * g, struct node * p) {
364
389
  struct str * savevar = NULL;
365
- if (K_needed(g, p->left)) {
390
+ if (K_needed_for_and(p->left)) {
366
391
  savevar = vars_newname(g);
367
392
  }
368
393
 
369
394
  write_comment(g, p);
370
395
 
371
- if (savevar) write_savecursor(g, p, savevar);
396
+ if (savevar) {
397
+ write_savecursor(g, p, savevar);
398
+ }
372
399
 
373
400
  p = p->left;
374
401
  while (p) {
@@ -385,20 +412,22 @@ static void generate_and(struct generator * g, struct node * p) {
385
412
 
386
413
  static void generate_or(struct generator * g, struct node * p) {
387
414
  struct str * savevar = NULL;
388
- if (K_needed(g, p->left)) {
415
+ if (K_needed_for_or(p->left)) {
389
416
  savevar = vars_newname(g);
390
417
  }
391
- int used = g->label_used;
392
418
 
419
+ int used = g->label_used;
393
420
  int a0 = g->failure_label;
394
421
  struct str * a1 = str_copy(g->failure_str);
395
422
 
396
- int out_lab = new_label(g);
397
- int end_unreachable = true;
423
+ bool end_unreachable = true;
398
424
 
399
425
  write_comment(g, p);
426
+ w(g, "~Mloop~N~+");
400
427
 
401
- if (savevar) write_savecursor(g, p, savevar);
428
+ if (savevar && K_needed_node_on_f(p)) {
429
+ write_savecursor(g, p, savevar);
430
+ }
402
431
 
403
432
  p = p->left;
404
433
  str_clear(g->failure_str);
@@ -409,28 +438,36 @@ static void generate_or(struct generator * g, struct node * p) {
409
438
  fprintf(stderr, "Error: \"or\" node without children nodes.");
410
439
  exit(1);
411
440
  }
412
- while (p->right) {
413
- g->failure_label = new_label(g);
441
+ while (p->right != NULL) {
442
+ int label = new_label(g);
443
+ g->failure_label = label;
414
444
  g->label_used = 0;
415
445
  generate(g, p);
416
446
  if (!g->unreachable) {
417
- wgotol(g, out_lab);
447
+ w(g, "~Mexit;~N");
418
448
  end_unreachable = false;
419
449
  }
420
450
 
421
451
  if (g->label_used)
422
452
  wsetl(g, g->failure_label);
423
453
  g->unreachable = false;
424
- if (savevar) write_restorecursor(g, p, savevar);
454
+ if (savevar) {
455
+ write_restorecursor(g, p, savevar);
456
+ }
425
457
  p = p->right;
426
458
  }
459
+
427
460
  g->label_used = used;
428
461
  g->failure_label = a0;
429
462
  str_delete(g->failure_str);
430
463
  g->failure_str = a1;
431
464
 
432
465
  generate(g, p);
433
- wsetl(g, out_lab);
466
+
467
+ if (!g->unreachable) {
468
+ w(g, "~Mexit;~N");
469
+ }
470
+ w(g, "~-~Mend loop;~N");
434
471
  if (!end_unreachable) {
435
472
  g->unreachable = false;
436
473
  }
@@ -449,7 +486,7 @@ static void generate_backwards(struct generator * g, struct node * p) {
449
486
 
450
487
  static void generate_not(struct generator * g, struct node * p) {
451
488
  struct str * savevar = NULL;
452
- if (K_needed(g, p->left)) {
489
+ if (K_needed_node_on_f(p->left)) {
453
490
  savevar = vars_newname(g);
454
491
  }
455
492
 
@@ -461,7 +498,8 @@ static void generate_not(struct generator * g, struct node * p) {
461
498
  write_savecursor(g, p, savevar);
462
499
  }
463
500
 
464
- g->failure_label = new_label(g);
501
+ int label = new_label(g);
502
+ g->failure_label = label;
465
503
  str_clear(g->failure_str);
466
504
 
467
505
  int l = g->failure_label;
@@ -487,11 +525,12 @@ static void generate_not(struct generator * g, struct node * p) {
487
525
 
488
526
  static void generate_try(struct generator * g, struct node * p) {
489
527
  struct str * savevar = NULL;
490
- if (K_needed(g, p->left)) {
528
+ if (K_needed(p->left)) {
491
529
  savevar = vars_newname(g);
492
530
  }
493
531
 
494
- g->failure_label = new_label(g);
532
+ int label = new_label(g);
533
+ g->failure_label = label;
495
534
  g->label_used = 0;
496
535
  str_clear(g->failure_str);
497
536
 
@@ -502,6 +541,7 @@ static void generate_try(struct generator * g, struct node * p) {
502
541
  }
503
542
 
504
543
  generate(g, p->left);
544
+
505
545
  if (g->label_used)
506
546
  wsetl(g, g->failure_label);
507
547
  g->unreachable = false;
@@ -513,14 +553,12 @@ static void generate_try(struct generator * g, struct node * p) {
513
553
 
514
554
  static void generate_set(struct generator * g, struct node * p) {
515
555
  write_comment(g, p);
516
- g->V[0] = p->name;
517
- writef(g, "~M~V0 := True;~N", p);
556
+ writef(g, "~M~V := True;~N", p);
518
557
  }
519
558
 
520
559
  static void generate_unset(struct generator * g, struct node * p) {
521
560
  write_comment(g, p);
522
- g->V[0] = p->name;
523
- writef(g, "~M~V0 := False;~N", p);
561
+ writef(g, "~M~V := False;~N", p);
524
562
  }
525
563
 
526
564
  static void generate_fail(struct generator * g, struct node * p) {
@@ -530,10 +568,9 @@ static void generate_fail(struct generator * g, struct node * p) {
530
568
  }
531
569
 
532
570
  /* generate_test() also implements 'reverse' */
533
-
534
571
  static void generate_test(struct generator * g, struct node * p) {
535
572
  struct str * savevar = NULL;
536
- if (K_needed(g, p->left)) {
573
+ if (K_needed(p->left)) {
537
574
  savevar = vars_newname(g);
538
575
  }
539
576
 
@@ -555,23 +592,26 @@ static void generate_test(struct generator * g, struct node * p) {
555
592
 
556
593
  static void generate_do(struct generator * g, struct node * p) {
557
594
  struct str * savevar = NULL;
558
- if (K_needed(g, p->left)) {
595
+ if (K_needed(p->left)) {
559
596
  savevar = vars_newname(g);
560
597
  }
561
598
 
562
599
  write_comment(g, p);
563
- if (savevar) write_savecursor(g, p, savevar);
600
+ if (savevar) {
601
+ write_savecursor(g, p, savevar);
602
+ }
564
603
 
565
604
  if (p->left->type == c_call) {
566
605
  /* Optimise do <call> */
567
606
  write_comment(g, p->left);
568
- g->V[0] = p->left->name;
569
- w(g, "~M~V0 (Z, Result);~N");
607
+ writef(g, "~M~V (Z, Result);~N", p->left);
570
608
  } else {
571
- g->failure_label = new_label(g);
609
+ int label = new_label(g);
610
+ g->failure_label = label;
572
611
  str_clear(g->failure_str);
573
612
 
574
613
  generate(g, p->left);
614
+
575
615
  if (g->label_used)
576
616
  wsetl(g, g->failure_label);
577
617
  g->unreachable = false;
@@ -600,14 +640,13 @@ static void generate_GO_grouping(struct generator * g, struct node * p, int is_g
600
640
  struct grouping * q = p->name->grouping;
601
641
  g->S[0] = p->mode == m_forward ? "" : "_Backward";
602
642
  g->S[1] = complement ? "In" : "Out";
603
- g->V[0] = p->name;
604
643
  g->I[0] = q->smallest_ch;
605
644
  g->I[1] = q->largest_ch;
606
645
  if (is_goto) {
607
- writef(g, "~M~S1_Grouping~S0 (Z, ~V0, ~I0, ~I1, True, C);~N", p);
646
+ writef(g, "~M~S1_Grouping~S0 (Z, ~V, ~I0, ~I1, True, C);~N", p);
608
647
  write_failure_if(g, "C < 0", p);
609
648
  } else {
610
- writef(g, "~M~S1_Grouping~S0 (Z, ~V0, ~I0, ~I1, True, C);~N", p);
649
+ writef(g, "~M~S1_Grouping~S0 (Z, ~V, ~I0, ~I1, True, C);~N", p);
611
650
  write_failure_if(g, "C < 0", p);
612
651
 
613
652
  if (p->mode == m_forward)
@@ -618,24 +657,24 @@ static void generate_GO_grouping(struct generator * g, struct node * p, int is_g
618
657
  g->temporary_used = true;
619
658
  }
620
659
 
621
- static void generate_GO(struct generator * g, struct node * p, int style) {
660
+ static void generate_GO(struct generator * g, struct node * p, int is_goto) {
622
661
  write_comment(g, p);
623
662
 
624
663
  int used = g->label_used;
625
-
626
664
  int a0 = g->failure_label;
627
665
 
628
- int end_unreachable = false;
629
- int golab = new_label(g);
666
+ bool end_unreachable = false;
667
+
630
668
  w(g, "~Mloop~N~+");
631
669
 
632
670
  struct str * savevar = NULL;
633
- if (style == 1 || repeat_restore(g, p->left)) {
671
+ if (is_goto || repeat_restore(p->left)) {
634
672
  savevar = vars_newname(g);
635
673
  write_savecursor(g, p, savevar);
636
674
  }
637
675
 
638
- g->failure_label = new_label(g);
676
+ int label = new_label(g);
677
+ g->failure_label = label;
639
678
  g->label_used = 0;
640
679
  str_clear(g->failure_str);
641
680
  generate(g, p->left);
@@ -646,10 +685,10 @@ static void generate_GO(struct generator * g, struct node * p, int style) {
646
685
  end_unreachable = true;
647
686
  } else {
648
687
  /* include for goto; omit for gopast */
649
- if (style == 1) write_restorecursor(g, p, savevar);
650
- g->I[0] = golab;
688
+ if (is_goto) write_restorecursor(g, p, savevar);
651
689
  w(g, "~Mexit;~N");
652
690
  }
691
+
653
692
  g->unreachable = false;
654
693
  if (g->label_used)
655
694
  wsetl(g, g->failure_label);
@@ -657,10 +696,10 @@ static void generate_GO(struct generator * g, struct node * p, int style) {
657
696
  write_restorecursor(g, p, savevar);
658
697
  str_delete(savevar);
659
698
  }
699
+
660
700
  g->label_used = used;
661
701
  g->failure_label = a0;
662
702
 
663
- write_check_limit(g, p);
664
703
  generate_next(g, p);
665
704
 
666
705
  w(g, "~-~Mend loop;~N");
@@ -669,8 +708,8 @@ static void generate_GO(struct generator * g, struct node * p, int style) {
669
708
  }
670
709
 
671
710
  static void generate_loop(struct generator * g, struct node * p) {
672
- struct str * loopvar = vars_newname(g);
673
711
  write_comment(g, p);
712
+ struct str * loopvar = vars_newname(g);
674
713
  g->B[0] = str_data(loopvar);
675
714
  w(g, "~Mfor ~B0 in reverse 1 .. ");
676
715
  generate_AE(g, p->AE);
@@ -686,16 +725,23 @@ static void generate_loop(struct generator * g, struct node * p) {
686
725
  static void generate_repeat_or_atleast(struct generator * g, struct node * p, struct str * loopvar) {
687
726
  int replab = new_label(g);
688
727
  wsetl(g, replab);
728
+ // We only actually loop via `goto` to replab, but if we don't generate
729
+ // a dummy `loop` ... `exit; end loop;` structure then gnat emits:
730
+ //
731
+ // info: code between label and backwards goto rewritten as loop [enabled by default]
689
732
  writef(g, "~N~Mloop~N~+", p);
690
733
 
691
734
  struct str * savevar = NULL;
692
- if (repeat_restore(g, p->left)) {
735
+ if (repeat_restore(p->left)) {
693
736
  savevar = vars_newname(g);
694
737
  write_savecursor(g, p, savevar);
695
738
  }
696
739
 
697
- g->failure_label = new_label(g);
740
+ int label = new_label(g);
741
+ g->failure_label = label;
698
742
  g->label_used = 0;
743
+ str_clear(g->failure_str);
744
+
699
745
  generate(g, p->left);
700
746
 
701
747
  if (!g->unreachable) {
@@ -725,10 +771,10 @@ static void generate_repeat(struct generator * g, struct node * p) {
725
771
  }
726
772
 
727
773
  static void generate_atleast(struct generator * g, struct node * p) {
728
- struct str * loopvar = vars_newname(g);
729
-
730
774
  write_comment(g, p);
775
+
731
776
  w(g, "~{");
777
+ struct str * loopvar = vars_newname(g);
732
778
  g->B[0] = str_data(loopvar);
733
779
  write_declare(g, "~B0 : Integer", p);
734
780
  w(g, "~M~B0 := ");
@@ -747,12 +793,6 @@ static void generate_atleast(struct generator * g, struct node * p) {
747
793
  str_delete(loopvar);
748
794
  }
749
795
 
750
- static void generate_setmark(struct generator * g, struct node * p) {
751
- write_comment(g, p);
752
- g->V[0] = p->name;
753
- writef(g, "~M~V0 := Z.C;~N", p);
754
- }
755
-
756
796
  static void generate_tomark(struct generator * g, struct node * p) {
757
797
  write_comment(g, p);
758
798
  g->S[0] = p->mode == m_forward ? ">" : "<";
@@ -764,14 +804,6 @@ static void generate_tomark(struct generator * g, struct node * p) {
764
804
  w(g, "~MZ.C := "); generate_AE(g, p->AE); writef(g, ";~N", p);
765
805
  }
766
806
 
767
- static void generate_atmark(struct generator * g, struct node * p) {
768
- write_comment(g, p);
769
- w(g, "~Mif Z.C /= "); generate_AE(g, p->AE); writef(g, " then~N~+", p);
770
- write_failure(g);
771
- w(g, "~-~Mend if;~N");
772
- g->unreachable = false;
773
- }
774
-
775
807
  static void generate_hop(struct generator * g, struct node * p) {
776
808
  write_comment(g, p);
777
809
  g->S[0] = p->mode == m_forward ? "" : "_Backward";
@@ -783,24 +815,12 @@ static void generate_hop(struct generator * g, struct node * p) {
783
815
  g->temporary_used = true;
784
816
  }
785
817
 
786
- static void generate_delete(struct generator * g, struct node * p) {
787
- write_comment(g, p);
788
- writef(g, "~MSlice_Del (Z);~N", p);
789
- }
790
-
791
818
  static void generate_tolimit(struct generator * g, struct node * p) {
792
819
  write_comment(g, p);
793
820
  g->S[0] = p->mode == m_forward ? "" : "b";
794
821
  writef(g, "~MZ.C := Z.L~S0;~N", p);
795
822
  }
796
823
 
797
- static void generate_atlimit(struct generator * g, struct node * p) {
798
- write_comment(g, p);
799
- g->S[0] = p->mode == m_forward ? "" : "b";
800
- g->S[1] = p->mode == m_forward ? "<" : ">";
801
- write_failure_if(g, "Z.C ~S1 Z.L~S0", p);
802
- }
803
-
804
824
  static void generate_leftslice(struct generator * g, struct node * p) {
805
825
  write_comment(g, p);
806
826
  g->S[0] = p->mode == m_forward ? "Bra" : "Ket";
@@ -815,34 +835,35 @@ static void generate_rightslice(struct generator * g, struct node * p) {
815
835
 
816
836
  static void generate_assignto(struct generator * g, struct node * p) {
817
837
  write_comment(g, p);
818
- g->V[0] = p->name;
819
- writef(g, "~M~V0 := Assign_To (Z, ~V0);~N", p);
820
- write_failure_if(g, "~V0 == 0", p);
838
+ writef(g, "~M~V := Assign_To (Z, ~V);~N", p);
839
+ write_failure_if(g, "~V == 0", p);
821
840
  }
822
841
 
823
842
  static void generate_sliceto(struct generator * g, struct node * p) {
824
843
  write_comment(g, p);
825
- g->V[0] = p->name;
826
- writef(g, "~M~V0 := Ada.Strings.Unbounded.To_Unbounded_String (Slice_To (Z));~N", p);
844
+ writef(g, "~MZ.L~W := Z.Ket - Z.Bra;~N", p);
845
+ writef(g, "~M~V (1 .. Z.L~W) := Z.P (Z.Bra + 1 .. Z.Ket);~N", p);
827
846
  }
828
847
 
829
848
  static void generate_address(struct generator * g, struct node * p) {
830
849
  symbol * b = p->literalstring;
831
850
  if (b != NULL) {
832
851
  write_literal_string(g, b);
852
+ write_string(g, ", ");
853
+ write_int(g, SIZE(b));
833
854
  } else {
834
- w(g, "Ada.Strings.Unbounded.To_String (");
835
855
  write_varref(g, p->name);
836
- w(g, ")");
856
+ write_string(g, ", Z.L");
857
+ write_varname(g, p->name);
837
858
  }
838
859
  }
839
860
 
840
861
  static void generate_insert(struct generator * g, struct node * p, int style) {
841
- int keep_c = style == c_attach;
842
862
  write_comment(g, p);
863
+ int keep_c = style == c_attach;
843
864
  if (p->mode == m_backward) keep_c = !keep_c;
844
865
  if (keep_c) w(g, "~MC := Z.C;~N");
845
- writef(g, "~MInsert (Z, Z.C, Z.C, ", p);
866
+ writef(g, "~MInsert (Z, ", p);
846
867
  generate_address(g, p);
847
868
  writef(g, ");~N", p);
848
869
  if (keep_c) {
@@ -851,34 +872,40 @@ static void generate_insert(struct generator * g, struct node * p, int style) {
851
872
  }
852
873
  }
853
874
 
854
- static void generate_assignfrom(struct generator * g, struct node * p) {
855
- int keep_c = p->mode == m_forward; /* like 'attach' */
856
-
875
+ static void generate_stringassign(struct generator * g, struct node * p) {
857
876
  write_comment(g, p);
858
- if (keep_c) writef(g, "~MC := Z.C;~N", p);
877
+ int keep_c = p->mode == m_forward; /* like 'attach' */
878
+ if (keep_c) {
879
+ writef(g, "~MC := Z.C;~N", p);
880
+ g->temporary_used = true;
881
+ }
859
882
  if (p->mode == m_forward) {
860
- writef(g, "~MInsert (Z, Z.C, Z.L, ", p);
883
+ /* like 'attach' */
884
+ writef(g, "~MReplace (Z, Z.C, Z.L, ", p);
861
885
  } else {
862
- writef(g, "~MInsert (Z, Z.Lb, Z.C, ", p);
886
+ writef(g, "~MReplace (Z, Z.Lb, Z.C, ", p);
863
887
  }
864
888
  generate_address(g, p);
865
889
  writef(g, ");~N", p);
866
890
  if (keep_c) {
867
891
  w(g, "~MZ.C := C;~N");
868
- g->temporary_used = true;
869
892
  }
870
893
  }
871
894
 
872
895
  static void generate_slicefrom(struct generator * g, struct node * p) {
873
896
  write_comment(g, p);
897
+ if (p->literalstring && SIZE(p->literalstring) == 0) {
898
+ w(g, "~MSlice_Del (Z);~N");
899
+ return;
900
+ }
874
901
  w(g, "~MSlice_From (Z, ");
875
902
  generate_address(g, p);
876
- writef(g, ");~N", p);
903
+ w(g, ");~N");
877
904
  }
878
905
 
879
906
  static void generate_setlimit(struct generator * g, struct node * p) {
880
- struct str * varname = vars_newname(g);
881
907
  write_comment(g, p);
908
+ struct str * varname = vars_newname(g);
882
909
 
883
910
  g->B[0] = str_data(varname);
884
911
  write_declare(g, "~B0 : Integer", p);
@@ -895,21 +922,20 @@ static void generate_setlimit(struct generator * g, struct node * p) {
895
922
  write_comment(g, q);
896
923
 
897
924
  g->S[0] = q->mode == m_forward ? ">" : "<";
898
-
899
925
  w(g, "~Mif Z.C ~S0 "); generate_AE(g, q->AE); writef(g, " then~N~+", q);
900
- w(g, "~MResult := False;~N");
901
- w(g, "~Mreturn;~-~N");
902
- w(g, "~Mend if;~N");
903
- w(g, "~M~B0");
926
+ write_failure(g);
927
+ w(g, "~-~Mend if;~N");
904
928
  g->unreachable = false;
905
929
 
906
930
  if (p->mode == m_forward) {
907
- w(g, " := Z.L - Z.C; Z.L := ");
931
+ w(g, "~M~B0 := Z.L; Z.L := ");
932
+ generate_AE(g, q->AE);
933
+ w(g, "; ~B0 := ~B0 - Z.L;~N");
908
934
  } else {
909
- w(g, " := Z.Lb; Z.Lb := ");
935
+ w(g, "~M~B0 := Z.Lb; Z.Lb := ");
936
+ generate_AE(g, q->AE);
937
+ w(g, ";~N");
910
938
  }
911
- generate_AE(g, q->AE);
912
- w(g, ";~N");
913
939
 
914
940
  if (p->mode == m_forward) {
915
941
  str_assign(g->failure_str, "Z.L := Z.L + ");
@@ -967,62 +993,89 @@ static void generate_setlimit(struct generator * g, struct node * p) {
967
993
  static void generate_dollar(struct generator * g, struct node * p) {
968
994
  write_comment(g, p);
969
995
 
996
+ int used = g->label_used;
997
+ int a0 = g->failure_label;
998
+ struct str * a1 = str_copy(g->failure_str);
999
+ int label = new_label(g);
1000
+ g->failure_label = label;
1001
+ g->label_used = 0;
1002
+ str_clear(g->failure_str);
1003
+
970
1004
  struct str * savevar = vars_newname(g);
971
1005
  g->B[0] = str_data(savevar);
972
- g->V[0] = p->name;
973
1006
 
974
- {
975
- struct str * saved_output = g->outbuf;
976
- str_clear(g->failure_str);
977
- g->outbuf = g->failure_str;
978
- writef(g, "~V0 := FCurrent; "
979
- "FCurrent := ~B0_Current; "
980
- "FCursor := ~B0_Cursor; "
981
- "FLimit := ~B0_Limit; "
982
- "FBkLimit := ~B0_BkLimit; "
983
- "FBra := ~B0_Bra; "
984
- "FKet := ~B0_Ket;", p);
985
- g->failure_str = g->outbuf;
986
- g->outbuf = saved_output;
987
- }
988
-
989
- write_declare(g, "~B0_Current : AnsiString", p);
990
- write_declare(g, "~B0_Cursor : Integer", p);
991
- write_declare(g, "~B0_Limit : Integer", p);
992
- write_declare(g, "~B0_BkLimit : Integer", p);
993
- write_declare(g, "~B0_Bra : Integer", p);
994
- write_declare(g, "~B0_Ket : Integer", p);
1007
+ write_declare(g, "~B0_C : Char_Index", p);
1008
+ write_declare(g, "~B0_Len : Char_Index", p);
1009
+ write_declare(g, "~B0_L : Char_Index", p);
1010
+ write_declare(g, "~B0_Lb : Char_Index", p);
1011
+ write_declare(g, "~B0_Bra : Char_Index", p);
1012
+ write_declare(g, "~B0_Ket : Char_Index", p);
1013
+ write_declare(g, "~B0_P : String (1 .. WORD_MAX_LENGTH)", p);
995
1014
  writef(g, "~{"
996
- "~M~B0_Current := FCurrent;~N"
997
- "{ ~M~B0_Current := Copy(FCurrent, 1, FLimit); }~N"
998
- "~M~B0_Cursor := FCursor;~N"
999
- "~M~B0_Limit := FLimit;~N"
1000
- "~M~B0_BkLimit := FBkLimit;~N"
1001
- "~M~B0_Bra := FBra;~N"
1002
- "~M~B0_Ket := FKet;~N"
1003
- "~MFCurrent := ~V0;~N"
1004
- "~MFCursor := 0;~N"
1005
- "~MFLimit := Length(current);~N", p);
1015
+ "~M~B0_C := Z.C;~N"
1016
+ "~M~B0_Len := Z.Len;~N"
1017
+ "~M~B0_L := Z.L;~N"
1018
+ "~M~B0_Lb := Z.Lb;~N"
1019
+ "~M~B0_Bra := Z.Bra;~N"
1020
+ "~M~B0_Ket := Z.Ket;~N"
1021
+ "~M~B0_P := Z.P;~N"
1022
+ "~MZ.P := ~V;~N"
1023
+ "~MZ.Len := Z.L~W;~N"
1024
+ "~MZ.C := 0;~N"
1025
+ "~MZ.Bra := 0;~N"
1026
+ "~MZ.Ket := 0;~N"
1027
+ "~MZ.L := Z.Len;~N", p);
1028
+ if (p->left->possible_signals == -1) {
1029
+ /* Assume failure. */
1030
+ write_declare(g, "~B0_F : Boolean", p);
1031
+ w(g, "~M~B0_F := True;~N");
1032
+ }
1033
+
1006
1034
  generate(g, p->left);
1007
- if (!g->unreachable) {
1008
- write_margin(g);
1009
- write_str(g, g->failure_str);
1010
- write_newline(g);
1035
+
1036
+ if (!g->unreachable && p->left->possible_signals == -1) {
1037
+ /* Mark success. */
1038
+ g->B[0] = str_data(savevar);
1039
+ w(g, "~M~B0_F := False;~N");
1040
+ }
1041
+
1042
+ if (g->label_used)
1043
+ wsetl(g, g->failure_label);
1044
+
1045
+ g->label_used = used;
1046
+ g->failure_label = a0;
1047
+ str_delete(g->failure_str);
1048
+ g->failure_str = a1;
1049
+
1050
+ g->B[0] = str_data(savevar);
1051
+ writef(g, "~M~V := Z.P;~N"
1052
+ "~MZ.L~W := Z.Len;~N"
1053
+ "~MZ.C := ~B0_C;~N"
1054
+ "~MZ.Len := ~B0_Len;~N"
1055
+ "~MZ.L := ~B0_L;~N"
1056
+ "~MZ.Lb := ~B0_Lb;~N"
1057
+ "~MZ.Bra := ~B0_Bra;~N"
1058
+ "~MZ.Ket := ~B0_Ket;~N"
1059
+ "~MZ.P := ~B0_P;~N", p);
1060
+
1061
+ if (p->left->possible_signals == 0) {
1062
+ // p->left always signals f.
1063
+ w(g, "~M~f~N");
1064
+ } else if (p->left->possible_signals == -1) {
1065
+ write_failure_if(g, "~B0_F", p);
1011
1066
  }
1012
1067
  w(g, "~}");
1068
+
1013
1069
  str_delete(savevar);
1014
1070
  }
1015
1071
 
1016
1072
  static void generate_integer_assign(struct generator * g, struct node * p, const char * s) {
1017
1073
  write_comment(g, p);
1018
- g->V[0] = p->name;
1019
- w(g, "~M~V0 := ");
1020
-
1074
+ writef(g, "~M~V := ", p);
1021
1075
  if (s != NULL) {
1022
1076
  g->S[0] = s;
1023
- w(g, "~V0 ~S0 ");
1077
+ writef(g, "~V ~S0 ", p);
1024
1078
  }
1025
-
1026
1079
  generate_AE(g, p->AE);
1027
1080
  w(g, ";~N");
1028
1081
  }
@@ -1030,7 +1083,7 @@ static void generate_integer_assign(struct generator * g, struct node * p, const
1030
1083
  static void generate_integer_test(struct generator * g, struct node * p) {
1031
1084
  write_comment(g, p);
1032
1085
  int relop = p->type;
1033
- int optimise_to_return = (g->failure_label == x_return && p->right && p->right->type == c_functionend);
1086
+ int optimise_to_return = tailcallable(g, p);
1034
1087
  if (optimise_to_return) {
1035
1088
  w(g, "~MResult := (");
1036
1089
  p->right = NULL;
@@ -1053,31 +1106,30 @@ static void generate_integer_test(struct generator * g, struct node * p) {
1053
1106
  }
1054
1107
 
1055
1108
  static void generate_call(struct generator * g, struct node * p) {
1056
- int signals = check_possible_signals_list(g, p->name->definition, c_define, 0);
1109
+ int signals = p->name->definition->possible_signals;
1057
1110
  write_comment(g, p);
1058
- g->V[0] = p->name;
1059
- if (g->failure_label == x_return) {
1060
- if (p->right && p->right->type == c_functionend) {
1061
- /* Tail call. */
1062
- writef(g, "~M~V0 (Z, Result);~N", p);
1063
- return;
1064
- }
1065
- if (signals == 0) {
1066
- /* Always fails. */
1067
- writef(g, "~M~V0 (Z, Result);~N", p);
1068
- w(g, "~Mreturn~N");
1069
- return;
1070
- }
1111
+ if (tailcallable(g, p)) {
1112
+ /* Tail call. */
1113
+ writef(g, "~M~V (Z, Result);~N", p);
1114
+ w(g, "~Mreturn;~N");
1115
+ p->right = NULL;
1116
+ return;
1117
+ }
1118
+ if (just_return_on_fail(g) && signals == 0) {
1119
+ /* Always fails. */
1120
+ writef(g, "~M~V (Z, Result);~N", p);
1121
+ w(g, "~Mreturn~N");
1122
+ return;
1071
1123
  }
1072
1124
  if (signals == 1) {
1073
1125
  /* Always succeeds. */
1074
- writef(g, "~M~V0 (Z, Result);~N", p);
1126
+ writef(g, "~M~V (Z, Result);~N", p);
1075
1127
  } else if (signals == 0) {
1076
1128
  /* Always fails. */
1077
- writef(g, "~M~V0 (Z, Result);~N", p);
1129
+ writef(g, "~M~V (Z, Result);~N", p);
1078
1130
  write_failure(g);
1079
1131
  } else {
1080
- writef(g, "~M~V0 (Z, Result);~N", p);
1132
+ writef(g, "~M~V (Z, Result);~N", p);
1081
1133
  write_failure_if(g, "not Result", p);
1082
1134
  }
1083
1135
  }
@@ -1088,52 +1140,54 @@ static void generate_grouping(struct generator * g, struct node * p, int complem
1088
1140
  struct grouping * q = p->name->grouping;
1089
1141
  g->S[0] = p->mode == m_forward ? "" : "_Backward";
1090
1142
  g->S[1] = complement ? "Out_" : "In_";
1091
- g->V[0] = p->name;
1092
1143
  g->I[0] = q->smallest_ch;
1093
1144
  g->I[1] = q->largest_ch;
1094
- writef(g, "~M~S1Grouping~S0 (Z, ~V0, ~I0, ~I1, False, C);~N", p);
1095
- write_failure_if(g, "C /= 0", p);
1145
+ if (tailcallable(g, p)) {
1146
+ writef(g, "~M~S1Grouping~S0 (Z, ~V, ~I0, ~I1, False, C);~N", p);
1147
+ w(g, "~MResult := (C = 0);~N");
1148
+ p->right = NULL;
1149
+ } else {
1150
+ writef(g, "~M~S1Grouping~S0 (Z, ~V, ~I0, ~I1, False, C);~N", p);
1151
+ write_failure_if(g, "C /= 0", p);
1152
+ }
1096
1153
  g->temporary_used = true;
1097
1154
  }
1098
1155
 
1099
1156
  static void generate_namedstring(struct generator * g, struct node * p) {
1100
1157
  write_comment(g, p);
1101
1158
  g->S[0] = p->mode == m_forward ? "" : "_Backward";
1102
- g->V[0] = p->name;
1103
- writef(g, "~MC := Eq_S~S0 (Z, Ada.Strings.Unbounded.To_String (~V0));", p);
1104
- write_failure_if(g, "C = 0", p);
1105
- g->temporary_used = true;
1159
+ if (tailcallable(g, p)) {
1160
+ writef(g, "~MEq_S~S0 (Z, ~V, Z.L~W, Result);~N", p);
1161
+ p->right = NULL;
1162
+ } else {
1163
+ writef(g, "~MEq_S~S0 (Z, ~V, Z.L~W, Result);~N", p);
1164
+ write_failure_if(g, "not Result", p);
1165
+ }
1106
1166
  }
1107
1167
 
1108
1168
  static void generate_literalstring(struct generator * g, struct node * p) {
1109
- symbol * b = p->literalstring;
1110
1169
  write_comment(g, p);
1111
1170
  g->S[0] = p->mode == m_forward ? "" : "_Backward";
1112
- g->L[0] = b;
1113
- writef(g, "~MC := Eq_S~S0 (Z, ~L0);~N", p);
1114
- write_failure_if(g, "C = 0", p);
1115
- if (p->mode == m_forward) {
1116
- writef(g, "~MZ.C := Z.C + C;~N", p);
1171
+ g->I[0] = SIZE(p->literalstring);
1172
+ if (tailcallable(g, p)) {
1173
+ writef(g, "~MEq_S~S0 (Z, ~L, ~I0, Result);~N", p);
1174
+ p->right = NULL;
1117
1175
  } else {
1118
- writef(g, "~MZ.C := Z.C - C;~N", p);
1176
+ writef(g, "~MEq_S~S0 (Z, ~L, ~I0, Result);~N", p);
1177
+ write_failure_if(g, "not Result", p);
1119
1178
  }
1120
- g->temporary_used = true;
1121
1179
  }
1122
1180
 
1123
1181
  static void generate_define(struct generator * g, struct node * p) {
1124
- struct name * q = p->name;
1125
- if (q->type == t_routine && !q->used) return;
1126
-
1127
1182
  write_newline(g);
1128
1183
  write_comment(g, p);
1129
1184
 
1130
1185
  /* Generate function header. */
1131
- g->V[0] = q;
1132
- w(g, "~Mprocedure ~W0 (Z : in out Context_Type; Result : out Boolean) is~N");
1186
+ writef(g, "~Mprocedure ~W (Z : in out Context_Type; Result : out Boolean) is~N", p);
1133
1187
 
1134
1188
  /* Save output. */
1135
- struct str *saved_output = g->outbuf;
1136
- struct str *saved_declarations = g->declarations;
1189
+ struct str * saved_output = g->outbuf;
1190
+ struct str * saved_declarations = g->declarations;
1137
1191
  g->outbuf = str_new();
1138
1192
  g->declarations = str_new();
1139
1193
 
@@ -1145,7 +1199,7 @@ static void generate_define(struct generator * g, struct node * p) {
1145
1199
 
1146
1200
  /* Generate function body. */
1147
1201
  w(g, "~{");
1148
- int signals = check_possible_signals_list(g, p->left, c_define, 0);
1202
+ int signals = p->left->possible_signals;
1149
1203
  g->temporary_used = false;
1150
1204
  generate(g, p->left);
1151
1205
  if (p->left->right) {
@@ -1154,17 +1208,50 @@ static void generate_define(struct generator * g, struct node * p) {
1154
1208
  generate(g, p->left->right);
1155
1209
  }
1156
1210
  }
1157
- g->V[0] = q;
1158
- w(g, "~-~Mend ~W0;~N");
1159
1211
 
1160
- if (g->temporary_used) {
1161
- str_append_string(saved_output, " C : Result_Index;\n");
1212
+ #define FINAL_RETURN "\n return;\n"
1213
+ #define FINAL_RETURN_LEN (sizeof(FINAL_RETURN) - 1)
1214
+ if (memcmp(str_data(g->outbuf) + str_len(g->outbuf) - FINAL_RETURN_LEN,
1215
+ FINAL_RETURN, FINAL_RETURN_LEN) == 0) {
1216
+ // If generate_functionend() has just added a return we remove it again.
1217
+ // This is really only a cosmetic improvement.
1218
+ str_pop_n(g->outbuf, FINAL_RETURN_LEN - 1);
1162
1219
  }
1163
1220
 
1221
+ writef(g, "~-~Mend ~W;~N", p);
1222
+
1164
1223
  if (need_among_var(p->left)) {
1165
1224
  str_append_string(saved_output, " A : Integer;\n");
1166
1225
  }
1167
1226
 
1227
+ if (g->temporary_used) {
1228
+ str_append_string(saved_output, " C : Result_Index;\n");
1229
+ }
1230
+
1231
+ /* Declare localised variables. */
1232
+ struct str * temp = g->outbuf;
1233
+ g->outbuf = saved_output;
1234
+ for (struct name * name = g->analyser->names; name; name = name->next) {
1235
+ if (name->local_to == p->name) {
1236
+ switch (name->type) {
1237
+ case t_string:
1238
+ assert(0);
1239
+ break;
1240
+ case t_integer:
1241
+ w(g, " ");
1242
+ write_varname(g, name);
1243
+ w(g, " : Integer;\n");
1244
+ break;
1245
+ case t_boolean:
1246
+ w(g, " ");
1247
+ write_varname(g, name);
1248
+ w(g, " : Boolean;\n");
1249
+ break;
1250
+ }
1251
+ }
1252
+ }
1253
+ g->outbuf = temp;
1254
+
1168
1255
  if (g->var_number) {
1169
1256
  str_append(saved_output, g->declarations);
1170
1257
  }
@@ -1178,7 +1265,7 @@ static void generate_define(struct generator * g, struct node * p) {
1178
1265
 
1179
1266
  static void generate_functionend(struct generator * g, struct node * p) {
1180
1267
  (void)p;
1181
- w(g, "~MResult := True;~N");
1268
+ w(g, "~MResult := True;~N~Mreturn;~N");
1182
1269
  }
1183
1270
 
1184
1271
  static void generate_substring(struct generator * g, struct node * p) {
@@ -1192,8 +1279,7 @@ static void generate_substring(struct generator * g, struct node * p) {
1192
1279
  int n_cases = 0;
1193
1280
  symbol cases[2];
1194
1281
  int shortest_size = x->shortest_size;
1195
- int call_done = 0;
1196
- int need_among_handler = (x->function_count > 0);
1282
+ int block_opened = 0;
1197
1283
 
1198
1284
  g->S[0] = p->mode == m_forward ? "" : "_Backward";
1199
1285
  g->I[0] = x->number;
@@ -1240,7 +1326,8 @@ static void generate_substring(struct generator * g, struct node * p) {
1240
1326
  }
1241
1327
  }
1242
1328
 
1243
- if (block != -1 || n_cases <= 2) {
1329
+ int pre_check = (block != -1 || n_cases <= 2);
1330
+ if (pre_check) {
1244
1331
  char buf[64];
1245
1332
  char buf2[128];
1246
1333
  char buf3[64];
@@ -1248,13 +1335,16 @@ static void generate_substring(struct generator * g, struct node * p) {
1248
1335
  g->I[3] = bitmap;
1249
1336
  g->I[4] = shortest_size - 1;
1250
1337
  g->S[3] = buf3;
1251
- snprintf(buf3, sizeof(buf3), "16#%x#", bitmap);
1338
+ checked_snprintf(buf3, sizeof(buf3), "16#%x#", bitmap);
1252
1339
  if (p->mode == m_forward) {
1253
- if (shortest_size == 1)
1254
- sprintf(buf, "Z.C");
1255
- else
1256
- sprintf(buf, "Z.C + %d", shortest_size - 1);
1257
- snprintf(buf2, sizeof(buf2), "Character'Pos (Z.P (%s + 1))", buf);
1340
+ if (shortest_size == 1) {
1341
+ checked_snprintf(buf, sizeof(buf), "Z.C");
1342
+ } else {
1343
+ checked_snprintf(buf, sizeof(buf),
1344
+ "Z.C + %d", shortest_size - 1);
1345
+ }
1346
+ checked_snprintf(buf2, sizeof(buf2),
1347
+ "Character'Pos (Z.P (%s + 1))", buf);
1258
1348
  g->S[1] = buf;
1259
1349
  g->S[2] = buf2;
1260
1350
  if (shortest_size == 1) {
@@ -1271,12 +1361,8 @@ static void generate_substring(struct generator * g, struct node * p) {
1271
1361
  writef(g, "~Mif Z.C - ~I4 <= Z.Lb", p);
1272
1362
  }
1273
1363
  }
1274
- if (n_cases == 0) {
1275
- /* We get this for the degenerate case: among ( '' )
1276
- * This doesn't seem to be a useful construct, but it is
1277
- * syntactically valid.
1278
- */
1279
- } else if (n_cases == 1) {
1364
+ assert(n_cases > 0);
1365
+ if (n_cases == 1) {
1280
1366
  g->I[4] = cases[0];
1281
1367
  writef(g, " or else ~S2 /= ~I4", p);
1282
1368
  } else if (n_cases == 2) {
@@ -1287,40 +1373,58 @@ static void generate_substring(struct generator * g, struct node * p) {
1287
1373
  writef(g, " or else Check_Among (Z, ~S1, ~I2, ~S3)", p);
1288
1374
  }
1289
1375
  writef(g, " then~+~N", p);
1290
- if (empty_case != -1) {
1376
+ if (empty_case != -1 && !among_cases[empty_case].function) {
1291
1377
  /* If the among includes the empty string, it can never fail
1292
1378
  * so not matching the bitmap means we match the empty string.
1293
1379
  */
1294
1380
  g->I[4] = among_cases[empty_case].result;
1295
1381
  writef(g, "~MA := ~I4;~-~N~Melse~+~N", p);
1296
- if (need_among_handler) {
1297
- writef(g, "~MFind_Among~S0 (Z, A_~I0, Among_String, Among_Handler'Access, A);~N", p);
1298
- } else {
1299
- writef(g, "~MFind_Among~S0 (Z, A_~I0, Among_String, null, A);~N", p);
1300
- }
1301
- if (!x->always_matches) {
1302
- write_failure_if(g, "A = 0", p);
1303
- }
1304
- call_done = 1;
1382
+ block_opened = 1;
1305
1383
  } else {
1306
- write_failure(g);
1384
+ writef(g, "~f", p);
1385
+ writef(g, "~-~Mend if;~N", p);
1307
1386
  }
1308
- writef(g, "~-~Mend if;~N", p);
1309
1387
  } else {
1310
1388
  #ifdef OPTIMISATION_WARNINGS
1311
1389
  printf("Couldn't shortcut among %d\n", x->number);
1312
1390
  #endif
1313
1391
  }
1314
1392
 
1315
- if (!call_done) {
1316
- if (need_among_handler) {
1317
- writef(g, "~MFind_Among~S0 (Z, A_~I0, Among_String, Among_Handler'Access, A);~N", p);
1318
- } else {
1319
- writef(g, "~MFind_Among~S0 (Z, A_~I0, Among_String, null, A);~N", p);
1320
- }
1393
+ g->S[1] = (x->function_count > 0) ? "Among_Handler'Access" : "null";
1394
+
1395
+ if (x->amongvar_needed) {
1396
+ writef(g, "~MFind_Among~S0 (Z, A_~I0, Among_String, ~S1, A);~N", p);
1321
1397
  if (!x->always_matches) {
1322
1398
  write_failure_if(g, "A = 0", p);
1323
1399
  }
1400
+ if (block_opened) writef(g, "~-~Mend if;~N", p);
1401
+ return;
1402
+ }
1403
+
1404
+ if (pre_check && !x->function_count) {
1405
+ // If all cases are one symbol long (so one byte of UTF-8, one
1406
+ // character long in fixed-width encodings) then we don't need to call
1407
+ // the helper and can just inc/dec the cursor by 1.
1408
+ if (x->longest_size == 1 && !x->always_matches) {
1409
+ if (p->mode == m_forward) {
1410
+ w(g, "~MZ.C := Z.C + 1;~N");
1411
+ } else {
1412
+ w(g, "~MZ.C := Z.C - 1;~N");
1413
+ }
1414
+ // Suppress generating table for this among.
1415
+ x->used = false;
1416
+ return;
1417
+ }
1418
+ }
1419
+
1420
+ writef(g, "~MFind_Among~S0 (Z, A_~I0, Among_String, ~S1, A);~N", p);
1421
+ if (x->always_matches) {
1422
+ // The result in `A` can't be zero.
1423
+ } else if (x->command_count == 0 && tailcallable(g, p)) {
1424
+ writef(g, "~MResult := A /= 0;~N", p);
1425
+ x->node->right = NULL;
1426
+ } else {
1427
+ write_failure_if(g, "A = 0", p);
1324
1428
  }
1325
1429
  }
1326
1430
 
@@ -1352,10 +1456,23 @@ static void generate_among(struct generator * g, struct node * p) {
1352
1456
  }
1353
1457
  }
1354
1458
 
1355
- static void generate_booltest(struct generator * g, struct node * p) {
1459
+ static void generate_booltest(struct generator * g, struct node * p, int inverted) {
1356
1460
  write_comment(g, p);
1357
- g->V[0] = p->name;
1358
- write_failure_if(g, "not ~V0", p);
1461
+ if (tailcallable(g, p)) {
1462
+ // Optimise at end of function.
1463
+ if (inverted) {
1464
+ writef(g, "~MResult := not ~V;~N", p);
1465
+ } else {
1466
+ writef(g, "~MResult := ~V;~N", p);
1467
+ }
1468
+ p->right = NULL;
1469
+ return;
1470
+ }
1471
+ if (inverted) {
1472
+ write_failure_if(g, "~V", p);
1473
+ } else {
1474
+ write_failure_if(g, "not ~V", p);
1475
+ }
1359
1476
  }
1360
1477
 
1361
1478
  static void generate_false(struct generator * g, struct node * p) {
@@ -1367,7 +1484,7 @@ static void generate_debug(struct generator * g, struct node * p) {
1367
1484
  write_comment(g, p);
1368
1485
  g->I[0] = g->debug_count++;
1369
1486
  g->I[1] = p->line_number;
1370
- writef(g, "~Mdebug(~I0, ~I1);~N", p);
1487
+ writef(g, "~Mdebug(Z, ~I0, ~I1);~N", p);
1371
1488
  }
1372
1489
 
1373
1490
  static void generate(struct generator * g, struct node * p) {
@@ -1400,25 +1517,21 @@ static void generate(struct generator * g, struct node * p) {
1400
1517
  case c_repeat: generate_repeat(g, p); break;
1401
1518
  case c_loop: generate_loop(g, p); break;
1402
1519
  case c_atleast: generate_atleast(g, p); break;
1403
- case c_setmark: generate_setmark(g, p); break;
1404
1520
  case c_tomark: generate_tomark(g, p); break;
1405
- case c_atmark: generate_atmark(g, p); break;
1406
1521
  case c_hop: generate_hop(g, p); break;
1407
- case c_delete: generate_delete(g, p); break;
1408
1522
  case c_next: generate_next(g, p); break;
1409
1523
  case c_tolimit: generate_tolimit(g, p); break;
1410
- case c_atlimit: generate_atlimit(g, p); break;
1411
1524
  case c_leftslice: generate_leftslice(g, p); break;
1412
1525
  case c_rightslice: generate_rightslice(g, p); break;
1413
1526
  case c_assignto: generate_assignto(g, p); break;
1414
1527
  case c_sliceto: generate_sliceto(g, p); break;
1415
- case c_assign: generate_assignfrom(g, p); break;
1528
+ case c_stringassign: generate_stringassign(g, p); break;
1416
1529
  case c_insert:
1417
1530
  case c_attach: generate_insert(g, p, p->type); break;
1418
1531
  case c_slicefrom: generate_slicefrom(g, p); break;
1419
1532
  case c_setlimit: generate_setlimit(g, p); break;
1420
1533
  case c_dollar: generate_dollar(g, p); break;
1421
- case c_mathassign: generate_integer_assign(g, p, NULL); break;
1534
+ case c_assign: generate_integer_assign(g, p, NULL); break;
1422
1535
  case c_plusassign: generate_integer_assign(g, p, "+"); break;
1423
1536
  case c_minusassign: generate_integer_assign(g, p, "-"); break;
1424
1537
  case c_multiplyassign:generate_integer_assign(g, p, "*"); break;
@@ -1438,7 +1551,8 @@ static void generate(struct generator * g, struct node * p) {
1438
1551
  case c_literalstring: generate_literalstring(g, p); break;
1439
1552
  case c_among: generate_among(g, p); break;
1440
1553
  case c_substring: generate_substring(g, p); break;
1441
- case c_booltest: generate_booltest(g, p); break;
1554
+ case c_booltest: generate_booltest(g, p, false); break;
1555
+ case c_not_booltest: generate_booltest(g, p, true); break;
1442
1556
  case c_false: generate_false(g, p); break;
1443
1557
  case c_true: break;
1444
1558
  case c_debug: generate_debug(g, p); break;
@@ -1454,57 +1568,53 @@ static void generate(struct generator * g, struct node * p) {
1454
1568
 
1455
1569
  /* Class declaration generation. */
1456
1570
  static void generate_unit_start(struct generator * g) {
1457
- g->margin = 0;
1458
1571
  write_start_comment(g, "-- ", NULL);
1459
1572
  }
1460
1573
 
1461
1574
  static void generate_method_decl(struct generator * g, struct name * q) {
1462
- g->V[0] = q;
1463
- w(g, "~Mprocedure ~W0 (Z : in out Context_Type; Result : out Boolean);~N");
1575
+ w(g, "~Mprocedure ");
1576
+ write_varref(g, q);
1577
+ w(g, " (Z : in out Context_Type; Result : out Boolean);~N");
1464
1578
  }
1465
1579
 
1466
1580
  static void generate_method_decls(struct generator * g, enum name_types type) {
1467
- struct among * a = g->analyser->amongs;
1468
- int need_among_handler = 0;
1469
-
1470
1581
  for (struct name * q = g->analyser->names; q; q = q->next) {
1471
1582
  if ((enum name_types)q->type == type) {
1472
1583
  generate_method_decl(g, q);
1473
1584
  }
1474
1585
  }
1475
-
1476
- while (a != NULL && need_among_handler == 0) {
1477
- need_among_handler = (a->function_count > 0);
1478
- a = a->next;
1479
- }
1480
- if (need_among_handler) {
1481
- w(g, "~N~Mprocedure Among_Handler (Context : in out Stemmer.Context_Type'Class; Operation : in Operation_Index; Result : out Boolean);~N");
1482
- }
1483
1586
  }
1484
1587
 
1485
1588
  static void generate_member_decls(struct generator * g) {
1486
1589
  w(g, " type Context_Type is new Stemmer.Context_Type with");
1487
- if (g->analyser->name_count[t_string] > 0 ||
1488
- g->analyser->name_count[t_integer] > 0 ||
1489
- g->analyser->name_count[t_boolean] > 0) {
1590
+ if (g->analyser->variable_count > 0) {
1490
1591
  w(g, " record~N~+");
1491
1592
  for (struct name * q = g->analyser->names; q; q = q->next) {
1492
- g->V[0] = q;
1593
+ if (q->local_to) continue;
1493
1594
  switch (q->type) {
1494
1595
  case t_string:
1495
- w(g, "~M~W0 : Ada.Strings.Unbounded.Unbounded_String;~N");
1596
+ write_margin(g);
1597
+ write_varname(g, q);
1598
+ w(g, " : String (1 .. WORD_MAX_LENGTH);~N");
1599
+ write_margin(g);
1600
+ write_char(g, 'L');
1601
+ write_varname(g, q);
1602
+ w(g, " : Char_Index := 0;~N");
1496
1603
  break;
1497
1604
  case t_integer:
1498
- w(g, "~M~W0 : Integer;~N");
1605
+ write_margin(g);
1606
+ write_varname(g, q);
1607
+ w(g, " : Integer;~N");
1499
1608
  break;
1500
1609
  case t_boolean:
1501
- w(g, "~M~W0 : Boolean;~N");
1610
+ write_margin(g);
1611
+ write_varname(g, q);
1612
+ w(g, " : Boolean;~N");
1502
1613
  break;
1503
1614
  }
1504
1615
  }
1505
1616
 
1506
- w(g, "~-");
1507
- w(g, "~- end record;~N");
1617
+ w(g, "~-~Mend record;~N");
1508
1618
  } else {
1509
1619
  w(g, " null record;~N");
1510
1620
  }
@@ -1518,7 +1628,6 @@ static int generate_among_string(struct generator * g, struct among * x, int cou
1518
1628
 
1519
1629
  for (int i = 0; i < x->literalstring_count; i++, v++) {
1520
1630
  /* Write among's string. */
1521
- g->L[0] = v->b;
1522
1631
  g->I[1] = i;
1523
1632
  if (count + SIZE(v->b) > limit) {
1524
1633
  w(g, "~N~M& ");
@@ -1527,7 +1636,7 @@ static int generate_among_string(struct generator * g, struct among * x, int cou
1527
1636
  } else if (count > 0) {
1528
1637
  w(g, " & ");
1529
1638
  }
1530
- w(g, "~L0");
1639
+ write_literal_string(g, v->b);
1531
1640
  count += SIZE(v->b) + 5;
1532
1641
  }
1533
1642
  return count;
@@ -1541,7 +1650,7 @@ static int generate_among_table(struct generator * g, struct among * x, int star
1541
1650
  g->I[0] = x->number;
1542
1651
 
1543
1652
  g->I[1] = x->literalstring_count - 1;
1544
- w(g, "~MA_~I0 : constant Among_Array_Type (0 .. ~I1) := ~+(~N");
1653
+ w(g, "~N~MA_~I0 : constant Among_Array_Type (0 .. ~I1) := ~+(~N");
1545
1654
 
1546
1655
  v = x->b;
1547
1656
  for (int i = 0; i < x->literalstring_count; i++) {
@@ -1575,47 +1684,37 @@ static int generate_among_table(struct generator * g, struct among * x, int star
1575
1684
  w(g, ",~N");
1576
1685
  }
1577
1686
  }
1578
- w(g, ");~-~N~N");
1687
+ w(g, ");~-~N");
1579
1688
  return start_pos;
1580
1689
  }
1581
1690
 
1582
- static int generate_amongs(struct generator * g) {
1583
- struct among * a = g->analyser->amongs;
1584
- if (!a) return 0;
1585
- int count;
1586
- int start_pos;
1691
+ static void generate_amongs(struct generator * g) {
1692
+ if (!g->analyser->amongs) return;
1587
1693
 
1588
- w(g, "~MAmong_String : constant String := ~+");
1589
- count = 0;
1590
- while (a != NULL) {
1591
- count = generate_among_string(g, a, count);
1592
- a = a->next;
1694
+ struct str * s = g->outbuf;
1695
+ g->outbuf = g->declarations;
1696
+
1697
+ w(g, "~N~MAmong_String : constant String := ~+");
1698
+ int count = 0;
1699
+ for (struct among * x = g->analyser->amongs; x != NULL; x = x->next) {
1700
+ if (x->used) {
1701
+ count = generate_among_string(g, x, count);
1702
+ }
1593
1703
  }
1594
- w(g, ";~N~-~N");
1704
+ w(g, ";~N~-");
1595
1705
 
1596
1706
  int operation = 0;
1597
- start_pos = 1;
1598
- a = g->analyser->amongs;
1599
- while (a != NULL) {
1600
- start_pos = generate_among_table(g, a, start_pos, &operation);
1601
- a = a->next;
1707
+ int start_pos = 1;
1708
+ for (struct among * x = g->analyser->amongs; x != NULL; x = x->next) {
1709
+ if (x->used) {
1710
+ start_pos = generate_among_table(g, x, start_pos, &operation);
1711
+ }
1602
1712
  }
1603
- return operation;
1604
- }
1713
+ g->outbuf = s;
1605
1714
 
1606
- static int generate_constructor(struct generator * g) {
1607
- return generate_amongs(g);
1608
- }
1715
+ if (operation == 0) return;
1609
1716
 
1610
- static void generate_methods(struct generator * g) {
1611
- for (struct node * p = g->analyser->program; p; p = p->right) {
1612
- generate(g, p);
1613
- g->unreachable = false;
1614
- }
1615
- }
1616
-
1617
- static int generate_operations_dispatcher(struct generator * g) {
1618
- int operation = 0;
1717
+ operation = 0;
1619
1718
 
1620
1719
  w(g, "~N~Mprocedure Among_Handler (Context : in out Stemmer.Context_Type'Class; Operation : in Operation_Index; Result : out Boolean) is~N");
1621
1720
  w(g, "~Mbegin~+~N~M");
@@ -1626,50 +1725,51 @@ static int generate_operations_dispatcher(struct generator * g) {
1626
1725
  if (v[i].function != NULL) {
1627
1726
  operation++;
1628
1727
  g->I[2] = operation;
1629
- w(g, "when ~I2 =>~N~M");
1630
- g->V[0] = v[i].function;
1631
- w(g, " ~W0 (Context_Type (Context), Result);~N~M");
1728
+ w(g, "when ~I2 =>~N~M ");
1729
+ write_varname(g, v[i].function);
1730
+ w(g, " (Context_Type (Context), Result);~N~M");
1632
1731
  }
1633
1732
  }
1634
1733
  }
1635
1734
  w(g, "when others =>~N~M");
1636
1735
  w(g, " Result := False;~-~N~Mend case;~-~N~M");
1637
- w(g, "end Among_Handler;~N~-");
1638
- return operation;
1736
+ w(g, "end Among_Handler;~N");
1737
+ }
1738
+
1739
+ static void generate_methods(struct generator * g) {
1740
+ for (struct node * p = g->analyser->program; p; p = p->right) {
1741
+ generate(g, p);
1742
+ g->unreachable = false;
1743
+ }
1639
1744
  }
1640
1745
 
1641
- static void set_bit(symbol * b, int i) { b[i/8] |= 1 << i%8; }
1746
+ static void set_bit(symbol * b, int i) { b[i >> 3] |= 1 << (i & 7); }
1642
1747
 
1643
1748
  static void generate_grouping_table(struct generator * g, struct grouping * q) {
1644
1749
  int range = q->largest_ch - q->smallest_ch + 1;
1645
- int size = (range + 7)/ 8; /* assume 8 bits per symbol */
1750
+ int size = (range + 7) / 8; /* assume 8 bits per symbol */
1646
1751
  symbol * b = q->b;
1647
1752
  symbol * map = create_b(size);
1648
- int need_comma = 0;
1649
1753
 
1650
1754
  for (int i = 0; i < size; i++) map[i] = 0;
1651
1755
 
1652
1756
  for (int i = 0; i < SIZE(b); i++) set_bit(map, b[i] - q->smallest_ch);
1653
1757
 
1654
- g->V[0] = q->name;
1655
1758
  g->I[0] = 8 * size - 1;
1656
- w(g, "~N~M~W0 : constant Grouping_Array (0 .. ~I0) := (~N~+~M");
1759
+ w(g, "~N~M");
1760
+ write_varname(g, q->name);
1761
+ w(g, " : constant Grouping_Array (0 .. ~I0) := (~N~+~M");
1657
1762
  for (int i = 0; i < size; i++) {
1658
1763
  unsigned char m = map[i];
1659
- if (i != 0) {
1660
- w(g, ",~N~M");
1661
- need_comma = 0;
1662
- }
1764
+ if (i) w(g, ",~N~M");
1663
1765
  for (int j = 0; j < 8; j++) {
1664
- if (need_comma)
1665
- w(g, ", ");
1766
+ if (j) w(g, ", ");
1666
1767
 
1667
1768
  if (m & (1 << j)) {
1668
1769
  w(g, "True");
1669
1770
  } else {
1670
1771
  w(g, "False");
1671
1772
  }
1672
- need_comma = 1;
1673
1773
  }
1674
1774
  }
1675
1775
  w(g, "~N~-~M);~N");
@@ -1678,21 +1778,30 @@ static void generate_grouping_table(struct generator * g, struct grouping * q) {
1678
1778
  }
1679
1779
 
1680
1780
  static void generate_groupings(struct generator * g) {
1781
+ struct str * s = g->outbuf;
1782
+ g->outbuf = g->declarations;
1681
1783
  for (struct grouping * q = g->analyser->groupings; q; q = q->next) {
1682
- if (q->name->used)
1683
- generate_grouping_table(g, q);
1784
+ generate_grouping_table(g, q);
1684
1785
  }
1786
+ g->outbuf = s;
1685
1787
  }
1686
1788
 
1687
1789
  extern void generate_program_ada(struct generator * g) {
1790
+ g->margin_indent = " ";
1791
+
1688
1792
  g->outbuf = str_new();
1689
1793
  g->failure_str = str_new();
1690
1794
 
1691
1795
  generate_unit_start(g);
1692
1796
 
1693
1797
  /* generate implementation. */
1798
+ if (g->analyser->debug_used) {
1799
+ // System.Io is GNAT-specific, but apparently we can't use Text_IO in a
1800
+ // preelaborated package.
1801
+ w(g, "with System.Io;~N");
1802
+ }
1694
1803
  w(g, "package body Stemmer.");
1695
- w(g, g->options->package);
1804
+ write_string(g, g->options->package);
1696
1805
  w(g, " is~N~+~N");
1697
1806
  w(g, "~Mpragma Style_Checks (\"-mr\");~N");
1698
1807
  w(g, "~Mpragma Warnings (Off, \"*variable*is never read and never assigned*\");~N");
@@ -1702,37 +1811,103 @@ extern void generate_program_ada(struct generator * g) {
1702
1811
  w(g, "~Mpragma Warnings (Off, \"*is not referenced*\");~N");
1703
1812
  w(g, "~N");
1704
1813
 
1814
+ if (g->analyser->debug_used) {
1815
+ w(g, "~N"
1816
+ "~Mprocedure Debug (Z : in Context_Type'Class; N : in Integer; Line : in Integer) is~N~+"
1817
+ "~MLen : Integer;~N"
1818
+ "~MCh : Integer;~N"
1819
+ "~-~Mbegin~N~+"
1820
+ "~Mif N < 10 then~N~+"
1821
+ "~MSystem.Io.Put (\" \");~N"
1822
+ "~-~Mend if;~N"
1823
+ "~Mif N < 100 then~N~+"
1824
+ "~MSystem.Io.Put (\" \");~N"
1825
+ "~-~Mend if;~N"
1826
+ "~MSystem.Io.Put (N);~N"
1827
+ "~MSystem.Io.Put (\" (line \");~N"
1828
+ "~Mif Line < 10 then~N~+"
1829
+ "~MSystem.Io.Put (\" \");~N"
1830
+ "~-~Mend if;~N"
1831
+ "~Mif Line < 100 then~N~+"
1832
+ "~MSystem.Io.Put (\" \");~N"
1833
+ "~-~Mend if;~N"
1834
+ "~Mif Line < 1000 then~N~+"
1835
+ "~MSystem.Io.Put (\" \");~N"
1836
+ "~-~Mend if;~N"
1837
+ "~MSystem.Io.Put (Line);~N"
1838
+ "~MSystem.Io.Put (\"): [\");~N"
1839
+ "~MSystem.Io.Put (Z.Len);~N"
1840
+ "~MSystem.Io.Put (\"]'\");~N"
1841
+ "~MLen := Z.Len;~N"
1842
+ "~Mfor I in 0 .. Len + 1 loop~N~+"
1843
+ "~Mif Z.Lb = I then~N~+"
1844
+ "~MSystem.Io.Put (\"{\");~N"
1845
+ "~-~Mend if;~N"
1846
+ "~Mif Z.Bra = I then~N~+"
1847
+ "~MSystem.Io.Put (\"[\");~N"
1848
+ "~-~Mend if;~N"
1849
+ "~Mif Z.C = I then~N~+"
1850
+ "~MSystem.Io.Put (\"|\");~N"
1851
+ "~-~Mend if;~N"
1852
+ "~Mif Z.Ket = I then~N~+"
1853
+ "~MSystem.Io.Put (\"]\");~N"
1854
+ "~-~Mend if;~N"
1855
+ "~Mif Z.L = I then~N~+"
1856
+ "~MSystem.Io.Put (\"}\");~N"
1857
+ "~-~Mend if;~N"
1858
+ "~Mif I < Len then~N~+"
1859
+ "~MCh := Character'Pos (Z.P (I + 1));~N"
1860
+ "~Mif Ch = 0 then~N~+"
1861
+ "~MSystem.Io.Put (\"#\");~N"
1862
+ "~-~Melse~N~+"
1863
+ "~MSystem.Io.Put (Z.P (I + 1 .. I + 1));~N"
1864
+ "~-~Mend if;~N"
1865
+ "~-~Mend if;~N"
1866
+ "~-~Mend loop;~N"
1867
+ "~MSystem.Io.Put_Line (\"'\");~N"
1868
+ "~-~Mend Debug;~N");
1869
+ }
1705
1870
  generate_method_decls(g, t_routine);
1706
- generate_groupings(g);
1707
1871
 
1708
- int operations = generate_constructor(g);
1709
- generate_methods(g);
1710
- if (operations > 0) {
1711
- generate_operations_dispatcher(g);
1872
+ bool need_among_handler = false;
1873
+ for (struct among * a = g->analyser->amongs; a; a = a->next) {
1874
+ if (a->function_count > 0) {
1875
+ need_among_handler = true;
1876
+ break;
1877
+ }
1878
+ }
1879
+ if (need_among_handler) {
1880
+ w(g, "~N~Mprocedure Among_Handler (Context : in out Stemmer.Context_Type'Class; Operation : in Operation_Index; Result : out Boolean);~N");
1712
1881
  }
1713
1882
 
1714
- w(g, "end Stemmer.");
1715
- w(g, g->options->package);
1883
+ g->declarations = g->outbuf;
1884
+ g->outbuf = str_new();
1885
+
1886
+ generate_methods(g);
1887
+
1888
+ generate_amongs(g);
1889
+ generate_groupings(g);
1890
+
1891
+ w(g, "~-end Stemmer.");
1892
+ write_string(g, g->options->package);
1716
1893
  w(g, ";~N");
1717
1894
 
1895
+ output_str(g->options->output_src, g->declarations);
1896
+ str_delete(g->declarations);
1718
1897
  output_str(g->options->output_src, g->outbuf);
1719
-
1720
1898
  str_clear(g->outbuf);
1721
1899
 
1722
- g->margin = 0;
1723
1900
  write_start_comment(g, "-- ", NULL);
1724
- if (g->analyser->name_count[t_string]) {
1725
- w(g, "private with Ada.Strings.Unbounded;~N");
1726
- }
1727
1901
  w(g, "package Stemmer.");
1728
- w(g, g->options->package);
1902
+ write_string(g, g->options->package);
1729
1903
  w(g, " with SPARK_Mode is~N~+");
1730
1904
  w(g, " type Context_Type is new Stemmer.Context_Type with private;~N");
1731
- w(g, " procedure Stem (Z : in out Context_Type; Result : out Boolean);~N");
1905
+ generate_method_decls(g, t_external);
1906
+
1732
1907
  w(g, "private~N");
1733
1908
  generate_member_decls(g);
1734
1909
  w(g, "end Stemmer.");
1735
- w(g, g->options->package);
1910
+ write_string(g, g->options->package);
1736
1911
  w(g, ";~N");
1737
1912
  output_str(g->options->output_h, g->outbuf);
1738
1913
  str_delete(g->failure_str);