plugin-folder.c
1 //! @file plugin-folder.c
2 //! @author J. Marcel van der Veer
3
4 //! @section Copyright
5 //!
6 //! This file is part of Algol68G - an Algol 68 compiler-interpreter.
7 //! Copyright 2001-2024 J. Marcel van der Veer [algol68g@xs4all.nl].
8
9 //! @section License
10 //!
11 //! This program is free software; you can redistribute it and/or modify it
12 //! under the terms of the GNU General Public License as published by the
13 //! Free Software Foundation; either version 3 of the License, or
14 //! (at your option) any later version.
15 //!
16 //! This program is distributed in the hope that it will be useful, but
17 //! WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
18 //! or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
19 //! more details. You should have received a copy of the GNU General Public
20 //! License along with this program. If not, see [http://www.gnu.org/licenses/].
21
22 //! @section Synopsis
23 //!
24 //! Plugin compiler constant folder.
25
26 #include "a68g.h"
27 #include "a68g-prelude.h"
28 #include "a68g-genie.h"
29 #include "a68g-optimiser.h"
30 #include "a68g-plugin.h"
31 #include "a68g-transput.h"
32
33 // Constant folder .
34 // Uses interpreter routines to calculate compile-time expressions.
35
36 //! @brief Whether mode is handled by the constant folder.
37
38 BOOL_T folder_mode (MOID_T * m)
39 {
40 if (primitive_mode (m)) {
41 return A68_TRUE;
42 } else if (m == M_COMPLEX) {
43 return A68_TRUE;
44 } else {
45 return A68_FALSE;
46 }
47 }
48
49 // Constant unit check.
50
51 //! @brief Whether constant collateral clause.
52
53 BOOL_T constant_collateral (NODE_T * p)
54 {
55 if (p == NO_NODE) {
56 return A68_TRUE;
57 } else if (IS (p, UNIT)) {
58 return (BOOL_T) (folder_mode (MOID (p)) && constant_unit (SUB (p)) && constant_collateral (NEXT (p)));
59 } else {
60 return (BOOL_T) (constant_collateral (SUB (p)) && constant_collateral (NEXT (p)));
61 }
62 }
63
64 //! @brief Whether constant serial clause.
65
66 void count_constant_units (NODE_T * p, int *total, int *good)
67 {
68 if (p != NO_NODE) {
69 if (IS (p, UNIT)) {
70 (*total)++;
71 if (constant_unit (p)) {
72 (*good)++;
73 }
74 count_constant_units (NEXT (p), total, good);
75 } else {
76 count_constant_units (SUB (p), total, good);
77 count_constant_units (NEXT (p), total, good);
78 }
79 }
80 }
81
82 //! @brief Whether constant serial clause.
83
84 BOOL_T constant_serial (NODE_T * p, int want)
85 {
86 int total = 0, good = 0;
87 count_constant_units (p, &total, &good);
88 if (want > 0) {
89 return total == want && total == good;
90 } else {
91 return total == good;
92 }
93 }
94
95 //! @brief Whether constant argument.
96
97 BOOL_T constant_argument (NODE_T * p)
98 {
99 if (p == NO_NODE) {
100 return A68_TRUE;
101 } else if (IS (p, UNIT)) {
102 return (BOOL_T) (folder_mode (MOID (p)) && constant_unit (p) && constant_argument (NEXT (p)));
103 } else {
104 return (BOOL_T) (constant_argument (SUB (p)) && constant_argument (NEXT (p)));
105 }
106 }
107
108 //! @brief Whether constant call.
109
110 BOOL_T constant_call (NODE_T * p)
111 {
112 if (IS (p, CALL)) {
113 NODE_T *prim = SUB (p);
114 NODE_T *idf = stems_from (prim, IDENTIFIER);
115 if (idf != NO_NODE) {
116 for (int k = 0; PROCEDURE (&functions[k]) != NO_GPROC; k++) {
117 if (PROCEDURE (TAX (idf)) == PROCEDURE (&functions[k])) {
118 NODE_T *args = NEXT (prim);
119 return constant_argument (args);
120 }
121 }
122 }
123 }
124 return A68_FALSE;
125 }
126
127 //! @brief Whether constant monadic formula.
128
129 BOOL_T constant_monadic_formula (NODE_T * p)
130 {
131 if (IS (p, MONADIC_FORMULA)) {
132 NODE_T *op = SUB (p);
133 for (int k = 0; PROCEDURE (&monadics[k]) != NO_GPROC; k++) {
134 if (PROCEDURE (TAX (op)) == PROCEDURE (&monadics[k])) {
135 NODE_T *rhs = NEXT (op);
136 return constant_unit (rhs);
137 }
138 }
139 }
140 return A68_FALSE;
141 }
142
143 //! @brief Whether constant dyadic formula.
144
145 BOOL_T constant_formula (NODE_T * p)
146 {
147 if (IS (p, FORMULA)) {
148 NODE_T *lhs = SUB (p);
149 NODE_T *op = NEXT (lhs);
150 if (op == NO_NODE) {
151 return constant_monadic_formula (lhs);
152 } else {
153 for (int k = 0; PROCEDURE (&dyadics[k]) != NO_GPROC; k++) {
154 if (PROCEDURE (TAX (op)) == PROCEDURE (&dyadics[k])) {
155 NODE_T *rhs = NEXT (op);
156 return (BOOL_T) (constant_unit (lhs) && constant_unit (rhs));
157 }
158 }
159 }
160 }
161 return A68_FALSE;
162 }
163
164 //! @brief Whether constant unit.
165
166 BOOL_T constant_unit (NODE_T * p)
167 {
168 if (p == NO_NODE) {
169 return A68_FALSE;
170 } else if (IS (p, UNIT)) {
171 return constant_unit (SUB (p));
172 } else if (IS (p, TERTIARY)) {
173 return constant_unit (SUB (p));
174 } else if (IS (p, SECONDARY)) {
175 return constant_unit (SUB (p));
176 } else if (IS (p, PRIMARY)) {
177 return constant_unit (SUB (p));
178 } else if (IS (p, ENCLOSED_CLAUSE)) {
179 return constant_unit (SUB (p));
180 } else if (IS (p, CLOSED_CLAUSE)) {
181 return constant_serial (NEXT_SUB (p), 1);
182 } else if (IS (p, COLLATERAL_CLAUSE)) {
183 return folder_mode (MOID (p)) && constant_collateral (NEXT_SUB (p));
184 } else if (IS (p, WIDENING)) {
185 if (WIDEN_TO (p, INT, REAL)) {
186 return constant_unit (SUB (p));
187 } else if (WIDEN_TO (p, REAL, COMPLEX)) {
188 return constant_unit (SUB (p));
189 } else {
190 return A68_FALSE;
191 }
192 } else if (IS (p, IDENTIFIER)) {
193 if (A68_STANDENV_PROC (TAX (p))) {
194 for (int k = 0; PROCEDURE (&constants[k]) != NO_GPROC; k++) {
195 if (PROCEDURE (TAX (p)) == PROCEDURE (&constants[k])) {
196 return A68_TRUE;
197 }
198 }
199 return A68_FALSE;
200 } else {
201 // Possible constant folding.
202 NODE_T *def = NODE (TAX (p));
203 BOOL_T ret = A68_FALSE;
204 if (STATUS (p) & COOKIE_MASK) {
205 diagnostic (A68_WARNING, p, WARNING_UNINITIALISED);
206 } else {
207 STATUS (p) |= COOKIE_MASK;
208 if (folder_mode (MOID (p)) && def != NO_NODE && NEXT (def) != NO_NODE && IS (NEXT (def), EQUALS_SYMBOL)) {
209 ret = constant_unit (NEXT_NEXT (def));
210 }
211 }
212 STATUS (p) &= !(COOKIE_MASK);
213 return ret;
214 }
215 } else if (IS (p, DENOTATION)) {
216 return primitive_mode (MOID (p));
217 } else if (IS (p, MONADIC_FORMULA)) {
218 return (BOOL_T) (folder_mode (MOID (p)) && constant_monadic_formula (p));
219 } else if (IS (p, FORMULA)) {
220 return (BOOL_T) (folder_mode (MOID (p)) && constant_formula (p));
221 } else if (IS (p, CALL)) {
222 return (BOOL_T) (folder_mode (MOID (p)) && constant_call (p));
223 } else if (IS (p, CAST)) {
224 return (BOOL_T) (folder_mode (MOID (SUB (p))) && constant_unit (NEXT_SUB (p)));
225 } else {
226 return A68_FALSE;
227 }
228 }
229
230 // Evaluate compile-time expressions using interpreter routines.
231
232 //! @brief Push denotation.
233
234 void push_denotation (NODE_T * p)
235 {
236 #define PUSH_DENOTATION(mode, decl) {\
237 decl z;\
238 NODE_T *s = (IS (SUB (p), SHORTETY) ? NEXT_SUB (p) : SUB (p));\
239 if (genie_string_to_value_internal (p, MODE (mode), NSYMBOL (s), (BYTE_T *) & z) == A68_FALSE) {\
240 diagnostic (A68_SYNTAX_ERROR, p, ERROR_IN_DENOTATION, MODE (mode));\
241 }\
242 PUSH_VALUE (p, VALUE (&z), decl);}
243
244 if (MOID (p) == M_INT) {
245 PUSH_DENOTATION (INT, A68_INT);
246 } else if (MOID (p) == M_REAL) {
247 PUSH_DENOTATION (REAL, A68_REAL);
248 } else if (MOID (p) == M_BOOL) {
249 PUSH_DENOTATION (BOOL, A68_BOOL);
250 } else if (MOID (p) == M_CHAR) {
251 if ((NSYMBOL (p))[0] == NULL_CHAR) {
252 PUSH_VALUE (p, NULL_CHAR, A68_CHAR);
253 } else {
254 PUSH_VALUE (p, (NSYMBOL (p))[0], A68_CHAR);
255 }
256 } else if (MOID (p) == M_BITS) {
257 PUSH_DENOTATION (BITS, A68_BITS);
258 }
259 #undef PUSH_DENOTATION
260 }
261
262 //! @brief Push widening.
263
264 void push_widening (NODE_T * p)
265 {
266 push_unit (SUB (p));
267 if (WIDEN_TO (p, INT, REAL)) {
268 A68_INT k;
269 POP_OBJECT (p, &k, A68_INT);
270 PUSH_VALUE (p, (REAL_T) VALUE (&k), A68_REAL);
271 } else if (WIDEN_TO (p, REAL, COMPLEX)) {
272 PUSH_VALUE (p, 0.0, A68_REAL);
273 }
274 }
275
276 //! @brief Code collateral units.
277
278 void push_collateral_units (NODE_T * p)
279 {
280 if (p == NO_NODE) {
281 return;
282 } else if (IS (p, UNIT)) {
283 push_unit (p);
284 } else {
285 push_collateral_units (SUB (p));
286 push_collateral_units (NEXT (p));
287 }
288 }
289
290 //! @brief Code argument.
291
292 void push_argument (NODE_T * p)
293 {
294 for (; p != NO_NODE; FORWARD (p)) {
295 if (IS (p, UNIT)) {
296 push_unit (p);
297 } else {
298 push_argument (SUB (p));
299 }
300 }
301 }
302
303 //! @brief Push unit.
304
305 void push_unit (NODE_T * p)
306 {
307 if (p == NO_NODE) {
308 return;
309 }
310 if (IS (p, UNIT)) {
311 push_unit (SUB (p));
312 } else if (IS (p, TERTIARY)) {
313 push_unit (SUB (p));
314 } else if (IS (p, SECONDARY)) {
315 push_unit (SUB (p));
316 } else if (IS (p, PRIMARY)) {
317 push_unit (SUB (p));
318 } else if (IS (p, ENCLOSED_CLAUSE)) {
319 push_unit (SUB (p));
320 } else if (IS (p, CLOSED_CLAUSE)) {
321 push_unit (SUB (NEXT_SUB (p)));
322 } else if (IS (p, COLLATERAL_CLAUSE)) {
323 push_collateral_units (NEXT_SUB (p));
324 } else if (IS (p, WIDENING)) {
325 push_widening (p);
326 } else if (IS (p, IDENTIFIER)) {
327 if (A68_STANDENV_PROC (TAX (p))) {
328 (void) (*(PROCEDURE (TAX (p)))) (p);
329 } else {
330 // Possible constant folding
331 NODE_T *def = NODE (TAX (p));
332 push_unit (NEXT_NEXT (def));
333 }
334 } else if (IS (p, DENOTATION)) {
335 push_denotation (p);
336 } else if (IS (p, MONADIC_FORMULA)) {
337 NODE_T *op = SUB (p);
338 NODE_T *rhs = NEXT (op);
339 push_unit (rhs);
340 (*(PROCEDURE (TAX (op)))) (op);
341 } else if (IS (p, FORMULA)) {
342 NODE_T *lhs = SUB (p);
343 NODE_T *op = NEXT (lhs);
344 if (op == NO_NODE) {
345 push_unit (lhs);
346 } else {
347 NODE_T *rhs = NEXT (op);
348 push_unit (lhs);
349 push_unit (rhs);
350 (*(PROCEDURE (TAX (op)))) (op);
351 }
352 } else if (IS (p, CALL)) {
353 NODE_T *prim = SUB (p);
354 NODE_T *args = NEXT (prim);
355 NODE_T *idf = stems_from (prim, IDENTIFIER);
356 push_argument (args);
357 (void) (*(PROCEDURE (TAX (idf)))) (p);
358 } else if (IS (p, CAST)) {
359 push_unit (NEXT_SUB (p));
360 }
361 }
362
363 //! @brief Code constant folding.
364
365 void constant_folder (NODE_T * p, FILE_T out, int phase)
366 {
367 if (phase == L_DECLARE) {
368 if (MOID (p) == M_COMPLEX) {
369 char acc[NAME_SIZE];
370 A68_REAL re, im;
371 (void) make_name (acc, CON, "", NUMBER (p));
372 A68_SP = 0;
373 push_unit (p);
374 POP_OBJECT (p, &im, A68_REAL);
375 POP_OBJECT (p, &re, A68_REAL);
376 indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "A68_COMPLEX %s = {", acc));
377 undentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "{INIT_MASK, %.*g}", A68_REAL_WIDTH + 2, VALUE (&re)));
378 undentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, ", {INIT_MASK, %.*g}", A68_REAL_WIDTH + 2, VALUE (&im)));
379 undent (out, "};\n");
380 ABEND (A68_SP > 0, ERROR_INTERNAL_CONSISTENCY, __func__);
381 }
382 } else if (phase == L_EXECUTE) {
383 if (MOID (p) == M_COMPLEX) {
384 // Done at declaration stage
385 }
386 } else if (phase == L_YIELD) {
387 if (MOID (p) == M_INT) {
388 A68_INT k;
389 A68_SP = 0;
390 push_unit (p);
391 POP_OBJECT (p, &k, A68_INT);
392 ASSERT (a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, A68_LD, VALUE (&k)) >= 0);
393 undent (out, A68 (edit_line));
394 ABEND (A68_SP > 0, ERROR_INTERNAL_CONSISTENCY, __func__);
395 } else if (MOID (p) == M_REAL) {
396 A68_REAL x;
397 A68_SP = 0;
398 push_unit (p);
399 POP_OBJECT (p, &x, A68_REAL);
400 // Mind overflowing or underflowing values.
401 if (!a68_finite_real (VALUE (&x))) {
402 A68_OPT (code_errors)++;
403 VALUE (&x) = 0.0;
404 }
405 if (VALUE (&x) == A68_REAL_MAX) {
406 undent (out, "A68_REAL_MAX");
407 } else if (VALUE (&x) == -A68_REAL_MAX) {
408 undent (out, "(-A68_REAL_MAX)");
409 } else {
410 ASSERT (a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "%.*g", A68_REAL_WIDTH + 2, VALUE (&x)) >= 0);
411 undent (out, A68 (edit_line));
412 }
413 ABEND (A68_SP > 0, ERROR_INTERNAL_CONSISTENCY, __func__);
414 } else if (MOID (p) == M_BOOL) {
415 A68_BOOL b;
416 A68_SP = 0;
417 push_unit (p);
418 POP_OBJECT (p, &b, A68_BOOL);
419 ASSERT (a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "%s", (VALUE (&b) ? "A68_TRUE" : "A68_FALSE")) >= 0);
420 undent (out, A68 (edit_line));
421 ABEND (A68_SP > 0, ERROR_INTERNAL_CONSISTENCY, __func__);
422 } else if (MOID (p) == M_CHAR) {
423 A68_CHAR c;
424 A68_SP = 0;
425 push_unit (p);
426 POP_OBJECT (p, &c, A68_CHAR);
427 if (VALUE (&c) == '\'') {
428 undentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "'\\\''"));
429 } else if (VALUE (&c) == '\\') {
430 undentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "'\\\\'"));
431 } else if (VALUE (&c) == NULL_CHAR) {
432 undentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "NULL_CHAR"));
433 } else if (IS_PRINT (VALUE (&c))) {
434 undentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "'%c'", (CHAR_T) VALUE (&c)));
435 } else {
436 undentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "(CHAR_T) %d", VALUE (&c)));
437 }
438 ABEND (A68_SP > 0, ERROR_INTERNAL_CONSISTENCY, __func__);
439 } else if (MOID (p) == M_BITS) {
440 A68_BITS b;
441 A68_SP = 0;
442 push_unit (p);
443 POP_OBJECT (p, &b, A68_BITS);
444 ASSERT (a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "(UNSIGNED_T) 0x" A68_LX, VALUE (&b)) >= 0);
445 undent (out, A68 (edit_line));
446 ABEND (A68_SP > 0, ERROR_INTERNAL_CONSISTENCY, __func__);
447 } else if (MOID (p) == M_COMPLEX) {
448 char acc[NAME_SIZE];
449 (void) make_name (acc, CON, "", NUMBER (p));
450 undentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "(A68_REAL *) %s", acc));
451 }
452 }
453 }
© 2002-2024 J.M. van der Veer (jmvdveer@xs4all.nl)
|