summaryrefslogtreecommitdiff
path: root/src/runtime/c/teyjus/simulator/printterm.c
blob: cedc631471cedf5eef06171e4be049fd5a9d5c68 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
//////////////////////////////////////////////////////////////////////////////
//Copyright 2008
//  Andrew Gacek, Steven Holte, Gopalan Nadathur, Xiaochu Qi, Zach Snow
//////////////////////////////////////////////////////////////////////////////
// This file is part of Teyjus.                                             //
//                                                                          //
// Teyjus is free software: you can redistribute it and/or modify           //
// it under the terms of the GNU General Public License as published by     //
// the Free Software Foundation, either version 3 of the License, or        //
// (at your option) any later version.                                      //
//                                                                          //
// Teyjus is distributed in the hope that it will be useful,                //
// but WITHOUT ANY WARRANTY; without even the implied warranty of           //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            //
// GNU General Public License for more details.                             //
//                                                                          //
// You should have received a copy of the GNU General Public License        //
// along with Teyjus.  If not, see <http://www.gnu.org/licenses/>.          //
//////////////////////////////////////////////////////////////////////////////
/****************************************************************************
 *                                                                          *
 * File printterm.c. This file contains routines for printing out lambda    *
 * terms. It is assumed that these routines will be needed in two           *
 * situations: printing out answers to queries and displaying terms as      *
 * needed by invocation of builtin goals.                                   *
 * The difference between these two situations is in the display of         *
 * free term variables. Only when displaying answers is an attempt made to  *
 * present these using sensible names: in this case, either the name in the *
 * query is used or a concise name is cooked up. In the other situation,    *
 * the address of the variable cell is used as the name.                    *
 *                                                                          *
 * Certain assumptions are relevant to avoiding name clashes. For local     *
 * constants, the assumption is that no constant names in user              *
 * programs begin with <lc- and end with >. The use of this idea is         *
 * buried inside the routine PRINT_writeHCName.                             *
 * Violation of this condition is *not* checked. For term variables, the    *
 * assumption is that bound variables do not begin with _.                  *
 *                                                                          *
 ****************************************************************************/
#include <stdlib.h>
#include <string.h>
#include "printterm.h"
#include "mctypes.h"
#include "mcstring.h"
#include "hnorm.h"
#include "dataformats.h"
#include "abstmachine.h"
#include "io-datastructures.h"
#include "builtins/builtins.h"
#include "../system/stream.h"
#include "../system/error.h"
#include "../system/operators.h"
#include "../tables/pervasives.h"

//temp
#include <stdio.h>

/* This variable records the number of query variables */
int PRINT_numQueryVars;

/* flag determining whether or not to print sensible names for free vars */
Boolean PRINT_names = FALSE;

static void PRINT_writeTerm(WordPtr outStream, DF_TermPtr tmPtr, 
                            OP_FixityType infx, int inprec, OP_TermContext tc);

/****************************************************************************
 *                   Auxiliary routines used in this file                   *
 ****************************************************************************/
static Boolean PRINT_parenNeeded(OP_FixityType opfx, int opprec, 
                                 OP_TermContext context, OP_FixityType fx, 
                                 int prec)
{
    Boolean pparen = FALSE;
    if (context == OP_LEFT_TERM) {
        switch (fx) {
        case OP_INFIX: case OP_INFIXR: case OP_POSTFIX:
            if (opprec <= prec) pparen = TRUE;   break;
        case OP_INFIXL: case OP_POSTFIXL: 
        {
            switch (opfx) {
            case OP_PREFIX: case OP_INFIX: case OP_INFIXL: case OP_POSTFIX:
            case OP_POSTFIXL: 
                if (opprec < prec) pparen = TRUE; break;
            default:
                if (opprec <= prec) pparen = TRUE; break;
            }
            break;
        }
        default:
			break;
        }
    } else if (context == OP_RIGHT_TERM) {
        switch (fx) {
        case OP_INFIX: case OP_INFIXL: case OP_PREFIX:
            if (opprec <= prec) pparen = TRUE; break;
        case OP_INFIXR: case OP_PREFIXR:
        {
            switch (opfx) {
            case OP_INFIXL: case OP_POSTFIXL:
                if (opprec <= prec) pparen = TRUE; break;
            default:
                if (opprec < prec) pparen = TRUE; break;
            }
        }
        default:
			break;
        }
    }
    return pparen;
}

