a68g-pretty.c

     
   1  //! @file a68g-pretty.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  //! Lay-out formatter for Algol 68.
  25  
  26  // Basic indenter for hopeless code.
  27  // It applies one style only.
  28  
  29  #include "a68g.h"
  30  #include "a68g-genie.h"
  31  #include "a68g-parser.h"
  32  #include "a68g-optimiser.h"
  33  #include "a68g-prelude.h"
  34  
  35  #define MAX_INDENT 60
  36  
  37  #define ONE_LINER (A68_TRUE)
  38  #define KEYWORD (A68_TRUE)
  39  #define BLANK {put_str (" ");}
  40  
  41  #define IS_OPEN_SYMBOL(p) (IS (p, OPEN_SYMBOL) || IS (p, SUB_SYMBOL) || IS (p, ACCO_SYMBOL))
  42  #define IS_CLOSE_SYMBOL(p) (IS (p, CLOSE_SYMBOL) || IS (p, BUS_SYMBOL) || IS (p, OCCA_SYMBOL))
  43  #define IS_IDENTIFIER(p) (IS (p, IDENTIFIER) || IS (p, DEFINING_IDENTIFIER) || IS (p, FIELD_IDENTIFIER))
  44  
  45  void indent_declarer (NODE_T *);
  46  void indent_serial (NODE_T *, BOOL_T, NODE_T **);
  47  void indent_statement (NODE_T *);
  48  void indent_format (NODE_T *);
  49  
  50  //! @brief Write newline and indent.
  51  
  52  void put_nl (void)
  53  {
  54    WRITE (A68_INDENT (fd), "\n");
  55    for (A68_INDENT (col) = 1; A68_INDENT (col) < A68_INDENT (ind); A68_INDENT (col)++) {
  56      if (A68_INDENT (col) <= MAX_INDENT) {
  57        WRITE (A68_INDENT (fd), " ");
  58      }
  59    }
  60  }
  61  
  62  //! @brief Write a string.
  63  
  64  void put_str (char *txt)
  65  {
  66    WRITE (A68_INDENT (fd), txt);
  67    A68_INDENT (col) += (int) strlen (txt);
  68  }
  69  
  70  //! @brief Write a character.
  71  
  72  void put_ch (char ch)
  73  {
  74    char str[2];
  75    str[0] = ch;
  76    str[1] = NULL_CHAR;
  77    put_str (str);
  78  }
  79  
  80  //! @brief Write pragment string.
  81  
  82  void put_pragment (NODE_T * p)
  83  {
  84    for (char *txt = NPRAGMENT (p); txt != NO_TEXT && txt[0] != NULL_CHAR; txt++) {
  85      if (txt[0] == NEWLINE_CHAR) {
  86        put_nl ();
  87      } else {
  88        put_ch (txt[0]);
  89      }
  90    }
  91  }
  92  
  93  //! @brief Write pragment string.
  94  
  95  void pretty_pragment (NODE_T * p, BOOL_T keyw)
  96  {
  97    if (NPRAGMENT (p) != NO_TEXT) {
  98      if (NPRAGMENT_TYPE (p) == BOLD_COMMENT_SYMBOL || NPRAGMENT_TYPE (p) == BOLD_PRAGMAT_SYMBOL) {
  99        if (!keyw) {
 100          put_nl ();
 101        }
 102        put_pragment (p);
 103        put_nl ();
 104        put_nl ();
 105      } else {
 106        if (!keyw && (int) strlen (NPRAGMENT (p)) < 20) {
 107          if (A68_INDENT (col) > A68_INDENT (ind)) {
 108            BLANK;
 109          }
 110          put_pragment (p);
 111          BLANK;
 112        } else {
 113          if (A68_INDENT (col) > A68_INDENT (ind)) {
 114            put_nl ();
 115          }
 116          put_pragment (p);
 117          put_nl ();
 118        }
 119      }
 120    }
 121  }
 122  
 123  //! @brief Write with typographic display features.
 124  
 125  void put_sym (NODE_T * p, BOOL_T keyw)
 126  {
 127    char *txt = NSYMBOL (p);
 128    char *sym = NCHAR_IN_LINE (p);
 129    int n = 0, size = (int) strlen (txt);
 130    pretty_pragment (p, keyw);
 131    if (txt[0] != sym[0] || (int) strlen (sym) - 1 <= size) {
 132  // Without features..
 133      put_str (txt);
 134    } else {
 135  // With features. Preserves spaces in identifiers etcetera..
 136      while (n < size) {
 137        put_ch (sym[0]);
 138        if (TO_LOWER (txt[0]) == TO_LOWER (sym[0])) {
 139          txt++;
 140          n++;
 141        }
 142        sym++;
 143      }
 144    }
 145  }
 146  
 147  //! @brief Count units and separators in a sub-tree.
 148  
 149  void count (NODE_T * p, int *units, int *seps)
 150  {
 151    for (; p != NO_NODE; FORWARD (p)) {
 152      if (IS (p, UNIT)) {
 153        (*units)++;
 154        count (SUB (p), units, seps);
 155      } else if (IS (p, SEMI_SYMBOL)) {
 156        (*seps)++;
 157      } else if (IS (p, COMMA_SYMBOL)) {
 158        (*seps)++;
 159      } else if (IS (p, CLOSED_CLAUSE)) {
 160        (*units)--;
 161      } else if (IS (p, COLLATERAL_CLAUSE)) {
 162        (*units)--;
 163        count (SUB (p), units, seps);
 164      } else {
 165        count (SUB (p), units, seps);
 166      }
 167    }
 168  }
 169  
 170  //! @brief Count units and separators in a sub-tree.
 171  
 172  void count_stowed (NODE_T * p, int *units, int *seps)
 173  {
 174    for (; p != NO_NODE; FORWARD (p)) {
 175      if (IS (p, UNIT)) {
 176        MOID_T *v = MOID (p);
 177        BOOL_T stowed = (BOOL_T) (IS_FLEX (v) || IS_ROW (v) || IS_STRUCT (v));
 178        if (stowed) {
 179          (*units)++;
 180        }
 181      } else if (IS (p, SEMI_SYMBOL)) {
 182        (*seps)++;
 183      } else if (IS (p, COMMA_SYMBOL)) {
 184        (*seps)++;
 185      } else {
 186        count_stowed (SUB (p), units, seps);
 187      }
 188    }
 189  }
 190  
 191  //! @brief Count enclosed_clauses in a sub-tree.
 192  
 193  void count_enclos (NODE_T * p, int *enclos, int *seps)
 194  {
 195    for (; p != NO_NODE; FORWARD (p)) {
 196      if (IS (p, ENCLOSED_CLAUSE)) {
 197        (*enclos)++;
 198      } else if (IS (p, SEMI_SYMBOL)) {
 199        (*seps)++;
 200      } else if (IS (p, COMMA_SYMBOL)) {
 201        (*seps)++;
 202      } else {
 203        count_enclos (SUB (p), enclos, seps);
 204      }
 205    }
 206  }
 207  
 208  //! @brief Indent sizety.
 209  
 210  void indent_sizety (NODE_T * p)
 211  {
 212    for (; p != NO_NODE; FORWARD (p)) {
 213      if (IS (p, LONGETY) || IS (p, SHORTETY)) {
 214        indent_sizety (SUB (p));
 215      } else if (IS (p, LONG_SYMBOL) || IS (p, SHORT_SYMBOL)) {
 216        put_sym (p, !KEYWORD);
 217        BLANK;
 218      }
 219    }
 220  }
 221  
 222  //! @brief Indent generic list.
 223  
 224  void indent_generic_list (NODE_T * p, NODE_T ** what, BOOL_T one_liner)
 225  {
 226    for (; p != NULL; FORWARD (p)) {
 227      if (IS_OPEN_SYMBOL (p)) {
 228        put_sym (p, KEYWORD);
 229        A68_INDENT (ind) = A68_INDENT (col);
 230      } else if (IS_CLOSE_SYMBOL (p)) {
 231        put_sym (p, KEYWORD);
 232      } else if (IS (p, BEGIN_SYMBOL)) {
 233        put_sym (p, KEYWORD);
 234        BLANK;
 235      } else if (IS (p, END_SYMBOL)) {
 236        BLANK;
 237        put_sym (p, KEYWORD);
 238      } else if (IS (p, AT_SYMBOL)) {
 239        if (NSYMBOL (p)[0] == '@') {
 240          put_sym (p, !KEYWORD);
 241        } else {
 242          BLANK;
 243          put_sym (p, !KEYWORD);
 244          BLANK;
 245        }
 246      } else if (IS (p, COLON_SYMBOL)) {
 247        BLANK;
 248        put_sym (p, !KEYWORD);
 249        BLANK;
 250      } else if (IS (p, DOTDOT_SYMBOL)) {
 251        BLANK;
 252        put_sym (p, !KEYWORD);
 253        BLANK;
 254      } else if (IS (p, UNIT)) {
 255        *what = p;
 256        indent_statement (SUB (p));
 257      } else if (IS (p, SPECIFIER)) {
 258        NODE_T *q = SUB (p);
 259        put_sym (q, KEYWORD);
 260        FORWARD (q);
 261        indent_declarer (q);
 262        FORWARD (q);
 263        if (IS_IDENTIFIER (q)) {
 264          BLANK;
 265          put_sym (q, !KEYWORD);
 266          FORWARD (q);
 267        }
 268        put_sym (q, !KEYWORD);
 269        FORWARD (q);
 270        put_sym (NEXT (p), !KEYWORD);     // : 
 271        BLANK;
 272        FORWARD (p);
 273      } else if (IS (p, COMMA_SYMBOL)) {
 274        put_sym (p, !KEYWORD);
 275        if (one_liner) {
 276          BLANK;
 277        } else {
 278          put_nl ();
 279        }
 280      } else {
 281        indent_generic_list (SUB (p), what, one_liner);
 282      }
 283    }
 284  }
 285  
 286  //! @brief Indent declarer pack.
 287  
 288  void indent_pack (NODE_T * p)
 289  {
 290    for (; p != NO_NODE; FORWARD (p)) {
 291      if (IS_OPEN_SYMBOL (p) || IS_CLOSE_SYMBOL (p)) {
 292        put_sym (p, KEYWORD);
 293      } else if (IS (p, COMMA_SYMBOL)) {
 294        put_sym (p, !KEYWORD);
 295        BLANK;
 296      } else if (IS (p, VOID_SYMBOL)) {
 297        put_sym (p, !KEYWORD);
 298      } else if (IS (p, DECLARER)) {
 299        indent_declarer (p);
 300        if (NEXT (p) != NO_NODE && IS_IDENTIFIER (NEXT (p))) {
 301          BLANK;
 302        }
 303      } else if (IS_IDENTIFIER (p)) {
 304        put_sym (p, !KEYWORD);
 305      } else {
 306        indent_pack (SUB (p));
 307      }
 308    }
 309  }
 310  
 311  //! @brief Indent declarer.
 312  
 313  void indent_declarer (NODE_T * p)
 314  {
 315    if (IS (p, DECLARER)) {
 316      indent_declarer (SUB (p));
 317    } else if (IS (p, LONGETY) || IS (p, SHORTETY)) {
 318      indent_sizety (SUB (p));
 319      indent_declarer (NEXT (p));
 320    } else if (IS (p, VOID_SYMBOL)) {
 321      put_sym (p, !KEYWORD);
 322    } else if (IS (p, REF_SYMBOL)) {
 323      put_sym (p, !KEYWORD);
 324      BLANK;
 325      indent_declarer (NEXT (p));
 326    } else if (IS_FLEX (p)) {
 327      put_sym (p, !KEYWORD);
 328      BLANK;
 329      indent_declarer (NEXT (p));
 330    } else if (IS (p, BOUNDS) || IS (p, FORMAL_BOUNDS)) {
 331      NODE_T *what = NO_NODE;
 332      int pop_ind = A68_INDENT (ind);
 333      indent_generic_list (SUB (p), &what, ONE_LINER);
 334      A68_INDENT (ind) = pop_ind;
 335      BLANK;
 336      indent_declarer (NEXT (p));
 337    } else if (IS_STRUCT (p) || IS_UNION (p)) {
 338      NODE_T *pack = NEXT (p);
 339      put_sym (p, !KEYWORD);
 340      BLANK;
 341      indent_pack (pack);
 342    } else if (IS (p, PROC_SYMBOL)) {
 343      NODE_T *q = NEXT (p);
 344      put_sym (p, KEYWORD);
 345      BLANK;
 346      if (IS (q, FORMAL_DECLARERS)) {
 347        indent_pack (SUB (q));
 348        BLANK;
 349        FORWARD (q);
 350      }
 351      indent_declarer (q);
 352      return;
 353    } else if (IS (p, OP_SYMBOL)) {       // Operator plan
 354      NODE_T *q = NEXT (p);
 355      put_sym (p, KEYWORD);
 356      BLANK;
 357      if (IS (q, FORMAL_DECLARERS)) {
 358        indent_pack (SUB (q));
 359        BLANK;
 360        FORWARD (q);
 361      }
 362      indent_declarer (q);
 363      return;
 364    } else if (IS (p, INDICANT)) {
 365      put_sym (p, !KEYWORD);
 366    }
 367  }
 368  
 369  //! @brief Indent conditional.
 370  
 371  void indent_conditional (NODE_T * p)
 372  {
 373    for (; p != NO_NODE; FORWARD (p)) {
 374      if (IS (p, IF_PART) || IS (p, ELIF_IF_PART)) {
 375        NODE_T *what = NO_NODE;
 376        int pop_ind = A68_INDENT (col);
 377        put_sym (SUB (p), KEYWORD);
 378        BLANK;
 379        A68_INDENT (ind) = A68_INDENT (col);
 380        indent_serial (NEXT_SUB (p), !ONE_LINER, &what);
 381        A68_INDENT (ind) = pop_ind;
 382        put_nl ();
 383      } else if (IS (p, THEN_PART)) {
 384        NODE_T *what = NO_NODE;
 385        int pop_ind = A68_INDENT (col);
 386        put_sym (SUB (p), KEYWORD);
 387        BLANK;
 388        A68_INDENT (ind) = A68_INDENT (col);
 389        indent_serial (NEXT_SUB (p), !ONE_LINER, &what);
 390        A68_INDENT (ind) = pop_ind;
 391        put_nl ();
 392      } else if (IS (p, ELSE_PART)) {
 393        NODE_T *what = NO_NODE;
 394        int pop_ind = A68_INDENT (col);
 395        put_sym (SUB (p), KEYWORD);
 396        BLANK;
 397        A68_INDENT (ind) = A68_INDENT (col);
 398        indent_serial (NEXT_SUB (p), !ONE_LINER, &what);
 399        A68_INDENT (ind) = pop_ind;
 400        put_nl ();
 401      } else if (IS (p, ELIF_PART)) {
 402        indent_conditional (SUB (p));
 403      } else if (IS (p, FI_SYMBOL)) {
 404        put_sym (p, KEYWORD);
 405      } else if (IS (p, OPEN_PART)) {
 406        NODE_T *what = NO_NODE;
 407        put_sym (SUB (p), KEYWORD);
 408        indent_serial (NEXT_SUB (p), ONE_LINER, &what);
 409      } else if (IS (p, ELSE_OPEN_PART)) {
 410        NODE_T *what = NO_NODE;
 411        BLANK;
 412        put_sym (SUB (p), KEYWORD);
 413        BLANK;
 414        indent_serial (NEXT_SUB (p), ONE_LINER, &what);
 415      } else if (IS (p, CHOICE)) {
 416        NODE_T *what = NO_NODE;
 417        BLANK;
 418        put_sym (SUB (p), KEYWORD);
 419        BLANK;
 420        indent_serial (NEXT_SUB (p), ONE_LINER, &what);
 421      } else if (IS (p, BRIEF_ELIF_PART)) {
 422        indent_conditional (SUB (p));
 423      } else if (IS_CLOSE_SYMBOL (p)) {
 424        put_sym (p, KEYWORD);
 425      }
 426    }
 427  }
 428  
 429  //! @brief Indent integer case clause.
 430  
 431  void indent_case (NODE_T * p)
 432  {
 433    for (; p != NO_NODE; FORWARD (p)) {
 434      if (IS (p, CASE_PART) || IS (p, OUSE_PART)) {
 435        NODE_T *what = NO_NODE;
 436        int pop_ind = A68_INDENT (col);
 437        put_sym (SUB (p), KEYWORD);
 438        BLANK;
 439        A68_INDENT (ind) = A68_INDENT (col);
 440        indent_serial (NEXT_SUB (p), !ONE_LINER, &what);
 441        A68_INDENT (ind) = pop_ind;
 442        put_nl ();
 443      } else if (IS (p, CASE_IN_PART)) {
 444        NODE_T *what = NO_NODE;
 445        int pop_ind = A68_INDENT (col);
 446        put_sym (SUB (p), KEYWORD);
 447        BLANK;
 448        A68_INDENT (ind) = A68_INDENT (col);
 449        indent_generic_list (NEXT_SUB (p), &what, ONE_LINER);
 450        A68_INDENT (ind) = pop_ind;
 451        put_nl ();
 452      } else if (IS (p, OUT_PART)) {
 453        NODE_T *what = NO_NODE;
 454        int pop_ind = A68_INDENT (col);
 455        put_sym (SUB (p), KEYWORD);
 456        BLANK;
 457        A68_INDENT (ind) = A68_INDENT (col);
 458        indent_serial (NEXT_SUB (p), !ONE_LINER, &what);
 459        A68_INDENT (ind) = pop_ind;
 460        put_nl ();
 461      } else if (IS (p, CASE_OUSE_PART)) {
 462        indent_case (SUB (p));
 463      } else if (IS (p, ESAC_SYMBOL)) {
 464        put_sym (p, KEYWORD);
 465      } else if (IS (p, OPEN_PART)) {
 466        NODE_T *what = NO_NODE;
 467        put_sym (SUB (p), KEYWORD);
 468        indent_serial (NEXT_SUB (p), ONE_LINER, &what);
 469      } else if (IS (p, ELSE_OPEN_PART)) {
 470        NODE_T *what = NO_NODE;
 471        BLANK;
 472        put_sym (SUB (p), KEYWORD);
 473        BLANK;
 474        indent_serial (NEXT_SUB (p), ONE_LINER, &what);
 475      } else if (IS (p, CASE_CHOICE_CLAUSE)) {
 476        NODE_T *what = NO_NODE;
 477        BLANK;
 478        put_sym (SUB (p), KEYWORD);
 479        BLANK;
 480        indent_generic_list (NEXT_SUB (p), &what, ONE_LINER);
 481      } else if (IS (p, CHOICE)) {
 482        NODE_T *what = NO_NODE;
 483        BLANK;
 484        put_sym (SUB (p), KEYWORD);
 485        BLANK;
 486        indent_serial (NEXT_SUB (p), ONE_LINER, &what);
 487      } else if (IS (p, BRIEF_OUSE_PART)) {
 488        indent_case (SUB (p));
 489      } else if (IS_CLOSE_SYMBOL (p)) {
 490        put_sym (p, KEYWORD);
 491      }
 492    }
 493  }
 494  
 495  //! @brief Indent conformity clause.
 496  
 497  void indent_conformity (NODE_T * p)
 498  {
 499    for (; p != NO_NODE; FORWARD (p)) {
 500      if (IS (p, CASE_PART) || IS (p, OUSE_PART)) {
 501        NODE_T *what = NO_NODE;
 502        int pop_ind = A68_INDENT (col);
 503        put_sym (SUB (p), KEYWORD);
 504        BLANK;
 505        A68_INDENT (ind) = A68_INDENT (col);
 506        indent_serial (NEXT_SUB (p), !ONE_LINER, &what);
 507        A68_INDENT (ind) = pop_ind;
 508        put_nl ();
 509      } else if (IS (p, CONFORMITY_IN_PART)) {
 510        NODE_T *what = NO_NODE;
 511        int pop_ind = A68_INDENT (col);
 512        put_sym (SUB (p), KEYWORD);
 513        BLANK;
 514        A68_INDENT (ind) = A68_INDENT (col);
 515        indent_generic_list (NEXT_SUB (p), &what, ONE_LINER);
 516        A68_INDENT (ind) = pop_ind;
 517        put_nl ();
 518      } else if (IS (p, OUT_PART)) {
 519        NODE_T *what = NO_NODE;
 520        int pop_ind = A68_INDENT (col);
 521        put_sym (SUB (p), KEYWORD);
 522        BLANK;
 523        A68_INDENT (ind) = A68_INDENT (col);
 524        indent_serial (NEXT_SUB (p), !ONE_LINER, &what);
 525        A68_INDENT (ind) = pop_ind;
 526        put_nl ();
 527      } else if (IS (p, CONFORMITY_OUSE_PART)) {
 528        indent_conformity (SUB (p));
 529      } else if (IS (p, ESAC_SYMBOL)) {
 530        put_sym (p, KEYWORD);
 531      } else if (IS (p, OPEN_PART)) {
 532        NODE_T *what = NO_NODE;
 533        put_sym (SUB (p), KEYWORD);
 534        indent_serial (NEXT_SUB (p), ONE_LINER, &what);
 535      } else if (IS (p, ELSE_OPEN_PART)) {
 536        NODE_T *what = NO_NODE;
 537        BLANK;
 538        put_sym (SUB (p), KEYWORD);
 539        BLANK;
 540        indent_serial (NEXT_SUB (p), ONE_LINER, &what);
 541      } else if (IS (p, CONFORMITY_CHOICE)) {
 542        NODE_T *what = NO_NODE;
 543        BLANK;
 544        put_sym (SUB (p), KEYWORD);
 545        BLANK;
 546        indent_generic_list (NEXT_SUB (p), &what, ONE_LINER);
 547      } else if (IS (p, CHOICE)) {
 548        NODE_T *what = NO_NODE;
 549        BLANK;
 550        put_sym (SUB (p), KEYWORD);
 551        BLANK;
 552        indent_serial (NEXT_SUB (p), ONE_LINER, &what);
 553      } else if (IS (p, BRIEF_CONFORMITY_OUSE_PART)) {
 554        indent_conformity (SUB (p));
 555      } else if (IS_CLOSE_SYMBOL (p)) {
 556        put_sym (p, KEYWORD);
 557      }
 558    }
 559  }
 560  
 561  //! @brief Indent loop.
 562  
 563  void indent_loop (NODE_T * p)
 564  {
 565    int parts = 0, pop_ind = A68_INDENT (col);
 566    for (; p != NO_NODE; FORWARD (p)) {
 567      if (IS (p, FOR_PART)) {
 568        put_sym (SUB (p), KEYWORD);
 569        BLANK;
 570        put_sym (NEXT_SUB (p), !KEYWORD);
 571        BLANK;
 572        parts++;
 573      } else if (is_one_of (p, FROM_PART, BY_PART, TO_PART, STOP)) {
 574        put_sym (SUB (p), KEYWORD);
 575        BLANK;
 576        indent_statement (NEXT_SUB (p));
 577        BLANK;
 578        parts++;
 579      } else if (IS (p, WHILE_PART)) {
 580        NODE_T *what = NO_NODE;
 581        A68_INDENT (ind) = pop_ind;
 582        if (parts > 0) {
 583          put_nl ();
 584        }
 585        put_sym (SUB (p), KEYWORD);
 586        BLANK;
 587        A68_INDENT (ind) = A68_INDENT (col);
 588        indent_serial (NEXT_SUB (p), !ONE_LINER, &what);
 589        A68_INDENT (ind) = pop_ind;
 590        parts++;
 591      } else if (is_one_of (p, DO_PART, ALT_DO_PART, STOP)) {
 592        NODE_T *q = SUB (p);
 593        NODE_T *what = NO_NODE;
 594        A68_INDENT (ind) = pop_ind;
 595        if (parts > 0) {
 596          put_nl ();
 597        }
 598        put_sym (q, KEYWORD);     // DO
 599        BLANK;
 600        A68_INDENT (ind) = A68_INDENT (col);
 601        FORWARD (q);
 602        parts = 0;
 603        if (IS (q, SERIAL_CLAUSE)) {
 604          indent_serial (SUB (q), !ONE_LINER, &what);
 605          FORWARD (q);
 606          parts++;
 607        }
 608        if (IS (q, UNTIL_PART)) {
 609          int pop_ind2 = A68_INDENT (ind);
 610          if (parts > 0) {
 611            put_nl ();
 612          }
 613          put_sym (SUB (q), KEYWORD);
 614          BLANK;
 615          A68_INDENT (ind) = A68_INDENT (col);
 616          indent_serial (NEXT_SUB (q), !ONE_LINER, &what);
 617          A68_INDENT (ind) = pop_ind2;
 618          FORWARD (q);
 619        }
 620        A68_INDENT (ind) = pop_ind;
 621        put_nl ();
 622        put_sym (q, KEYWORD);     // OD
 623        parts++;
 624      }
 625    }
 626  }
 627  
 628  //! @brief Indent closed clause.
 629  
 630  void indent_closed (NODE_T * p)
 631  {
 632    int units = 0, seps = 0;
 633    count (SUB_NEXT (p), &units, &seps);
 634    if (units <= 3 && seps == (units - 1)) {
 635      put_sym (p, KEYWORD);
 636      if (IS (p, BEGIN_SYMBOL)) {
 637        NODE_T *what = NO_NODE;
 638        BLANK;
 639        indent_serial (SUB_NEXT (p), ONE_LINER, &what);
 640        BLANK;
 641      } else {
 642        NODE_T *what = NO_NODE;
 643        indent_serial (SUB_NEXT (p), ONE_LINER, &what);
 644      }
 645      put_sym (NEXT_NEXT (p), KEYWORD);
 646    } else if (units <= 3 && seps == (units - 1) && IS_OPEN_SYMBOL (p)) {
 647      NODE_T *what = NO_NODE;
 648      put_sym (p, KEYWORD);
 649      indent_serial (SUB_NEXT (p), ONE_LINER, &what);
 650      put_sym (NEXT_NEXT (p), KEYWORD);
 651    } else {
 652      NODE_T *what = NO_NODE;
 653      int pop_ind = A68_INDENT (col);
 654      put_sym (p, KEYWORD);
 655      if (IS (p, BEGIN_SYMBOL)) {
 656        BLANK;
 657      }
 658      A68_INDENT (ind) = A68_INDENT (col);
 659      indent_serial (SUB_NEXT (p), !ONE_LINER, &what);
 660      A68_INDENT (ind) = pop_ind;
 661      if (IS (NEXT_NEXT (p), END_SYMBOL)) {
 662        put_nl ();
 663      }
 664      put_sym (NEXT_NEXT (p), KEYWORD);
 665    }
 666  }
 667  
 668  //! @brief Indent collateral clause.
 669  
 670  void indent_collateral (NODE_T * p)
 671  {
 672    int units = 0, seps = 0;
 673    NODE_T *what = NO_NODE;
 674    int pop_ind = A68_INDENT (col);
 675    count_stowed (p, &units, &seps);
 676    if (units <= 3) {
 677      indent_generic_list (p, &what, ONE_LINER);
 678    } else {
 679      indent_generic_list (p, &what, !ONE_LINER);
 680    }
 681    A68_INDENT (ind) = pop_ind;
 682  }
 683  
 684  //! @brief Indent enclosed clause.
 685  
 686  void indent_enclosed (NODE_T * p)
 687  {
 688    if (IS (p, ENCLOSED_CLAUSE)) {
 689      indent_enclosed (SUB (p));
 690    } else if (IS (p, CLOSED_CLAUSE)) {
 691      indent_closed (SUB (p));
 692    } else if (IS (p, COLLATERAL_CLAUSE)) {
 693      indent_collateral (SUB (p));
 694    } else if (IS (p, PARALLEL_CLAUSE)) {
 695      put_sym (SUB (p), KEYWORD);
 696      indent_enclosed (NEXT_SUB (p));
 697    } else if (IS (p, CONDITIONAL_CLAUSE)) {
 698      indent_conditional (SUB (p));
 699    } else if (IS (p, CASE_CLAUSE)) {
 700      indent_case (SUB (p));
 701    } else if (IS (p, CONFORMITY_CLAUSE)) {
 702      indent_conformity (SUB (p));
 703    } else if (IS (p, LOOP_CLAUSE)) {
 704      indent_loop (SUB (p));
 705    }
 706  }
 707  
 708  //! @brief Indent a literal.
 709  
 710  void indent_literal (char *txt)
 711  {
 712    put_str ("\"");
 713    while (txt[0] != NULL_CHAR) {
 714      if (txt[0] == '\"') {
 715        put_str ("\"\"");
 716      } else {
 717        put_ch (txt[0]);
 718      }
 719      txt++;
 720    }
 721    put_str ("\"");
 722  }
 723  
 724  //! @brief Indent denotation.
 725  
 726  void indent_denotation (NODE_T * p)
 727  {
 728    if (IS (p, ROW_CHAR_DENOTATION)) {
 729      indent_literal (NSYMBOL (p));
 730    } else if (IS (p, LONGETY) || IS (p, SHORTETY)) {
 731      indent_sizety (SUB (p));
 732      indent_denotation (NEXT (p));
 733    } else {
 734      put_sym (p, !KEYWORD);
 735    }
 736  }
 737  
 738  //! @brief Indent label.
 739  
 740  void indent_label (NODE_T * p)
 741  {
 742    for (; p != NO_NODE; FORWARD (p)) {
 743      if (SUB (p) != NULL) {
 744        indent_label (SUB (p));
 745      } else if (IS (p, DEFINING_IDENTIFIER)) {
 746        put_sym (p, !KEYWORD);
 747        put_sym (NEXT (p), KEYWORD);
 748      }
 749    }
 750  }
 751  
 752  //! @brief Indent literal list.
 753  
 754  void indent_collection (NODE_T * p)
 755  {
 756    for (; p != NO_NODE; FORWARD (p)) {
 757      if (IS (p, FORMAT_OPEN_SYMBOL) || IS (p, FORMAT_CLOSE_SYMBOL)) {
 758        put_sym (p, !KEYWORD);
 759      } else if (IS (p, COMMA_SYMBOL)) {
 760        put_sym (p, !KEYWORD);
 761        BLANK;
 762      } else {
 763        indent_format (SUB (p));
 764      }
 765    }
 766  }
 767  
 768  //! @brief Indent format text.
 769  
 770  void indent_format (NODE_T * p)
 771  {
 772    for (; p != NO_NODE; FORWARD (p)) {
 773      if (IS (p, FORMAT_DELIMITER_SYMBOL)) {
 774        put_sym (p, !KEYWORD);
 775      } else if (IS (p, COLLECTION)) {
 776        indent_collection (SUB (p));
 777      } else if (IS (p, ENCLOSED_CLAUSE)) {
 778        indent_enclosed (SUB (p));
 779      } else if (IS (p, LITERAL)) {
 780        indent_literal (NSYMBOL (p));
 781      } else if (IS (p, STATIC_REPLICATOR)) {
 782        indent_denotation (p);
 783      } else if (IS (p, COMMA_SYMBOL)) {
 784        put_sym (p, !KEYWORD);
 785        BLANK;
 786      } else {
 787        if (SUB (p) != NO_NODE) {
 788          indent_format (SUB (p));
 789        } else {
 790          switch (ATTRIBUTE (p)) {
 791          case FORMAT_ITEM_A:
 792          case FORMAT_ITEM_B:
 793          case FORMAT_ITEM_C:
 794          case FORMAT_ITEM_D:
 795          case FORMAT_ITEM_E:
 796          case FORMAT_ITEM_ESCAPE:
 797          case FORMAT_ITEM_F:
 798          case FORMAT_ITEM_G:
 799          case FORMAT_ITEM_H:
 800          case FORMAT_ITEM_I:
 801          case FORMAT_ITEM_J:
 802          case FORMAT_ITEM_K:
 803          case FORMAT_ITEM_L:
 804          case FORMAT_ITEM_M:
 805          case FORMAT_ITEM_MINUS:
 806          case FORMAT_ITEM_N:
 807          case FORMAT_ITEM_O:
 808          case FORMAT_ITEM_P:
 809          case FORMAT_ITEM_PLUS:
 810          case FORMAT_ITEM_POINT:
 811          case FORMAT_ITEM_Q:
 812          case FORMAT_ITEM_R:
 813          case FORMAT_ITEM_S:
 814          case FORMAT_ITEM_T:
 815          case FORMAT_ITEM_U:
 816          case FORMAT_ITEM_V:
 817          case FORMAT_ITEM_W:
 818          case FORMAT_ITEM_X:
 819          case FORMAT_ITEM_Y:
 820          case FORMAT_ITEM_Z: {
 821              put_sym (p, !KEYWORD);
 822              break;
 823            }
 824          }
 825        }
 826      }
 827    }
 828  }
 829  
 830  //! @brief Constant folder - replace constant statement with value.
 831  
 832  BOOL_T indent_folder (NODE_T * p)
 833  {
 834    if (MOID (p) == M_INT) {
 835      A68_INT k;
 836      A68_SP = 0;
 837      push_unit (p);
 838      POP_OBJECT (p, &k, A68_INT);
 839      if (ERROR_COUNT (&A68_JOB) == 0) {
 840        ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, A68_LD, VALUE (&k)) >= 0);
 841        put_str (A68 (output_line));
 842        return A68_TRUE;
 843      } else {
 844        return A68_FALSE;
 845      }
 846    } else if (MOID (p) == M_REAL) {
 847      A68_REAL x;
 848      REAL_T conv;
 849      A68_SP = 0;
 850      push_unit (p);
 851      POP_OBJECT (p, &x, A68_REAL);
 852  // Mind overflowing or underflowing values.
 853      if (ERROR_COUNT (&A68_JOB) != 0) {
 854        return A68_FALSE;
 855      } else if (VALUE (&x) == A68_REAL_MAX) {
 856        return A68_FALSE;
 857      } else if (VALUE (&x) == -A68_REAL_MAX) {
 858        return A68_FALSE;
 859      } else {
 860        ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, "%.*g", A68_REAL_WIDTH, VALUE (&x)) >= 0);
 861        errno = 0;
 862        conv = strtod (A68 (output_line), NO_VAR);
 863        if (errno == ERANGE && conv == 0.0) {
 864          put_str ("0.0");
 865          return A68_TRUE;
 866        } else if (errno == ERANGE) {
 867          return A68_FALSE;
 868        } else {
 869          if (strchr (A68 (output_line), '.') == NO_TEXT && strchr (A68 (output_line), 'e') == NO_TEXT && strchr (A68 (output_line), 'E') == NO_TEXT) {
 870            a68_bufcat (A68 (output_line), ".0", BUFFER_SIZE);
 871          }
 872          put_str (A68 (output_line));
 873          return A68_TRUE;
 874        }
 875      }
 876    } else if (MOID (p) == M_BOOL) {
 877      A68_BOOL b;
 878      A68_SP = 0;
 879      push_unit (p);
 880      POP_OBJECT (p, &b, A68_BOOL);
 881      if (ERROR_COUNT (&A68_JOB) != 0) {
 882        return A68_FALSE;
 883      } else {
 884        ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, "%s", (VALUE (&b) ? "TRUE" : "FALSE")) >= 0);
 885        put_str (A68 (output_line));
 886        return A68_TRUE;
 887      }
 888    } else if (MOID (p) == M_CHAR) {
 889      A68_CHAR c;
 890      A68_SP = 0;
 891      push_unit (p);
 892      POP_OBJECT (p, &c, A68_CHAR);
 893      if (ERROR_COUNT (&A68_JOB) == 0) {
 894        return A68_FALSE;
 895      } else if (VALUE (&c) == '\"') {
 896        put_str ("\"\"\"\"");
 897        return A68_TRUE;
 898      } else {
 899        ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, "\"%c\"", (int) VALUE (&c)) >= 0);
 900        return A68_TRUE;
 901      }
 902    }
 903    return A68_FALSE;
 904  }
 905  
 906  //! @brief Indent statement.
 907  
 908  void indent_statement (NODE_T * p)
 909  {
 910    if (IS (p, LABEL)) {
 911      int enclos = 0, seps = 0;
 912      indent_label (SUB (p));
 913      FORWARD (p);
 914      count_enclos (SUB (p), &enclos, &seps);
 915      if (enclos == 0) {
 916        BLANK;
 917      } else {
 918        put_nl ();
 919      }
 920    }
 921    if (A68_INDENT (use_folder) && folder_mode (MOID (p)) && constant_unit (p)) {
 922      if (indent_folder (p)) {
 923        return;
 924      };
 925    }
 926    if (is_coercion (p)) {
 927      indent_statement (SUB (p));
 928    } else if (is_one_of (p, PRIMARY, SECONDARY, TERTIARY, UNIT, LABELED_UNIT, STOP)) {
 929      indent_statement (SUB (p));
 930    } else if (IS (p, ENCLOSED_CLAUSE)) {
 931      indent_enclosed (SUB (p));
 932    } else if (IS (p, DENOTATION)) {
 933      indent_denotation (SUB (p));
 934    } else if (IS (p, FORMAT_TEXT)) {
 935      indent_format (SUB (p));
 936    } else if (IS (p, IDENTIFIER)) {
 937      put_sym (p, !KEYWORD);
 938    } else if (IS (p, CAST)) {
 939      NODE_T *decl = SUB (p);
 940      NODE_T *rhs = NEXT (decl);
 941      indent_declarer (decl);
 942      BLANK;
 943      indent_enclosed (rhs);
 944    } else if (IS (p, CALL)) {
 945      NODE_T *primary = SUB (p);
 946      NODE_T *arguments = NEXT (primary);
 947      NODE_T *what = NO_NODE;
 948      int pop_ind = A68_INDENT (col);
 949      indent_statement (primary);
 950      BLANK;
 951      indent_generic_list (arguments, &what, ONE_LINER);
 952      A68_INDENT (ind) = pop_ind;
 953    } else if (IS (p, SLICE)) {
 954      NODE_T *primary = SUB (p);
 955      NODE_T *indexer = NEXT (primary);
 956      NODE_T *what = NO_NODE;
 957      int pop_ind = A68_INDENT (col);
 958      indent_statement (primary);
 959      indent_generic_list (indexer, &what, ONE_LINER);
 960      A68_INDENT (ind) = pop_ind;
 961    } else if (IS (p, SELECTION)) {
 962      NODE_T *selector = SUB (p);
 963      NODE_T *secondary = NEXT (selector);
 964      indent_statement (selector);
 965      indent_statement (secondary);
 966    } else if (IS (p, SELECTOR)) {
 967      NODE_T *identifier = SUB (p);
 968      put_sym (identifier, !KEYWORD);
 969      BLANK;
 970      put_sym (NEXT (identifier), !KEYWORD);      // OF
 971      BLANK;
 972    } else if (IS (p, GENERATOR)) {
 973      NODE_T *q = SUB (p);
 974      put_sym (q, !KEYWORD);
 975      BLANK;
 976      indent_declarer (NEXT (q));
 977    } else if (IS (p, FORMULA)) {
 978      NODE_T *lhs = SUB (p);
 979      NODE_T *op = NEXT (lhs);
 980      indent_statement (lhs);
 981      if (op != NO_NODE) {
 982        NODE_T *rhs = NEXT (op);
 983        BLANK;
 984        put_sym (op, !KEYWORD);
 985        BLANK;
 986        indent_statement (rhs);
 987      }
 988    } else if (IS (p, MONADIC_FORMULA)) {
 989      NODE_T *op = SUB (p);
 990      NODE_T *rhs = NEXT (op);
 991      put_sym (op, !KEYWORD);
 992      if (strchr (MONADS, (NSYMBOL (op))[0]) == NO_TEXT) {
 993        BLANK;
 994      }
 995      indent_statement (rhs);
 996    } else if (IS (p, NIHIL)) {
 997      put_sym (p, !KEYWORD);
 998    } else if (IS (p, AND_FUNCTION) || IS (p, OR_FUNCTION)) {
 999      NODE_T *lhs = SUB (p);
1000      NODE_T *op = NEXT (lhs);
1001      NODE_T *rhs = NEXT (op);
1002      indent_statement (lhs);
1003      BLANK;
1004      put_sym (op, !KEYWORD);
1005      BLANK;
1006      indent_statement (rhs);
1007    } else if (IS (p, TRANSPOSE_FUNCTION) || IS (p, DIAGONAL_FUNCTION) || IS (p, ROW_FUNCTION) || IS (p, COLUMN_FUNCTION)) {
1008      NODE_T *q = SUB (p);
1009      if (IS (p, TERTIARY)) {
1010        indent_statement (q);
1011        BLANK;
1012        FORWARD (q);
1013      }
1014      put_sym (q, !KEYWORD);
1015      BLANK;
1016      indent_statement (NEXT (q));
1017    } else if (IS (p, ASSIGNATION)) {
1018      NODE_T *dst = SUB (p);
1019      NODE_T *bec = NEXT (dst);
1020      NODE_T *src = NEXT (bec);
1021      indent_statement (dst);
1022      BLANK;
1023      put_sym (bec, !KEYWORD);
1024      BLANK;
1025      indent_statement (src);
1026    } else if (IS (p, ROUTINE_TEXT)) {
1027      NODE_T *q = SUB (p);
1028      int units, seps;
1029      if (IS (q, PARAMETER_PACK)) {
1030        indent_pack (SUB (q));
1031        BLANK;
1032        FORWARD (q);
1033      }
1034      indent_declarer (q);
1035      FORWARD (q);
1036      put_sym (q, !KEYWORD);      // :
1037      FORWARD (q);
1038      units = 0;
1039      seps = 0;
1040      count (q, &units, &seps);
1041      if (units <= 1) {
1042        BLANK;
1043        indent_statement (q);
1044      } else {
1045        put_nl ();
1046        indent_statement (q);
1047      }
1048    } else if (IS (p, IDENTITY_RELATION)) {
1049      NODE_T *lhs = SUB (p);
1050      NODE_T *op = NEXT (lhs);
1051      NODE_T *rhs = NEXT (op);
1052      indent_statement (lhs);
1053      BLANK;
1054      put_sym (op, !KEYWORD);
1055      BLANK;
1056      indent_statement (rhs);
1057    } else if (IS (p, JUMP)) {
1058      NODE_T *q = SUB (p);
1059      if (IS (q, GOTO_SYMBOL)) {
1060        put_sym (q, !KEYWORD);
1061        BLANK;
1062        FORWARD (q);
1063      }
1064      put_sym (q, !KEYWORD);
1065    } else if (IS (p, SKIP)) {
1066      put_sym (p, !KEYWORD);
1067    } else if (IS (p, ASSERTION)) {
1068      NODE_T *q = SUB (p);
1069      put_sym (q, KEYWORD);
1070      BLANK;
1071      indent_enclosed (NEXT (q));
1072    } else if (IS (p, CODE_CLAUSE)) {
1073      NODE_T *q = SUB (p);
1074      put_sym (q, KEYWORD);
1075      BLANK;
1076      FORWARD (q);
1077      indent_collection (SUB (q));
1078      FORWARD (q);
1079      put_sym (q, KEYWORD);
1080    }
1081  }
1082  
1083  //! @brief Indent identifier declarations.
1084  
1085  void indent_iddecl (NODE_T * p)
1086  {
1087    for (; p != NO_NODE; FORWARD (p)) {
1088      if (IS (p, IDENTITY_DECLARATION) || IS (p, VARIABLE_DECLARATION)) {
1089        indent_iddecl (SUB (p));
1090      } else if (IS (p, QUALIFIER)) {
1091        put_sym (SUB (p), !KEYWORD);
1092        BLANK;
1093      } else if (IS (p, DECLARER)) {
1094        indent_declarer (SUB (p));
1095        BLANK;
1096      } else if (IS (p, DEFINING_IDENTIFIER)) {
1097        NODE_T *q = p;
1098        int pop_ind = A68_INDENT (ind);
1099        put_sym (q, !KEYWORD);
1100        FORWARD (q);
1101        if (q != NO_NODE) {       // := unit
1102          BLANK;
1103          put_sym (q, !KEYWORD);
1104          BLANK;
1105          FORWARD (q);
1106          indent_statement (q);
1107        }
1108        A68_INDENT (ind) = pop_ind;
1109      } else if (IS (p, COMMA_SYMBOL)) {
1110        put_sym (p, !KEYWORD);
1111        BLANK;
1112      }
1113    }
1114  }
1115  
1116  //! @brief Indent procedure declarations.
1117  
1118  void indent_procdecl (NODE_T * p)
1119  {
1120    for (; p != NO_NODE; FORWARD (p)) {
1121      if (IS (p, PROCEDURE_DECLARATION) || IS (p, PROCEDURE_VARIABLE_DECLARATION)) {
1122        indent_procdecl (SUB (p));
1123      } else if (IS (p, PROC_SYMBOL)) {
1124        put_sym (p, KEYWORD);
1125        BLANK;
1126        A68_INDENT (ind) = A68_INDENT (col);
1127      } else if (IS (p, DEFINING_IDENTIFIER)) {
1128        NODE_T *q = p;
1129        int pop_ind = A68_INDENT (ind);
1130        put_sym (q, !KEYWORD);
1131        FORWARD (q);
1132        BLANK;
1133        put_sym (q, !KEYWORD);
1134        BLANK;
1135        FORWARD (q);
1136        indent_statement (q);
1137        A68_INDENT (ind) = pop_ind;
1138      } else if (IS (p, COMMA_SYMBOL)) {
1139        put_sym (p, !KEYWORD);
1140        put_nl ();
1141      }
1142    }
1143  }
1144  
1145  //! @brief Indent operator declarations.
1146  
1147  void indent_opdecl (NODE_T * p)
1148  {
1149    for (; p != NO_NODE; FORWARD (p)) {
1150      if (IS (p, OPERATOR_DECLARATION) || IS (p, BRIEF_OPERATOR_DECLARATION)) {
1151        indent_opdecl (SUB (p));
1152      } else if (IS (p, OP_SYMBOL)) {
1153        put_sym (p, KEYWORD);
1154        BLANK;
1155        A68_INDENT (ind) = A68_INDENT (col);
1156      } else if (IS (p, OPERATOR_PLAN)) {
1157        indent_declarer (SUB (p));
1158        BLANK;
1159        A68_INDENT (ind) = A68_INDENT (col);
1160      } else if (IS (p, DEFINING_OPERATOR)) {
1161        NODE_T *q = p;
1162        int pop_ind = A68_INDENT (ind);
1163        put_sym (q, !KEYWORD);
1164        FORWARD (q);
1165        BLANK;
1166        put_sym (q, !KEYWORD);
1167        BLANK;
1168        FORWARD (q);
1169        indent_statement (q);
1170        A68_INDENT (ind) = pop_ind;
1171      } else if (IS (p, COMMA_SYMBOL)) {
1172        put_sym (p, !KEYWORD);
1173        put_nl ();
1174      }
1175    }
1176  }
1177  
1178  //! @brief Indent priority declarations.
1179  
1180  void indent_priodecl (NODE_T * p)
1181  {
1182    for (; p != NO_NODE; FORWARD (p)) {
1183      if (IS (p, PRIORITY_DECLARATION)) {
1184        indent_priodecl (SUB (p));
1185      } else if (IS (p, PRIO_SYMBOL)) {
1186        put_sym (p, KEYWORD);
1187        BLANK;
1188      } else if (IS (p, DEFINING_OPERATOR)) {
1189        NODE_T *q = p;
1190        put_sym (q, !KEYWORD);
1191        FORWARD (q);
1192        BLANK;
1193        put_sym (q, !KEYWORD);
1194        BLANK;
1195        FORWARD (q);
1196        put_sym (q, !KEYWORD);
1197      } else if (IS (p, COMMA_SYMBOL)) {
1198        put_sym (p, !KEYWORD);
1199        BLANK;
1200      }
1201    }
1202  }
1203  
1204  //! @brief Indent mode declarations.
1205  
1206  void indent_modedecl (NODE_T * p)
1207  {
1208    for (; p != NO_NODE; FORWARD (p)) {
1209      if (IS (p, MODE_DECLARATION)) {
1210        indent_modedecl (SUB (p));
1211      } else if (IS (p, MODE_SYMBOL)) {
1212        put_sym (p, KEYWORD);
1213        BLANK;
1214        A68_INDENT (ind) = A68_INDENT (col);
1215      } else if (IS (p, DEFINING_INDICANT)) {
1216        NODE_T *q = p;
1217        int pop_ind = A68_INDENT (ind);
1218        put_sym (q, !KEYWORD);
1219        FORWARD (q);
1220        BLANK;
1221        put_sym (q, !KEYWORD);
1222        BLANK;
1223        FORWARD (q);
1224        indent_declarer (q);
1225        A68_INDENT (ind) = pop_ind;
1226      } else if (IS (p, COMMA_SYMBOL)) {
1227        put_sym (p, !KEYWORD);
1228        put_nl ();
1229      }
1230    }
1231  }
1232  
1233  //! @brief Indent declaration list.
1234  
1235  void indent_declist (NODE_T * p, BOOL_T one_liner)
1236  {
1237    for (; p != NO_NODE; FORWARD (p)) {
1238      if (IS (p, IDENTITY_DECLARATION) || IS (p, VARIABLE_DECLARATION)) {
1239        int pop_ind = A68_INDENT (ind);
1240        indent_iddecl (p);
1241        A68_INDENT (ind) = pop_ind;
1242      } else if (IS (p, PROCEDURE_DECLARATION) || IS (p, PROCEDURE_VARIABLE_DECLARATION)) {
1243        int pop_ind = A68_INDENT (ind);
1244        indent_procdecl (p);
1245        A68_INDENT (ind) = pop_ind;
1246      } else if (IS (p, OPERATOR_DECLARATION) || IS (p, BRIEF_OPERATOR_DECLARATION)) {
1247        int pop_ind = A68_INDENT (ind);
1248        indent_opdecl (p);
1249        A68_INDENT (ind) = pop_ind;
1250      } else if (IS (p, PRIORITY_DECLARATION)) {
1251        int pop_ind = A68_INDENT (ind);
1252        indent_priodecl (p);
1253        A68_INDENT (ind) = pop_ind;
1254      } else if (IS (p, MODE_DECLARATION)) {
1255        int pop_ind = A68_INDENT (ind);
1256        indent_modedecl (p);
1257        A68_INDENT (ind) = pop_ind;
1258      } else if (IS (p, COMMA_SYMBOL)) {
1259        put_sym (p, !KEYWORD);
1260        if (one_liner) {
1261          BLANK;
1262        } else {
1263          put_nl ();
1264        }
1265      } else {
1266        indent_declist (SUB (p), one_liner);
1267      }
1268    }
1269  }
1270  
1271  //! @brief Indent serial clause.
1272  
1273  void indent_serial (NODE_T * p, BOOL_T one_liner, NODE_T ** what)
1274  {
1275    for (; p != NO_NODE; FORWARD (p)) {
1276      if (IS (p, UNIT) || IS (p, LABELED_UNIT)) {
1277        int pop_ind = A68_INDENT (col);
1278        (*what) = p;
1279        indent_statement (p);
1280        A68_INDENT (ind) = pop_ind;
1281      } else if (IS (p, DECLARATION_LIST)) {
1282        (*what) = p;
1283        indent_declist (p, one_liner);
1284      } else if (IS (p, SEMI_SYMBOL)) {
1285        put_sym (p, !KEYWORD);
1286        if (!one_liner) {
1287          put_nl ();
1288          if ((*what) != NO_NODE && IS ((*what), DECLARATION_LIST)) {
1289  //        put_nl ();
1290          }
1291        } else {
1292          BLANK;
1293        }
1294      } else if (IS (p, EXIT_SYMBOL)) {
1295        if (NPRAGMENT (p) == NO_TEXT) {
1296          BLANK;
1297        }
1298        put_sym (p, !KEYWORD);
1299        if (!one_liner) {
1300          put_nl ();
1301        } else {
1302          BLANK;
1303        }
1304      } else {
1305        indent_serial (SUB (p), one_liner, what);
1306      }
1307    }
1308  }
1309  
1310  //! @brief Do not pretty-print the environ.
1311  
1312  void skip_environ (NODE_T * p)
1313  {
1314    for (; p != NO_NODE; FORWARD (p)) {
1315      if (LINE_NUMBER (p) == 0) {
1316        pretty_pragment (p, !KEYWORD);
1317        skip_environ (SUB (p));
1318      } else {
1319        NODE_T *what = NO_NODE;
1320        indent_serial (p, !ONE_LINER, &what);
1321      }
1322    }
1323  }
1324  
1325  //! @brief Indenter driver.
1326  
1327  void indenter (MODULE_T * q)
1328  {
1329    A68_INDENT (ind) = 1;
1330    A68_INDENT (col) = 1;
1331    A68_INDENT (indentation) = OPTION_INDENT (q);
1332    A68_INDENT (use_folder) = OPTION_FOLD (q);
1333    FILE_PRETTY_FD (q) = open (FILE_PRETTY_NAME (q), O_WRONLY | O_CREAT | O_TRUNC, A68_PROTECTION);
1334    ABEND (FILE_PRETTY_FD (q) == -1, ERROR_ACTION, __func__);
1335    FILE_PRETTY_OPENED (q) = A68_TRUE;
1336    A68_INDENT (fd) = FILE_PRETTY_FD (q);
1337    skip_environ (TOP_NODE (q));
1338    ASSERT (close (A68_INDENT (fd)) == 0);
1339    FILE_PRETTY_OPENED (q) = A68_FALSE;
1340  }