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