/* making a name from the address of an unbound term variable */
static long PRINT_makeNumberName(DF_TermPtr tmPtr)
{ return (long)tmPtr - (long)AM_heapBeg;                      }


/****************************************************************************
 * Routines for printing out keywords and punctuation symbols in the course *
 * of displaying lambda terms. These have been extracted out of the other   *
 * routines so as to make stylistic changes at a later point easier to      *
 * effect.                                                                  *
 ****************************************************************************/
static void PRINT_writeLParen(WordPtr outStream)
{ STREAM_printf(outStream, "(");                             }

static void PRINT_writeRParen(WordPtr outStream)
{ STREAM_printf(outStream, ")");                             }

static void PRINT_writeConsSymbol(WordPtr outStream)
{ STREAM_printf(outStream, " :: ");                          }

static void PRINT_writeNilSymbol(WordPtr outStream)
{ STREAM_printf(outStream, "nil");                           }

static void PRINT_writeInfixLam(WordPtr outStream)
{ STREAM_printf(outStream, "\\ ");                           }

static void PRINT_writeSpace(WordPtr outStream, int i)
{ while (i--) STREAM_printf(outStream, " ");                 }    

static void PRINT_writeEquals(WordPtr outStream) 
{ STREAM_printf(outStream, " = ");                           }

static void PRINT_writeComma(WordPtr outStream)
{ STREAM_printf(outStream, ",");                             }

static void PRINT_writeDPairStart(WordPtr outStream)
{ STREAM_printf(outStream, "<");                             }
    
static void PRINT_writeDPairEnd(WordPtr outStream)
{ STREAM_printf(outStream, ">");                             }

/***************************************************************************
 * Writing out terms corresponding to the builtin constants.               *
 ***************************************************************************/
/* Writing out an integer term to a given output stream */
static void PRINT_writeInt(WordPtr outStream, DF_TermPtr tmPtr)
{ STREAM_printf(outStream, "%d", DF_intValue(tmPtr));        }

/* Writing out a float term to a given output stream */
static void PRINT_writeFloat(WordPtr outStream, DF_TermPtr tmPtr)
{ STREAM_printf(outStream, "%f", DF_floatValue(tmPtr));      }

/* Writing out a string term to a given output stream */
static void PRINT_writeString(WordPtr outStream, DF_TermPtr tmPtr)
{ STREAM_printf(outStream, "\"%s\"", MCSTR_toCString(DF_strValue(tmPtr))); }

/* Writing out a stream constant to a given output stream */
static void PRINT_writeStream(WordPtr outStream, DF_TermPtr tmPtr)
{
    WordPtr stream = DF_streamTabIndex(tmPtr);
    STREAM_printf(outStream, "<stream ");
    if (stream == STREAM_ILLEGAL) STREAM_printf(outStream, "-- closed>");
    else STREAM_printf(outStream, "-- \"%s\">", STREAM_getName(stream));
}

/****************************************************************************
 *  Writing out a constant. Use the index into the runtime constant table   *
 *  stored in the constant to get the constant name if one exists. If one   *
 *  does not exist, i.e. if the constant is a local or hidden one, look for *
 *  it in a list of constants. If it is not in this list, make up a new     *
 *  name. Eventually, the name consists of three parts: a generic name for  *
 *  hidden constants, a part based on the runtime table index and a part    *
 *  based on the universe index.                                            *
 ****************************************************************************/
/* A structure for maintaining information about local constants encountered
while printing; this structure enables the assignment of a unique integer
to each runtime symbol table slot for such a constant. */
typedef struct  PRINT_ConstList_ *PRINT_ConstList;

