a68g-listing.c

     
   1  //! @file a68g-listing.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  //! Old-school listing file.
  25  
  26  #include "a68g.h"
  27  #include "a68g-prelude.h"
  28  #include "a68g-listing.h"
  29  #include "a68g-parser.h"
  30  #include "a68g-optimiser.h"
  31  
  32  // Routines for making a "fat" listing file.
  33  
  34  #define SHOW_EQ A68_FALSE
  35  
  36  //! @brief a68_print_short_mode.
  37  
  38  void a68_print_short_mode (FILE_T f, MOID_T * z)
  39  {
  40    if (IS (z, STANDARD)) {
  41      int i = DIM (z);
  42      if (i > 0) {
  43        while (i--) {
  44          WRITE (f, "LONG ");
  45        }
  46      } else if (i < 0) {
  47        while (i++) {
  48          WRITE (f, "SHORT ");
  49        }
  50      }
  51      ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, "%s", NSYMBOL (NODE (z))) >= 0);
  52      WRITE (f, A68 (output_line));
  53    } else if (IS_REF (z) && IS (SUB (z), STANDARD)) {
  54      WRITE (f, "REF ");
  55      a68_print_short_mode (f, SUB (z));
  56    } else if (IS (z, PROC_SYMBOL) && PACK (z) == NO_PACK && IS (SUB (z), STANDARD)) {
  57      WRITE (f, "PROC ");
  58      a68_print_short_mode (f, SUB (z));
  59    } else {
  60      ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, "#%d", NUMBER (z)) >= 0);
  61      WRITE (f, A68 (output_line));
  62    }
  63  }
  64  
  65  //! @brief A68g_print_flat_mode.
  66  
  67  void a68_print_flat_mode (FILE_T f, MOID_T * z)
  68  {
  69    if (IS (z, STANDARD)) {
  70      int i = DIM (z);
  71      if (i > 0) {
  72        while (i--) {
  73          WRITE (f, "LONG ");
  74        }
  75      } else if (i < 0) {
  76        while (i++) {
  77          WRITE (f, "SHORT ");
  78        }
  79      }
  80      ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, "%s", NSYMBOL (NODE (z))) >= 0);
  81      WRITE (f, A68 (output_line));
  82    } else if (IS_REF (z)) {
  83      ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, "REF ") >= 0);
  84      WRITE (f, A68 (output_line));
  85      a68_print_short_mode (f, SUB (z));
  86    } else if (IS (z, PROC_SYMBOL) && DIM (z) == 0) {
  87      ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, "PROC ") >= 0);
  88      WRITE (f, A68 (output_line));
  89      a68_print_short_mode (f, SUB (z));
  90    } else if (IS_ROW (z)) {
  91      int i = DIM (z);
  92      WRITE (f, "[");
  93      while (--i) {
  94        WRITE (f, ", ");
  95      }
  96      WRITE (f, "] ");
  97      a68_print_short_mode (f, SUB (z));
  98    } else {
  99      a68_print_short_mode (f, z);
 100    }
 101  }
 102  
 103  //! @brief Brief_fields_flat.
 104  
 105  void a68_print_short_pack (FILE_T f, PACK_T * pack)
 106  {
 107    if (pack != NO_PACK) {
 108      a68_print_short_mode (f, MOID (pack));
 109      if (NEXT (pack) != NO_PACK) {
 110        ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, ", ") >= 0);
 111        WRITE (f, A68 (output_line));
 112        a68_print_short_pack (f, NEXT (pack));
 113      }
 114    }
 115  }
 116  
 117  //! @brief A68g_print_mode.
 118  
 119  void a68_print_mode (FILE_T f, MOID_T * z)
 120  {
 121    if (z != NO_MOID) {
 122      if (IS (z, STANDARD)) {
 123        a68_print_flat_mode (f, z);
 124      } else if (IS (z, INDICANT)) {
 125        WRITE (f, NSYMBOL (NODE (z)));
 126      } else if (z == M_COLLITEM) {
 127        WRITE (f, "\"COLLITEM\"");
 128      } else if (IS_REF (z)) {
 129        WRITE (f, "REF ");
 130        a68_print_flat_mode (f, SUB (z));
 131      } else if (IS_FLEX (z)) {
 132        WRITE (f, "FLEX ");
 133        a68_print_flat_mode (f, SUB (z));
 134      } else if (IS_ROW (z)) {
 135        int i = DIM (z);
 136        WRITE (f, "[");
 137        while (--i) {
 138          WRITE (f, ", ");
 139        }
 140        WRITE (f, "] ");
 141        a68_print_flat_mode (f, SUB (z));
 142      } else if (IS_STRUCT (z)) {
 143        WRITE (f, "STRUCT (");
 144        a68_print_short_pack (f, PACK (z));
 145        WRITE (f, ")");
 146      } else if (IS_UNION (z)) {
 147        WRITE (f, "UNION (");
 148        a68_print_short_pack (f, PACK (z));
 149        WRITE (f, ")");
 150      } else if (IS (z, PROC_SYMBOL)) {
 151        WRITE (f, "PROC ");
 152        if (PACK (z) != NO_PACK) {
 153          WRITE (f, "(");
 154          a68_print_short_pack (f, PACK (z));
 155          WRITE (f, ") ");
 156        }
 157        a68_print_flat_mode (f, SUB (z));
 158      } else if (IS (z, IN_TYPE_MODE)) {
 159        WRITE (f, "\"SIMPLIN\"");
 160      } else if (IS (z, OUT_TYPE_MODE)) {
 161        WRITE (f, "\"SIMPLOUT\"");
 162      } else if (IS (z, ROWS_SYMBOL)) {
 163        WRITE (f, "\"ROWS\"");
 164      } else if (IS (z, SERIES_MODE)) {
 165        WRITE (f, "\"SERIES\" (");
 166        a68_print_short_pack (f, PACK (z));
 167        WRITE (f, ")");
 168      } else if (IS (z, STOWED_MODE)) {
 169        WRITE (f, "\"STOWED\" (");
 170        a68_print_short_pack (f, PACK (z));
 171        WRITE (f, ")");
 172      }
 173    }
 174  }
 175  
 176  //! @brief Print_mode_flat.
 177  
 178  void print_mode_flat (FILE_T f, MOID_T * m)
 179  {
 180    if (m != NO_MOID) {
 181      a68_print_mode (f, m);
 182      if (NODE (m) != NO_NODE && NUMBER (NODE (m)) > 0) {
 183        ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, " node %d", NUMBER (NODE (m))) >= 0);
 184        WRITE (f, A68 (output_line));
 185      }
 186      if (EQUIVALENT_MODE (m) != NO_MOID) {
 187        ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, " equi #%d", NUMBER (EQUIVALENT (m))) >= 0);
 188        WRITE (f, A68 (output_line));
 189      }
 190      if (SLICE (m) != NO_MOID) {
 191        ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, " slice #%d", NUMBER (SLICE (m))) >= 0);
 192        WRITE (f, A68 (output_line));
 193      }
 194      if (TRIM (m) != NO_MOID) {
 195        ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, " trim #%d", NUMBER (TRIM (m))) >= 0);
 196        WRITE (f, A68 (output_line));
 197      }
 198      if (ROWED (m) != NO_MOID) {
 199        ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, " rowed #%d", NUMBER (ROWED (m))) >= 0);
 200        WRITE (f, A68 (output_line));
 201      }
 202      if (DEFLEXED (m) != NO_MOID) {
 203        ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, " deflex #%d", NUMBER (DEFLEXED (m))) >= 0);
 204        WRITE (f, A68 (output_line));
 205      }
 206      if (MULTIPLE (m) != NO_MOID) {
 207        ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, " multiple #%d", NUMBER (MULTIPLE (m))) >= 0);
 208        WRITE (f, A68 (output_line));
 209      }
 210      if (NAME (m) != NO_MOID) {
 211        ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, " name #%d", NUMBER (NAME (m))) >= 0);
 212        WRITE (f, A68 (output_line));
 213      }
 214      if (USE (m)) {
 215        ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, " used") >= 0);
 216        WRITE (f, A68 (output_line));
 217      }
 218      if (DERIVATE (m)) {
 219        ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, " derivate") >= 0);
 220        WRITE (f, A68 (output_line));
 221      }
 222      if (SIZE (m) > 0) {
 223        ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, " size %d", SIZE (m)) >= 0);
 224        WRITE (f, A68 (output_line));
 225      }
 226      if (HAS_ROWS (m)) {
 227        WRITE (f, " []");
 228      }
 229    }
 230  }
 231  
 232  //! @brief Xref_tags.
 233  
 234  void xref_tags (FILE_T f, TAG_T * s, int a)
 235  {
 236    for (; s != NO_TAG; FORWARD (s)) {
 237      NODE_T *where_tag = NODE (s);
 238      if ((where_tag != NO_NODE) && ((STATUS_TEST (where_tag, CROSS_REFERENCE_MASK)) || TAG_TABLE (s) == A68_STANDENV)) {
 239        WRITE (f, "\n     ");
 240        ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, "tag %d ", NUMBER (s)) >= 0);
 241        WRITE (f, A68 (output_line));
 242        switch (a) {
 243        case IDENTIFIER: {
 244            a68_print_mode (f, MOID (s));
 245            ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, " %s", NSYMBOL (NODE (s))) >= 0);
 246            WRITE (f, A68 (output_line));
 247            break;
 248          }
 249        case INDICANT: {
 250            ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, "indicant %s ", NSYMBOL (NODE (s))) >= 0);
 251            WRITE (f, A68 (output_line));
 252            a68_print_mode (f, MOID (s));
 253            break;
 254          }
 255        case PRIO_SYMBOL: {
 256            ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, "priority %s %d", NSYMBOL (NODE (s)), PRIO (s)) >= 0);
 257            WRITE (f, A68 (output_line));
 258            break;
 259          }
 260        case OP_SYMBOL: {
 261            ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, "operator %s ", NSYMBOL (NODE (s))) >= 0);
 262            WRITE (f, A68 (output_line));
 263            a68_print_mode (f, MOID (s));
 264            break;
 265          }
 266        case LABEL: {
 267            ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, "label %s", NSYMBOL (NODE (s))) >= 0);
 268            WRITE (f, A68 (output_line));
 269            break;
 270          }
 271        case ANONYMOUS: {
 272            switch (PRIO (s)) {
 273            case ROUTINE_TEXT: {
 274                ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, "routine text ") >= 0);
 275                break;
 276              }
 277            case FORMAT_TEXT: {
 278                ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, "format text ") >= 0);
 279                break;
 280              }
 281            case FORMAT_IDENTIFIER: {
 282                ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, "format item ") >= 0);
 283                break;
 284              }
 285            case COLLATERAL_CLAUSE: {
 286                ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, "display ") >= 0);
 287                break;
 288              }
 289            case GENERATOR: {
 290                ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, "generator ") >= 0);
 291                break;
 292              }
 293            }
 294            WRITE (f, A68 (output_line));
 295            a68_print_mode (f, MOID (s));
 296            break;
 297          }
 298        default: {
 299            ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, "internal %d ", a) >= 0);
 300            WRITE (f, A68 (output_line));
 301            a68_print_mode (f, MOID (s));
 302            break;
 303          }
 304        }
 305        if (NODE (s) != NO_NODE && NUMBER (NODE (s)) > 0) {
 306          ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, ", node %d", NUMBER (NODE (s))) >= 0);
 307          WRITE (f, A68 (output_line));
 308        }
 309        if (where_tag != NO_NODE && INFO (where_tag) != NO_NINFO && LINE (INFO (where_tag)) != NO_LINE) {
 310          ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, ", line %d", LINE_NUMBER (where_tag)) >= 0);
 311          WRITE (f, A68 (output_line));
 312        }
 313      }
 314    }
 315  }
 316  
 317  //! @brief Xref_decs.
 318  
 319  void xref_decs (FILE_T f, TABLE_T * t)
 320  {
 321    if (INDICANTS (t) != NO_TAG) {
 322      xref_tags (f, INDICANTS (t), INDICANT);
 323    }
 324    if (OPERATORS (t) != NO_TAG) {
 325      xref_tags (f, OPERATORS (t), OP_SYMBOL);
 326    }
 327    if (PRIO (t) != NO_TAG) {
 328      xref_tags (f, PRIO (t), PRIO_SYMBOL);
 329    }
 330    if (IDENTIFIERS (t) != NO_TAG) {
 331      xref_tags (f, IDENTIFIERS (t), IDENTIFIER);
 332    }
 333    if (LABELS (t) != NO_TAG) {
 334      xref_tags (f, LABELS (t), LABEL);
 335    }
 336    if (ANONYMOUS (t) != NO_TAG) {
 337      xref_tags (f, ANONYMOUS (t), ANONYMOUS);
 338    }
 339  }
 340  
 341  //! @brief Xref1_moid.
 342  
 343  void xref1_moid (FILE_T f, MOID_T * p)
 344  {
 345    ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, "\n     #%d ", NUMBER (p)) >= 0);
 346    WRITE (f, A68 (output_line));
 347    print_mode_flat (f, p);
 348  }
 349  
 350  //! @brief Moid_listing.
 351  
 352  void moid_listing (FILE_T f, MOID_T * m)
 353  {
 354    if (m == NO_MOID) {
 355      return;
 356    }
 357    for (; m != NO_MOID; FORWARD (m)) {
 358      xref1_moid (f, m);
 359    }
 360    WRITE (f, "\n");
 361    ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, "\n     MODE STRING  #%d ", NUMBER (M_STRING)) >= 0);
 362    WRITE (f, A68 (output_line));
 363    ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, "\n     MODE COMPLEX #%d ", NUMBER (M_COMPLEX)) >= 0);
 364    WRITE (f, A68 (output_line));
 365    ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, "\n     MODE SEMA    #%d ", NUMBER (M_SEMA)) >= 0);
 366    WRITE (f, A68 (output_line));
 367  }
 368  
 369  //! @brief Cross_reference.
 370  
 371  void cross_reference (FILE_T f, NODE_T * p, LINE_T * l)
 372  {
 373    if (p != NO_NODE && CROSS_REFERENCE_SAFE (&A68_JOB)) {
 374      for (; p != NO_NODE; FORWARD (p)) {
 375        if (is_new_lexical_level (p) && l == LINE (INFO (p))) {
 376          TABLE_T *c = TABLE (SUB (p));
 377          ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, "\n\n[level %d", LEVEL (c)) >= 0);
 378          WRITE (f, A68 (output_line));
 379          if (PREVIOUS (c) == A68_STANDENV) {
 380            ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, ", in standard environ") >= 0);
 381          } else {
 382            ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, ", in level %d", LEVEL (PREVIOUS (c))) >= 0);
 383          }
 384          WRITE (f, A68 (output_line));
 385  #if (A68_LEVEL >= 3)
 386          ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, ", %llu increment]", AP_INCREMENT (c)) >= 0);
 387  #else
 388          ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, ", %u increment]", AP_INCREMENT (c)) >= 0);
 389  #endif
 390          WRITE (f, A68 (output_line));
 391          if (c != NO_TABLE) {
 392            xref_decs (f, c);
 393          }
 394          WRITE (f, "\n");
 395        }
 396        cross_reference (f, SUB (p), l);
 397      }
 398    }
 399  }
 400  
 401  //! @brief Tree listing for source line.
 402  
 403  BOOL_T empty_leaf (NODE_T * p)
 404  {
 405  #define TEST_LEAVE(n)\
 406    if (IS (p, (n)) && NEXT (p) == NO_NODE && PREVIOUS (p) == NO_NODE) {\
 407      return A68_TRUE;\
 408    }
 409    TEST_LEAVE (ENCLOSED_CLAUSE);
 410    TEST_LEAVE (UNIT);
 411    TEST_LEAVE (TERTIARY);
 412    TEST_LEAVE (SECONDARY);
 413    TEST_LEAVE (PRIMARY);
 414    TEST_LEAVE (DENOTATION);
 415    return A68_FALSE;
 416  #undef TEST_LEAVE
 417  }
 418  
 419  //! @brief Tree listing for source line.
 420  
 421  void tree_listing (FILE_T f, NODE_T * q, int x, LINE_T * l, int *ld, BOOL_T comment)
 422  {
 423    for (; q != NO_NODE; FORWARD (q)) {
 424      NODE_T *p = q;
 425      int dist;
 426      if (((STATUS_TEST (p, TREE_MASK)) || comment) && l == LINE (INFO (p))) {
 427        if (*ld < 0) {
 428          *ld = x;
 429        }
 430  // Indent.
 431        if (comment && empty_leaf (p)) {
 432          ;
 433        } else {
 434          if (comment) {
 435            WRITE (f, "\n// ");
 436            ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, "%06d ", NUMBER (p)) >= 0);
 437            WRITE (f, A68 (output_line));
 438          } else {
 439            WRITE (f, "\n     ");
 440            ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, "%02d %06d p%02d ", x, NUMBER (p), PROCEDURE_LEVEL (INFO (p))) >= 0);
 441            WRITE (f, A68 (output_line));
 442            if (TABLE (p) != NO_TABLE && PREVIOUS (TABLE (p)) != NO_TABLE) {
 443              ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, "%02d-%02d-%02d ", (TABLE (p) != NO_TABLE ? LEX_LEVEL (p) : 0), (TABLE (p) != NO_TABLE ? LEVEL (PREVIOUS (TABLE (p))) : 0), (NON_LOCAL (p) != NO_TABLE ? LEVEL (NON_LOCAL (p)) : 0)
 444                      ) >= 0);
 445            } else {
 446              ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, "%02d-  -%02d", (TABLE (p) != NO_TABLE ? LEX_LEVEL (p) : 0), (NON_LOCAL (p) != NO_TABLE ? LEVEL (NON_LOCAL (p)) : 0)
 447                      ) >= 0);
 448            }
 449            WRITE (f, A68 (output_line));
 450            if (MOID (q) != NO_MOID) {
 451              ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, "#%04d ", NUMBER (MOID (p))) >= 0);
 452            } else {
 453              ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, "      ") >= 0);
 454            }
 455            WRITE (f, A68 (output_line));
 456          }
 457          for (int k = 0; k < (x - *ld); k++) {
 458            WRITE (f, A68 (marker)[k]);
 459          }
 460          if (MOID (p) != NO_MOID) {
 461            ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, "%s ", moid_to_string (MOID (p), MOID_WIDTH, NO_NODE)) >= 0);
 462            WRITE (f, A68 (output_line));
 463          }
 464          ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, "%s", non_terminal_string (A68 (edit_line), ATTRIBUTE (p))) >= 0);
 465          WRITE (f, A68 (output_line));
 466          if (SUB (p) == NO_NODE) {
 467            ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, " \"%s\"", NSYMBOL (p)) >= 0);
 468            WRITE (f, A68 (output_line));
 469          }
 470          if (!comment) {
 471            if (TAX (p) != NO_TAG) {
 472              ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, ", tag %06u", (unt) NUMBER (TAX (p))) >= 0);
 473              WRITE (f, A68 (output_line));
 474              if (MOID (TAX (p)) != NO_MOID) {
 475                ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, ", mode %06u", (unt) NUMBER (MOID (TAX (p)))) >= 0);
 476                WRITE (f, A68 (output_line));
 477              }
 478            }
 479            if (GINFO (p) != NO_GINFO && propagator_name ((const PROP_PROC *) UNIT (&GPROP (p))) != NO_TEXT) {
 480              ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, ", %s", propagator_name ((const PROP_PROC *) UNIT (&GPROP (p)))) >= 0);
 481              WRITE (f, A68 (output_line));
 482            }
 483            if (GINFO (p) != NO_GINFO && COMPILE_NAME (GINFO (p)) != NO_TEXT) {
 484              ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, ", %s", COMPILE_NAME (GINFO (p))) >= 0);
 485              WRITE (f, A68 (output_line));
 486            }
 487            if (GINFO (p) != NO_GINFO && COMPILE_NODE (GINFO (p)) > 0) {
 488              ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, ", %6d", COMPILE_NODE (GINFO (p))) >= 0);
 489              WRITE (f, A68 (output_line));
 490            }
 491          }
 492        }
 493        dist = x - (*ld);
 494        if (dist >= 0 && dist < BUFFER_SIZE) {
 495          A68 (marker)[dist] = (NEXT (p) != NO_NODE && l == LINE (INFO (NEXT (p))) ? "|" : " ");
 496        }
 497      }
 498      tree_listing (f, SUB (p), x + 1, l, ld, comment);
 499      dist = x - (*ld);
 500      if (dist >= 0 && dist < BUFFER_SIZE) {
 501        A68 (marker)[dist] = " ";
 502      }
 503    }
 504  }
 505  
 506  //! @brief Leaves_to_print.
 507  
 508  int leaves_to_print (NODE_T * p, LINE_T * l)
 509  {
 510    int z = 0;
 511    for (; p != NO_NODE && z == 0; FORWARD (p)) {
 512      if (l == LINE (INFO (p)) && ((STATUS_TEST (p, TREE_MASK)))) {
 513        z++;
 514      } else {
 515        z += leaves_to_print (SUB (p), l);
 516      }
 517    }
 518    return z;
 519  }
 520  
 521  //! @brief List_source_line.
 522  
 523  void list_source_line (FILE_T f, LINE_T * line, BOOL_T tree)
 524  {
 525    int k = (int) strlen (STRING (line)) - 1;
 526    if (NUMBER (line) <= 0) {
 527  // Mask the prelude and postlude.
 528      return;
 529    }
 530    if ((STRING (line))[k] == NEWLINE_CHAR) {
 531      (STRING (line))[k] = NULL_CHAR;
 532    }
 533  // Print source line.
 534    write_source_line (f, line, NO_NODE, A68_ALL_DIAGNOSTICS);
 535  // Cross reference for lexical levels starting at this line.
 536    if (OPTION_CROSS_REFERENCE (&A68_JOB)) {
 537      cross_reference (f, TOP_NODE (&A68_JOB), line);
 538    }
 539  // Syntax tree listing connected with this line.
 540    if (tree && OPTION_TREE_LISTING (&A68_JOB)) {
 541      if (TREE_LISTING_SAFE (&A68_JOB) && leaves_to_print (TOP_NODE (&A68_JOB), line)) {
 542        int ld = -1, k2;
 543        WRITE (f, "\n\nSyntax tree");
 544        for (k2 = 0; k2 < BUFFER_SIZE; k2++) {
 545          A68 (marker)[k2] = " ";
 546        }
 547        tree_listing (f, TOP_NODE (&A68_JOB), 1, line, &ld, A68_FALSE);
 548        WRITE (f, "\n");
 549      }
 550    }
 551  }
 552  
 553  //! @brief Source_listing.
 554  
 555  void write_source_listing (void)
 556  {
 557    FILE_T f = FILE_LISTING_FD (&A68_JOB);
 558    int listed = 0;
 559    WRITE (FILE_LISTING_FD (&A68_JOB), NEWLINE_STRING);
 560    WRITE (FILE_LISTING_FD (&A68_JOB), "\nSource listing");
 561    WRITE (FILE_LISTING_FD (&A68_JOB), "\n------ -------");
 562    WRITE (FILE_LISTING_FD (&A68_JOB), NEWLINE_STRING);
 563    if (FILE_LISTING_OPENED (&A68_JOB) == 0) {
 564      diagnostic (A68_ERROR, NO_NODE, ERROR_CANNOT_WRITE_LISTING, NO_LINE, 0);
 565      return;
 566    }
 567    for (LINE_T *line = TOP_LINE (&A68_JOB); line != NO_LINE; FORWARD (line)) {
 568      if (NUMBER (line) > 0 && LIST (line)) {
 569        listed++;
 570      }
 571      list_source_line (f, line, A68_FALSE);
 572    }
 573  // Warn if there was no source at all.
 574    if (listed == 0) {
 575      ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, "\n     No lines to list") >= 0);
 576      WRITE (f, A68 (output_line));
 577    }
 578  }
 579  
 580  //! @brief Write_source_listing.
 581  
 582  void write_tree_listing (void)
 583  {
 584    WRITE (FILE_LISTING_FD (&A68_JOB), NEWLINE_STRING);
 585    WRITE (FILE_LISTING_FD (&A68_JOB), "\nSyntax tree listing");
 586    WRITE (FILE_LISTING_FD (&A68_JOB), "\n------ ---- -------");
 587    WRITE (FILE_LISTING_FD (&A68_JOB), NEWLINE_STRING);
 588    if (FILE_LISTING_OPENED (&A68_JOB) == 0) {
 589      diagnostic (A68_ERROR, NO_NODE, ERROR_CANNOT_WRITE_LISTING, NO_LINE, 0);
 590      return;
 591    }
 592    FILE_T f = FILE_LISTING_FD (&A68_JOB);
 593    int listed = 0;
 594    for (LINE_T *line = TOP_LINE (&A68_JOB); line != NO_LINE; FORWARD (line)) {
 595      if (NUMBER (line) > 0 && LIST (line)) {
 596        listed++;
 597      }
 598      list_source_line (f, line, A68_TRUE);
 599    }
 600  // Warn if there was no source at all.
 601    if (listed == 0) {
 602      ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, "\n     No lines to list") >= 0);
 603      WRITE (f, A68 (output_line));
 604    }
 605  }
 606  
 607  //! @brief Write_object_listing.
 608  
 609  void write_object_listing (void)
 610  {
 611    if (OPTION_OBJECT_LISTING (&A68_JOB)) {
 612      WRITE (FILE_LISTING_FD (&A68_JOB), NEWLINE_STRING);
 613      WRITE (FILE_LISTING_FD (&A68_JOB), "\nObject listing");
 614      WRITE (FILE_LISTING_FD (&A68_JOB), "\n------ -------");
 615      WRITE (FILE_LISTING_FD (&A68_JOB), NEWLINE_STRING);
 616      plugin_driver_emit (FILE_LISTING_FD (&A68_JOB));
 617    }
 618  }
 619  
 620  //! @brief Write_listing.
 621  
 622  void write_listing (void)
 623  {
 624    FILE_T f = FILE_LISTING_FD (&A68_JOB);
 625    if (OPTION_MOID_LISTING (&A68_JOB) && TOP_MOID (&A68_JOB) != NO_MOID) {
 626      WRITE (FILE_LISTING_FD (&A68_JOB), NEWLINE_STRING);
 627      WRITE (FILE_LISTING_FD (&A68_JOB), "\nMode listing");
 628      WRITE (FILE_LISTING_FD (&A68_JOB), "\n---- -------");
 629      WRITE (FILE_LISTING_FD (&A68_JOB), NEWLINE_STRING);
 630      moid_listing (f, TOP_MOID (&A68_JOB));
 631    }
 632    if (OPTION_STANDARD_PRELUDE_LISTING (&A68_JOB) && A68_STANDENV != NO_TABLE) {
 633      WRITE (FILE_LISTING_FD (&A68_JOB), NEWLINE_STRING);
 634      WRITE (FILE_LISTING_FD (&A68_JOB), "\nStandard prelude listing");
 635      WRITE (FILE_LISTING_FD (&A68_JOB), "\n-------- ------- -------");
 636      WRITE (FILE_LISTING_FD (&A68_JOB), NEWLINE_STRING);
 637      xref_decs (f, A68_STANDENV);
 638    }
 639    if (TOP_REFINEMENT (&A68_JOB) != NO_REFINEMENT) {
 640      REFINEMENT_T *x = TOP_REFINEMENT (&A68_JOB);
 641      WRITE (FILE_LISTING_FD (&A68_JOB), NEWLINE_STRING);
 642      WRITE (FILE_LISTING_FD (&A68_JOB), "\nRefinement listing");
 643      WRITE (FILE_LISTING_FD (&A68_JOB), "\n---------- -------");
 644      WRITE (FILE_LISTING_FD (&A68_JOB), NEWLINE_STRING);
 645      while (x != NO_REFINEMENT) {
 646        ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, "\n  \"%s\"", NAME (x)) >= 0);
 647        WRITE (f, A68 (output_line));
 648        if (LINE_DEFINED (x) != NO_LINE) {
 649          ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, ", defined in line %d", NUMBER (LINE_DEFINED (x))) >= 0);
 650          WRITE (f, A68 (output_line));
 651        }
 652        if (LINE_APPLIED (x) != NO_LINE) {
 653          ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, ", applied in line %d", NUMBER (LINE_APPLIED (x))) >= 0);
 654          WRITE (f, A68 (output_line));
 655        }
 656        switch (APPLICATIONS (x)) {
 657        case 0: {
 658            ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, ", not applied") >= 0);
 659            WRITE (f, A68 (output_line));
 660            break;
 661          }
 662        case 1: {
 663            break;
 664          }
 665        default: {
 666            ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, ", applied more than once") >= 0);
 667            WRITE (f, A68 (output_line));
 668            break;
 669          }
 670        }
 671        FORWARD (x);
 672      }
 673    }
 674    if (OPTION_LIST (&A68_JOB) != NO_OPTION_LIST) {
 675      int k = 1;
 676      WRITE (FILE_LISTING_FD (&A68_JOB), NEWLINE_STRING);
 677      WRITE (FILE_LISTING_FD (&A68_JOB), "\nPragmat listing");
 678      WRITE (FILE_LISTING_FD (&A68_JOB), "\n------- -------");
 679      WRITE (FILE_LISTING_FD (&A68_JOB), NEWLINE_STRING);
 680      for (OPTION_LIST_T *l = OPTION_LIST (&A68_JOB); l != NO_OPTION_LIST; FORWARD (l)) {
 681        ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, "\n%d: %s", k++, STR (l)) >= 0);
 682        WRITE (f, A68 (output_line));
 683      }
 684    }
 685  }
 686  
 687  //! @brief Write_listing_header.
 688  
 689  void write_listing_header (void)
 690  {
 691    FILE_T f = FILE_LISTING_FD (&A68_JOB);
 692    state_version (FILE_LISTING_FD (&A68_JOB));
 693    WRITE (FILE_LISTING_FD (&A68_JOB), "\nFile \"");
 694    WRITE (FILE_LISTING_FD (&A68_JOB), FILE_SOURCE_NAME (&A68_JOB));
 695    WRITE (FILE_LISTING_FD (&A68_JOB), "\"");
 696    if (OPTION_STATISTICS_LISTING (&A68_JOB)) {
 697      if (ERROR_COUNT (&A68_JOB) + WARNING_COUNT (&A68_JOB) > 0) {
 698        ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, "\nDiagnostics: %d error(s), %d warning(s)", ERROR_COUNT (&A68_JOB), WARNING_COUNT (&A68_JOB)) >= 0);
 699        WRITE (f, A68 (output_line));
 700        for (LINE_T *z = TOP_LINE (&A68_JOB); z != NO_LINE; FORWARD (z)) {
 701          if (DIAGNOSTICS (z) != NO_DIAGNOSTIC) {
 702            write_source_line (f, z, NO_NODE, A68_TRUE);
 703          }
 704        }
 705      }
 706    }
 707  }