rts-char.c
1 //! @file rts-char.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-2026 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 //! CHAR, STRING and BYTES routines.
25
26 #include "a68g.h"
27 #include "a68g-genie.h"
28 #include "a68g-prelude.h"
29 #include "a68g-transput.h"
30
31 // OP (CHAR, CHAR) BOOL.
32
33 #define A68G_CMP_CHAR(n, OP)\
34 void n (NODE_T * p) {\
35 A68G_CHAR i, j;\
36 POP_OBJECT (p, &j, A68G_CHAR);\
37 POP_OBJECT (p, &i, A68G_CHAR);\
38 PUSH_VALUE (p, (BOOL_T) (TO_UCHAR (VALUE (&i)) OP TO_UCHAR (VALUE (&j))), A68G_BOOL);\
39 }
40
41 A68G_CMP_CHAR (genie_eq_char, ==);
42 A68G_CMP_CHAR (genie_ne_char, !=);
43 A68G_CMP_CHAR (genie_lt_char, <);
44 A68G_CMP_CHAR (genie_gt_char, >);
45 A68G_CMP_CHAR (genie_le_char, <=);
46 A68G_CMP_CHAR (genie_ge_char, >=);
47
48 //! @brief OP ABS = (CHAR) INT
49
50 void genie_abs_char (NODE_T * p)
51 {
52 A68G_CHAR i;
53 POP_OBJECT (p, &i, A68G_CHAR);
54 PUSH_VALUE (p, TO_UCHAR (VALUE (&i)), A68G_INT);
55 }
56
57 //! @brief OP REPR = (INT) CHAR
58
59 void genie_repr_char (NODE_T * p)
60 {
61 A68G_INT k;
62 POP_OBJECT (p, &k, A68G_INT);
63 PRELUDE_ERROR (VALUE (&k) < 0 || VALUE (&k) > (int) UCHAR_MAX, p, ERROR_OUT_OF_BOUNDS, M_CHAR);
64 PUSH_VALUE (p, (char) (VALUE (&k)), A68G_CHAR);
65 }
66
67 // OP (CHAR) BOOL.
68
69 #define A68G_CHAR_BOOL(n, OP)\
70 void n (NODE_T * p) {\
71 A68G_CHAR ch;\
72 POP_OBJECT (p, &ch, A68G_CHAR);\
73 PUSH_VALUE (p, (BOOL_T) (OP (VALUE (&ch)) == 0 ? A68G_FALSE : A68G_TRUE), A68G_BOOL);\
74 }
75
76 A68G_CHAR_BOOL (genie_is_alnum, IS_ALNUM);
77 A68G_CHAR_BOOL (genie_is_alpha, IS_ALPHA);
78 A68G_CHAR_BOOL (genie_is_cntrl, IS_CNTRL);
79 A68G_CHAR_BOOL (genie_is_digit, IS_DIGIT);
80 A68G_CHAR_BOOL (genie_is_graph, IS_GRAPH);
81 A68G_CHAR_BOOL (genie_is_lower, IS_LOWER);
82 A68G_CHAR_BOOL (genie_is_print, IS_PRINT);
83 A68G_CHAR_BOOL (genie_is_punct, IS_PUNCT);
84 A68G_CHAR_BOOL (genie_is_space, IS_SPACE);
85 A68G_CHAR_BOOL (genie_is_upper, IS_UPPER);
86 A68G_CHAR_BOOL (genie_is_xdigit, IS_XDIGIT);
87
88 #define A68G_CHAR_CHAR(n, OP)\
89 void n (NODE_T * p) {\
90 A68G_CHAR *ch;\
91 POP_OPERAND_ADDRESS (p, ch, A68G_CHAR);\
92 VALUE (ch) = (char) (OP (TO_UCHAR (VALUE (ch))));\
93 }
94
95 A68G_CHAR_CHAR (genie_to_lower, TO_LOWER);
96 A68G_CHAR_CHAR (genie_to_upper, TO_UPPER);
97
98 // STRING in A68 is defined as MODE STRING = FLEX [] CHAR.
99 // Below routines appear complex since A68 can alias a STRING
100 // to either a row or column in a CHAR matrix. To mitigate,
101 // operations distinguish between common and generic cases.
102 // Most STRING values will be 'common', for instance not aliased.
103
104 //! @brief OP + = (CHAR, CHAR) STRING
105
106 void genie_add_char (NODE_T * p)
107 {
108 // Right operand.
109 A68G_CHAR b;
110 POP_OBJECT (p, &b, A68G_CHAR);
111 CHECK_INIT (p, INITIALISED (&b), M_CHAR);
112 // Left operand.
113 A68G_CHAR a;
114 POP_OBJECT (p, &a, A68G_CHAR);
115 CHECK_INIT (p, INITIALISED (&a), M_CHAR);
116 // Make sum array.
117 A68G_REF c = heap_generator (p, M_STRING, DESCRIPTOR_SIZE (1));
118 A68G_REF d = heap_generator_2 (p, M_STRING, 2, SIZE (M_CHAR));
119 A68G_ARRAY *arr_3; A68G_TUPLE *tup_3; BYTE_T *str_3;
120 GET_DESCRIPTOR (arr_3, tup_3, &c);
121 DIM (arr_3) = 1;
122 SLICE (arr_3) = M_CHAR;
123 SLICE_SIZE (arr_3) = SIZE (M_CHAR);
124 SLICE_OFFSET (arr_3) = 0;
125 FIELD_OFFSET (arr_3) = 0;
126 ARRAY (arr_3) = d;
127 LWB (tup_3) = 1;
128 UPB (tup_3) = 2;
129 SHIFT (tup_3) = LWB (tup_3);
130 SPAN (tup_3) = 1;
131 // Add chars.
132 str_3 = DEREF (BYTE_T, &ARRAY (arr_3));
133 MOVE ((BYTE_T *) & str_3[0], (BYTE_T *) & a, SIZE (M_CHAR));
134 MOVE ((BYTE_T *) & str_3[SIZE (M_CHAR)], (BYTE_T *) & b, SIZE (M_CHAR));
135 PUSH_REF (p, c);
136 }
137
138 //! @brief OP ELEM = (INT, STRING) CHAR # ALGOL68C #
139
140 void genie_elem_string (NODE_T * p)
141 {
142 A68G_REF z;
143 POP_REF (p, &z);
144 CHECK_REF (p, z, M_STRING);
145 A68G_INT k;
146 POP_OBJECT (p, &k, A68G_INT);
147 A68G_ARRAY *arr; A68G_TUPLE *tup;
148 GET_DESCRIPTOR (arr, tup, &z);
149 PRELUDE_ERROR (VALUE (&k) < LWB (tup), p, ERROR_INDEX_OUT_OF_BOUNDS, NO_TEXT);
150 PRELUDE_ERROR (VALUE (&k) > UPB (tup), p, ERROR_INDEX_OUT_OF_BOUNDS, NO_TEXT);
151 BYTE_T *str = DEREF (BYTE_T, &(ARRAY (arr)));
152 A68G_CHAR *ch = (A68G_CHAR *) & (str[INDEX_1_DIM (arr, tup, VALUE (&k))]);
153 PUSH_VALUE (p, VALUE (ch), A68G_CHAR);
154 }
155
156 //! @brief OP + = (STRING, STRING) STRING
157
158 void genie_add_string (NODE_T * p)
159 {
160 const size_t size_char = SIZE (M_CHAR);
161 // Right operand.
162 A68G_REF b;
163 POP_REF (p, &b);
164 CHECK_INIT (p, INITIALISED (&b), M_STRING);
165 A68G_ARRAY *arr_2; A68G_TUPLE *tup_2;
166 GET_DESCRIPTOR (arr_2, tup_2, &b);
167 int l_2 = ROW_SIZE (tup_2);
168 // Left operand.
169 A68G_REF a;
170 POP_REF (p, &a);
171 CHECK_REF (p, a, M_STRING);
172 A68G_ARRAY *arr_1; A68G_TUPLE *tup_1;
173 GET_DESCRIPTOR (arr_1, tup_1, &a);
174 int l_1 = ROW_SIZE (tup_1);
175 // Make sum array.
176 A68G_REF ref_s = heap_generator (p, M_STRING, DESCRIPTOR_SIZE (1));
177 A68G_REF new_s = heap_generator_2 (p, M_STRING, l_1 + l_2, size_char);
178 // Recompute since garbage collection might have moved data.
179 GET_DESCRIPTOR (arr_1, tup_1, &a);
180 GET_DESCRIPTOR (arr_2, tup_2, &b);
181 A68G_ARRAY *arr_3; A68G_TUPLE *tup_3;
182 GET_DESCRIPTOR (arr_3, tup_3, &ref_s);
183 DIM (arr_3) = 1;
184 SLICE (arr_3) = M_CHAR;
185 SLICE_SIZE (arr_3) = size_char;
186 SLICE_OFFSET (arr_3) = 0;
187 FIELD_OFFSET (arr_3) = 0;
188 ARRAY (arr_3) = new_s;
189 LWB (tup_3) = 1;
190 UPB (tup_3) = l_1 + l_2;
191 SHIFT (tup_3) = LWB (tup_3);
192 SPAN (tup_3) = 1;
193 // Add strings.
194 BYTE_T *sum = DEREF (BYTE_T, &ARRAY (arr_3));
195 size_t m = 0;
196 if (ROW_SIZE (tup_1) > 0) {
197 if (SPAN (tup_1) == 1) {
198 // Common case.
199 size_t n_1 = l_1 * size_char;
200 BYTE_T *s_1 = DEREF (BYTE_T, &ARRAY (arr_1));
201 MOVE (sum, & s_1[INDEX_1_DIM (arr_1, tup_1, LWB (tup_1))], n_1);
202 m = n_1;
203 } else {
204 // Generic case.
205 BYTE_T *s_1 = DEREF (BYTE_T, &ARRAY (arr_1));
206 m = 0;
207 for (INT_T k = LWB (tup_1); k <= UPB (tup_1); k++) {
208 MOVE ((BYTE_T *) & sum[m], (BYTE_T *) & s_1[INDEX_1_DIM (arr_1, tup_1, k)], size_char);
209 m += size_char;
210 }
211 }
212 }
213 if (ROW_SIZE (tup_2) > 0) {
214 if (SPAN (tup_2) == 1) {
215 // Common case.
216 size_t n_2 = l_2 * size_char;
217 BYTE_T *s_2 = DEREF (BYTE_T, &ARRAY (arr_2));
218 MOVE (& sum[m], & s_2[INDEX_1_DIM (arr_2, tup_2, LWB (tup_2))], n_2);
219 } else {
220 // Generic case.
221 BYTE_T *s_2 = DEREF (BYTE_T, &ARRAY (arr_2));
222 for (INT_T k = LWB (tup_2); k <= UPB (tup_2); k++) {
223 MOVE ((BYTE_T *) & sum[m], (BYTE_T *) & s_2[INDEX_1_DIM (arr_2, tup_2, k)], size_char);
224 m += size_char;
225 }
226 }
227 }
228 PUSH_REF (p, ref_s);
229 }
230
231 //! @brief OP * = (INT, STRING) STRING
232
233 void genie_times_int_string (NODE_T * p)
234 {
235 A68G_REF a;
236 POP_REF (p, &a);
237 A68G_INT k;
238 POP_OBJECT (p, &k, A68G_INT);
239 PRELUDE_ERROR (VALUE (&k) < 0, p, ERROR_INVALID_ARGUMENT, M_INT);
240 CHECK_INT_SHORTEN (p, VALUE (&k));
241 PUSH_REF (p, empty_string (p));
242 while (VALUE (&k)--) {
243 PUSH_REF (p, a);
244 genie_add_string (p);
245 }
246 }
247
248 //! @brief OP * = (STRING, INT) STRING
249
250 void genie_times_string_int (NODE_T * p)
251 {
252 A68G_INT k;
253 POP_OBJECT (p, &k, A68G_INT);
254 A68G_REF a;
255 POP_REF (p, &a);
256 PUSH_VALUE (p, VALUE (&k), A68G_INT);
257 PUSH_REF (p, a);
258 genie_times_int_string (p);
259 }
260
261 //! @brief OP * = (INT, CHAR) STRING
262
263 void genie_times_int_char (NODE_T * p)
264 {
265 // Pop operands.
266 A68G_CHAR a;
267 POP_OBJECT (p, &a, A68G_CHAR);
268 A68G_INT s_size;
269 POP_OBJECT (p, &s_size, A68G_INT);
270 PRELUDE_ERROR (VALUE (&s_size) < 0, p, ERROR_INVALID_ARGUMENT, M_INT);
271 CHECK_INT_SHORTEN (p, VALUE (&s_size));
272 // Make new string.
273 A68G_REF z, row; A68G_ARRAY arr; A68G_TUPLE tup;
274 NEW_ROW_1D (z, row, arr, tup, M_ROW_CHAR, M_CHAR, (int) (VALUE (&s_size)));
275 BYTE_T *s = ADDRESS (&row);
276 size_t m = 0;
277 for (INT_T k = 0; k < VALUE (&s_size); k++) {
278 A68G_CHAR ch;
279 STATUS (&ch) = INIT_MASK;
280 VALUE (&ch) = VALUE (&a);
281 *(A68G_CHAR *) & s[m] = ch;
282 m += SIZE (M_CHAR);
283 }
284 PUSH_REF (p, z);
285 }
286
287 //! @brief OP * = (CHAR, INT) STRING
288
289 void genie_times_char_int (NODE_T * p)
290 {
291 A68G_INT k;
292 POP_OBJECT (p, &k, A68G_INT);
293 A68G_CHAR a;
294 POP_OBJECT (p, &a, A68G_CHAR);
295 PUSH_VALUE (p, VALUE (&k), A68G_INT);
296 PUSH_VALUE (p, VALUE (&a), A68G_CHAR);
297 genie_times_int_char (p);
298 }
299
300 //! @brief OP +:= = (REF STRING, STRING) REF STRING
301
302 void genie_plusab_string (NODE_T * p)
303 {
304 genie_f_and_becomes (p, M_REF_STRING, genie_add_string);
305 }
306
307 //! @brief OP +=: = (STRING, REF STRING) REF STRING
308
309 void genie_plusto_string (NODE_T * p)
310 {
311 A68G_REF ref_a;
312 POP_REF (p, &ref_a);
313 CHECK_REF (p, ref_a, M_REF_STRING);
314 A68G_REF a = *DEREF (A68G_REF, &ref_a);
315 CHECK_INIT (p, INITIALISED (&a), M_STRING);
316 A68G_REF ref_b;
317 POP_REF (p, &ref_b);
318 PUSH_REF (p, ref_b);
319 PUSH_REF (p, a);
320 genie_add_string (p);
321 POP_REF (p, DEREF (A68G_REF, &ref_a));
322 PUSH_REF (p, ref_a);
323 }
324
325 //! @brief OP *:= = (REF STRING, INT) REF STRING
326
327 void genie_timesab_string (NODE_T * p)
328 {
329 A68G_INT k;
330 POP_OBJECT (p, &k, A68G_INT);
331 PRELUDE_ERROR (VALUE (&k) < 0, p, ERROR_INVALID_ARGUMENT, M_INT);
332 A68G_REF ref;
333 POP_REF (p, &ref);
334 CHECK_REF (p, ref, M_REF_STRING);
335 A68G_REF a = *DEREF (A68G_REF, &ref);
336 CHECK_INIT (p, INITIALISED (&a), M_STRING);
337 // Multiplication as repeated addition cf. RR.
338 PUSH_REF (p, empty_string (p));
339 for (INT_T i = 1; i <= VALUE (&k); i++) {
340 PUSH_REF (p, a);
341 genie_add_string (p);
342 }
343 // The stack contains a STRING, promote to REF STRING.
344 POP_REF (p, DEREF (A68G_REF, &ref));
345 PUSH_REF (p, ref);
346 }
347
348 //! @brief Difference between two STRINGs in the stack.
349
350 int string_diff (NODE_T * p)
351 {
352 // Pop operands.
353 A68G_REF row2;
354 POP_REF (p, &row2);
355 CHECK_INIT (p, INITIALISED (&row2), M_STRING);
356 A68G_ARRAY *arr_2; A68G_TUPLE *tup_2;
357 GET_DESCRIPTOR (arr_2, tup_2, &row2);
358 int len_2 = ROW_SIZE (tup_2);
359 A68G_REF row1;
360 POP_REF (p, &row1);
361 CHECK_INIT (p, INITIALISED (&row1), M_STRING);
362 A68G_ARRAY *arr_1; A68G_TUPLE *tup_1;
363 GET_DESCRIPTOR (arr_1, tup_1, &row1);
364 int len_1 = ROW_SIZE (tup_1);
365 // Compute string diference.
366 int dif = 0;
367 size_t size = (len_1 > len_2 ? len_1 : len_2);
368 BYTE_T *s_1 = (len_1 > 0 ? DEREF (BYTE_T, &ARRAY (arr_1)) : NO_BYTE);
369 BYTE_T *s_2 = (len_2 > 0 ? DEREF (BYTE_T, &ARRAY (arr_2)) : NO_BYTE);
370 INT_T m_1 = INDEX_1_DIM (arr_1, tup_1, LWB (tup_1));
371 INT_T m_2 = INDEX_1_DIM (arr_2, tup_2, LWB (tup_2));
372 INT_T m = 0;
373 if (SPAN (tup_1) == 1 && SPAN (tup_2) == 1) {
374 // Common case.
375 for (INT_T k = 0; k < size && dif == 0; k++) {
376 int a = 0, b = 0;
377 if (len_1 > 0 && k < len_1) {
378 A68G_CHAR *ch = (A68G_CHAR *) & s_1[m_1 + m];
379 a = (int) VALUE (ch);
380 }
381 if (len_2 > 0 && k < len_2) {
382 A68G_CHAR *ch = (A68G_CHAR *) & s_2[m_2 + m];
383 b = (int) VALUE (ch);
384 }
385 m += SIZE (M_CHAR);
386 dif = (TO_UCHAR (a) - TO_UCHAR (b));
387 }
388 } else {
389 // Generic case.
390 for (INT_T k = 0; k < size && dif == 0; k++) {
391 int a = 0, b = 0;
392 if (len_1 > 0 && k < len_1) {
393 A68G_CHAR *ch = (A68G_CHAR *) & s_1[m_1 + m];
394 a = (int) VALUE (ch);
395 }
396 if (len_2 > 0 && k < len_2) {
397 A68G_CHAR *ch = (A68G_CHAR *) & s_2[m_2 + m];
398 b = (int) VALUE (ch);
399 }
400 m += SIZE (M_CHAR);
401 dif = (TO_UCHAR (a) - TO_UCHAR (b));
402 }
403 }
404 return dif;
405 }
406
407 // OP (STRING, STRING) BOOL.
408
409 #define A68G_CMP_STRING(n, OP)\
410 void n (NODE_T * p) {\
411 int k = string_diff (p);\
412 PUSH_VALUE (p, (BOOL_T) (k OP 0), A68G_BOOL);\
413 }
414
415 A68G_CMP_STRING (genie_eq_string, ==);
416 A68G_CMP_STRING (genie_ne_string, !=);
417 A68G_CMP_STRING (genie_lt_string, <);
418 A68G_CMP_STRING (genie_gt_string, >);
419 A68G_CMP_STRING (genie_le_string, <=);
420 A68G_CMP_STRING (genie_ge_string, >=);
421
422 //! @brief PROC char in string = (CHAR, REF INT, STRING) BOOL
423
424 void genie_char_in_string (NODE_T * p)
425 {
426 A68G_REF ref_str;
427 POP_REF (p, &ref_str);
428 A68G_ROW row = *(A68G_REF *) &ref_str;
429 CHECK_INIT (p, INITIALISED (&row), M_ROWS);
430 A68G_ARRAY *arr; A68G_TUPLE *tup;
431 GET_DESCRIPTOR (arr, tup, &row);
432 A68G_REF ref_pos;
433 POP_REF (p, &ref_pos);
434 A68G_CHAR c;
435 POP_OBJECT (p, &c, A68G_CHAR);
436 reset_transput_buffer (PATTERN_BUFFER);
437 add_a_string_transput_buffer (p, PATTERN_BUFFER, (BYTE_T *) & ref_str);
438 int len = get_transput_buffer_index (PATTERN_BUFFER);
439 char *q = get_transput_buffer (PATTERN_BUFFER);
440 char ch = (char) VALUE (&c);
441 for (INT_T k = 0; k < len; k++) {
442 if (q[k] == ch) {
443 A68G_INT pos;
444 STATUS (&pos) = INIT_MASK;
445 VALUE (&pos) = k + LOWER_BOUND (tup);
446 *DEREF (A68G_INT, &ref_pos) = pos;
447 PUSH_VALUE (p, A68G_TRUE, A68G_BOOL);
448 return;
449 }
450 }
451 PUSH_VALUE (p, A68G_FALSE, A68G_BOOL);
452 }
453
454 //! @brief PROC last char in string = (CHAR, REF INT, STRING) BOOL
455
456 void genie_last_char_in_string (NODE_T * p)
457 {
458 A68G_REF ref_str;
459 POP_REF (p, &ref_str);
460 A68G_ROW row = *(A68G_REF *) &ref_str;
461 CHECK_INIT (p, INITIALISED (&row), M_ROWS);
462 A68G_ARRAY *arr; A68G_TUPLE *tup;
463 GET_DESCRIPTOR (arr, tup, &row);
464 A68G_REF ref_pos;
465 POP_REF (p, &ref_pos);
466 A68G_CHAR c;
467 POP_OBJECT (p, &c, A68G_CHAR);
468 reset_transput_buffer (PATTERN_BUFFER);
469 add_a_string_transput_buffer (p, PATTERN_BUFFER, (BYTE_T *) & ref_str);
470 int len = get_transput_buffer_index (PATTERN_BUFFER);
471 char *q = get_transput_buffer (PATTERN_BUFFER);
472 char ch = (char) VALUE (&c);
473 for (INT_T k = len - 1; k >= 0; k--) {
474 if (q[k] == ch) {
475 A68G_INT pos;
476 STATUS (&pos) = INIT_MASK;
477 VALUE (&pos) = k + LOWER_BOUND (tup);
478 *DEREF (A68G_INT, &ref_pos) = pos;
479 PUSH_VALUE (p, A68G_TRUE, A68G_BOOL);
480 return;
481 }
482 }
483 PUSH_VALUE (p, A68G_FALSE, A68G_BOOL);
484 }
485
486 //! @brief PROC string in string = (STRING, REF INT, STRING) BOOL
487
488 void genie_string_in_string (NODE_T * p)
489 {
490 A68G_REF ref_str;
491 POP_REF (p, &ref_str);
492 A68G_ROW row = *(A68G_REF *) &ref_str;
493 CHECK_INIT (p, INITIALISED (&row), M_ROWS);
494 A68G_ARRAY *arr; A68G_TUPLE *tup;
495 GET_DESCRIPTOR (arr, tup, &row);
496 A68G_REF ref_pos;
497 POP_REF (p, &ref_pos);
498 A68G_REF ref_pat;
499 POP_REF (p, &ref_pat);
500 reset_transput_buffer (PATTERN_BUFFER);
501 reset_transput_buffer (STRING_BUFFER);
502 add_a_string_transput_buffer (p, PATTERN_BUFFER, (BYTE_T *) & ref_pat);
503 add_a_string_transput_buffer (p, STRING_BUFFER, (BYTE_T *) & ref_str);
504 char *q = strstr (get_transput_buffer (STRING_BUFFER), get_transput_buffer (PATTERN_BUFFER));
505 if (q != NO_TEXT) {
506 if (!IS_NIL (ref_pos)) {
507 A68G_INT pos;
508 STATUS (&pos) = INIT_MASK;
509 // ANSI standard leaves pointer difference undefined.
510 VALUE (&pos) = LOWER_BOUND (tup) + (int) get_transput_buffer_index (STRING_BUFFER) - strlen (q);
511 *DEREF (A68G_INT, &ref_pos) = pos;
512 }
513 PUSH_VALUE (p, A68G_TRUE, A68G_BOOL);
514 } else {
515 PUSH_VALUE (p, A68G_FALSE, A68G_BOOL);
516 }
517 }
518
519 // [LONG] BYTES are A68's implementation of fixed-length strings.
520 // Compare to vintage FORTRAN where an INTEGER value held 4 characters,
521 // In A68G, a [LONG] BYTES value is a fixed-length array of characters,
522 // like PASCAL's PACKED ARRAY OF CHAR.
523
524 //! @brief OP ELEM = (INT, BYTES) CHAR
525
526 void genie_elem_bytes (NODE_T * p)
527 {
528 A68G_BYTES j;
529 POP_OBJECT (p, &j, A68G_BYTES);
530 A68G_INT i;
531 POP_OBJECT (p, &i, A68G_INT);
532 PRELUDE_ERROR (VALUE (&i) < 1 || VALUE (&i) > A68G_BYTES_WIDTH, p, ERROR_OUT_OF_BOUNDS, M_INT);
533 if (VALUE (&i) > strlen (VALUE (&j))) {
534 genie_null_char (p);
535 } else {
536 PUSH_VALUE (p, VALUE (&j)[VALUE (&i) - 1], A68G_CHAR);
537 }
538 }
539
540 //! @brief PROC bytes pack = (STRING) BYTES
541
542 void genie_bytespack (NODE_T * p)
543 {
544 A68G_REF z;
545 POP_REF (p, &z);
546 CHECK_REF (p, z, M_STRING);
547 PRELUDE_ERROR (a68g_string_size (p, z) > A68G_BYTES_WIDTH, p, ERROR_OUT_OF_BOUNDS, M_STRING);
548 A68G_BYTES b;
549 STATUS (&b) = INIT_MASK;
550 ASSERT (a_to_c_string (p, VALUE (&b), z) != NO_TEXT);
551 PUSH_BYTES (p, VALUE (&b));
552 }
553
554 //! @brief PROC bytes pack = (STRING) BYTES
555
556 void genie_add_bytes (NODE_T * p)
557 {
558 A68G_BYTES *i, *j;
559 POP_OPERAND_ADDRESSES (p, i, j, A68G_BYTES);
560 PRELUDE_ERROR ((strlen (VALUE (i)) + strlen (VALUE (j))) > A68G_BYTES_WIDTH, p, ERROR_OUT_OF_BOUNDS, M_BYTES);
561 a68g_bufcat (VALUE (i), VALUE (j), A68G_BYTES_WIDTH);
562 }
563
564 //! @brief OP +:= = (REF BYTES, BYTES) REF BYTES
565
566 void genie_plusab_bytes (NODE_T * p)
567 {
568 genie_f_and_becomes (p, M_REF_BYTES, genie_add_bytes);
569 }
570
571 //! @brief OP +=: = (BYTES, REF BYTES) REF BYTES
572
573 void genie_plusto_bytes (NODE_T * p)
574 {
575 A68G_REF z;
576 POP_REF (p, &z);
577 CHECK_REF (p, z, M_REF_BYTES);
578 A68G_BYTES *address = DEREF (A68G_BYTES, &z);
579 CHECK_INIT (p, INITIALISED (address), M_BYTES);
580 A68G_BYTES i;
581 POP_OBJECT (p, &i, A68G_BYTES);
582 PRELUDE_ERROR ((strlen (VALUE (address)) + strlen (VALUE (&i))) > A68G_BYTES_WIDTH, p, ERROR_OUT_OF_BOUNDS, M_BYTES);
583 A68G_BYTES j;
584 a68g_bufcpy (VALUE (&j), VALUE (&i), A68G_BYTES_WIDTH);
585 a68g_bufcat (VALUE (&j), VALUE (address), A68G_BYTES_WIDTH);
586 a68g_bufcpy (VALUE (address), VALUE (&j), A68G_BYTES_WIDTH);
587 PUSH_REF (p, z);
588 }
589
590 //! @brief Difference between BYTE strings.
591
592 int compare_bytes (NODE_T * p)
593 {
594 A68G_BYTES y;
595 POP_OBJECT (p, &y, A68G_BYTES);
596 A68G_BYTES x;
597 POP_OBJECT (p, &x, A68G_BYTES);
598 return strcmp (VALUE (&x), VALUE (&y));
599 }
600
601 // OP (BYTES, BYTES) BOOL.
602
603 #define A68G_CMP_BYTES(n, OP)\
604 void n (NODE_T * p) {\
605 int k = compare_bytes (p);\
606 PUSH_VALUE (p, (BOOL_T) (k OP 0), A68G_BOOL);\
607 }
608
609 A68G_CMP_BYTES (genie_eq_bytes, ==);
610 A68G_CMP_BYTES (genie_ne_bytes, !=);
611 A68G_CMP_BYTES (genie_lt_bytes, <);
612 A68G_CMP_BYTES (genie_gt_bytes, >);
613 A68G_CMP_BYTES (genie_le_bytes, <=);
614 A68G_CMP_BYTES (genie_ge_bytes, >=);
615
616 //! @brief OP LENG = (BYTES) LONG BYTES
617
618 void genie_leng_bytes (NODE_T * p)
619 {
620 A68G_LONG_BYTES a;
621 a68g_bufset (VALUE (&a), 0, sizeof (VALUE (&a)));
622 POP_OBJECT (p, (A68G_BYTES *) &a, A68G_BYTES);
623 PUSH_LONG_BYTES (p, VALUE (&a));
624 }
625
626 //! @brief OP SHORTEN = (LONG BYTES) BYTES
627
628 void genie_shorten_bytes (NODE_T * p)
629 {
630 A68G_LONG_BYTES a;
631 POP_OBJECT (p, &a, A68G_LONG_BYTES);
632 PRELUDE_ERROR (strlen (VALUE (&a)) >= A68G_BYTES_WIDTH, p, ERROR_OUT_OF_BOUNDS, M_BYTES);
633 PUSH_BYTES (p, VALUE (&a));
634 }
635
636 //! @brief OP ELEM = (INT, LONG BYTES) CHAR
637
638 void genie_elem_long_bytes (NODE_T * p)
639 {
640 A68G_LONG_BYTES j;
641 POP_OBJECT (p, &j, A68G_LONG_BYTES);
642 A68G_INT i;
643 POP_OBJECT (p, &i, A68G_INT);
644 PRELUDE_ERROR (VALUE (&i) < 1 || VALUE (&i) > A68G_LONG_BYTES_WIDTH, p, ERROR_OUT_OF_BOUNDS, M_INT);
645 if (VALUE (&i) > strlen (VALUE (&j))) {
646 genie_null_char (p);
647 } else {
648 PUSH_VALUE (p, VALUE (&j)[VALUE (&i) - 1], A68G_CHAR);
649 }
650 }
651
652 //! @brief PROC long bytes pack = (STRING) LONG BYTES
653
654 void genie_long_bytespack (NODE_T * p)
655 {
656 A68G_REF z;
657 POP_REF (p, &z);
658 CHECK_REF (p, z, M_STRING);
659 PRELUDE_ERROR (a68g_string_size (p, z) > A68G_LONG_BYTES_WIDTH, p, ERROR_OUT_OF_BOUNDS, M_STRING);
660 A68G_LONG_BYTES b;
661 STATUS (&b) = INIT_MASK;
662 ASSERT (a_to_c_string (p, VALUE (&b), z) != NO_TEXT);
663 PUSH_LONG_BYTES (p, VALUE (&b));
664 }
665
666 //! @brief OP + = (LONG BYTES, LONG BYTES) LONG BYTES
667
668 void genie_add_long_bytes (NODE_T * p)
669 {
670 A68G_LONG_BYTES *i, *j;
671 POP_OPERAND_ADDRESSES (p, i, j, A68G_LONG_BYTES);
672 PRELUDE_ERROR ((strlen (VALUE (i)) + strlen (VALUE (j))) > A68G_LONG_BYTES_WIDTH, p, ERROR_OUT_OF_BOUNDS, M_LONG_BYTES);
673 a68g_bufcat (VALUE (i), VALUE (j), A68G_LONG_BYTES_WIDTH);
674 }
675
676 //! @brief OP +:= = (REF LONG BYTES, LONG BYTES) REF LONG BYTES
677
678 void genie_plusab_long_bytes (NODE_T * p)
679 {
680 genie_f_and_becomes (p, M_REF_LONG_BYTES, genie_add_long_bytes);
681 }
682
683 //! @brief OP +=: = (LONG BYTES, REF LONG BYTES) REF LONG BYTES
684
685 void genie_plusto_long_bytes (NODE_T * p)
686 {
687 A68G_REF z;
688 POP_REF (p, &z);
689 CHECK_REF (p, z, M_REF_LONG_BYTES);
690 A68G_LONG_BYTES *address = DEREF (A68G_LONG_BYTES, &z);
691 CHECK_INIT (p, INITIALISED (address), M_LONG_BYTES);
692 A68G_LONG_BYTES i;
693 POP_OBJECT (p, &i, A68G_LONG_BYTES);
694 PRELUDE_ERROR ((strlen (VALUE (address)) + strlen (VALUE (&i))) > A68G_LONG_BYTES_WIDTH, p, ERROR_OUT_OF_BOUNDS, M_LONG_BYTES);
695 A68G_LONG_BYTES j;
696 a68g_bufcpy (VALUE (&j), VALUE (&i), A68G_LONG_BYTES_WIDTH);
697 a68g_bufcat (VALUE (&j), VALUE (address), A68G_LONG_BYTES_WIDTH);
698 a68g_bufcpy (VALUE (address), VALUE (&j), A68G_LONG_BYTES_WIDTH);
699 PUSH_REF (p, z);
700 }
701
702 //! @brief Difference between LONG BYTE strings.
703
704 int compare_long_bytes (NODE_T * p)
705 {
706 A68G_LONG_BYTES y;
707 POP_OBJECT (p, &y, A68G_LONG_BYTES);
708 A68G_LONG_BYTES x;
709 POP_OBJECT (p, &x, A68G_LONG_BYTES);
710 return strcmp (VALUE (&x), VALUE (&y));
711 }
712
713 // OP (LONG BYTES, LONG BYTES) BOOL.
714
715 #define A68G_CMP_LONG_BYTES(n, OP)\
716 void n (NODE_T * p) {\
717 int k = compare_long_bytes (p);\
718 PUSH_VALUE (p, (BOOL_T) (k OP 0), A68G_BOOL);\
719 }
720
721 A68G_CMP_LONG_BYTES (genie_eq_long_bytes, ==);
722 A68G_CMP_LONG_BYTES (genie_ne_long_bytes, !=);
723 A68G_CMP_LONG_BYTES (genie_lt_long_bytes, <);
724 A68G_CMP_LONG_BYTES (genie_gt_long_bytes, >);
725 A68G_CMP_LONG_BYTES (genie_le_long_bytes, <=);
726 A68G_CMP_LONG_BYTES (genie_ge_long_bytes, >=);
727
|
© 2002-2026 J.M. van der Veer (jmvdveer@xs4all.nl)
|