struct  PRINT_ConstList_ 
{
    int   constInd;
    int   count;
    PRINT_ConstList  next; 
};

static PRINT_ConstList PRINT_clist = NULL;
static int PRINT_lccount = 0;

static void PRINT_cleanCList()
{
    PRINT_ConstList tmp;
    
    PRINT_lccount = 0;
    while (PRINT_clist){
        tmp = PRINT_clist;
        PRINT_clist = PRINT_clist -> next;
        free(tmp);
    }
}

/* writing out a hidden (local) constant name; as side effect, a note may be 
   made of a new hidden (local) constant seen during this printing. */
static void PRINT_writeHCName(WordPtr outStream, int constInd, int uc)
{
    PRINT_ConstList lclist = PRINT_clist;
    while (lclist && (lclist->constInd != constInd)) lclist = lclist->next;
    
    if (!lclist) {
        lclist = (PRINT_ConstList)EM_malloc(sizeof(struct PRINT_ConstList_));
        lclist->constInd = constInd;
        lclist->count    = PRINT_lccount++;
        lclist->next     = PRINT_clist;
        PRINT_clist      = lclist;
    }
    
    STREAM_printf(outStream, "<lc-%d-%d>", lclist->count, uc);
}

/* Writing out a constant, hidden or global. */
static void PRINT_writeConst(WordPtr outStream, DF_TermPtr tmPtr)
{
    int   constInd = DF_constTabIndex(tmPtr);
    char* name     = AM_cstName(constInd);
    
    if (name) STREAM_printf(outStream, "%s", name);
    else PRINT_writeHCName(outStream, constInd, DF_constUnivCount(tmPtr));
}

/****************************************************************************
 * Writing out a free variable. Two situations are possible, one where a    *
 * symbolic name is to be produced and the other where the `address' could  *
 * serve as the name. In the first case, if the variable is a query         *
 * variable, then its name from the query is used. Otherwise a new name is  *
 * invented that is distinct from other free term variable names; the       *
 * initial segment of the name guarantees that it will be distinct from     *
 * that of  bound variables.                                                *
 ****************************************************************************/
/* counter used to generate free variable name */
static int  PRINT_fvcounter = 1;

/* Create a free term variable name; this starts with _ has a standard
   string prefix and then a digit sequence */
static DF_StrDataPtr PRINT_makeFVarName()
{
    int           digits = 0;
    int           i = PRINT_fvcounter;
    int           length;
    char*         cname;
    DF_StrDataPtr fvname;

    while(i) { digits++; i = i/10; }

    length = digits + 3;
    cname = (char*)EM_malloc(sizeof(char)*length);
    cname[0] = '_';
    cname[1] = 'T';
    cname[length-1] = '\0';
    
    i = PRINT_fvcounter;
    while(i) {
        cname[digits+1] = (i%10 + '0');
        i = i/10;
        digits--;
    }
    PRINT_fvcounter++;

    fvname = (DF_StrDataPtr)EM_malloc(sizeof(Word)*(MCSTR_numWords(length) +
						    DF_STRDATA_HEAD_SIZE));
    DF_mkStrDataHead((MemPtr)fvname);
    MCSTR_toString((MemPtr)((MemPtr)fvname + DF_STRDATA_HEAD_SIZE),
                   cname, length);
    free(cname);
    return fvname;
}

/* Does a made up name occur in the free term variable table? Clash can
only occur with names in the user query */
static Boolean PRINT_nameInFVTab(DF_StrDataPtr name)
{
    int i;
    for (i = 0; i < PRINT_numQueryVars ; i++){
      if (MCSTR_sameStrs(DF_strDataValue(name), 
			 DF_strDataValue(IO_freeVarTab[i].varName)))
	return TRUE;
    }
    return FALSE;
}

