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