summaryrefslogtreecommitdiff
path: root/trans.c
blob: d78c5cd329510ce90c247f068cbf1c94fae4c79c (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
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/* MIRANDA TRANS */
/* performs translation to combinatory logic */

/**************************************************************************
 * Copyright (C) Research Software Limited 1985-90.  All rights reserved. *
 * The Miranda system is distributed as free software under the terms in  *
 * the file "COPYING" which is included in the distribution.              *
 *                                                                        *
 * Revised to C11 standard and made 64bit compatible, January 2020        *
 *------------------------------------------------------------------------*/

#include "data.h"
#include "big.h"
#include "lex.h"

 /* miscellaneous declarations  */
extern word nill,Void;
extern word listdiff_fn,count_fn,from_fn;
extern word diagonalise,concat;
extern word lastname,initialising;
extern word current_id,echoing;
extern word errs;
word newtyps=NIL;  /* list of typenames declared in current script */
word SGC=NIL; /* list of user defined sui-generis constructors */
#define sui_generis(k) (/* k==Void|| */ member(SGC,k))
                       /* 3/10/88 decision to treat `()' as lifted */
static word abshfnck(word,word);
static word abstr(word,word);
static word combine(word,word);
static void decl1(word,word);
static word fixrepeats(word);
static word getrel(word,word);
static word here_inf(word);
static word imageless(word,word,word);
static word invgetrel(word,word);
static word leftfactor(word);
static word less(word,word);
static word less1(word,word);
static word liscomb(word,word);
static word makeshow(word,word);
static word mklazy(word);
static word mkshowt(word,word);
static word mktuple(word);
static void nameclash(word);
static int nclchk(word,word,word);
static word new_mklazy(word);
static word primconstr(word);
static void respec_error(word);
static word scanpattern(word,word,word,word);
static word sort(word);
static word translet(word,word);
static word transletrec(word,word);
static word transtries(word,word);
static word transzf(word,word,word);

word abstract(x,e) /* abstraction of template x from compiled expression e */
word x,e;
{ switch(tag[x])
  { case ID:
    	if(isconstructor(x))
      	return(sui_generis(x)?ap(K,e):
	       	ap2(Ug,primconstr(x),e));
    	else return(abstr(x,e));
    case CONS:
    	if(hd[x]==CONST)
	  if(tag[tl[x]]==INT)return(ap2(MATCHINT,tl[x],e));
	  else return(ap2(MATCH,tl[x]==NILS?NIL:tl[x],e));
    	else return(ap(U_,abstract(hd[x],abstract(tl[x],e))));
    case TCONS:
    case PAIR: /* tuples */
    	return(ap(U,abstract(hd[x],abstract(tl[x],e))));
    case AP:
  	if(sui_generis(head(x)))
    	return(ap(Uf,abstract(hd[x],abstract(tl[x],e))));
  	if(tag[hd[x]]==AP&&hd[hd[x]]==PLUS) /* n+k pattern */
    	return(ap2(ATLEAST,tl[hd[x]],abstract(tl[x],e)));
  	while(tag[x]==AP)
    	     { e= abstract(tl[x],e);
       	       x= hd[x]; }
           /* now x must be a constructor */
    default: ; }
  if(isconstructor(x))
    return(ap2(Ug,primconstr(x),e));
  printf("error in declaration of \"%s\", undeclared constructor in pattern: ",
	 get_id(current_id));  /* something funny here - fix later */
  out(stdout,x);
  printf("\n");
  return(NIL);
}

word primconstr(x)
word x;
{ x=id_val(x);
  while(tag[x]!=CONSTRUCTOR)x=tl[x];
  return(x);
  /* => constructor values are of the form TRY f k where k is the
     original constructor value, and ! constructors are of the form
     MKSTRICT i k */
}

word memb(l,x)  /* tests if x is a member of list "l" - used in testing for 
              repeated names - see rule for "v2" in rules.y */
word l,x;
{ if(tag[x]==TVAR)  /* type variable! */
    while(l!=NIL&&!eqtvar(hd[l],x))l= tl[l];
  else while(l!=NIL&&hd[l]!=x)l= tl[l];
  return(l!=NIL); }

word abstr(x,e)   /*  "bracket abstraction" of variable x from code e */
word x,e;
{ switch(tag[e])
  { case TCONS:
    case PAIR:
    case CONS: return(liscomb(abstr(x,hd[e]),abstr(x,tl[e])));
    case AP: if(hd[e]==BADCASE||hd[e]==CONFERROR)
               return(ap(K,e)); /* don't go inside error info */
             return(combine(abstr(x,hd[e]),abstr(x,tl[e])));
    case LAMBDA:
    case LET:
    case LETREC:
    case TRIES:
    case LABEL:
    case SHOW:
    case LEXER:
    case SHARE: fprintf(stderr,"impossible event in abstr (tag=%d)\n",tag[e]),
		exit(1);
    default: if(x==e||isvar_t(x)&&isvar_t(e)&&eqtvar(x,e))
               return(I); /* see note */
             return(ap(K,e));
}} /* note - we allow abstraction wrt tvars - see genshfns() */

#define mkindex(i)  ((i)<256?(i):make(INT,i,0))
   /* will fall over if i >= IBASE */

word abstrlist(x,e)  /* abstraction of list of variables x from code e */
word x,e;
{ switch(tag[e])
  { case TCONS:
    case PAIR:
    case CONS: return(liscomb(abstrlist(x,hd[e]),abstrlist(x,tl[e])));
    case AP: if(hd[e]==BADCASE||hd[e]==CONFERROR)
               return(ap(K,e)); /* don't go inside error info */
             else return(combine(abstrlist(x,hd[e]),abstrlist(x,tl[e])));
    case LAMBDA: case LET: case LETREC: case TRIES: case LABEL: case SHOW:
    case LEXER:
    case SHARE: fprintf(stderr,
			"impossible event in abstrlist (tag=%d)\n",tag[e]),
		exit(1);
    default: { word i=0;
	       while(x!=NIL&&hd[x]!=e)i++,x=tl[x];
	       if(x==NIL)return(ap(K,e));
	       return(ap(SUBSCRIPT,mkindex(i))); }
}}

word rv_script=0; /* flags readvals in use (for garbage collector) */

word codegen(x) /* returns expression x with abstractions performed */
word x;
{ extern word commandmode,cook_stdin,common_stdin,common_stdinb,rv_expr;
  switch(tag[x])
  { case AP: if(commandmode /* beware of corrupting lastexp */
		&&x!=cook_stdin&&x!=common_stdin&&x!=common_stdinb) /* but share $+ $- */
	       return(make(AP,codegen(hd[x]),codegen(tl[x])));
             if(tag[hd[x]]==AP&&hd[hd[x]]==APPEND&&tl[hd[x]]==NIL)
               return(codegen(tl[x])); /* post typecheck reversal of HR bug fix */
              hd[x]=codegen(hd[x]); tl[x]=codegen(tl[x]);
	       /* otherwise do in situ */
	      return(tag[hd[x]]==AP&&hd[hd[x]]==G_ALT?leftfactor(x):x);
    case TCONS:
    case PAIR: return(make(CONS,codegen(hd[x]),codegen(tl[x])));
    case CONS: if(commandmode)
		 return(make(CONS,codegen(hd[x]),codegen(tl[x])));
	       /* otherwise do in situ (see declare) */
               hd[x]=codegen(hd[x]); tl[x]=codegen(tl[x]);
	       return(x);
    case LAMBDA: return(abstract(hd[x],codegen(tl[x])));
    case LET: return(translet(hd[x],tl[x]));
    case LETREC: return(transletrec(hd[x],tl[x]));
    case TRIES: return(transtries(hd[x],tl[x]));
    case LABEL: return(codegen(tl[x]));
    case SHOW: return(makeshow(hd[x],tl[x]));
    case LEXER:
         { word r=NIL,uses_state=0;;
           while(x!=NIL)
              { word rule=abstr(mklexvar(0),codegen(tl[tl[hd[x]]]));
                rule=abstr(mklexvar(1),rule);
                if(!(tag[rule]==AP&&hd[rule]==K))uses_state=1;
                r=cons(cons(hd[hd[x]], /* start condition stuff */
                            cons(ap(hd[tl[hd[x]]],NIL),   /* matcher [] */
                                 rule)),
                       r);
                x=tl[x]; }
           if(!uses_state)  /* strip off (K -) from each rule */
             { for(x=r;x!=NIL;x=tl[x])tl[tl[hd[x]]]=tl[tl[tl[hd[x]]]];
               r = ap(LEX_RPT,ap(LEX_TRY,r)); }
           else r = ap(LEX_RPT1,ap(LEX_TRY1,r));
           return(ap(r,0)); } /* 0 startcond */
    case STARTREADVALS:
	 if(ispoly(tl[x]))
	   { extern word cook_stdin,ND;
	     printf("type error - %s used at polymorphic type :: [",
	             cook_stdin&&x==hd[cook_stdin]?"$+":"readvals or $+");
	     out_type(redtvars(tl[x])),printf("]\n");
             polyshowerror=1;
             if(current_id)
	       ND=add1(current_id,ND),
               id_type(current_id)=wrong_t,
               id_val(current_id)=UNDEF;
	     if(hd[x])sayhere(hd[x],1); }
	 if(commandmode)rv_expr=1; else rv_script=1;
	 return(x);
    case SHARE: if(tl[x]!= -1) /* arbitrary flag for already visited */
		  hd[x]=codegen(hd[x]),tl[x]= -1;
		return(hd[x]);
    default: if(x==NILS)return(NIL);
             return(x); /* identifier, private name, or constant */
}}

int lfrule=0;

word leftfactor(x)
/* grammar optimisations - x is of the form ap2(G_ALT,...)
   G_ALT(G_SEQ a b) a  => G_SEQ a (G_ALT b G_UNIT)
   G_ALT(G_SEQ a b)(G_SEQ a c) => G_SEQ a (G_ALT b c)
   G_ALT(G_SEQ a b)(G_ALT a d) => G_ALT(G_SEQ a (G_ALT b G_UNIT)) d
   G_ALT(G_SEQ a b)(G_ALT(G_SEQ a c) d) => G_ALT(G_SEQ a (G_ALT b c)) d
*/
word x;
{ word a,b,c,d;
  if(tag[c=tl[hd[x]]]==AP&&tag[hd[c]]==AP&&hd[hd[c]]==G_SEQ)
    a=tl[hd[c]],b=tl[c];  else return(x);
  if(same(a,d=tl[x])) 
    { hd[x]=ap(G_SEQ,a), tl[x]=ap2(G_ALT,b,G_UNIT); lfrule++;
      /* printob("rule1: ",x); */
      return(x); }
  if(tag[d]==AP&&tag[hd[d]]==AP)
    c=hd[hd[d]]; else return(x);
  if(c==G_SEQ&&same(a,tl[hd[d]])) 
    { c=tl[d], 
      hd[x]=ap(G_SEQ,a), tl[x]=leftfactor(ap2(G_ALT,b,c)); lfrule++;
      /* printob("rule2: ",x); */
      return(x); }
  if(c!=G_ALT)return(x);
  if(same(a,c=tl[hd[d]]))
    { d=tl[d];
      hd[x]=ap(G_ALT,ap2(G_SEQ,a,ap2(G_ALT,b,G_UNIT)));
      tl[x]=d; lfrule++;
      /* printob("rule3: ",x); */
      return(leftfactor(x)); }
  if(tag[c]==AP&&tag[hd[c]]==AP&&hd[hd[c]]==G_SEQ
     &&same(a,tl[hd[c]]))
    { c=tl[c],d=tl[d], 
      hd[x]=ap(G_ALT,ap2(G_SEQ,a,leftfactor(ap2(G_ALT,b,c))));
      tl[x]=d; lfrule++;
      /* printob("rule4: ",x); */
      return(leftfactor(x)); }
  return(x);
}

word same(x,y) /* structural equality */
word x,y;
{ if(x==y)return(1);
  if(tag[x]==ATOM||tag[y]==ATOM||tag[x]!=tag[y])return(0);
  if(tag[x]<INT)return(hd[x]==hd[y]&&tl[x]==tl[y]);
  if(tag[x]>STRCONS)return(same(hd[x],hd[y])&&same(tl[x],tl[y]));
  return(hd[x]==hd[y]&&same(tl[x],tl[y])); /* INT..STRCONS */
}

static word was_poly;
int polyshowerror=0;

word makeshow(here,type)
word here,type;
{ word f;
  extern word ND;
  was_poly=0; f=mkshow(0,0,type);
  /* printob("showfn=",f); /* DEBUG */
  if(here&&was_poly)
    { extern char *current_script;
      printf("type error in definition of %s\n",get_id(current_id));
      sayhere(here,0);
      printf(" use of \"show\" at polymorphic type ");
      out_type(redtvars(type));
      putchar('\n');
      id_type(current_id)=wrong_t;
      id_val(current_id)=UNDEF;
      polyshowerror=1;
      ND=add1(current_id,ND);
      was_poly=0; }
  return(f);
}

word mkshow(s,p,t) /* build a show function appropriate to type t */
word s,p,t; /* p is precedence - 0 for top level, 1 for internal */
           /* s flags special case invoked from genshfns */
{ extern word shownum1,showbool,showchar,showlist,showstring,showparen,
             showvoid,showpair,showfunction,showabstract,showwhat;
  word a=NIL;
  while(tag[t]==AP)a=cons(tl[t],a),t=hd[t];
  switch(t)
  { case num_t: return(p?shownum1:SHOWNUM);
    case bool_t: return(showbool);
    case char_t: return(showchar);
    case list_t: if(hd[a]==char_t)return(showstring);
		 return(ap(showlist,mkshow(s,0,hd[a])));
    case comma_t: return(ap(showparen,ap2(showpair,mkshow(s,0,hd[a]),
					   mkshowt(s,hd[tl[a]]))));
    case void_t: return(showvoid);
    case arrow_t:return(showfunction);
    default: if(tag[t]==ID)
	       { word r=t_showfn(t);
		 if(r==0) /* abstype without show function */
		   return(showabstract);
		 if(r==showwhat) /* dont apply to parameter showfns */
		   return(r);
	         while(a!=NIL)r=ap(r,mkshow(s,1,hd[a])),a=tl[a];
		 if(t_class(t)==algebraic_t)r=ap(r,p);
		 return(r);
		   /* note that abstype-showfns have only one precedence
		      and show their components (if any) at precedence 1
		      - if the latter is a problem could do parenthesis
		      stripping */
	       }
	     if(isvar_t(t)){ if(s)return(t); /* see genshfns */
			     was_poly=1; 
			     return(showwhat); }
			/* arbitrary - could be any strict function */
	     if(tag[t]==STRCONS) /* pname */ /* DEBUG */
	       { printf("warning - mkshow applied to suppressed type\n");
		 return(showwhat); }
	     else { printf("impossible event in mkshow ("),
	            out_type(t), printf(")\n");
	            return(showwhat); }
  }
}

word mkshowt(s,t) /* t is a (possibly singleton) tuple type */
word s,t; /* flags special call from genshfns */
{ extern word showpair;
  if(tl[t]==void_t)return(mkshow(s,0,tl[hd[t]]));
  return(ap2(showpair,mkshow(s,0,tl[hd[t]]),mkshowt(s,tl[t])));
}

word algshfns=NIL; /* list of showfunctions for all algebraic  types in scope
		     (list of pnames) - needed to make dumps */

void genshfns() /* called after meta type check - create show functions for
	      algebraic types */
{ word s;
  for(s=newtyps;s!=NIL;s=tl[s])
  if(t_class(hd[s])==algebraic_t)
     { word f=0,r=t_info(hd[s]); /* r is list of constructors */
       word ush= tl[r]==NIL&&member(SGC,hd[r])?Ush1:Ush;
       for(;r!=NIL;r=tl[r])
	  { word t=id_type(hd[r]),k=id_val(hd[r]);
	    while(tag[k]!=CONSTRUCTOR)k=tl[k];/* lawful and !'d constructors*/
	    /* k now holds constructor(i,hd[r]) */
	    /* k=constructor(hd[k],datapair(get_id(tl[k]),0));
	      /* this `freezes' the name of the constructor */
	      /* incorrect, makes showfns immune to aliasing, should be
		 done at mkshow time, not genshfn time - FIX LATER */
            while(isarrow_t(t))
		 k=ap(k,mkshow(1,1,tl[hd[t]])),t=tl[t]; /* NB 2nd arg */
	    k=ap(ush,k);
	    while(iscompound_t(t))k=abstr(tl[t],k),t=hd[t];
				/* see kahrs.bug.m (this is the fix) */
	    if(f)f=ap2(TRY,k,f);
	    else f=k;
	  }
       /* f~=0, placeholder types dealt with in specify() */
       pn_val(t_showfn(hd[s]))=f;
       algshfns=cons(t_showfn(hd[s]),algshfns);
     }
  else 
  if(t_class(hd[s])==abstract_t) /* if showfn present check type is ok */
     if(t_showfn(hd[s]))
     if(!abshfnck(hd[s],id_type(t_showfn(hd[s]))))
       printf("warning - \"%s\" has type inappropriate for a show-function\n",
	      get_id(t_showfn(hd[s]))),t_showfn(hd[s])=0;
}

word abshfnck(t,f) /* t is an abstype, is f right type for its showfn? */
word t,f;
{ word n=t_arity(t),i=1;
  while(i<=n)
       if(isarrow_t(f))
       { word h=tl[hd[f]];
	 if(!(isarrow_t(h)&&isvar_t(tl[hd[h]])&&gettvar(tl[hd[h]])==i
	      &&islist_t(tl[h])&&tl[tl[h]]==char_t))return(0);
         i++,f=tl[f]; 
       } else return(0);
  if(!(isarrow_t(f)&&islist_t(tl[f])&&tl[tl[f]]==char_t))return(0);
  f=tl[hd[f]];
  while(iscompound_t(f)&&isvar_t(tl[f])&&gettvar(tl[f])==n--)f=hd[f];
  return(f==t);
}

word transtries(id,x)
word id,x; /* x is a list of alternative values, in reverse order */
{ word r,h=0,earliest;
  if(fallible(hd[x])) /* add default last case */
    { word oldn=tag[id]==ID?datapair(get_id(id),0):0;
      r=ap(BADCASE,h=cons(oldn,0));
	 /* 0 is placeholder for here-info */
         /* oldn omitted if id is pattern - FIX LATER */ }
  else r=codegen(earliest=hd[x]), x = tl[x];
  while(x!=NIL)r=ap2(TRY,codegen(earliest=hd[x]),r), x=tl[x];
  if(h)tl[h]=hd[earliest]; /* first line-no is the best marker */
  return(r);
}

word translet(d,e) /* compile block with body e and def d */
word d,e;
{ word x=mklazy(d);
  return(ap(abstract(dlhs(x),codegen(e)),codegen(dval(x))));
}
/* nasty bug, codegen(dval(x)) was interfering with abstract(dlhs(x)...
   to fix made codegen on tuples be NOT in situ 20/11/88  */

word transletrec(dd,e) /* better method,  using list indexing - Jan 88 */
word e,dd;
{ word lhs=NIL,rhs=NIL,pn=1;
  /* list of defs (x=e) is combined to listwise def `xs=es' */
  for(;dd!=NIL;dd=tl[dd])
     { word x=hd[dd];
       if(tag[dlhs(x)]==ID)  /* couldn't be constructor, by grammar */
         lhs=cons(dlhs(x),lhs),
         rhs=cons(codegen(dval(x)),rhs);
       else { word i=0,ids,p=mkgvar(pn++); /* see note 1 */
	      x=new_mklazy(x); ids=dlhs(x);
	      lhs=cons(p,lhs),rhs=cons(codegen(dval(x)),rhs);
              for(;ids!=NIL;ids=tl[ids],i++)
		 lhs=cons(hd[ids],lhs),
		 rhs=cons(ap2(SUBSCRIPT,mkindex(i),p),rhs);
	    }
     }
  if(tl[lhs]==NIL) /* singleton */
    return(ap(abstr(hd[lhs],codegen(e)),ap(Y,abstr(hd[lhs],hd[rhs]))));
  return(ap(abstrlist(lhs,codegen(e)),ap(Y,abstrlist(lhs,rhs))));
}
/* note 1: we here use the alternative `mklazy' transformation
   pat = e =>  x1=p!0;...;xn=p!(n-1);p=(lambda(pat)[xs])e|conferror;
   where p is a private name (need be unique only within a given letrec)
*/

word mklazy(d) /* transforms local p=e to ids=($p.ids)e|conferror */
word d;
{ if(irrefutable(dlhs(d)))return(d);
{ word ids=mktuple(dlhs(d));
  if(ids==NIL){ printf("impossible event in mklazy\n"); return(d); }
  dval(d)=ap2(TRY,ap(lambda(dlhs(d),ids),dval(d)),
			  ap(CONFERROR,cons(dlhs(d),here_inf(dval(d)))));
  dlhs(d)=ids;
  return(d);
}}

word new_mklazy(d) /* transforms local p=e to ids=($p.ids)e|conferror
                 with ids a LIST (not tuple as formerly) */
word d;
{ word ids=get_ids(dlhs(d));
  if(ids==NIL){ printf("impossible event in new_mklazy\n"); return(d); }
  dval(d)=ap2(TRY,ap(lambda(dlhs(d),ids),dval(d)),
			  ap(CONFERROR,cons(dlhs(d),here_inf(dval(d)))));
  dlhs(d)=ids;
  return(d);
}

word here_inf(rhs) /* rhs is of form tries(id,val_list) */
word rhs;
{ word x=tl[rhs];
  while(tl[x]!=NIL)x=tl[x]; /* find earliest alternative */
  return(hd[hd[x]]); /* hd[x] is of form label(here_info,value) */
}

word irrefutable(x) /* x built from suigeneris constr's and (unrepeated) names */
word x;
{ if(tag[x]==CONS)return(0); /* includes constants */
  if(isconstructor(x))return(sui_generis(x));
  if(tag[x]==ID)return(1);
  if(tag[x]==AP&&tag[hd[x]]==AP&&hd[hd[x]]==PLUS) /* n+k pattern */
    return(0);
  return(irrefutable(hd[x])&&irrefutable(tl[x]));
}

word combine(x,y)
word x,y;
{ word a,b,a1,b1;
  a= tag[x]==AP&&hd[x]==K;
  b= tag[y]==AP&&hd[y]==K;
  if(a&&b)return(ap(K,ap(tl[x],tl[y])));
            /* rule of K propagation */
  if(a&&y==I)return(tl[x]);
               /* rule 'eta */
  b1= tag[y]==AP&&tag[hd[y]]==AP&&hd[hd[y]]==B;
  if(a)if(b1)return(ap3(B1,tl[x],tl[hd[y]],tl[y])); else
       /* Mark Scheevel's new B1 introduction rule -- adopted Aug 83 */
       if(tag[tl[x]]==AP&&tag[hd[tl[x]]]==AP&&hd[hd[tl[x]]]==COND)
	 return(ap3(COND,tl[hd[tl[x]]],ap(K,tl[tl[x]]),y));
       else return(ap2(B,tl[x],y));
  a1= tag[x]==AP&&tag[hd[x]]==AP&&hd[hd[x]]==B;
  if(b)if(a1)if(tag[tl[hd[x]]]==AP&&hd[tl[hd[x]]]==COND)
	       return(ap3(COND,tl[tl[hd[x]]],tl[x],y));
	     else return(ap3(C1,tl[hd[x]],tl[x],tl[y]));
       else return(ap2(C,x,tl[y]));
  if(a1)if(tag[tl[hd[x]]]==AP&&hd[tl[hd[x]]]==COND)
	  return(ap3(COND,tl[tl[hd[x]]],tl[x],y));
	else return(ap3(S1,tl[hd[x]],tl[x],y));
  else return(ap2(S,x,y)); }

word liscomb(x,y)  /* the CONSy analogue of "combine" */
word x,y;
{ word a,b;
  a= tag[x]==AP&&hd[x]==K;
  b=  tag[y]==AP&&hd[y]==K;
  if(a&&b)return(ap(K,cons(tl[x],tl[y])));
                       /* K propagation again */
  if(a)if(y==I)return(ap(P,tl[x])); /* eta P - new rule added 20/11/88 */
       else return(ap2(B_p,tl[x],y));
  if(b)return(ap2(C_p,x,tl[y]));
  return(ap2(S_p,x,y)); }
/* B_p,C_p,S_p are the CONSy analogues of B,C,S
   see MIRANDA REDUCE for their definitions */

word compzf(e,qq,diag) /* compile a zf expression with body e and qualifiers qq
		     (listed in reverse order); diag is 0 for sequential
		     and 1 for diagonalising zf expressions */
word e,qq,diag;
{ word hold=NIL,r=0,g1= -1; /* r is number of generators */
  while(qq!=NIL) /* unreverse qualifier list */
       { if(hd[hd[qq]]==REPEAT)qq=fixrepeats(qq);
         hold=cons(hd[qq],hold);
	 if(hd[hd[qq]]==GUARD)r++; /* count filters */
	 qq = tl[qq]; }
  for(qq=hold;qq!=NIL&&hd[hd[qq]]==GUARD;qq=tl[qq])r--; /* less leading filters */
  if(hd[hd[hold]]==GENERATOR)g1=tl[tl[hd[hold]]]; /* rhs of 1st generator */
  e=transzf(e,hold,diag?diagonalise:concat);
  /* diagonalise [ // ] comprehensions, but not [ | ] ones */
  if(diag)
    while(r--)e=ap(concat,e); /* see funny version of rule 3 below */
  return(e==g1?ap2(APPEND,NIL,e):e); /* test in g1 is to fix HR bug */
}
/* HR bug - if Rule 1 applied at outermost level, type info is lost
   eg [p|p<-3] ==> 3  (reported by Ham Richards, Nov 89)
*/

word transzf(e,qq,conc)  /* Bird and Wadler page 63 */
word e,qq,conc;
{ word q,q2;
  if(qq==NIL)return(cons(e,NIL));
  q=hd[qq];
  if(hd[q]==GUARD)
    return(ap3(COND,tl[q],transzf(e,tl[qq],conc),NIL));
  if(tl[qq]==NIL)
    if(hd[tl[q]]==e&&isvariable(e))return(tl[tl[q]]); /* Rule 1 */
    else if(irrefutable(hd[tl[q]]))
	 return(ap2(MAP,lambda(hd[tl[q]],e),tl[tl[q]])); /* Rule 2 */
	 else /* Rule 2 warped for refutable patterns */
	 return(ap2(FLATMAP,lambda(hd[tl[q]],cons(e,NIL)),tl[tl[q]]));
  q2=hd[tl[qq]];
  if(hd[q2]==GUARD)
    if(conc==concat) /* Rule 3 */
    { tl[tl[q]]=ap2(FILTER,lambda(hd[tl[q]],tl[q2]),tl[tl[q]]);
      tl[qq]=tl[tl[qq]];
      return(transzf(e,qq,conc)); }
    else  /* funny [//] version of Rule 3 to avoid creating weak lists */
    { e=ap3(COND,tl[q2],cons(e,NIL),NIL);
      tl[qq]=tl[tl[qq]];
      return(transzf(e,qq,conc)); } /* plus wrap result with concat */
  return(ap(conc,transzf(transzf(e,tl[qq],conc),cons(q,NIL),conc)));
  /* Rule 4 */
}

word fixrepeats(qq)  /* expands multi-lhs generators in zf expressions */
word qq;
{ word q = hd[qq];
  word rhs = q;
  qq = tl[qq];
  while(hd[rhs]==REPEAT)rhs = tl[tl[rhs]];
  rhs = tl[tl[rhs]];  /* rhs now contains the common right hand side */
  while(hd[q]==REPEAT)
    { qq = cons(cons(GENERATOR,cons(hd[tl[q]],rhs)),qq);
      q = tl[tl[q]];
    }
  return(cons(q,qq));
} /* EFFICIENCY PROBLEM - rhs gets re-evaluated for each lhs, fix later */
  /* likewise re-typechecked, although this probably doesn't matter */

word lastlink(x) /* finds last link of a list -- needed with zf body elision */
word x;
{ while(tl[x]!=NIL)x=tl[x];
  return(x);
}

#define ischar(x) ((x)>=0&&(x)<=255)

word genlhs(x) /* x is an expression found on the lhs of <- and genlhs returns
             the corresponding pattern */
word x;
{ word hold;
  switch(tag[x])
  { case AP:
  	if(tag[hd[x]]==AP&&hd[hd[x]]==PLUS&&isnat(tl[x]))
          return(ap2(PLUS,tl[x],genlhs(tl[hd[x]])));  /* n+k pattern */
    case CONS:
    case TCONS:
    case PAIR:
  	hold=genlhs(hd[x]); return(make(tag[x],hold,genlhs(tl[x])));
    case ID:
    	if(member(idsused,x))return(cons(CONST,x));
    	if(!isconstructor(x))idsused=cons(x,idsused); return(x);
    case INT: return(cons(CONST,x));
    case DOUBLE: syntax("floating point literal in pattern\n");
		 return(nill);
    case ATOM: if(x==True||x==False||x==NILS||x==NIL||ischar(x))
		 return(cons(CONST,x));
    default: syntax("illegal form on left of <-\n");
	     return(nill);
}}

word speclocs=NIL; /* list of cons(id,hereinfo) giving location of spec for
		     ids both defined and specified - needed to locate errs
		     in meta_tcheck, abstr_mcheck */
word getspecloc(x)
word x;
{ word s=speclocs;
  while(s!=NIL&&hd[hd[s]]!=x)s=tl[s];
  return(s==NIL?id_who(x):tl[hd[s]]); }

void declare(x,e)    /* translates  <pattern> = <exp>  at top level  */
word x,e;
{ if(tag[x]==ID&&!isconstructor(x))decl1(x,e);else
  { word bindings=scanpattern(x,x,share(tries(x,cons(e,NIL)),undef_t),
			     ap(CONFERROR,cons(x,hd[e])));
			     /* hd[e] is here-info */
  /* note creation of share node to force sharing on code generation
     and typechecking */
    if(bindings==NIL){ errs=hd[e];
		       syntax("illegal lhs for definition\n");
		       return; }
    lastname=0;
    while(bindings!=NIL)
	 { word h;
	   if(id_val(h=hd[hd[bindings]])!=UNDEF)
	     { errs=hd[e]; nameclash(h); return; }
	   id_val(h)=tl[hd[bindings]];
	   if(id_who(h)!=NIL)speclocs=cons(cons(h,id_who(h)),speclocs);
	   id_who(h)=hd[e]; /* here-info */
           if(id_type(h)==undef_t)addtoenv(h);
	   bindings = tl[bindings];
         }
}}

word scanpattern(p,x,e,fail) /* declare ids in x as components of `p=e', each as
		                n = ($p.n)e,  result is list of bindings */
word p,x,e,fail;
{ if(hd[x]==CONST||isconstructor(x))return(NIL);
  if(tag[x]==ID){ word binding=
		  cons(x,ap2(TRY,ap(lambda(p,x),e),fail));
		  return(cons(binding,NIL)); }
  if(tag[x]==AP&&tag[hd[x]]==AP&&hd[hd[x]]==PLUS) /* n+k pattern */
    return(scanpattern(p,tl[x],e,fail));
  return(shunt(scanpattern(p,hd[x],e,fail),scanpattern(p,tl[x],e,fail)));
}

word get_ids(x) /* return list of names in pattern x (without repetitions) */
word x;
{ if(hd[x]==CONST||isconstructor(x))return(NIL);
  if(tag[x]==ID)return(cons(x,NIL));
  if(tag[x]==AP&&tag[hd[x]]==AP&&hd[hd[x]]==PLUS) /* n+k pattern */
    return(get_ids(tl[x]));
  return(UNION(get_ids(hd[x]),get_ids(tl[x])));
}

word mktuple(x) /* extract tuple-structure of names from pattern x */
word x;
{ if(hd[x]==CONST||isconstructor(x))return(NIL);
  if(tag[x]==ID)return(x);
  if(tag[x]==AP&&tag[hd[x]]==AP&&hd[hd[x]]==PLUS) /* n+k pattern */
    return(mktuple(tl[x]));
{ word y=mktuple(tl[x]); x=mktuple(hd[x]);
  return(x==NIL?y:y==NIL?x:pair(x,y));
}}

void decl1(x,e)  /* declare name x to have the value denoted by e */
word x,e;
{ if(id_val(x)!=UNDEF&&lastname!=x)
    { errs=hd[e]; nameclash(x); return; }
  if(id_val(x)==UNDEF)
    { id_val(x)= tries(x,cons(e,NIL));
      if(id_who(x)!=NIL)speclocs=cons(cons(x,id_who(x)),speclocs);
      id_who(x)= hd[e]; /* here-info */
      if(id_type(x)==undef_t)addtoenv(x);
    } else
  if(!fallible(hd[tl[id_val(x)]]))
    errs=hd[e],
    printf("%ssyntax error: unreachable case in defn of \"%s\"\n",
	    echoing?"\n":"",get_id(x)),
                acterror();
  else tl[id_val(x)]= cons(e,tl[id_val(x)]);
/* multi-clause definitions are composed as tries(id,rhs_list)
   where id is included purely for diagnostic purposes
   note that rhs_list is reversed - put right by code generation */
}

word fallible(e) /* e is "fallible" rhs - if not sure, says yes */
word e;
{ for(;;)
  { if(tag[e]==LABEL)e=tl[e];
    if(tag[e]==LETREC||tag[e]==LET)e=tl[e]; else
    if(tag[e]==LAMBDA)
      if(irrefutable(hd[e]))e=tl[e];
      else return(1); else
    if(tag[e]==AP&&tag[hd[e]]==AP&&tag[hd[hd[e]]]==AP&&hd[hd[hd[e]]]==COND)
	 e=tl[e]; else
    return(e==FAIL);   /* test for nested (COND a b FAIL) */
  }
} /* NOTE
     When an rhs contains FAIL as a result of compiling an elseless guard set
     it is of the form
	XX ::= ap3(COND,a,b,FAIL) | let[rec](def[s],XX) | lambda(pat,XX)
     an rhs is fallible if
	1) it is an XX, as above, or
	2) it is of the form lambda(pat1,...,lambda(patn,e)...)
	   where at least one of the patterns pati is refutable.
  */

/* combinator to select i'th out of n args *//*
word k(i,n)
int i,n;
{ if(i==1)return(n==1?I:n==2?K:ap2(B,K,k(1,n-1)));
  if(i==2&&n==2)return(KI); /* redundant but saves space *//*
  return(ap(K,k(i-1,n-1)));
} /* not currently used */

#define arity_check if(t_arity(tf)!=arity)\
  printf("%ssyntax error: \
wrong number of parameters for typename \"%s\" (%ld expected)\n",\
          echoing?"\n":"",get_id(tf),t_arity(tf)),errs=here,acterror()

void decltype(tf,class,info,here)  /* declare a user defined type */
word tf,class,info,here;
{ word arity=0;
  extern word errs;
  while(tag[tf]==AP)arity++,tf=hd[tf];
  if(class==synonym_t&&id_type(tf)==type_t&&t_class(tf)==abstract_t
     &&t_info(tf)==undef_t)
    { /* this is binding for declared but not yet bound abstract typename */
      arity_check;
      id_who(tf)=here;
      t_info(tf)=info;
      return; }
  if(class==abstract_t&&id_type(tf)==type_t&&t_class(tf)==synonym_t)
    { /* this is abstype declaration of already bound typename */
      arity_check;
      t_class(tf)=abstract_t;
      return; }
  if(id_val(tf)!=UNDEF)
    { errs=here; nameclash(tf); return; }
  if(class!=synonym_t)newtyps=add1(tf,newtyps);
  id_val(tf)=make_typ(arity,class==algebraic_t?make_pn(UNDEF):0,class,info);
  if(id_type(tf)!=undef_t){ errs=here; respec_error(tf); return; }
  else addtoenv(tf);
  id_who(tf)=here;
  id_type(tf)=type_t;
}

void declconstr(x,n,t)  /* declare x to be constructor number n of type t */
word x,n,t;   /* x must be an identifier */
{ id_val(x)=constructor(n,x);
  if(n>>16)
    { syntax("algebraic type has too many constructors\n"); return; }
  if(id_type(x)!=undef_t){ errs=id_who(x); respec_error(x); return; }
  else addtoenv(x);
  id_type(x) = t;
} /* the value of a constructor x is constructor(constr_tag,x)
     where constr_tag is a small natural number */

word block(defs,e,keep) /* semantics of "where" - performs dependency analysis */
/* defs has form list(defn(pat,typ,val)), e is body of block */
/* if `keep' hold together as single letrec */
word defs,e,keep;
{ word ids=NIL,deftoids=NIL,g=NIL,d;
  extern word SYNERR,detrop;
  /* return(letrec(defs,e)); /* release one semantics was just this */
  if(SYNERR)return(NIL);  /* analysis falls over on empty patterns */
  for(d=defs;d!=NIL;d=tl[d])  /* first collect all ids defined in block */
     { word x = get_ids(dlhs(hd[d]));
       ids=UNION(ids,x);
       deftoids=cons(cons(hd[d],x),deftoids);
     }
  defs=sort(defs);
  for(d=defs;d!=NIL;d=tl[d]) /* now build dependency relation g */
     { word x=intersection(deps(dval(hd[d])),ids),y=NIL;
       for(;x!=NIL;x=tl[x])  /* replace each id by corresponding def */
	  y=add1(invgetrel(deftoids,hd[x]),y);
       g=cons(cons(hd[d],add1(hd[d],y)),g);
       /* treat all defs as recursive for now */
     }
  g=reverse(g); /* keep in address order of first components */
/* g is list(cons(def,defs)) 
   where defs are all on which def immediately depends, plus self */
  g = tclos(g);  /* now g is list(cons(def,ultdefs)) */
  { /* check for unused definitions */
    word x=intersection(deps(e),ids),y=NIL,*g1= &g;
    for(;x!=NIL;x=tl[x])
       { word d=invgetrel(deftoids,hd[x]);
         if(!member(y,d))y=UNION(y,getrel(g,d)); }
    defs=setdiff(defs,y);  /* these are de trop */
    if(defs!=NIL)detrop=append1(detrop,defs);
    if(keep)             /* if local polymorphism not required */
    return(letrec(y,e)); /* analysis was solely to find unwanted defs */
    /* remove redundant entries from g */
    /* no, leave in for typecheck - could remove afterwards
    while(*g1!=NIL&&defs!=NIL)
         if(hd[hd[*g1]]==hd[defs])*g1=tl[*g1]; else
         if(hd[hd[*g1]]<hd[defs])g1= &tl[*g1];
         else defs=tl[defs]; */
  }
  g = msc(g);    /* g is list(defgroup,ultdefs) */
  g = tsort(g);  /* g is list(defgroup) in dependency order */
  g = reverse(g); /* reconstruct block inside-first */
  while(g!=NIL)
       { if(tl[hd[g]]==NIL &&
	    intersection(get_ids(dlhs(hd[hd[g]])),deps(dval(hd[hd[g]])))==NIL
	   )e=let(hd[hd[g]],e);  /* single non-recursive def */
         else e=letrec(hd[g],e);
	 g=tl[g]; }
  return(e);
}
/* Implementation note:
   tsort will fall over if there is a non-list strong component because it
   was originally written on assumption that relation is over identifiers.
   Whence need to pretend all defs recursive until after tsort.
   Could do better - some defs may be subsidiary to others */

word tclos(r) /* fast transitive closure - destructive in r */
word r;   /* r is of form list(cons(x,xs)) */
{ word r1;
  for(r1=r;r1!=NIL;r1=tl[r1])
     { word x= less1(tl[hd[r1]],hd[hd[r1]]);
	     /* invariant x intersect tl[hd[r1]] = NIL */
       while(x!=NIL)
	    { x=imageless(r,x,tl[hd[r1]]);
	      tl[hd[r1]]=UNION(tl[hd[r1]],x); }
     }
  return(r);
}

word getrel(r,x) /* r is list(cons(x,xs)) - return appropriate xs, else NIL */
word r,x;
{ while(r!=NIL&&hd[hd[r]]!=x)r=tl[r];
  return(r==NIL?NIL:tl[hd[r]]);
}

word invgetrel(r,x) /* return first x1 such that `x1 r x' error if none found */
word r,x;
{ while(r!=NIL&&!member(tl[hd[r]],x))r=tl[r];
  if(r==NIL)fprintf(stderr,"impossible event in invgetrel\n"),exit(1);
  return(hd[hd[r]]);
}


word imageless(r,y,z) /* image of set y in reln r, less set z */
word r,y,z;
{ word i=NIL;
  while(r!=NIL&&y!=NIL)
       if(hd[hd[r]]==hd[y])
         i=UNION(i,less(tl[hd[r]],z)),r=tl[r],y=tl[y]; else
       if(hd[hd[r]]<hd[y])r=tl[r];
       else y=tl[y];
  return(i);
}

word less(x,y)  /* non-destructive set difference x-y */
word x,y;
{ word r=NIL;
  while(x!=NIL&&y!=NIL)
       if(hd[x]==hd[y])x=tl[x],y=tl[y]; else
       if(hd[x]<hd[y])r=cons(hd[x],r),x=tl[x];
       else y=tl[y];
  return(shunt(r,x));
}

word less1(x,a)  /* non-destructive set difference x- {a} */
word x,a;
{ word r=NIL;
  while(x!=NIL&&hd[x]!=a)r=cons(hd[x],r),x=tl[x];
  return(shunt(r,x==NIL?NIL:tl[x]));
}

word sort(x) /* into address order */
word x;
{ word a=NIL,b=NIL,hold=NIL;
  if(x==NIL||tl[x]==NIL)return(x);
  while(x!=NIL) /* split x */
       { hold=a,a=cons(hd[x],b),b=hold;
	 x=tl[x]; }
  a=sort(a),b=sort(b);
  /* now merge two halves back together */
  while(a!=NIL&&b!=NIL)
  if(hd[a]<hd[b])x=cons(hd[a],x),a=tl[a];
  else x=cons(hd[b],x),b=tl[b];
  if(a==NIL)a=b;
  while(a!=NIL)x=cons(hd[a],x),a=tl[a];
  return(reverse(x));
}

word sortrel(x) /* sort relation into address order of first components */
word x;  /* x is a list of cons(y,ys) */
{ word a=NIL,b=NIL,hold=NIL;
  if(x==NIL||tl[x]==NIL)return(x);
  while(x!=NIL) /* split x */
       { hold=a,a=cons(hd[x],b),b=hold;
	 x=tl[x]; }
  a=sortrel(a),b=sortrel(b);
  /* now merge two halves back together */
  while(a!=NIL&&b!=NIL)
  if(hd[hd[a]]<hd[hd[b]])x=cons(hd[a],x),a=tl[a];
  else x=cons(hd[b],x),b=tl[b];
  if(a==NIL)a=b;
  while(a!=NIL)x=cons(hd[a],x),a=tl[a];
  return(reverse(x));
}

void specify(x,t,h) /* semantics of a "::" statement */
word x,t,h;  /* N.B. t not yet in reduced form */
{ extern word showwhat;
  if(tag[x]!=ID&&t!=type_t){ errs=h;
			     syntax("incorrect use of ::\n");
                             return; }
  if(t==type_t)
    { word a=0;
      while(tag[x]==AP)a++,x=hd[x];
      if(!(id_val(x)==UNDEF&&id_type(x)==undef_t))
	{ errs=h; nameclash(x); return; }
      id_type(x)=type_t; 
      if(id_who(x)==NIL)id_who(x)=h; /* premise always true, see above */
        /* if specified and defined, locate by definition */
      id_val(x)=make_typ(a,showwhat,placeholder_t,NIL);/* placeholder type */
      addtoenv(x);
      newtyps=add1(x,newtyps);
      return; }
  if(id_type(x)!=undef_t){ errs=h; respec_error(x); return; }
  id_type(x)=t;
  if(id_who(x)==NIL)id_who(x)=h; /* as above */
  else speclocs=cons(cons(x,h),speclocs);
  if(id_val(x)==UNDEF)addtoenv(x);
}

void respec_error(x) /* only one type spec per name allowed - IS THIS RIGHT? */
word x;
{ extern word primenv;
  if(echoing)putchar('\n');
  printf("syntax error: type of \"%s\" already declared%s\n",get_id(x),
	 member(primenv,x)?" (in standard environment)":"");
  acterror();
}

void nameclash(x) /* only one top level binding per name allowed */
word x;
{ extern word primenv;
  if(echoing)putchar('\n');
  printf("syntax error: nameclash, \"%s\" already defined%s\n",get_id(x),
	 member(primenv,x)?" (in standard environment)":"");
  acterror();
}

void nclashcheck(n,dd,hr) /* is n already bound in list of definitions dd */
word n,dd,hr;
{ while(dd!=NIL&&!nclchk(n,dlhs(hd[dd]),hr))dd=tl[dd];
}

int nclchk(n,p,hr)  /* is n already bound in pattern p */
word n,p,hr;
{ if(hd[p]==CONST)return(0);
  if(tag[p]==ID)
    { if(n!=p)return(0);
      if(echoing)putchar('\n');
      errs=hr,
      printf(
"syntax error: conflicting definitions of \"%s\" in where clause\n",
      get_id(n)),
      acterror();
      return(1); }
  if(tag[p]==AP&&hd[p]==PLUS) /* hd of n+k pattern */
    return(0);
  return(nclchk(n,hd[p],hr)||nclchk(n,tl[p],hr));
}

word transtypeid(x)  /* recognises literal type constants - see rules.y */
word x;
{ char *n=get_id(x);
  return(strcmp(n,"bool")==0?bool_t:
         strcmp(n,"num")==0?num_t:
         strcmp(n,"char")==0?char_t:
         x);
}

/* end of MIRANDA TRANS */