/* The main routine for printing out an unbound term variable */
static void PRINT_writeFVar(WordPtr outStream, DF_TermPtr tmPtr)
{
    int           fvind = 0;
    DF_StrDataPtr fvname;

		//PRINT_names = TRUE;
    if (PRINT_names) {
        IO_freeVarTab[IO_freeVarTabTop].rigdes = tmPtr;
        
        while (tmPtr != IO_freeVarTab[fvind].rigdes) fvind++;
        
        if (fvind == IO_freeVarTabTop) {
            /* i.e., a free variable not seen before */
            if (IO_freeVarTabTop == IO_MAX_FREE_VARS) 
                EM_error(BI_ERROR_TYFVAR_CAP);
            
            while(1) {//make a name
                fvname = PRINT_makeFVarName();
                if (!PRINT_nameInFVTab(fvname)) break;
                free(fvname);
            }
            
            IO_freeVarTab[fvind].varName = fvname;
            IO_freeVarTabTop++;
        }
        STREAM_printf(outStream, 
	       MCSTR_toCString(DF_strDataValue(IO_freeVarTab[fvind].varName)));
    } else { //PRINT_names = FALSE
        STREAM_printf(outStream, "_%ld", PRINT_makeNumberName(tmPtr));
    }
}

/****************************************************************************
 * Routines for writing out bound variables (in lambda abstraction and      *
 * bound variable occurrence)                                               *
 ****************************************************************************/
/* prefix for bound variables */
static char* PRINT_bvname = "W";

/* a counter for determining the suffix part of bound variables */
static int PRINT_bvcounter = 1;

/* A structure for maintaining information about bound variable names */
typedef struct PRINT_BVList_ *PRINT_BVList;

struct PRINT_BVList_ {
  DF_StrDataPtr name;
  PRINT_BVList  next; };

/* the initial list of bound variable names; initialized in SIM_InitIo */
static  PRINT_BVList  PRINT_bvs = NULL;

static void PRINT_cleanBV(PRINT_BVList bv)
{
  free(bv->name);
  free(bv);
}

/* releasing the space for bound variables; needed only in case of error
   exit */  
static void PRINT_cleanBVList()
{
  PRINT_BVList tbvl;

  PRINT_bvcounter = 1;
  while (PRINT_bvs) {
    tbvl = PRINT_bvs; PRINT_bvs = PRINT_bvs->next; 
    PRINT_cleanBV(tbvl);
  }
}

/****************************************************************************
 * Writing out a bound variable                                             *
 ****************************************************************************/
static void PRINT_writeBVar(WordPtr outStream, DF_TermPtr tmPtr)
{
  int i;
  int bvind = DF_bvIndex(tmPtr);
  PRINT_BVList lbvs = PRINT_bvs;

  for (i = bvind; ((i != 1) && lbvs) ; i--) 
    lbvs = lbvs->next;

  // Is this checking and the else branch really necessary? 
  // Printing should start from top-level closed terms?
  if (lbvs) STREAM_printf(outStream, "%s", 
			  MCSTR_toCString(DF_strDataValue(lbvs->name)));
  else STREAM_printf(outStream, "#%d", i); 
}

/****************************************************************************
 * Writing out an empty list                                                *
 ****************************************************************************/
static void PRINT_writeNil(WordPtr outStream)
{  PRINT_writeNilSymbol(outStream);                      }

/****************************************************************************
 * Writing out a non-empty list.                                            *
 ****************************************************************************/
static void PRINT_writeCons(WordPtr outStream, DF_TermPtr tmPtr, 
                            OP_FixityType fx, int prec, OP_TermContext tc)
{
    DF_TermPtr    args     = DF_consArgs(tmPtr);
    OP_FixityType consfix  = (OP_FixityType)AM_cstFixity(PERV_CONS_INDEX);
    int           consprec = AM_cstPrecedence(PERV_CONS_INDEX);
    Boolean       pparen   = PRINT_parenNeeded(consfix, consprec, tc, fx,prec);

    if (pparen) PRINT_writeLParen(outStream);
    PRINT_writeTerm(outStream, args, consfix, consprec, OP_LEFT_TERM);    
    PRINT_writeConsSymbol(outStream);
    
    do {
        args++;
        tmPtr = DF_termDeref(args);
        if (DF_termTag(tmPtr) != DF_TM_TAG_CONS) break;
        args = DF_consArgs(tmPtr);
        PRINT_writeTerm(outStream, args, consfix, consprec, OP_LEFT_TERM);
        PRINT_writeConsSymbol(outStream);
    } while(1);
    
    PRINT_writeTerm(outStream, tmPtr, consfix, consprec, OP_RIGHT_TERM);
    if (pparen) PRINT_writeRParen(outStream);
}

