Added upstream from http://ftp.icm.edu.pl/pub/loglan/
[loglan.git] / sources / gen / oxen.c
1 /*     Loglan82 Compiler&Interpreter
2      Copyright (C) 1993 Institute of Informatics, University of Warsaw
3      Copyright (C)  1993, 1994 LITA, Pau
4      
5      This program is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published by
7      the Free Software Foundation; either version 2 of the License, or
8      (at your option) any later version.
9      
10      This program is distributed in the hope that it will be useful,
11      but WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13      GNU General Public License for more details.
14      
15 =======================================================================
16 */
17
18 /**********************************************************/
19 /*             auxiliary functions for GEN                */
20 /*   Written according to NEW m & ipmem declarations      */
21 /*   Last modified : Mar-01-90                            */
22 /**********************************************************/
23
24 #include <memory.h>
25 #include "glodefs.h"
26
27 address firstlabel;
28
29  /*  static void globrelease(address n, app ap);  */
30  /*  releases temporary variable with appetite ap and  */
31  /*  address n within global area                     */
32
33
34 #ifndef NO_PROTOTYPES
35
36 static void globrelease(address,app);
37 static int globspace(app);
38 static void result(argnr);
39
40 #else
41
42 static void globrelease();
43 static int globspace();
44 static void result();
45
46 #endif
47
48
49
50 args_struct args[4];
51     /* M^ [ FIRSTLABEL..MEMLIMIT ] IS USED FOR HANDLING LABELS */
52     /* FOR LABEL L :                                           */
53     /*  M^ [ MEMLIMIT-L+1 ] < 0                                */
54     /*          -->  = - VALUE OF ALREADY DEFINED LABEL        */
55     /*  M^ [ MEMLIMIT-L+1 ] > 0                                */
56     /*          -->  = HEAD OF UNSATISFIED REFERENCES LIST     */
57
58
59 bool        gtmpmap[ TEMPGUARD + 1 ] ;
60                /* MAP OF GLOBAL NON-REFERENCE TEMPORARY VARIABLES  */
61                
62 bool        rtmpmap[ MAXREFTEMP + 1 ] ;
63                /* MAP OF (LOCAL) REFERENCE TEMPORARY VARIABLES     */
64                
65 tmpmap      ltmpmap ;
66                /* MAP OF (LOCAL) NON-REFERENCE TEMPORARY VARIABLES */
67                /* TRUE STANDS FOR AVAILABLE WORD, FALSE FOR OCCUPIED ONE */
68                
69 int         loctmp ;   /* MAXIMAL NUMBER OF ALREADY USED WORDS FOR
70                           LOCAL (NON-REFERENCE) TEMPORARY VARIABLES */
71                           
72 int         reftmp ;   /* MAXIMAL NUMBER-1 OF ALREADY USED PAIRS OF WORDS
73                           FOR REFERENCE TEMPORARY VARIABLES         */
74
75 tmpmapdscr *  mapdscr[ MAXPROT + 1 ] ;
76                       /* FOR CLASS ONLY : MAP OF TEMPORARIES USED AT 'INNER' */
77
78 qaddr0 qcurr;
79 /**********************************************************/
80
81
82
83 void deflabel(lab)
84 int lab;
85  /* DEFINES NEW LABEL AND SATISFIES REFERENCES (IF ANY) */
86 {
87   address  n, k ;
88
89   n = MEMLIMIT - lab + 1;
90   if (n < firstlabel)
91     if (n < fre)
92       generror(MEMOVF) ;
93     else
94       firstlabel = n ;
95   k = m [ n ] ;
96   m [ n ] =  -(fre+base);
97   while (k > 0)
98   {
99     n = m [ k ] ;
100     m [ k ] = fre + base ;
101     k = n ;
102   }
103 } /* DEFLABEL */
104
105
106 void uselabel(lab) address lab;{
107   address  n ;          /* MAINTAINS THE USE OF LABEL LAB AT ADDRESS fre */
108
109   n = MEMLIMIT - lab + 1 ;
110   if (n < firstlabel)
111     if(n < fre)  generror(MEMOVF) ;
112     else         firstlabel = n ;
113   if (m [ n ] < 0) /* ALREADY DEFINED */ 
114     m [ fre ] =  -m [ n ] ;
115   else  /* ADD TO THE LIST OF UNSATISFIED REFERENCES */
116   {
117     m [ fre ] = m [ n ] ;
118     m [ n ] = fre ;
119   }
120
121 } /* USELABEL */
122
123
124
125 /* THE BEGINNING OF UNIT DESCRIBED AT 'IP' */
126
127 void begunit(ip) int ip;{
128    int i,k;
129    pointprdsc  prot = prototype[ipmem[ ip - 1 ]];
130
131    unitt = ipmem[ ip-1 ] ;
132    ipunit = ip ;
133
134    prot = prototype[unitt] ;
135    prot->codeaddr = fre + base;
136    if (prot->lthpreflist > 1){  /* prefixed unit */
137
138       k  =  prefix[ unitt ];
139       /*  ltmpmap =  mapdscr[k]->map ;*/
140       for (i=0; i<= MAXLOCTEMP; i++)  ltmpmap[i] = mapdscr[k]->map[i];
141
142       loctmp =  mapdscr[k]->locsize ;
143       reftmp =  mapdscr[k]->refsize ;
144
145    }else{
146
147       for (k = 1; k<= MAXLOCTEMP; k++)  ltmpmap[k] = TRUE;  /* index negated */
148        
149       /*     fillword(ltmpmap + 1, (char) TRUE, MAXLOCTEMP) ;
150
151       k = MAXLOCTEMP ; */
152      
153       loctmp = 0 ;
154       reftmp =  -1 ;
155    } 
156
157    for (k = 0; k <= MAXREFTEMP; k++)  rtmpmap[ k ] = TRUE ; 
158       
159    /*    memset(rtmpmap, (char) TRUE, MAXREFTEMP + 1) ;*/
160     
161    for (k = 1; k <= TEMPGUARD; k++)  gtmpmap[ k ] = TRUE ; 
162       
163    /*    memset(gtmpmap + 1, (char) TRUE, TEMPGUARD) ; */
164     
165
166    firstlabel = MEMLIMIT; /* IN FACT, MEMLIMIT+1 */
167
168    m[0]=m[MEMLIMIT]=0;
169    /* for (k = 0; k <= MEMLIMIT; k++)  m[k]=0;  */
170    /* memset( (char *)m, 0, (MEMLIMIT + 1)*sizeof(m[0]) ); */
171 }
172
173 void endunit(){
174   address systsize;
175   pointprdsc prot;
176   tmpmapdscr *mapd;
177
178   out() ;
179   /* with prototype[ unitt ] ^ do*/
180   { prot = prototype[ unitt ] ;
181    if(unitt != MAINBLOCK) 
182    if ((prot->kind == CLASS) || (prot->kind == LRECORD)
183     || (prot->kind == COROUTINE) || (prot->kind == PROCESS))
184     /*with mapdscr[ unitt ]^ do*/
185     { mapd = mapdscr[unitt] ;
186       mapd ->locsize = loctmp ;
187       mapd ->refsize = reftmp ;
188     }
189     switch(prot->kind)
190     {
191       case LRECORD : systsize = 0 ;
192                      break ;
193       case CLASS :
194       case BLOCK :
195       case PREFBLOCK : systsize = 2*(APREF+APINT) ;
196                                                    /* sl, dl, lsc, status sl */
197                        break ;
198       case LFUNCTION :
199       case LPROCEDURE : systsize = 3*APREF+2*APINT ; 
200                                             /* sl, dl, rpcdl, lsc, status sl */
201                         /*cbc add rpcdl field for procedures and functions...*/
202                         break ;                    
203       case COROUTINE : systsize =  3*APREF+2*APINT ;
204                                              /* sl, dl, cl,  lsc, status sl  */
205                        break ;
206       case PROCESS : systsize =  5*APREF+2*APINT+2*(lastprot+1);
207                   /* sl, dl, cl, chd, virtsc, lsc, statsl, display, display2 */
208                      break;
209       case HANDLER : systsize = 2*APREF+3*APINT ;
210                                         /* sl, dl, lsc, status sl, signal nr */
211                      break ;
212     } /* switch */
213     prot->span = prot->appetite + loctmp;
214     prot->appetite = prot->span + (reftmp + 1) * APREF + systsize;
215      if (prot->appetite > MAXAPPT)
216        generror(OBJTOLG);
217    } /* with prototype */;
218
219    /* clear dictionary of labels */
220    for(systsize =  firstlabel; systsize <= MEMLIMIT; systsize++)
221      m [ systsize ] =  0 ; 
222      
223    /* memset(m+firstlabel, (char)0, (MEMLIMIT-firstlabel+1)*sizeof(address)); */
224 }
225  
226  
227 static int globspace(ap) app ap;{
228
229  /* returns offset of the new temporary variable allocated in global area */
230  /*   indexed 1..maxcomtemp                                               */
231
232   int  n ;  /* 0..tempguard;*/
233   
234   n = 0 ;
235   switch(ap)
236   {
237     case  1 : while (!gtmpmap[ ++n ]) ; /*not guarded */
238               if (n > MAXCOMTEMP)
239                 generror(TMTEMP) ;
240               else 
241                 gtmpmap[ n ] = FALSE;
242               break ;
243    case   2 : do
244               {
245                 n++ ;
246                 n++ ;
247               }
248               while (!(gtmpmap[ n ] && gtmpmap[ n+1 ])) ;
249             if (n >= MAXCOMTEMP )
250               generror(TMTEMP) ;
251             else
252             {
253               gtmpmap[ n ] = FALSE ;
254               gtmpmap[ n + 1 ] = FALSE  ;
255             }
256             break ;
257     case  3 : do
258               n += 3 ;
259             while(!(gtmpmap[ n ]  &&  gtmpmap[ n+1 ]  &&  gtmpmap[ n+2 ])) ;
260             if (n > MAXCOMTEMP - 2)
261               generror(TMTEMP) ;
262             else
263             {
264               gtmpmap[ n ] = FALSE ; 
265               gtmpmap[ n+1 ] = FALSE ;
266               gtmpmap[ n+2 ] = FALSE ;
267             }
268             break ;
269    } /* switch */;
270
271    return(n) ;
272  } /* globspace */
273
274 static void globrelease(n,ap) address n; app ap;{
275
276  /* releases temporary variable with appetite ap and  */
277  /*  address n within global area                     */
278
279   gtmpmap[ n ] = TRUE;
280   switch(ap) 
281   {
282     case  1 : break ;
283     case  2 : gtmpmap[ n+1 ] = TRUE ;
284               break ;
285     case  3 : gtmpmap[ n+1 ] = TRUE ; 
286               gtmpmap[ n+2 ] = TRUE ;
287               break ;
288   } /* switch */
289 }
290
291 int locspace (ap)
292 app  ap ;
293  /* returns offset of the new temporary variable allocated within local area */
294  /* indexed -maxloctemp .. -1         for non-reference     or               */
295  /*                   0 .. maxreftemp for reference values                   */
296  
297 /*   label 77;  exit when successed */
298 {
299   int   n ;
300
301   if (ap == APVIRT) /* REFERENCE */
302   {/* reference variable, indexed 0..maxreftemp */
303     n = 0;
304     while ( !rtmpmap[ n ]  &&  (n < MAXREFTEMP))
305      ++n ;
306     if (rtmpmap[ n ])
307     {
308       rtmpmap[ n ] = FALSE;
309       if (n > reftmp)
310         reftmp = n ;
311     }
312     else
313       generror(TMTEMP);
314     return (n * APREF);
315   }
316   else
317   { /* non-reference, indexed 1..maxloctemp */
318     n = ap ;
319     while (n <= MAXLOCTEMP)
320     {  if (ltmpmap[ n ])
321          switch (ap)
322          { case 1 : ltmpmap[ n ] = FALSE ;
323                     goto label77 ;
324
325
326            case 2 : if (ltmpmap[ n-1 ])
327                     { ltmpmap[ n ] = FALSE ;
328                       ltmpmap[ n-1 ] = FALSE ;
329                       goto label77 ;
330                     }
331                     break ;
332
333            case 3 : if (ltmpmap[ n-1 ]  &&  ltmpmap[ n-2 ])
334                     { ltmpmap[ n ] = FALSE ;
335                       ltmpmap[ n-1 ] = FALSE ;
336                       ltmpmap[ n-2 ] = FALSE ;
337                       goto label77;
338                     }
339                     break ;
340          } /* switch */
341
342          /*dsw     else*/
343
344          n += ap ;
345     }  /* while */;
346       /* exit on failure */
347       generror(TMTEMP) ;
348
349   label77 : /* found */
350       if (n > loctmp)
351         loctmp =  n ;
352       return (-n) ;
353   } /* non-reference */
354 } /*locspace */
355
356 void locrelease(n, ap)
357 address n;
358 app ap ;
359
360 /* releases temporary variable of appetite ap allocated at address n */
361 /*   within local area                                               */
362
363 {
364   if (ap == APVIRT)                  /* reference variable */
365     rtmpmap[ n / APREF ] = TRUE ;
366   else{                              /* non-reference */
367                                      /*cmb indices to ltmpmap negated cmb*/
368     ltmpmap[ -n ] = TRUE ;
369     switch( ap ){
370        case 1 : break ;
371        case 2 : ltmpmap[ -n - 1 ] = TRUE ;
372                 break ;
373        case 3 : ltmpmap[ -n - 1 ] = TRUE ;
374                 ltmpmap[ -n - 2 ] = TRUE ;
375                 break ;
376     }
377   }
378 } /* locrelease */
379
380
381  void force(n, m, o1, o2)
382    /* FORCES THE N-TH ARGUMENT TO BE OF M-MODE WITH PARAMETERS O1,O2 */
383 argnr n ;
384 addrmode m ;
385 address o1, o2 ;
386
387 { args_struct * curr ; /* gsg for PASCAL WITH translation */
388   curr = args + n ; /* WITH ARGS[ N ] DO BEGIN */
389   
390   { curr->mode = m ;
391     curr->off1 = o1 ; 
392     curr->off2 = o2 ; 
393   }
394 } /* force */
395 /**********************************************************/
396
397
398  void forceconst(n)
399    /* FORCES THE N-TH ARGUMENT TO BE A CONSTANT */
400 argnr n ;  
401 { args_struct * curr ; /* gsg for PASCAL WITH translation */
402
403   curr = args + n ;
404 /*  WITH ARGS[ N ] DO BEGIN */
405   { curr->mode = CONSTANT ;
406     curr->off1 = tuple[ qcurr ].arg[ n ] ;
407   }
408 } /* forceconst */
409 /**********************************************************/
410
411
412
413  void forceprot(n)
414    /* FORCES THE N-TH ARGUMENT TO BE A PROTOTYPE NUMBER AS A CONSTANT */
415 argnr n ;
416 { args_struct * curr ; /* gsg for PASCAL WITH translation */
417
418   curr = args + n ;
419 /* WITH ARGS[ N ] DO BEGIN */
420   { curr->mode = CONSTANT ;
421     curr->off1 = ipmem[ tuple[ qcurr ].arg[ n ] - 1 ] ;
422   }
423 } /* forceprot */
424 /**********************************************************/
425
426  void argument(n)
427 /* PUTS THE DESCRIPTION OF THE N-TH ARGUMENT INTO ARGS[N] */
428 /* FOR TEMPORARY VARIABLES WITH NO NEXT USE AND NOT LIVE  */
429 /*  THE CORRESPONDING IS RELEASED                         */
430
431 argnr n ;
432 {
433   address w1 ; /* ( + 1) WORD OF SYMBOL TABLE ITEM */
434 /*  qaddr0 nextuse ; */
435   quadruple * curr1 ; /* gsg for PASCAL WITH translation */
436   args_struct * curr2 ; /* gsg for PASCAL WITH translation */
437   int  ad ;
438     
439   curr1 = tuple + qcurr ;
440   curr2 = args + n ;
441 /* WITH TUPLE[ QCURR ] DO BEGIN */
442   {
443     ad = curr1->arg[n] ; 
444     notrick  = ipmem[ ad ] ;
445      w1 = ipmem[ ++ad ] ;
446 /*     WITH ARGS[ N ] DO BEGIN */ /*  WITH TRICK.STI DO */
447      {
448        switch (smode(notrick)) {
449 /*CBC Replaced global absolute addressing by dot access to MAIN block object */
450 /*CBC  VARGLOB : {  MODE = GLOBAL ; OFF1 = ipmem[ W1-2 ] + MAIN } */
451
452         case VARGLOB : curr2->mode  =  DOTACCESS ;
453                        curr2->off1 = ipmem[ w1-2 ] ;
454                        curr2->off2 = MAINBLOCK ;
455                        break ;
456
457         case VARLOC  : curr2->mode = LOCAL ;
458                        curr2->off1 = ipmem[ w1 - 2 ] ;
459                        break ;
460
461 /*CBC Added new addressing mode for remote access through DISPLAY */
462         case VARMID  : curr2->mode = DOTACCESS ;
463                        curr2->off1 = ipmem[ w1 - 2 ] ;
464                        curr2->off2 =  /* DISPLAY +  */ ipmem[ w1 - 1 ] ;
465                        break ;
466
467         case TEMPVAR : if (slocal(notrick))
468                        {
469                          curr2->mode = TEMPLOCAL ;
470                          curr2->off1 = w1 ;
471                          if ( (curr1->nxtuse[ n ]==0) && (! slive(notrick)) )
472                            locrelease(w1, sap(notrick)) ;
473                        } /* slocal */
474                        else
475                        {
476                            curr2->mode = GLOBAL ;
477                            curr2->off1 = w1 + temporary ;
478                            if ((curr1->nxtuse[ n ]==0) && (! slive(notrick)) )
479                              globrelease(w1, sap(notrick)) ;
480                        } /* else */
481                        break ;
482                    
483         case INTCONST : curr2->mode = IMMEDIATE ; 
484                         curr2->off1 = w1 ;
485                         break ;
486    
487        case REALCONST : curr2->mode = GLOBAL ; 
488                         curr2->off1 = realbase + w1 ;
489                         break ;
490
491       } /* switch */
492     } /* WITH ARGS */
493   } /* WITH TUPLE */
494 } /* argument */
495 /**********************************************************/
496
497
498 static void result(n) argnr n;{
499
500  /* PUTS THE DESRIPTION OF N-TH ARGUMENT ( BEING DEFINED ) INTO ARGS[N].   */
501  /* FOR THE TEMPORARY VALUE THE NEW SPACE IS ASSIGNED                      */
502
503   int w1 ; /* ( + 1) WORD OF SYMBOL TABLE ITEM */
504   quadruple * curr1 ; /* gsg for PASCAL WITH translation */
505   args_struct * curr2 ; /* gsg for PASCAL WITH translation */
506
507   /*  int globspace(app) ; */
508
509   curr1 = tuple + qcurr ;
510   curr2 = args + n ;
511 /* WITH TUPLE[ QCURR ] DO BEGIN */
512   { notrick   = ipmem[ curr1->arg[ n ] ] ;
513     w1 = ipmem[ curr1->arg[ n ] + 1 ] ;
514 /*    WITH ARGS[ N ] DO BEGIN */ /* WITH TRICK.STI DO */
515     {
516        switch (smode(notrick)) {
517 /*CBC Replaced global absolute addressing by dot access to MAIN block object */
518 /*CBC  VARGLOB : {  MODE = GLOBAL ; OFF1 = (ipmem)[ W1-2 ] + MAIN } */
519        case VARGLOB : curr2->mode  =  DOTACCESS ;
520                       curr2->off1 = ipmem[ w1-2 ] ;
521                       curr2->off2 = MAINBLOCK ;
522                       break ;
523
524        case VARLOC  : curr2->mode = LOCAL ;
525                       curr2->off1 = ipmem[ w1-2 ] ;
526                       break ;
527
528 /*CBC Added new addressing mode for remote access through DISPLAY */
529        case VARMID  : curr2->mode = DOTACCESS ;
530                       curr2->off1 = ipmem[ w1 - 2 ] ;
531                       curr2->off2 =  /* DISPLAY +  */ ipmem[ w1 - 1 ] ;
532                       break ;
533
534        case TEMPVAR : /* ALLOCATE IT */
535                  if (slocal(notrick))
536                  { /* CANNOT USE GLOBAL TEMPORARIES */
537                    args[ n ].mode = TEMPLOCAL ;
538                    curr2->off1 = locspace(sap(notrick)) ;
539                    ipmem[ curr1->arg[ n ] + 1 ] = curr2->off1 ;
540                  }
541                  else
542                  { /* GLOBAL AREA MAY BE USED */
543                    args[ n ].mode = GLOBAL ;
544                    curr2->off1 = globspace(sap(notrick)) ;
545                    ipmem[ curr1->arg[ n ] + 1 ] = curr2->off1 ;
546                    curr2->off1 += temporary ;
547                  }
548                  break ;
549
550        case INTCONST :
551        case REALCONST : /* IMPOSSIBLE */
552                         break ;
553        } /* switch */
554      } /* WITH ARGS */
555   } /* WITH TUPLE */
556 } /* result */
557
558
559
560  void emit()
561 { ieopc trick ;
562   argnr i ;
563   args_struct * curr ; /* gsg for PASCAL WITH translation */
564   
565 #if (TALK > 31)
566    printf("on entrance to emit fre == %d\n", fre) ;
567 #endif
568    for (i = 1; i <= 3 ; i++)
569      trick.c2.eop.args[ i ] = (char)(args[ i ].mode) ;
570    trick.c2.eop.args[ 0 ]  =  (char)(tuple[ qcurr ].opcode) ;  /* opcode */
571
572 #if SMALL
573  m[ fre ] = trick.c0.int1f ;
574  m[ fre + 1 ] = trick.c0.int2f ;
575  LOG(fre);
576  LOG(fre + 1);
577 #elif LARGE || HUGE
578  m[ fre ]  =  trick.c1.intf ;
579  LOG(fre);
580 #endif
581
582 #if (TALK > 15)
583  printf(" emit  %d\n", trick.c2.eop.args[0]);
584 #endif
585
586  fre += APOPCODE ;
587
588  for (i = 1; i <= 3; i++) /* WITH ARGS[ I ] DO */
589  { curr = args + i ; /* gsg PASCAL WITH translation */
590
591    if (curr->mode != NOARGUMENT)
592    { 
593      m[ fre ] = curr->off1 ;
594      fre += APINT ;
595      if ( (curr->mode == REMOTE) || /*cbc*/ (curr->mode == DOTACCESS) )
596      { 
597        m[ fre ] = curr->off2 ;
598        fre += APINT ;
599      }
600    }
601  }
602  if (fre >= firstlabel)
603   generror(MEMOVF) ;
604 #if (TALK > 31)
605     printf("on exit from emit fre == %d\n", fre) ;
606 #endif
607 } /* emit */
608
609
610  void defaultargs()
611    /* PREPARES DEFAULT DESCRIPTIONS OF ARGUMENTS */
612
613 {
614   int d ;
615   /*  void  result(argnr) ;  */
616
617    for (d = 1; d <= 3; d++)
618      args[ d ].mode = NOARGUMENT ;
619    d = opdescr[tuple[qcurr].opcode ] ;  /*!!*/
620    if (d < 8)
621       /* NO RESULTS */
622       switch (d)
623       { case 0 : break ;
624
625         case 1 : forceconst(1) ;
626                  break ;
627
628         case 2 : argument(1) ;
629                  break ;
630
631         case 3 : argument(1) ;
632                  forceconst(2) ;
633                  break ;
634
635         case 4 : argument(1) ;
636                  forceconst(2) ;
637                  forceconst(3) ;
638                  break ;
639
640         case 5 : argument(1) ;
641                  argument(2) ;
642                  break ;
643
644         case 6 :  argument(1) ;
645                   argument(2) ;
646                   forceconst(3) ;
647                   break ;
648
649         case 7 : argument(1) ;
650                  argument(2) ;
651                  argument(3) ;
652                  break ;
653
654       } /* switch */
655    else
656    { /* AT LEAST ONE RESULT */
657      if (d < 14) /* 1 RESULT */
658        switch (d)
659        { case 8 : break ;
660
661          case 9 : forceconst(2) ;
662                   break ;
663
664          case 10 : forceconst(2) ;
665                    forceconst(3) ;
666                    break ;
667
668          case 11 : argument(2) ;
669                    break ;
670
671          case 12 : argument(2) ;
672                    forceconst(3) ;
673                    break ;
674
675          case 13 : argument(2) ;
676                    argument(3) ;
677                    break ;
678
679       } /* switch */
680
681       else { /* 2 RESULTS */
682         if (d == 14)
683         if (tuple[qcurr].opcode >= 4)
684           argument(3) ; /*!!*/
685                            /* open , slopen */
686         else forceconst(3) /* openrc , raise */  ;
687         result(2) ;
688       } /* 2 results */
689
690       result(1) ;
691     } /* at least one result */
692
693  } /* defaultargs */
694
695
696  void esac()
697  /* PRODUCES A DESCRIPTION OF 'CASE' */
698 {
699   int n,trick;
700   int lab,labnr,othrlab;
701   int val,valuee;
702   address tofill ;
703   
704  /*  WITH TUPLE[ QCURR ] DO */
705      {
706        labnr = next() ;        /* number of labels                   */
707        othrlab = next() ;      /* 'otherwise' label                  */
708        deflabel(othrlab - 1) ;/* 'switch' description label           */
709        m[ fre ] = next() ;    /* minimal value of 'switch' expression */
710        tofill = fre + 1 ;     /* to be filled with the number of branches */
711        fre += 2 ;
712        val = 0 ;
713        for (n = 1; n <= labnr; n++)
714        {
715          trick  = next() ;
716          valuee  =  iand(ishft(trick,-8),255) ;
717          lab  =  iand(trick,255) ;
718          while (val < valuee)
719          {
720            uselabel(othrlab) ;
721            fre ++ ;
722            val ++ ;
723          } /* while */
724          uselabel(othrlab + lab) ;
725          fre ++ ;
726          val ++ ;
727        } /* for */
728        m[ tofill ] = val ;
729      } /* with */
730 } /* esac */
731
732