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)