/****************************************************************************
 * Writing out an abstraction.                                              *
 ****************************************************************************/
/* creating a bound variable name with bound variable prefix followed by the*/
/* current bound variable counter value.                                    */
static DF_StrDataPtr PRINT_makeBVarName()
{
  int            digits = 0;
  int            i = PRINT_bvcounter;
  int            length;
  char*          cname;
  DF_StrDataPtr  bvname;

  while(i) { digits++; i = i/10; }

  length = digits + 2;
  cname = (char*)EM_malloc(sizeof(char)*length);
  strcpy(cname, PRINT_bvname);
  cname[length-1] = '\0';
  
  i = PRINT_bvcounter;
  while(i) {
    cname[digits] = (i%10 + '0');
    i = i/10;
    digits--;
  }
  PRINT_bvcounter++;

  bvname = (DF_StrDataPtr)EM_malloc(sizeof(Word)*(MCSTR_numWords(length) +
						  DF_STRDATA_HEAD_SIZE));
 
  DF_mkStrDataHead((MemPtr)bvname);
  MCSTR_toString((MemPtr)((MemPtr)bvname + DF_STRDATA_HEAD_SIZE),
		 cname, length);
  free(cname);
  return bvname;
}

static void PRINT_writeAbstBinders(WordPtr outStream, int nabs) 
{
  DF_StrDataPtr bvname;
  PRINT_BVList  tmpbvs;

  while(nabs > 0) {
    nabs--;
    while(1) {//make a bvname not in FV table
      bvname = PRINT_makeBVarName();
      if (!PRINT_nameInFVTab(bvname)) break;
      free(bvname);
    }

    //record the name into the head of the current bvlist
    tmpbvs = (PRINT_BVList)EM_malloc(sizeof(struct PRINT_BVList_));
    tmpbvs->name = bvname;
    tmpbvs->next = PRINT_bvs;
    PRINT_bvs = tmpbvs;
    //write out binder
    STREAM_printf(outStream, "%s", MCSTR_toCString(DF_strDataValue(bvname)));
    PRINT_writeInfixLam(outStream);
  }
}

static void PRINT_writeAbst(WordPtr outStream, DF_TermPtr tmPtr, 
                            OP_FixityType fx, int prec, OP_TermContext tc)
{    
    int     numabs = 0;
    Boolean pparen = PRINT_parenNeeded(OP_LAM_FIXITY,OP_LAM_PREC,tc,fx,prec);
    PRINT_BVList tmpbvs;
    int          tmpbvc = PRINT_bvcounter;
    
    if (pparen) PRINT_writeLParen(outStream);
    while (DF_isLam(tmPtr)){
        numabs += DF_lamNumAbs(tmPtr);
        tmPtr = DF_termDeref(DF_lamBody(tmPtr));
    }
    PRINT_writeAbstBinders(outStream, numabs);
    PRINT_writeTerm(outStream, tmPtr, OP_LAM_FIXITY,OP_LAM_PREC,OP_RIGHT_TERM);
    if (pparen) PRINT_writeRParen(outStream);

    while (numabs > 0) {
      numabs--;
      tmpbvs = PRINT_bvs;
      PRINT_bvs = PRINT_bvs->next;
      PRINT_cleanBV(tmpbvs);
    } 
    PRINT_bvcounter = tmpbvc;
}      

/****************************************************************************
 *                      WRITING OUT AN APPLICATION                          *
 *                                                                          *
 * Note that it is assumed that nested application structures are flattened *
 * during the full normalization process.                                   *
 ****************************************************************************/
