moids-to-string.c
1 //! @file moids-to-string.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-2023 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 //! Pretty-print a MOID.
25
26 #include "a68g.h"
27 #include "a68g-prelude.h"
28 #include "a68g-mp.h"
29 #include "a68g-genie.h"
30 #include "a68g-postulates.h"
31
32 // A pretty printer for moids.
33 // For example "PROC (REF STRUCT (REF SELF, UNION (INT, VOID))) REF SELF"
34 // for a procedure yielding a pointer to an object of its own mode.
35
36 void moid_to_string_2 (char *, MOID_T *, int *, NODE_T *);
37
38 //! @brief Add string to MOID text.
39
40 void add_to_moid_text (char *dst, char *str, int *w)
41 {
42 bufcat (dst, str, BUFFER_SIZE);
43 (*w) -= (int) strlen (str);
44 }
45
46 //! @brief Find a tag, searching symbol tables towards the root.
47
48 TAG_T *find_indicant_global (TABLE_T * table, MOID_T * mode)
49 {
50 if (table != NO_TABLE) {
51 TAG_T *s;
52 for (s = INDICANTS (table); s != NO_TAG; FORWARD (s)) {
53 if (MOID (s) == mode) {
54 return s;
55 }
56 }
57 return find_indicant_global (PREVIOUS (table), mode);
58 } else {
59 return NO_TAG;
60 }
61 }
62
63 //! @brief Pack to string.
64
65 void pack_to_string (char *b, PACK_T * p, int *w, BOOL_T text, NODE_T * idf)
66 {
67 for (; p != NO_PACK; FORWARD (p)) {
68 moid_to_string_2 (b, MOID (p), w, idf);
69 if (text) {
70 if (TEXT (p) != NO_TEXT) {
71 add_to_moid_text (b, " ", w);
72 add_to_moid_text (b, TEXT (p), w);
73 }
74 }
75 if (p != NO_PACK && NEXT (p) != NO_PACK) {
76 add_to_moid_text (b, ", ", w);
77 }
78 }
79 }
80
81 //! @brief Moid to string 2.
82
83 void moid_to_string_2 (char *b, MOID_T * n, int *w, NODE_T * idf)
84 {
85 // Oops. Should not happen.
86 if (n == NO_MOID) {
87 add_to_moid_text (b, "null", w);;
88 return;
89 }
90 // Reference to self through REF or PROC.
91 if (is_postulated (A68 (postulates), n)) {
92 add_to_moid_text (b, "SELF", w);
93 return;
94 }
95 // If declared by a mode-declaration, present the indicant.
96 if (idf != NO_NODE && !IS (n, STANDARD)) {
97 TAG_T *indy = find_indicant_global (TABLE (idf), n);
98 if (indy != NO_TAG) {
99 add_to_moid_text (b, NSYMBOL (NODE (indy)), w);
100 return;
101 }
102 }
103 // Write the standard modes.
104 if (n == M_HIP) {
105 add_to_moid_text (b, "HIP", w);
106 } else if (n == M_ERROR) {
107 add_to_moid_text (b, "ERROR", w);
108 } else if (n == M_UNDEFINED) {
109 add_to_moid_text (b, "unresolved mode", w);
110 } else if (n == M_C_STRING) {
111 add_to_moid_text (b, "C-STRING", w);
112 } else if (n == M_COMPLEX || n == M_COMPL) {
113 add_to_moid_text (b, "COMPLEX", w);
114 } else if (n == M_LONG_COMPLEX || n == M_LONG_COMPL) {
115 add_to_moid_text (b, "LONG COMPLEX", w);
116 } else if (n == M_LONG_LONG_COMPLEX || n == M_LONG_LONG_COMPL) {
117 add_to_moid_text (b, "LONG LONG COMPLEX", w);
118 } else if (n == M_STRING) {
119 add_to_moid_text (b, "STRING", w);
120 } else if (n == M_PIPE) {
121 add_to_moid_text (b, "PIPE", w);
122 } else if (n == M_SOUND) {
123 add_to_moid_text (b, "SOUND", w);
124 } else if (n == M_COLLITEM) {
125 add_to_moid_text (b, "COLLITEM", w);
126 } else if (IS (n, IN_TYPE_MODE)) {
127 add_to_moid_text (b, "\"SIMPLIN\"", w);
128 } else if (IS (n, OUT_TYPE_MODE)) {
129 add_to_moid_text (b, "\"SIMPLOUT\"", w);
130 } else if (IS (n, ROWS_SYMBOL)) {
131 add_to_moid_text (b, "\"ROWS\"", w);
132 } else if (n == M_VACUUM) {
133 add_to_moid_text (b, "\"VACUUM\"", w);
134 } else if (IS (n, VOID_SYMBOL) || IS (n, STANDARD) || IS (n, INDICANT)) {
135 if (DIM (n) > 0) {
136 int k = DIM (n);
137 if ((*w) >= k * (int) strlen ("LONG ") + (int) strlen (NSYMBOL (NODE (n)))) {
138 while (k--) {
139 add_to_moid_text (b, "LONG ", w);
140 }
141 add_to_moid_text (b, NSYMBOL (NODE (n)), w);
142 } else {
143 add_to_moid_text (b, "..", w);
144 }
145 } else if (DIM (n) < 0) {
146 int k = -DIM (n);
147 if ((*w) >= k * (int) strlen ("LONG ") + (int) strlen (NSYMBOL (NODE (n)))) {
148 while (k--) {
149 add_to_moid_text (b, "LONG ", w);
150 }
151 add_to_moid_text (b, NSYMBOL (NODE (n)), w);
152 } else {
153 add_to_moid_text (b, "..", w);
154 }
155 } else if (DIM (n) == 0) {
156 add_to_moid_text (b, NSYMBOL (NODE (n)), w);
157 }
158 // Write compounded modes.
159 } else if (IS_REF (n)) {
160 if ((*w) >= (int) strlen ("REF ..")) {
161 add_to_moid_text (b, "REF ", w);
162 moid_to_string_2 (b, SUB (n), w, idf);
163 } else {
164 add_to_moid_text (b, "REF ..", w);
165 }
166 } else if (IS_FLEX (n)) {
167 if ((*w) >= (int) strlen ("FLEX ..")) {
168 add_to_moid_text (b, "FLEX ", w);
169 moid_to_string_2 (b, SUB (n), w, idf);
170 } else {
171 add_to_moid_text (b, "FLEX ..", w);
172 }
173 } else if (IS_ROW (n)) {
174 int j = (int) strlen ("[] ..") + (DIM (n) - 1) * (int) strlen (",");
175 if ((*w) >= j) {
176 int k = DIM (n) - 1;
177 add_to_moid_text (b, "[", w);
178 while (k-- > 0) {
179 add_to_moid_text (b, ",", w);
180 }
181 add_to_moid_text (b, "] ", w);
182 moid_to_string_2 (b, SUB (n), w, idf);
183 } else if (DIM (n) == 1) {
184 add_to_moid_text (b, "[] ..", w);
185 } else {
186 int k = DIM (n);
187 add_to_moid_text (b, "[", w);
188 while (k--) {
189 add_to_moid_text (b, ",", w);
190 }
191 add_to_moid_text (b, "] ..", w);
192 }
193 } else if (IS_STRUCT (n)) {
194 int j = (int) strlen ("STRUCT ()") + (DIM (n) - 1) * (int) strlen (".., ") + (int) strlen ("..");
195 if ((*w) >= j) {
196 POSTULATE_T *save = A68 (postulates);
197 make_postulate (&A68 (postulates), n, NO_MOID);
198 add_to_moid_text (b, "STRUCT (", w);
199 pack_to_string (b, PACK (n), w, A68_TRUE, idf);
200 add_to_moid_text (b, ")", w);
201 free_postulate_list (A68 (postulates), save);
202 A68 (postulates) = save;
203 } else {
204 int k = DIM (n);
205 add_to_moid_text (b, "STRUCT (", w);
206 while (k-- > 0) {
207 add_to_moid_text (b, ",", w);
208 }
209 add_to_moid_text (b, ")", w);
210 }
211 } else if (IS_UNION (n)) {
212 int j = (int) strlen ("UNION ()") + (DIM (n) - 1) * (int) strlen (".., ") + (int) strlen ("..");
213 if ((*w) >= j) {
214 POSTULATE_T *save = A68 (postulates);
215 make_postulate (&A68 (postulates), n, NO_MOID);
216 add_to_moid_text (b, "UNION (", w);
217 pack_to_string (b, PACK (n), w, A68_FALSE, idf);
218 add_to_moid_text (b, ")", w);
219 free_postulate_list (A68 (postulates), save);
220 A68 (postulates) = save;
221 } else {
222 int k = DIM (n);
223 add_to_moid_text (b, "UNION (", w);
224 while (k-- > 0) {
225 add_to_moid_text (b, ",", w);
226 }
227 add_to_moid_text (b, ")", w);
228 }
229 } else if (IS (n, PROC_SYMBOL) && DIM (n) == 0) {
230 if ((*w) >= (int) strlen ("PROC ..")) {
231 add_to_moid_text (b, "PROC ", w);
232 moid_to_string_2 (b, SUB (n), w, idf);
233 } else {
234 add_to_moid_text (b, "PROC ..", w);
235 }
236 } else if (IS (n, PROC_SYMBOL) && DIM (n) > 0) {
237 int j = (int) strlen ("PROC () ..") + (DIM (n) - 1) * (int) strlen (".., ") + (int) strlen ("..");
238 if ((*w) >= j) {
239 POSTULATE_T *save = A68 (postulates);
240 make_postulate (&A68 (postulates), n, NO_MOID);
241 add_to_moid_text (b, "PROC (", w);
242 pack_to_string (b, PACK (n), w, A68_FALSE, idf);
243 add_to_moid_text (b, ") ", w);
244 moid_to_string_2 (b, SUB (n), w, idf);
245 free_postulate_list (A68 (postulates), save);
246 A68 (postulates) = save;
247 } else {
248 int k = DIM (n);
249 add_to_moid_text (b, "PROC (", w);
250 while (k-- > 0) {
251 add_to_moid_text (b, ",", w);
252 }
253 add_to_moid_text (b, ") ..", w);
254 }
255 } else if (IS (n, SERIES_MODE) || IS (n, STOWED_MODE)) {
256 int j = (int) strlen ("()") + (DIM (n) - 1) * (int) strlen (".., ") + (int) strlen ("..");
257 if ((*w) >= j) {
258 add_to_moid_text (b, "(", w);
259 pack_to_string (b, PACK (n), w, A68_FALSE, idf);
260 add_to_moid_text (b, ")", w);
261 } else {
262 int k = DIM (n);
263 add_to_moid_text (b, "(", w);
264 while (k-- > 0) {
265 add_to_moid_text (b, ",", w);
266 }
267 add_to_moid_text (b, ")", w);
268 }
269 } else {
270 char str[SMALL_BUFFER_SIZE];
271 ASSERT (snprintf (str, (size_t) SMALL_BUFFER_SIZE, "\\%d", ATTRIBUTE (n)) >= 0);
272 add_to_moid_text (b, str, w);
273 }
274 }
275
276 //! @brief Pretty-formatted mode "n"; "w" is a measure of width.
277
278 char *moid_to_string (MOID_T * n, int w, NODE_T * idf)
279 {
280 #define MAX_MTS 8
281 // We use a static buffer of MAX_MTS strings. This value 8 should be safe.
282 // No more than MAX_MTS calls can be pending in for instance printf.
283 // Instead we could allocate each string on the heap but that leaks memory.
284 static int mts_buff_ptr = 0;
285 static char mts_buff[8][BUFFER_SIZE];
286 char *a = &(mts_buff[mts_buff_ptr][0]);
287 mts_buff_ptr++;
288 if (mts_buff_ptr >= MAX_MTS) {
289 mts_buff_ptr = 0;
290 }
291 a[0] = NULL_CHAR;
292 if (w >= BUFFER_SIZE) {
293 w = BUFFER_SIZE - 1;
294 }
295 A68 (postulates) = NO_POSTULATE;
296 if (n != NO_MOID) {
297 moid_to_string_2 (a, n, &w, idf);
298 } else {
299 bufcat (a, "null", BUFFER_SIZE);
300 }
301 return a;
302 #undef MAX_MTS
303 }