parser-top-down.c
1 //! @file parser-top-down.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 //! Top-down parser for control structure.
25
26 #include "a68g.h"
27 #include "a68g-parser.h"
28
29 // Top-down parser, elaborates the control structure.
30
31 //! @brief Substitute brackets.
32
33 void substitute_brackets (NODE_T * p)
34 {
35 for (; p != NO_NODE; FORWARD (p)) {
36 substitute_brackets (SUB (p));
37 switch (ATTRIBUTE (p)) {
38 case ACCO_SYMBOL: {
39 ATTRIBUTE (p) = OPEN_SYMBOL;
40 break;
41 }
42 case OCCA_SYMBOL: {
43 ATTRIBUTE (p) = CLOSE_SYMBOL;
44 break;
45 }
46 case SUB_SYMBOL: {
47 ATTRIBUTE (p) = OPEN_SYMBOL;
48 break;
49 }
50 case BUS_SYMBOL: {
51 ATTRIBUTE (p) = CLOSE_SYMBOL;
52 break;
53 }
54 }
55 }
56 }
57
58 //! @brief Intelligible diagnostic from syntax tree branch.
59
60 char *phrase_to_text (NODE_T * p, NODE_T ** w)
61 {
62 #define MAX_TERMINALS 8
63 int count = 0, line = -1;
64 static BUFFER buffer;
65 for (buffer[0] = NULL_CHAR; p != NO_NODE && count < MAX_TERMINALS; FORWARD (p)) {
66 if (LINE_NUMBER (p) > 0) {
67 int gatt = get_good_attribute (p);
68 char *z = non_terminal_string (A68 (input_line), gatt);
69 // Where to put the error message? Bob Uzgalis noted that actual content of a
70 // diagnostic is not as important as accurately indicating *were* the problem is!
71 if (w != NO_VAR) {
72 if (count == 0 || (*w) == NO_NODE) {
73 *w = p;
74 } else if (dont_mark_here (*w)) {
75 *w = p;
76 }
77 }
78 // Add initiation.
79 if (count == 0) {
80 if (w != NO_VAR) {
81 a68_bufcat (buffer, "construct beginning with", BUFFER_SIZE);
82 }
83 } else if (count == 1) {
84 a68_bufcat (buffer, " followed by", BUFFER_SIZE);
85 } else if (count == 2) {
86 a68_bufcat (buffer, " and then", BUFFER_SIZE);
87 } else if (count >= 3) {
88 a68_bufcat (buffer, " and", BUFFER_SIZE);
89 }
90 // Attribute or symbol.
91 if (z != NO_TEXT && SUB (p) != NO_NODE) {
92 if (gatt == IDENTIFIER || gatt == OPERATOR || gatt == DENOTATION) {
93 ASSERT (a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, " \"%s\"", NSYMBOL (p)) >= 0);
94 a68_bufcat (buffer, A68 (edit_line), BUFFER_SIZE);
95 } else {
96 if (strchr ("aeio", z[0]) != NO_TEXT) {
97 a68_bufcat (buffer, " an", BUFFER_SIZE);
98 } else {
99 a68_bufcat (buffer, " a", BUFFER_SIZE);
100 }
101 ASSERT (a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, " %s", z) >= 0);
102 a68_bufcat (buffer, A68 (edit_line), BUFFER_SIZE);
103 }
104 } else if (z != NO_TEXT && SUB (p) == NO_NODE) {
105 ASSERT (a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, " \"%s\"", NSYMBOL (p)) >= 0);
106 a68_bufcat (buffer, A68 (edit_line), BUFFER_SIZE);
107 } else if (NSYMBOL (p) != NO_TEXT) {
108 ASSERT (a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, " \"%s\"", NSYMBOL (p)) >= 0);
109 a68_bufcat (buffer, A68 (edit_line), BUFFER_SIZE);
110 }
111 // Add "starting in line nn".
112 if (z != NO_TEXT && line != LINE_NUMBER (p)) {
113 line = LINE_NUMBER (p);
114 if (gatt == SERIAL_CLAUSE || gatt == ENQUIRY_CLAUSE || gatt == INITIALISER_SERIES) {
115 a68_bufcat (buffer, " starting", BUFFER_SIZE);
116 }
117 ASSERT (a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, " in line %d", line) >= 0);
118 a68_bufcat (buffer, A68 (edit_line), BUFFER_SIZE);
119 }
120 count++;
121 }
122 }
123 if (p != NO_NODE && count == MAX_TERMINALS) {
124 a68_bufcat (buffer, " etcetera", BUFFER_SIZE);
125 }
126 return buffer;
127 }
128
129 // Next is a top-down parser that branches out the basic blocks.
130 // After this we can assign symbol tables to basic blocks.
131 // This renders the two-level grammar LALR.
132
133 //! @brief Give diagnose from top-down parser.
134
135 void top_down_diagnose (NODE_T * start, NODE_T * p, int clause, int expected)
136 {
137 NODE_T *issue = (p != NO_NODE ? p : start);
138 if (expected != 0) {
139 diagnostic (A68_SYNTAX_ERROR, issue, ERROR_EXPECTED_NEAR, expected, clause, NSYMBOL (start), LINE (INFO (start)));
140 } else {
141 diagnostic (A68_SYNTAX_ERROR, issue, ERROR_UNBALANCED_KEYWORD, clause, NSYMBOL (start), LINE (INFO (start)));
142 }
143 }
144
145 //! @brief Check for premature exhaustion of tokens.
146
147 void tokens_exhausted (const NODE_T * p, NODE_T * q)
148 {
149 if (p == NO_NODE) {
150 diagnostic (A68_SYNTAX_ERROR, q, ERROR_KEYWORD);
151 longjmp (A68_PARSER (top_down_crash_exit), 1);
152 }
153 }
154
155 // This part specifically branches out loop clauses.
156
157 //! @brief Whether in cast or formula with loop clause.
158
159 int is_loop_cast_formula (NODE_T * p)
160 {
161 // Accept declarers that can appear in such casts but not much more.
162 if (IS (p, VOID_SYMBOL)) {
163 return 1;
164 } else if (IS (p, INT_SYMBOL)) {
165 return 1;
166 } else if (IS_REF (p)) {
167 return 1;
168 } else if (is_one_of (p, OPERATOR, BOLD_TAG, STOP)) {
169 return 1;
170 } else if (whether (p, UNION_SYMBOL, OPEN_SYMBOL, STOP)) {
171 return 2;
172 } else if (is_one_of (p, OPEN_SYMBOL, SUB_SYMBOL, STOP)) {
173 int k = 0;
174 for (; p != NO_NODE && (is_one_of (p, OPEN_SYMBOL, SUB_SYMBOL, STOP)); FORWARD (p), k++) {
175 ;
176 }
177 return p != NO_NODE && (whether (p, UNION_SYMBOL, OPEN_SYMBOL, STOP) ? k : 0);
178 }
179 return 0;
180 }
181
182 //! @brief Skip a unit in a loop clause (FROM u BY u TO u).
183
184 NODE_T *top_down_skip_loop_unit (NODE_T * p)
185 {
186 // Unit may start with, or consist of, a loop.
187 if (is_loop_keyword (p)) {
188 p = top_down_loop (p);
189 }
190 // Skip rest of unit.
191 while (p != NO_NODE) {
192 int k = is_loop_cast_formula (p);
193 if (k != 0) {
194 // operator-cast series ...
195 while (p != NO_NODE && k != 0) {
196 while (k != 0) {
197 FORWARD (p);
198 k--;
199 }
200 k = is_loop_cast_formula (p);
201 }
202 // ... may be followed by a loop clause.
203 if (is_loop_keyword (p)) {
204 p = top_down_loop (p);
205 }
206 } else if (is_loop_keyword (p) || IS (p, OD_SYMBOL)) {
207 // new loop or end-of-loop.
208 return p;
209 } else if (IS (p, COLON_SYMBOL)) {
210 FORWARD (p);
211 // skip routine header: loop clause.
212 if (p != NO_NODE && is_loop_keyword (p)) {
213 p = top_down_loop (p);
214 }
215 } else if (is_one_of (p, SEMI_SYMBOL, COMMA_SYMBOL, STOP) || IS (p, EXIT_SYMBOL)) {
216 // Statement separators.
217 return p;
218 } else {
219 FORWARD (p);
220 }
221 }
222 return NO_NODE;
223 }
224
225 //! @brief Skip a loop clause.
226
227 NODE_T *top_down_skip_loop_series (NODE_T * p)
228 {
229 BOOL_T siga;
230 do {
231 p = top_down_skip_loop_unit (p);
232 siga = (BOOL_T) (p != NO_NODE && (is_one_of (p, SEMI_SYMBOL, EXIT_SYMBOL, COMMA_SYMBOL, COLON_SYMBOL, STOP)));
233 if (siga) {
234 FORWARD (p);
235 }
236 } while (!(p == NO_NODE || !siga));
237 return p;
238 }
239
240 //! @brief Make branch of loop parts.
241
242 NODE_T *top_down_loop (NODE_T * p)
243 {
244 NODE_T *start = p, *q = p;
245 if (IS (q, FOR_SYMBOL)) {
246 tokens_exhausted (FORWARD (q), start);
247 if (IS (q, IDENTIFIER)) {
248 ATTRIBUTE (q) = DEFINING_IDENTIFIER;
249 } else {
250 top_down_diagnose (start, q, LOOP_CLAUSE, IDENTIFIER);
251 longjmp (A68_PARSER (top_down_crash_exit), 1);
252 }
253 tokens_exhausted (FORWARD (q), start);
254 if (is_one_of (q, FROM_SYMBOL, BY_SYMBOL, TO_SYMBOL, DOWNTO_SYMBOL, WHILE_SYMBOL, STOP)) {
255 ;
256 } else if (IS (q, DO_SYMBOL)) {
257 ATTRIBUTE (q) = ALT_DO_SYMBOL;
258 } else {
259 top_down_diagnose (start, q, LOOP_CLAUSE, STOP);
260 longjmp (A68_PARSER (top_down_crash_exit), 1);
261 }
262 }
263 if (IS (q, FROM_SYMBOL)) {
264 start = q;
265 q = top_down_skip_loop_unit (NEXT (q));
266 tokens_exhausted (q, start);
267 if (is_one_of (q, BY_SYMBOL, TO_SYMBOL, DOWNTO_SYMBOL, WHILE_SYMBOL, STOP)) {
268 ;
269 } else if (IS (q, DO_SYMBOL)) {
270 ATTRIBUTE (q) = ALT_DO_SYMBOL;
271 } else {
272 top_down_diagnose (start, q, LOOP_CLAUSE, STOP);
273 longjmp (A68_PARSER (top_down_crash_exit), 1);
274 }
275 make_sub (start, PREVIOUS (q), FROM_SYMBOL);
276 }
277 if (IS (q, BY_SYMBOL)) {
278 start = q;
279 q = top_down_skip_loop_series (NEXT (q));
280 tokens_exhausted (q, start);
281 if (is_one_of (q, TO_SYMBOL, DOWNTO_SYMBOL, WHILE_SYMBOL, STOP)) {
282 ;
283 } else if (IS (q, DO_SYMBOL)) {
284 ATTRIBUTE (q) = ALT_DO_SYMBOL;
285 } else {
286 top_down_diagnose (start, q, LOOP_CLAUSE, STOP);
287 longjmp (A68_PARSER (top_down_crash_exit), 1);
288 }
289 make_sub (start, PREVIOUS (q), BY_SYMBOL);
290 }
291 if (is_one_of (q, TO_SYMBOL, DOWNTO_SYMBOL, STOP)) {
292 start = q;
293 q = top_down_skip_loop_series (NEXT (q));
294 tokens_exhausted (q, start);
295 if (IS (q, WHILE_SYMBOL)) {
296 ;
297 } else if (IS (q, DO_SYMBOL)) {
298 ATTRIBUTE (q) = ALT_DO_SYMBOL;
299 } else {
300 top_down_diagnose (start, q, LOOP_CLAUSE, STOP);
301 longjmp (A68_PARSER (top_down_crash_exit), 1);
302 }
303 make_sub (start, PREVIOUS (q), TO_SYMBOL);
304 }
305 if (IS (q, WHILE_SYMBOL)) {
306 start = q;
307 q = top_down_skip_loop_series (NEXT (q));
308 tokens_exhausted (q, start);
309 if (IS (q, DO_SYMBOL)) {
310 ATTRIBUTE (q) = ALT_DO_SYMBOL;
311 } else {
312 top_down_diagnose (start, q, LOOP_CLAUSE, DO_SYMBOL);
313 longjmp (A68_PARSER (top_down_crash_exit), 1);
314 }
315 make_sub (start, PREVIOUS (q), WHILE_SYMBOL);
316 }
317 if (is_one_of (q, DO_SYMBOL, ALT_DO_SYMBOL, STOP)) {
318 int k = ATTRIBUTE (q);
319 start = q;
320 q = top_down_skip_loop_series (NEXT (q));
321 tokens_exhausted (q, start);
322 if (!IS (q, OD_SYMBOL)) {
323 top_down_diagnose (start, q, LOOP_CLAUSE, OD_SYMBOL);
324 longjmp (A68_PARSER (top_down_crash_exit), 1);
325 }
326 make_sub (start, q, k);
327 }
328 NODE_T *save = NEXT (start);
329 make_sub (p, start, LOOP_CLAUSE);
330 return save;
331 }
332
333 //! @brief Driver for making branches of loop parts.
334
335 void top_down_loops (NODE_T * p)
336 {
337 NODE_T *q = p;
338 for (; q != NO_NODE; FORWARD (q)) {
339 if (SUB (q) != NO_NODE) {
340 top_down_loops (SUB (q));
341 }
342 }
343 q = p;
344 while (q != NO_NODE) {
345 if (is_loop_keyword (q) != STOP) {
346 q = top_down_loop (q);
347 } else {
348 FORWARD (q);
349 }
350 }
351 }
352
353 //! @brief Driver for making branches of until parts.
354
355 void top_down_untils (NODE_T * p)
356 {
357 NODE_T *q = p;
358 for (; q != NO_NODE; FORWARD (q)) {
359 if (SUB (q) != NO_NODE) {
360 top_down_untils (SUB (q));
361 }
362 }
363 q = p;
364 while (q != NO_NODE) {
365 if (IS (q, UNTIL_SYMBOL)) {
366 NODE_T *u = q;
367 while (NEXT (u) != NO_NODE) {
368 FORWARD (u);
369 }
370 make_sub (q, PREVIOUS (u), UNTIL_SYMBOL);
371 return;
372 } else {
373 FORWARD (q);
374 }
375 }
376 }
377
378 // Branch anything except parts of a loop.
379
380 //! @brief Skip serial/enquiry clause (unit series).
381
382 NODE_T *top_down_series (NODE_T * p)
383 {
384 BOOL_T siga = A68_TRUE;
385 while (siga) {
386 siga = A68_FALSE;
387 p = top_down_skip_unit (p);
388 if (p != NO_NODE) {
389 if (is_one_of (p, SEMI_SYMBOL, EXIT_SYMBOL, COMMA_SYMBOL, STOP)) {
390 siga = A68_TRUE;
391 FORWARD (p);
392 }
393 }
394 }
395 return p;
396 }
397
398 //! @brief Make branch of BEGIN .. END.
399
400 NODE_T *top_down_begin (NODE_T * begin_p)
401 {
402 NODE_T *end_p = top_down_series (NEXT (begin_p));
403 if (end_p == NO_NODE || !IS (end_p, END_SYMBOL)) {
404 top_down_diagnose (begin_p, end_p, ENCLOSED_CLAUSE, END_SYMBOL);
405 longjmp (A68_PARSER (top_down_crash_exit), 1);
406 return NO_NODE;
407 } else {
408 make_sub (begin_p, end_p, BEGIN_SYMBOL);
409 return NEXT (begin_p);
410 }
411 }
412
413 //! @brief Make branch of CODE .. EDOC.
414
415 NODE_T *top_down_code (NODE_T * code_p)
416 {
417 NODE_T *edoc_p = top_down_series (NEXT (code_p));
418 if (edoc_p == NO_NODE || !IS (edoc_p, EDOC_SYMBOL)) {
419 diagnostic (A68_SYNTAX_ERROR, code_p, ERROR_KEYWORD);
420 longjmp (A68_PARSER (top_down_crash_exit), 1);
421 return NO_NODE;
422 } else {
423 make_sub (code_p, edoc_p, CODE_SYMBOL);
424 return NEXT (code_p);
425 }
426 }
427
428 //! @brief Make branch of ( .. ).
429
430 NODE_T *top_down_open (NODE_T * open_p)
431 {
432 NODE_T *then_bar_p = top_down_series (NEXT (open_p)), *elif_bar_p;
433 if (then_bar_p != NO_NODE && IS (then_bar_p, CLOSE_SYMBOL)) {
434 make_sub (open_p, then_bar_p, OPEN_SYMBOL);
435 return NEXT (open_p);
436 }
437 if (then_bar_p == NO_NODE || !IS (then_bar_p, THEN_BAR_SYMBOL)) {
438 top_down_diagnose (open_p, then_bar_p, ENCLOSED_CLAUSE, STOP);
439 longjmp (A68_PARSER (top_down_crash_exit), 1);
440 }
441 make_sub (open_p, PREVIOUS (then_bar_p), OPEN_SYMBOL);
442 elif_bar_p = top_down_series (NEXT (then_bar_p));
443 if (elif_bar_p != NO_NODE && IS (elif_bar_p, CLOSE_SYMBOL)) {
444 make_sub (then_bar_p, PREVIOUS (elif_bar_p), THEN_BAR_SYMBOL);
445 make_sub (open_p, elif_bar_p, OPEN_SYMBOL);
446 return NEXT (open_p);
447 }
448 if (elif_bar_p != NO_NODE && IS (elif_bar_p, THEN_BAR_SYMBOL)) {
449 NODE_T *close_p = top_down_series (NEXT (elif_bar_p));
450 if (close_p == NO_NODE || !IS (close_p, CLOSE_SYMBOL)) {
451 top_down_diagnose (open_p, elif_bar_p, ENCLOSED_CLAUSE, CLOSE_SYMBOL);
452 longjmp (A68_PARSER (top_down_crash_exit), 1);
453 }
454 make_sub (then_bar_p, PREVIOUS (elif_bar_p), THEN_BAR_SYMBOL);
455 make_sub (elif_bar_p, PREVIOUS (close_p), THEN_BAR_SYMBOL);
456 make_sub (open_p, close_p, OPEN_SYMBOL);
457 return NEXT (open_p);
458 }
459 if (elif_bar_p != NO_NODE && IS (elif_bar_p, ELSE_BAR_SYMBOL)) {
460 NODE_T *close_p = top_down_open (elif_bar_p);
461 make_sub (then_bar_p, PREVIOUS (elif_bar_p), THEN_BAR_SYMBOL);
462 make_sub (open_p, elif_bar_p, OPEN_SYMBOL);
463 return close_p;
464 } else {
465 top_down_diagnose (open_p, elif_bar_p, ENCLOSED_CLAUSE, CLOSE_SYMBOL);
466 longjmp (A68_PARSER (top_down_crash_exit), 1);
467 return NO_NODE;
468 }
469 }
470
471 //! @brief Make branch of [ .. ].
472
473 NODE_T *top_down_sub (NODE_T * sub_p)
474 {
475 NODE_T *bus_p = top_down_series (NEXT (sub_p));
476 if (bus_p != NO_NODE && IS (bus_p, BUS_SYMBOL)) {
477 make_sub (sub_p, bus_p, SUB_SYMBOL);
478 return NEXT (sub_p);
479 } else {
480 top_down_diagnose (sub_p, bus_p, 0, BUS_SYMBOL);
481 longjmp (A68_PARSER (top_down_crash_exit), 1);
482 return NO_NODE;
483 }
484 }
485
486 //! @brief Make branch of { .. }.
487
488 NODE_T *top_down_acco (NODE_T * acco_p)
489 {
490 NODE_T *occa_p = top_down_series (NEXT (acco_p));
491 if (occa_p != NO_NODE && IS (occa_p, OCCA_SYMBOL)) {
492 make_sub (acco_p, occa_p, ACCO_SYMBOL);
493 return NEXT (acco_p);
494 } else {
495 top_down_diagnose (acco_p, occa_p, ENCLOSED_CLAUSE, OCCA_SYMBOL);
496 longjmp (A68_PARSER (top_down_crash_exit), 1);
497 return NO_NODE;
498 }
499 }
500
501 //! @brief Make branch of IF .. THEN .. ELSE .. FI.
502
503 NODE_T *top_down_if (NODE_T * if_p)
504 {
505 NODE_T *then_p = top_down_series (NEXT (if_p)), *elif_p;
506 if (then_p == NO_NODE || !IS (then_p, THEN_SYMBOL)) {
507 top_down_diagnose (if_p, then_p, CONDITIONAL_CLAUSE, THEN_SYMBOL);
508 longjmp (A68_PARSER (top_down_crash_exit), 1);
509 }
510 make_sub (if_p, PREVIOUS (then_p), IF_SYMBOL);
511 elif_p = top_down_series (NEXT (then_p));
512 if (elif_p != NO_NODE && IS (elif_p, FI_SYMBOL)) {
513 make_sub (then_p, PREVIOUS (elif_p), THEN_SYMBOL);
514 make_sub (if_p, elif_p, IF_SYMBOL);
515 return NEXT (if_p);
516 }
517 if (elif_p != NO_NODE && IS (elif_p, ELSE_SYMBOL)) {
518 NODE_T *fi_p = top_down_series (NEXT (elif_p));
519 if (fi_p == NO_NODE || !IS (fi_p, FI_SYMBOL)) {
520 top_down_diagnose (if_p, fi_p, CONDITIONAL_CLAUSE, FI_SYMBOL);
521 longjmp (A68_PARSER (top_down_crash_exit), 1);
522 } else {
523 make_sub (then_p, PREVIOUS (elif_p), THEN_SYMBOL);
524 make_sub (elif_p, PREVIOUS (fi_p), ELSE_SYMBOL);
525 make_sub (if_p, fi_p, IF_SYMBOL);
526 return NEXT (if_p);
527 }
528 }
529 if (elif_p != NO_NODE && IS (elif_p, ELIF_SYMBOL)) {
530 NODE_T *fi_p = top_down_if (elif_p);
531 make_sub (then_p, PREVIOUS (elif_p), THEN_SYMBOL);
532 make_sub (if_p, elif_p, IF_SYMBOL);
533 return fi_p;
534 } else {
535 top_down_diagnose (if_p, elif_p, CONDITIONAL_CLAUSE, FI_SYMBOL);
536 longjmp (A68_PARSER (top_down_crash_exit), 1);
537 return NO_NODE;
538 }
539 }
540
541 //! @brief Make branch of CASE .. IN .. OUT .. ESAC.
542
543 NODE_T *top_down_case (NODE_T * case_p)
544 {
545 NODE_T *in_p = top_down_series (NEXT (case_p)), *ouse_p;
546 if (in_p == NO_NODE || !IS (in_p, IN_SYMBOL)) {
547 top_down_diagnose (case_p, in_p, ENCLOSED_CLAUSE, IN_SYMBOL);
548 longjmp (A68_PARSER (top_down_crash_exit), 1);
549 }
550 make_sub (case_p, PREVIOUS (in_p), CASE_SYMBOL);
551 ouse_p = top_down_series (NEXT (in_p));
552 if (ouse_p != NO_NODE && IS (ouse_p, ESAC_SYMBOL)) {
553 make_sub (in_p, PREVIOUS (ouse_p), IN_SYMBOL);
554 make_sub (case_p, ouse_p, CASE_SYMBOL);
555 return NEXT (case_p);
556 }
557 if (ouse_p != NO_NODE && IS (ouse_p, OUT_SYMBOL)) {
558 NODE_T *esac_p = top_down_series (NEXT (ouse_p));
559 if (esac_p == NO_NODE || !IS (esac_p, ESAC_SYMBOL)) {
560 top_down_diagnose (case_p, esac_p, ENCLOSED_CLAUSE, ESAC_SYMBOL);
561 longjmp (A68_PARSER (top_down_crash_exit), 1);
562 } else {
563 make_sub (in_p, PREVIOUS (ouse_p), IN_SYMBOL);
564 make_sub (ouse_p, PREVIOUS (esac_p), OUT_SYMBOL);
565 make_sub (case_p, esac_p, CASE_SYMBOL);
566 return NEXT (case_p);
567 }
568 }
569 if (ouse_p != NO_NODE && IS (ouse_p, OUSE_SYMBOL)) {
570 NODE_T *esac_p = top_down_case (ouse_p);
571 make_sub (in_p, PREVIOUS (ouse_p), IN_SYMBOL);
572 make_sub (case_p, ouse_p, CASE_SYMBOL);
573 return esac_p;
574 } else {
575 top_down_diagnose (case_p, ouse_p, ENCLOSED_CLAUSE, ESAC_SYMBOL);
576 longjmp (A68_PARSER (top_down_crash_exit), 1);
577 return NO_NODE;
578 }
579 }
580
581 //! @brief Skip a unit.
582
583 NODE_T *top_down_skip_unit (NODE_T * p)
584 {
585 while (p != NO_NODE && !is_unit_terminator (p)) {
586 if (IS (p, BEGIN_SYMBOL)) {
587 p = top_down_begin (p);
588 } else if (IS (p, SUB_SYMBOL)) {
589 p = top_down_sub (p);
590 } else if (IS (p, OPEN_SYMBOL)) {
591 p = top_down_open (p);
592 } else if (IS (p, IF_SYMBOL)) {
593 p = top_down_if (p);
594 } else if (IS (p, CASE_SYMBOL)) {
595 p = top_down_case (p);
596 } else if (IS (p, CODE_SYMBOL)) {
597 p = top_down_code (p);
598 } else if (IS (p, ACCO_SYMBOL)) {
599 p = top_down_acco (p);
600 } else {
601 FORWARD (p);
602 }
603 }
604 return p;
605 }
606
607 NODE_T *top_down_skip_format (NODE_T *);
608
609 //! @brief Make branch of ( .. ) in a format.
610
611 NODE_T *top_down_format_open (NODE_T * open_p)
612 {
613 NODE_T *close_p = top_down_skip_format (NEXT (open_p));
614 if (close_p != NO_NODE && IS (close_p, FORMAT_CLOSE_SYMBOL)) {
615 make_sub (open_p, close_p, FORMAT_OPEN_SYMBOL);
616 return NEXT (open_p);
617 } else {
618 top_down_diagnose (open_p, close_p, 0, FORMAT_CLOSE_SYMBOL);
619 longjmp (A68_PARSER (top_down_crash_exit), 1);
620 return NO_NODE;
621 }
622 }
623
624 //! @brief Skip a format text.
625
626 NODE_T *top_down_skip_format (NODE_T * p)
627 {
628 while (p != NO_NODE) {
629 if (IS (p, FORMAT_OPEN_SYMBOL)) {
630 p = top_down_format_open (p);
631 } else if (is_one_of (p, FORMAT_CLOSE_SYMBOL, FORMAT_DELIMITER_SYMBOL, STOP)) {
632 return p;
633 } else {
634 FORWARD (p);
635 }
636 }
637 return NO_NODE;
638 }
639
640 //! @brief Make branch of $ .. $.
641
642 void top_down_formats (NODE_T * p)
643 {
644 for (NODE_T *q = p; q != NO_NODE; FORWARD (q)) {
645 if (SUB (q) != NO_NODE) {
646 top_down_formats (SUB (q));
647 }
648 }
649 for (NODE_T *q = p; q != NO_NODE; FORWARD (q)) {
650 if (IS (q, FORMAT_DELIMITER_SYMBOL)) {
651 NODE_T *f = NEXT (q);
652 while (f != NO_NODE && !IS (f, FORMAT_DELIMITER_SYMBOL)) {
653 if (IS (f, FORMAT_OPEN_SYMBOL)) {
654 f = top_down_format_open (f);
655 } else {
656 f = NEXT (f);
657 }
658 }
659 if (f == NO_NODE) {
660 top_down_diagnose (p, f, FORMAT_TEXT, FORMAT_DELIMITER_SYMBOL);
661 longjmp (A68_PARSER (top_down_crash_exit), 1);
662 } else {
663 make_sub (q, f, FORMAT_DELIMITER_SYMBOL);
664 }
665 }
666 }
667 }
668
669 //! @brief Make branches of phrases for the bottom-up parser.
670
671 void top_down_parser (NODE_T * p)
672 {
673 if (p != NO_NODE) {
674 if (!setjmp (A68_PARSER (top_down_crash_exit))) {
675 (void) top_down_series (p);
676 top_down_loops (p);
677 top_down_untils (p);
678 top_down_formats (p);
679 }
680 }
681 }
© 2002-2024 J.M. van der Veer (jmvdveer@xs4all.nl)
|