/* Getting the fixity and precedence for the head of an application. 
   Assume the pointer to the term head is already dereferenced. */
static void PRINT_getHeadInfo(DF_TermPtr hdPtr, OP_FixityType *fx, int* prec)
{
    int cstInd;
    switch (DF_termTag(hdPtr)) {
    case DF_TM_TAG_CONST:
        cstInd = DF_constTabIndex(hdPtr);
        if (AM_cstName(cstInd)) {
            *fx   = (OP_FixityType)AM_cstFixity(cstInd);
            *prec = AM_cstPrecedence(cstInd);
        } else {
            *fx   = OP_NONE;
            *prec = 0;
        }
        break;
    case DF_TM_TAG_VAR:
        *fx   = OP_NONE;
        *prec = OP_MINPREC;
        break;
    case DF_TM_TAG_BVAR:
        *fx   = OP_NONE;
        *prec = OP_MINPREC;
        break;
    }
}    
        
/* Writing out a term with a prefix operator as head; we use the knowledge
that the operator must be a constant here and that the pointer to it is
fully dereferenced */
static void PRINT_writePrefixTerm(WordPtr outStream, DF_TermPtr head,
                                  OP_FixityType opfx, int opprec,
                                  OP_TermContext tc, OP_FixityType fx,int prec,
                                  DF_TermPtr args)
{
    Boolean pparen = PRINT_parenNeeded(opfx, opprec, tc, fx, prec);
    
    if (pparen) PRINT_writeLParen(outStream);
    PRINT_writeConst(outStream, head);
    PRINT_writeSpace(outStream, 1);
    PRINT_writeTerm(outStream, args, opfx, opprec, OP_RIGHT_TERM);
    if (pparen) PRINT_writeRParen(outStream);
}

static void PRINT_writeInfixTerm(WordPtr outStream, DF_TermPtr head,
                                 OP_FixityType opfx, int opprec, 
                                 OP_TermContext tc, OP_FixityType fx, int prec,
                                 DF_TermPtr args)
{
    Boolean pparen = PRINT_parenNeeded(opfx, opprec, tc, fx, prec);
    if(pparen) PRINT_writeLParen(outStream);
    PRINT_writeTerm(outStream, args, opfx, opprec, OP_LEFT_TERM);
    PRINT_writeSpace(outStream, 1);
    PRINT_writeConst(outStream, head);
    PRINT_writeSpace(outStream, 1);
    PRINT_writeTerm(outStream, args+1, opfx, opprec, OP_RIGHT_TERM);
    if (pparen) PRINT_writeRParen(outStream);
}                                  

static void PRINT_writePostfixTerm(WordPtr outStream, DF_TermPtr head,
                                   OP_FixityType opfx, int opprec, 
                                   OP_TermContext tc,OP_FixityType fx,int prec,
                                   DF_TermPtr args) 
{
    Boolean pparen = PRINT_parenNeeded(opfx, opprec, tc, fx, prec);
    if(pparen) PRINT_writeLParen(outStream);
    PRINT_writeTerm(outStream, args, opfx, opprec, OP_LEFT_TERM);
    PRINT_writeSpace(outStream, 1);
    PRINT_writeConst(outStream, head);
    if (pparen) PRINT_writeRParen(outStream);
}                                  

/* Main routine for writing out an application term */
static void PRINT_writeApp(WordPtr outStream, DF_TermPtr tmPtr, 
                           OP_FixityType infx, int inprec, OP_TermContext tc)
{   
  
    DF_TermPtr head   = DF_termDeref(DF_appFunc(tmPtr));
    DF_TermPtr args   = DF_appArgs(tmPtr);
    int        arity  = DF_appArity(tmPtr);
    Boolean    pparen = PRINT_parenNeeded(OP_APP_FIXITY, OP_APP_PREC, tc, infx,
                                          inprec);
    OP_FixityType  fix = 0;
    int            prec = 0;

    HN_hnorm(tmPtr);
    PRINT_getHeadInfo(AM_head, &fix, &prec);  
    
    switch(fix){
    case OP_PREFIX: case OP_PREFIXR:
      if (arity == 1) {
	pparen = FALSE;
	PRINT_writePrefixTerm(outStream, head, fix, prec, tc, infx, inprec,
			      args);
	
       } else { 
	 if (pparen) PRINT_writeLParen(outStream);
	 PRINT_writePrefixTerm(outStream, head, fix, prec, OP_LEFT_TERM,
			       OP_APP_FIXITY, OP_APP_PREC, args);
       }
      arity--; args++;
      break;
    case OP_INFIX: case OP_INFIXL: case OP_INFIXR:
      if (arity == 2) {
	pparen = FALSE;
	PRINT_writeInfixTerm(outStream, head, fix, prec, tc, infx, inprec, 
			     args);
      } else {
	if (pparen) PRINT_writeLParen(outStream);
	PRINT_writeInfixTerm(outStream, head, fix, prec, OP_LEFT_TERM,
			     OP_APP_FIXITY, OP_APP_PREC, args);
      }
      arity -= 2; args += 2;
      break;
    case OP_POSTFIX: case OP_POSTFIXL:
      if (arity == 1) {
	pparen = FALSE;
	PRINT_writePostfixTerm(outStream, head, fix, prec, tc, infx,
			       inprec, args);
      }  else { 
	if (pparen) PRINT_writeLParen(outStream);
	PRINT_writePostfixTerm(outStream, head, fix, prec, OP_LEFT_TERM,
			       OP_APP_FIXITY, OP_APP_PREC, args);
      }
      break;
    case OP_NONE:
      if (pparen) PRINT_writeLParen(outStream);
      PRINT_writeTerm(outStream,head,OP_APP_FIXITY,OP_APP_PREC,OP_LEFT_TERM);
      break;
    } /*switch*/

    /* print the arguments (if any) of the application */
    while (arity > 0) {
        PRINT_writeSpace(outStream, 1);
        PRINT_writeTerm(outStream, args, OP_APP_FIXITY, OP_APP_PREC,
			OP_RIGHT_TERM);
        args++;
        arity--;
    }
    if (pparen) PRINT_writeRParen(outStream);
}


/*****************************************************************************
 * The main routine for writing out a term; this is called by the interface  *
 * routines to do the real job of printing.                                  *
 *****************************************************************************/
static void PRINT_writeTerm(WordPtr outStream, DF_TermPtr tmPtr, 
                            OP_FixityType infx, int inprec, OP_TermContext tc)
{
    tmPtr = DF_termDeref(tmPtr);
    switch (DF_termTag(tmPtr)) {
    case DF_TM_TAG_INT:     PRINT_writeInt(outStream, tmPtr);    break;
    case DF_TM_TAG_FLOAT:   PRINT_writeFloat(outStream, tmPtr);  break;
    case DF_TM_TAG_STR:     PRINT_writeString(outStream, tmPtr); break;
    case DF_TM_TAG_STREAM:  PRINT_writeStream(outStream, tmPtr); break;
    case DF_TM_TAG_CONST:   PRINT_writeConst(outStream, tmPtr);  break;
    case DF_TM_TAG_VAR:     PRINT_writeFVar(outStream, tmPtr);   break;
    case DF_TM_TAG_BVAR:    PRINT_writeBVar(outStream, tmPtr);   break;
    case DF_TM_TAG_NIL:     PRINT_writeNil(outStream);           break;
    case DF_TM_TAG_CONS:    
        PRINT_writeCons(outStream, tmPtr, infx, inprec, tc);     break;
    case DF_TM_TAG_LAM:     
        PRINT_writeAbst(outStream, tmPtr, infx, inprec, tc);     break;
    case DF_TM_TAG_APP:
        PRINT_writeApp(outStream, tmPtr, infx, inprec, tc);      break;
    } /* switch */    
}


/* Printing a term to a specified output stream; names will be invented for
free variables if the boolean variable PRINT_names is set. */
void PRINT_fPrintTerm(WordPtr outStream, DF_TermPtr tmPtr)
{
  HN_lnorm(tmPtr);
  PRINT_writeTerm(outStream, tmPtr, OP_NONE, 0, OP_WHOLE_TERM);
}

/* Printing routine for debugging */
void PRINT_printTerm(DF_TermPtr tmPtr)
{
    PRINT_fPrintTerm(STREAM_stdout, tmPtr);
    STREAM_printf(STREAM_stdout, "\n");
}

/* printing an answer substitution pair */
static void PRINT_printSubsPair(WordPtr outStream, int ind)
{
    DF_TermPtr tmPtr;
    char *varName = 
        MCSTR_toCString(DF_strDataValue(IO_freeVarTab[ind].varName));    

    /* print the variable name if it is not an anonymous variable */
    if (strcmp(varName, "_") != 0) {        
        STREAM_printf(outStream, varName);
        
        /* Print the equals sign */
        PRINT_writeEquals(outStream);
        
        /* Print the binding of the variable */
        tmPtr = IO_freeVarTab[ind].rigdes;
        HN_lnorm(tmPtr);
        PRINT_writeTerm(outStream, tmPtr, OP_NONE, 0, OP_WHOLE_TERM);
    }    
}

void PRINT_showAnswerSubs()
{
    int i;
    
    PRINT_names = TRUE;
    
    for (i = 0; i < PRINT_numQueryVars; i++) {
        PRINT_printSubsPair(STREAM_stdout, i);
        STREAM_printf(STREAM_stdout, "\n");
    }
}

/* Printing a disagreement pair to a specified output stream */
static void PRINT_printDPair(WordPtr outStream, DF_DisPairPtr dpair)
{
    DF_TermPtr tmPtr;
    
    PRINT_writeDPairStart(outStream);
    
    tmPtr = DF_disPairFirstTerm(dpair);
    HN_lnorm(tmPtr);
    PRINT_writeTerm(outStream, tmPtr, OP_NONE, 0, OP_WHOLE_TERM);
    
    PRINT_writeComma(outStream);
    PRINT_writeSpace(outStream, 1);
    
    tmPtr = DF_disPairSecondTerm(dpair);
    HN_lnorm(tmPtr);    
    PRINT_writeTerm(outStream, tmPtr, OP_NONE, 0, OP_WHOLE_TERM);

    PRINT_writeDPairEnd(outStream);
}

void PRINT_showDisAgreeList()
{
    DF_DisPairPtr liveList = AM_llreg;
    
    while (DF_isNEmpDisSet(liveList)) {
        PRINT_printDPair(STREAM_stdout, liveList);
        liveList = DF_disPairNext(liveList);
        STREAM_printf(STREAM_stdout, "\n");
    }    
}

void PRINT_setQueryFreeVariables()
{
    PRINT_numQueryVars = IO_freeVarTabTop;
}

/* Use this function to reset the top of the free variable table
after a read; this is logical and also needed to avoid trying 
to release print name space accidentally at some other point. */
void PRINT_resetFreeVarTab()
{
  IO_freeVarTabTop = PRINT_numQueryVars;
}


void PRINT_resetPrintState()
{
    /* release space for term variables created during printing */
    while (IO_freeVarTabTop > PRINT_numQueryVars){
        IO_freeVarTabTop--;
        free(IO_freeVarTab[IO_freeVarTabTop].varName);
    }
    
    /* reset counters used in names of anonymous term and type variables */
    PRINT_fvcounter = 1; 

    /* free space for information created for local consts and reset counter */
    PRINT_cleanCList();    
    
    /* free space for information created for bound vars and reset counter */
    PRINT_cleanBVList();
}

Boolean PRINT_queryHasVars()
{
    int i = PRINT_numQueryVars - 1;
    while (!(i < 0) && 
           (strcmp(MCSTR_toCString(DF_strDataValue(IO_freeVarTab[i].varName)),
                   "_") == 0)) 
        i--;
    
    if (i < 0) return FALSE;
    else return TRUE;
    
}