home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 18 REXX / 18-REXX.zip / rximc175.zip / calc.c < prev    next >
Text File  |  2002-08-06  |  51KB  |  1,173 lines

  1. /* The calculating routines of REXX/imc         (C) Ian Collier 1992 */
  2.  
  3. #include<stdio.h>
  4. #include<memory.h>
  5. #include<string.h>
  6. #include<stdlib.h>
  7. #include<setjmp.h>
  8. #include<sys/types.h>
  9. #include<sys/time.h>
  10. #include"const.h"
  11. #include"globals.h"
  12. #include"functions.h"
  13. #include"rexxsaa.h"
  14.  
  15. /* scanning() is the expression evaluator, called 30 times from various parts
  16.    of the interpreter to collect an expression from a program line.  The
  17.    program line is given as the "line" parameter, and the character pointer
  18.    as "ptr".  An expression will be evaluated and placed on the calculator
  19.    stack.  In addition its address on the stack will be returned and its
  20.    length will be placed in len.  On exit, ptr will point to the character
  21.    immediately following the expression (it will not point to a space). */
  22. char *scanning(line,ptr,len)
  23. char *line;
  24. int *ptr,*len;
  25. {
  26. /* the following identifiers are arranged in order as defined by the
  27.    constants OPpower, OPmul, ... , OPggeq.  binops contains the character
  28.    codes of all the binary operators, and binpri contains their priorities. */
  29.       
  30.    static char binops[]={POWER,'*','/','+','-',' ',CONCAT,'=',EQU,'<',LEQ,'>',GEQ,NEQ,'&',LXOR,'|','%',MOD,NNEQ,LESS,GRTR,LLEQ, GGEQ};
  31.    static char binpri[]={  10,  8,  8,  7,  7,  6,  6,     5,  5,  5,  5,  5,  5,  5,  3,  2,   2,  8,  8,  5   ,5   ,5    ,5    ,5};
  32.    void binplus();
  33.    void binmin();
  34.    void binmul();
  35.    void bindiv();
  36.    void bincat();
  37.    void binexp();
  38.    void binbool();
  39.    void binrel();
  40.    void unnot();
  41.    void unmin();
  42.    void unplus();
  43.    static void (*binprg[])() ={binexp, /* This array contains the addresses */
  44.                                binmul, /* of all the functions which are    */
  45.                                bindiv, /* called to implement the various   */
  46.                                binplus,/* operators, in the order such that */
  47.                                binmin, /* binprg(OPxyz) is the routine to   */
  48.                                bincat, /* implement the xyz operator        */
  49.                                bincat,
  50.                                binrel,
  51.                                binrel,
  52.                                binrel,
  53.                                binrel,
  54.                                binrel,
  55.                                binrel,
  56.                                binrel,
  57.                                binbool,
  58.                                binbool,
  59.                                binbool,
  60.                                bindiv,
  61.                                bindiv,
  62.                                binrel,
  63.                                binrel,
  64.                                binrel,
  65.                                binrel,
  66.                                binrel,
  67.                                unmin,
  68.                                unplus,
  69.                                unnot};
  70.    struct {char op;char pri;} opstack[maxopstack]; /* an operation stack */
  71.    int opptr=1;              /* the operation stack pointer */
  72.    int lp;
  73.    char *exp;
  74.    int expn;
  75.    int explen;
  76.    int t;
  77.    int n;
  78.    int dot;
  79.    int endnum;
  80.    char quote;
  81.    char varname[maxvarname];
  82.    char *vg;
  83.    char op,pri;
  84.    char ch,c1;
  85.    int intermed=trcflag&Tintermed; /* whether to trace intermediate results */
  86.    static char what[4]=">>>";      /* the trace prefix to use */
  87.    
  88.    opstack[0].pri=0;               /* The bottom of stack marker */
  89.    trcresult++; /* count levels - trace result only on outer level */
  90.    while(1){ /* loop until expression has finished */
  91.       lp=1;
  92.       while(lp){ /* loop until a value has been stacked */
  93.          if(opptr>=maxopstack-1)die(Eopstk);
  94.          switch(line[*ptr]){
  95.             case ')': die(Erpar);
  96.             case ',': die(Ecomma);
  97.             case '(':(*ptr)++, /* parenthesised expressions are stacked by */
  98.                scanning(line,ptr,&explen); /* calling scanning recursively */
  99.                if(line[(*ptr)++]!=')')die(Elpar);  /* it must end with ')' */
  100.                lp=0;
  101.                what[1]=0;      /* Prevent the value from being traced, since */
  102.                break;          /* scanning() already traced it               */
  103.             case '+':(*ptr)++,/* for unary '+' stack code OPplus, priority 11 */
  104.                opstack[opptr].op=OPplus,
  105.                opstack[opptr++].pri=11;
  106.                break;
  107.             case '-':(*ptr)++, /* for unary '-' stack code OPneg, priority 11 */
  108.                opstack[opptr].op=OPneg,
  109.                opstack[opptr++].pri=11;
  110.                break;
  111.             case '\\':(*ptr)++,      /* for '\' stack code OPnot, priority 11 */
  112.                opstack[opptr].op=OPnot,
  113.                opstack[opptr++].pri=11;
  114.                break;
  115.             case '\'':             /* Quoted expression... */
  116.             case '\"':quote=line[(*ptr)++],
  117.                expn= *ptr;
  118.                while(line[expn++]!=quote||line[expn]==quote)
  119.                   if(line[expn-1]==quote)expn++; /* search for close quote */
  120.                if(line[expn]=='X'&&!rexxsymboldot(line[expn+1]))
  121.                   stackx(line+*ptr,expn-*ptr-1),expn++;/* stack hex */
  122.                else if(line[expn]=='B'&&!rexxsymboldot(line[expn+1]))
  123.                   stackb(line+*ptr,expn-*ptr-1),expn++;/* stack bin */
  124.                else stackq(line+*ptr,expn-*ptr-1,quote); /* stack string */
  125.                    /* A string constant has been found, but if
  126.                       it is followed by '(' it is a function call which
  127.                       bypasses the internal label search. */
  128.                if(line[expn]=='('){
  129.                   (*ptr)=expn+1;
  130.                   exp=delete(&n);
  131.                   if(n>maxvarname-1)die(Elong); /* the function name is */
  132.                   memcpy(varname,exp,n);        /* stored in varname    */
  133.                   t=1;
  134.                   goto rxfncall;
  135.                }
  136.                (*ptr)=expn;          /* step past string constant in line. */
  137.                lp=0;                 /* signal "stacked a value" */
  138.                what[1]='L';
  139.                break;
  140.             default:                 /* stack a variable or literal or
  141.                                         call a function. */
  142.                if(line[*ptr]<0)die(Ebadexpr);
  143.                if(!(t=rexxsymbol(line[*ptr]))&&line[*ptr]!='.')die(Ebadexpr);
  144.                what[1]='L';
  145.                if(t!=1){             /* a constant symbol. Special processing
  146.                               is required to ensure that if the symbol is a
  147.                               number in exponential format then any "+" or "-"
  148.                               in the number is treated as part of it */
  149.                   n=1;dot=0;  /* dot is the count of dots in the number; n is
  150.                               a flag meaning: 0 an ordinary constant symbol,
  151.                               1 an exponent is allowed, 2 this is the
  152.                               character after "E". */
  153.                   endnum=0;   /* The position of any "+" or "-" in case the
  154.                               exponent is badly formed (e.g. in 1e+23.4) */
  155.                   for(expn= *ptr;;expn++){
  156.                      c1=line[expn];
  157.                      if(!n) /* stop whenever a non-symbol character is found */
  158.                         if(!rexxsymboldot(c1)){ /* But remove a "+" or "-" if
  159.                                                 the exponent was empty */
  160.                            if(endnum&&endnum+1==expn)expn=endnum; 
  161.                            break;
  162.                         }
  163.                         else if(endnum&&(c1<'0'||c1>'9'))
  164.                            {expn=endnum;break;} /* Remove a non-numeric */
  165.                         else;                   /* exponent following a sign */
  166.                      else {
  167.                         if(alphanum(c1)<2){  /* not number or dot */
  168.                            if(n==2&&(c1=='-'||c1=='+')){
  169.                               n=0; /* OK to have + or - after an E */
  170.                               endnum=expn; 
  171.                               continue;
  172.                            }
  173.                            if(n==1&&c1=='E')
  174.                               {n=2;continue;}/* Expect an optional sign next */
  175.                            n=0;              /* it's not a number any more */
  176.                            if(!rexxsymboldot(c1))
  177.                               break;         /* allow only symbol characters */
  178.                         }
  179.                         if(n==2)n=0;         /* No sign after the 'E' */
  180.                         else if(c1=='.'&&dot++>0)n=0; /* a second dot found */
  181.                      }
  182.                   }
  183.                   if(expn==*ptr)die(Ebadexpr); /* The symbol has zero length */
  184.                   stack(line+*ptr,expn-*ptr),  /* Stack the constant symbol */
  185.                   (*ptr)=expn;                 /* step past it. */
  186.                }else{ /* A symbol follows.  If a '(' follows the symbol, then
  187.                          it is a function call */
  188.                   n=0,t=0;           /* t=0 -> search internal definitions */
  189.                   for(expn= *ptr;rexxsymboldot(varname[n++]=line[expn++]);)
  190.                      if(n>=maxvarname-1)die(Elong);
  191.                      /* the symbol has been copied to varname */
  192.                   if(--n>0&&varname[n-1]!='.'&&varname[n]=='('){
  193.                      *ptr=expn;   /* Step past the symbol */
  194. /* A function call has now been found. varname holds its name, and n holds
  195.    its length.  t!=0 if the name was in quotes, t=0 otherwise. */
  196.       rxfncall:      varname[n]=0; /* The name is nul-terminated (it cannot */
  197.                      n=0;          /* contain a nul character) */
  198.                      if(line[*ptr]!=')') /* Unless no arguments given... */
  199.                      while(1){           /* get each one by calling scanning */
  200.                         if((ch=line[*ptr])==','||ch==')')stacknull();
  201.                         else scanning(line,ptr,&explen);
  202.                         n++;
  203.                         if((ch=line[*ptr])==',')++*ptr;
  204.                         else if(ch!=')')die(Elpar);
  205.                         else break;
  206.                      }
  207.                      ++*ptr; /* Step past the ')'.  n contains the arg count.*/
  208.                      if(!rxcall(0,varname,n,t,RXFUNCTION))  /* This is where */
  209.                         die(Enoresult);          /* the function gets called */
  210.                      lp=0;
  211.                      what[1]='F';
  212.                      break;
  213.                   }
  214.                   /* else ignore the result of the search for a function name
  215.                   and try to get a variable instead */
  216.                   getvarname(line,ptr,varname,&explen,maxvarname),
  217.                   vg=varget(varname,explen,&expn);
  218.                   if(vg==cnull){ /* See if novalue errors are caught */
  219.                      if((varname[0]&128)&&!memchr(varname,'.',explen))
  220.                         varname[explen++]='.';/* Add a dot to undefined stem */
  221.                      varname[0]&=127;     /* if OK stack the variable's name */
  222.                      varname[explen]=0;
  223.                      if((sgstack[interplev].bits&(1<<Inovalue)) &&
  224.                           (interact<0 || interact+1!=interplev))
  225.                         errordata=varname,
  226.                         die(Enovalue);
  227.                      stack(varname,explen);
  228.                   }
  229.                   else what[1]='V',stack(vg,expn); /* it was found */
  230.                }
  231.                lp=0;
  232.          }
  233.       }
  234.       if(intermed&&what[1])tracelast(what);
  235.       /* at this point a (possibly null) list of operators and their priorities
  236.          have been stacked, and a value has just been placed on the calculator
  237.          stack. The next character will either be a terminator or an (explicit
  238.          or implicit) binary operator.  Special case: if it is a unary
  239.          operator (i.e. "logical not"), then it is a syntax error. */
  240.       ch=line[*ptr];
  241.       if(ch=='\\')die(Ebadexpr);
  242.       if((c1=line[*ptr])==-1||!c1||c1==')'||c1==','||c1<SYMBOL)pri=0;
  243.          /* terminators are ';', 'EOL', ')', ',' and all `words'.  Priority 0
  244.          signals that a terminator was found. */
  245.       else{
  246.          (*ptr)++;                                        /* Go past the op */
  247.          for(op=0;binops[op]!=ch&&op<24;op++);      /* "op" holds its index */
  248.          if(op<24)pri=binpri[op];               /* "pri" holds its priority */
  249.          else (*ptr)--, /* The char is not a binary operator, so it must be */
  250.               op=OPcat, /* an implicit concatenation, priority 6. */
  251.               pri=6;
  252.       }
  253.       /* Having found the next operator and its priority (priority 16 highest,
  254.         0 meaning no further operators), we now examine previous operations
  255.         to see whether they should be done now. If not, another value is
  256.         stacked unless the priorities of both the current operator and the
  257.         top stacked operator are zero, in which case evaluation has finished.*/
  258.       while(opstack[opptr-1].pri>=pri&&opstack[opptr-1].pri){
  259.          opptr--,
  260.          eworkptr=0,
  261.          binprg[opstack[opptr].op](opstack[opptr].op); /* This does the op */
  262.          if(intermed)
  263.             what[1]=(opstack[opptr].op>23?'P':'O'), /* Trace the op's result */
  264.             tracelast(what);
  265.       }
  266.       if(!pri)break;
  267.       opstack[opptr].op=op,     /* The binary operator just encountered is */
  268.       opstack[opptr++].pri=pri; /* stacked before finding the next value.  */
  269.    } /* Evaluation has finished, so the top stack value is returned. */
  270.    (*len)= *((int *)(cstackptr+ecstackptr)-1);
  271.    if(!--trcresult &&(trcflag&Tresults))               /* trace the result */
  272.       tracelast(">>>");
  273.    if(!trcresult)timeflag&= (~2); /* clear timestamp after a result */
  274.    return cstackptr+ecstackptr-align(*len)-four;
  275. }
  276.  
  277. void tracelast(type) /* trace the last value on the stack */
  278. char *type;          /* The trace prefix to use */
  279. {
  280.    char *exp=cstackptr+ecstackptr-four;
  281.    int len= *(int *)exp;
  282.    exp -=align(len);
  283.    traceline(type,exp,len);
  284. }
  285.    
  286. void traceline(type,exp,len) /* trace a result or other string */
  287. char *type;      /* the trace prefix to use */
  288. char *exp;       /* the string to be traced */
  289. int len;         /* the length of the string */
  290. {
  291.    int i;
  292.    traceput("      ",6);
  293.    traceput(type,3);
  294.    traceput("   ",3);
  295.    for(i=0;i<traceindent*pstacklev;i++)tracechar(' ');
  296.    tracechar('"');
  297.    traceput(exp,len);
  298.    traceput("\"\n",2);
  299. }
  300.  
  301. void stack(exp,len)  /* stack a copy of exp whose length is explen */
  302. char *exp;
  303. int len;
  304. {
  305.    int alen=align(len);
  306.    mtest(cstackptr,cstacklen,ecstackptr+alen+2*four,len+256);
  307.    memcpy(cstackptr+ecstackptr,exp,len), /* The string goes on first */
  308.    ecstackptr+=alen,                     /* it is padded into alignment */
  309.    (*(int *)(cstackptr+ecstackptr))=len, /* The length is then appended. */
  310.    ecstackptr+=four;
  311. }
  312.  
  313. void stackq(exp,len,quote)  /* stack a copy of exp whose length is explen, */
  314. char *exp;                  /* reducing double quotes to single quotes */
  315. int len;
  316. char quote;  /* The type of quote mark to reduce from double to single */
  317. {            /* It is guaranteed that this always occurs in pairs */
  318.    int i=0,l=0;
  319.    char *p;
  320.    char c;
  321.    mtest(cstackptr,cstacklen,ecstackptr+len+3*four,len+256);
  322.    for(p=cstackptr+ecstackptr;i<len;i++){ /* Copy the string */
  323.      p[l]=c=exp[i],
  324.      l++;
  325.      if(c==quote)i++;    /* Omit the next character after a quote. */
  326.    }
  327.    ecstackptr+=align(l), /* Pad the string */
  328.    (*(int *)(cstackptr+ecstackptr))=l, /* and append the length. */
  329.    ecstackptr+=four;
  330. }
  331.  
  332. void stackx(exp,len)  /* Interpret exp (whose length is len) as a hex
  333.                          constant and stack it */
  334. char *exp;
  335. int len;
  336. {
  337.    int l=0,o;
  338.    unsigned char m,n;
  339.    char d;
  340.    mtest(cstackptr,cstacklen,ecstackptr+len/2+3*four,len/2+256);
  341. /* while(exp[0]==' '&&len)exp++,len--; */ /* leading spaces OK if uncommented*/
  342.    if(len&&(exp[0]==' '||exp[0]=='\t'))die(Ehex);  /* leading spaces not OK */
  343.    for(o=0;o<len&&exp[o]!=' '&&exp[o]!='\t';o++);/* Find length of first chunk */
  344.    (o%2)?(o=1):(o=2); /* If odd, the first hex byte has 1 digit, otherwise 2 */
  345.    while(len){
  346.       while((exp[0]==' '||exp[0]=='\t')&&len)exp++,len--;  /* Skip spaces */
  347. /*    if(len==0)break;  */         /* OK for trailing blanks if uncommented */
  348.       if(len<o)die(Ehex);          /* Error if less than a whole byte exists */
  349.       for(m=(n=0);m<o;m++){        /* for one byte... */
  350.          d=(*(exp++))-'0',         /* convert a digit to hex */
  351.          len--;
  352.          if(d<0)die(Ehex);
  353.          if(d>9)if((d-=7)<10)die(Ehex);
  354.          if(d>15)if((d-=32)<10)die(Ehex);
  355.          if(d>15)die(Ehex);
  356.          n=n*16+d;                 /* and accumulate */
  357.       }
  358.       o=2,                         /* Each byte except the first has 2 digits*/
  359.       cstackptr[ecstackptr++]=n,   /* Stack each byte */
  360.       l++;
  361.    }
  362.    ecstackptr+=toalign(l),         /* pad the string */
  363.    (*(int *)(cstackptr+ecstackptr))=l, /* and append the length. */
  364.    ecstackptr+=four;
  365. }
  366. void stackb(exp,len)  /* Interpret exp as a binary constant and stack it */
  367. char *exp;
  368. int len;
  369. {
  370.    int l;
  371.    int al=align(len/8+1); /* maximum amount of space needed */
  372.    unsigned char c=0,n,b,d;
  373.    if(!len){stack(exp,len);return;} /* ''b is allowed */
  374.    mtest(cstackptr,cstacklen,ecstackptr+al+2*four,al+256);
  375.    if(len && (exp[0]==' '||exp[0]=='\t'))
  376.       die(Ebin);                    /* leading spaces not OK */
  377.    for(l=b=0;l<len;l++)b+=(exp[l]!=' '&&exp[l]!='\t'); /* find number of digits (nonblanks)*/
  378.    l=0;
  379.    n=(((b-1)%8)>=4)+1;              /* number of nybbles in first byte */
  380.    b=(b-1)%4+1;                     /* number of bits in first nybble */
  381.    while(len){
  382.       while((exp[0]==' '||exp[0]=='\t')&&len)exp++,len--;  /* Skip spaces */
  383.       if(len<b)die(Ehex);           /* Error if less than one nybble exists */
  384.       while(b--){                   /* for each bit of the nybble... */
  385.          d=exp++[0]-'0';
  386.          if(d>1)die(Ebin);
  387.          c=(c<<1)|d;                /* add to the current character */
  388.          len--;
  389.       }
  390.       b=4;                          /* next nybble has 4 bits */
  391.       if(!--n){                     /* a byte was completed */
  392.          cstackptr[ecstackptr++]=c, /* Stack each byte */
  393.          l++;
  394.          n=2;                       /* next byte has 2 nybbles */
  395.       }
  396.    }
  397.    if(n!=2)die(Ebin);               /* half a byte was encountered */
  398.    ecstackptr+=toalign(l),          /* pad the string */
  399.    (*(int *)(cstackptr+ecstackptr))=l, /* and append the length. */
  400.    ecstackptr+=four;
  401. }
  402. void stackint(i) /* stack an integer i */
  403. int i;
  404. {
  405.    char num[20];
  406.    sprintf(num,"%d",i);
  407.    stack(num,strlen(num));
  408. }
  409.  
  410. void stacknull() /* Stack a null - i.e. a value with length -1 */
  411. {
  412.    mtest(cstackptr,cstacklen,ecstackptr+2*four,256);
  413.    (*(int *)(cstackptr+ecstackptr))= -1,
  414.    ecstackptr+=four;
  415. }
  416.  
  417. /* The various binary and unary operators follow.  Each one operates on the
  418.    top 1 or 2 values on the calculator stack, deletes them, and stacks a
  419.    result.  The single parameter to each routine is the operator number
  420.    (e.g. OPplus), which serves to distinguish between two or more operators
  421.    implemented by the same routine.  Some routines do not use the operator
  422.    number.  Formatting of the result of arithmetic operators, including
  423.    rounding to the required precision, is handled by stacknum(). */
  424.  
  425. void binplus(op) /* Implements OPadd - the binary + operator */
  426. char op;
  427. {
  428.    int n1,n2,n3;
  429.    int m1,m2;
  430.    int z1,z2;
  431.    int e1,e2,e3;
  432.    int l1,l2,l3;
  433.    int i;
  434.    int c=0;
  435.    int d1,d2;
  436.    if((n2=num(&m2,&e2,&z2,&l2))<0)die(Enum); /* The two numbers are fetched */
  437.    delete(&l3);                              /* and deleted from the stack  */
  438.    if((n1=num(&m1,&e1,&z1,&l1))<0)die(Enum);
  439.    delete(&l3);
  440.    if(z1&&z2){stack("0",1);return;}
  441.    if(z1){stacknum(workptr+n2,l2,e2,m2);return;}
  442.    if(z2){stacknum(workptr+n1,l1,e1,m1);return;}
  443.    if(e1<e2)n3=n2,n2=n1,n1=n3,n3=m2,m2=m1,m1=n3,
  444.             e3=e2,e2=e1,e1=e3,l3=l2,l2=l1,l1=l3; /* now e1>=e2 always */
  445.    n3=eworkptr+1,e3=e1;                 /* Initialise a third number. */
  446.    if(m1==m2){ /* add two numbers; the sign of the result is m1 */
  447.       l3=(l1>l2+e1-e2)?l1:(l2+e1-e2);
  448.       if(l3>precision+2)l3=precision+2;
  449.       mtest(workptr,worklen,eworkptr+l3+2,l3+256); /* Make space for 3rd num */
  450.       for(i=l3-1;i>=0;i--){
  451.          if(i>=l1)d1=0;
  452.          else d1=workptr[n1+i]-'0';   /* Get each digit from n1 */
  453.          d2=i+e2-e1;                  /* this gives the position of the  */
  454.          if(d2<0||d2>=l2)d2=0;        /* corresponding digit in n2 */
  455.          else d2=workptr[n2+d2]-'0';  /* Get the digit from n2 */
  456.          d2+=d1+c;                    /* add with carry */
  457.          c=d2/10,d2%=10;
  458.          workptr[n3+i]=d2+'0';        /* Store the answer */
  459.       }
  460.       if(c)n3--,workptr[n3]='0'+c,l3++,e3++; /* carry to the left */
  461.    }
  462.    else{ /* subtract the smaller from the larger. The sign of n1-n2 is m1 */
  463.       if(e1==e2){ /* compare to see which is the largest */
  464.          for(i=0;i<l1&&i<l2;i++){
  465.             if(workptr[n1+i]<workptr[n2+i]){ /* swap numbers */
  466.                n3=n2,n2=n1,n1=n3,l3=l2,l2=l1,l1=l3,m1=m2;
  467.                break;
  468.             }
  469.             if(workptr[n1+i]>workptr[n2+i])break; /* order OK */
  470.          }
  471.          if((i==l1&&i==l2)||i>=precision){ /* numbers are equal; return zero */
  472.             stack("0",1);
  473.             return;
  474.          }
  475.          if(i==l1)n3=n2,n2=n1,n1=n3,l3=l2,l2=l1,l1=l3,m1=m2;
  476.             /* n1 is an initial segment of n2; swap since n1<n2 */
  477.       }/* at this point, n1>n2.  Now the subtraction goes exactly like the
  478.           earlier addition. */
  479.       l3=(l1>l2+e1-e2)?l1:(l2+e1-e2);
  480.       if(l3>precision+2)l3=precision+2;
  481.       mtest(workptr,worklen,eworkptr+precision,precision+256);
  482.       n3=eworkptr;
  483.       for(i=l3;i>=0;i--){
  484.          if(i>=l1)d1='0';
  485.          else d1=workptr[n1+i];
  486.          d2=i+e2-e1;
  487.          if(d2<0||d2>=l2)d2='0';
  488.          else d2=workptr[n2+d2];
  489.          d1-=d2+c;
  490.          if(d1<0)d1+=10,c=1;
  491.          else c=0;
  492.          if(i<precision)workptr[n3+i]=d1+'0';
  493.       }
  494.       if(l3>precision)l3=precision;
  495.       while(l3&&workptr[n3]=='0')l3--,n3++,e3--;
  496.    }
  497.    stacknum(workptr+n3,l3,e3,m1);/* After the operation the result is stacked*/
  498. }
  499.  
  500. void binmin(op) /* OPsub, the binary - operator, is implemented by */
  501. char op;        /* negating and adding. */
  502. {
  503.    unmin(op),
  504.    binplus(op);
  505. }
  506.  
  507. void binmul(op) /* OPmul, the binary * operator */
  508. char op;
  509. {
  510.    int n1,n2,m1,m2,e1,e2,z1,z2,l1,l2;
  511.    int n3,l3;
  512.    int i,j,k;
  513.    int c,d,d1;
  514.    if((n1=num(&m1,&e1,&z1,&l1))<0)die(Enum); /* Get each number and delete */ 
  515.    delete(&l3);                              /* from the stack */
  516.    if((n2=num(&m2,&e2,&z2,&l2))<0)die(Enum);
  517.    delete(&l3);
  518.    if(l1>precision+2)l1=precision+2;
  519.    if(l2>precision+2)l2=precision+2;
  520.    l3=l1+l2;
  521.    if(z1||z2){stack("0",1);return;}          /* zero times x is zero */
  522.    if(l1<l2)i=l2,l2=l1,l1=i,i=n2,n2=n1,n1=i; /* make sure n2 is the shorter */
  523.    mtest(workptr,worklen,eworkptr+l3,l3+256);/* Make room for the answer */
  524.    n3=eworkptr;                              /* this is where it goes */
  525.    for(i=0;i<l3;workptr[n3+(i++)]='0');      /* Initially it is zero */
  526.    for(i=l2-1;i>=0;i--){                     /* Now a long multiplication */
  527.       c=0,
  528.       d1=workptr[n2+i]-'0';
  529.       for(j=l1-1;j>=0;j--){
  530.          k=i+j+1,
  531.          d=(workptr[n1+j]-'0')*d1+c+workptr[n3+k]-'0',
  532.          c=d/10,
  533.          d%=10,
  534.          workptr[n3+k]=d+'0';
  535.       }
  536.       workptr[n3+i]+=c;
  537.    }
  538.    if(abs(e1+=e2+1)+2>maxexp)die(Eoflow);    /* Calculate the exponent */
  539.    for(;l3>0&&workptr[n3]=='0';e1--,n3++,l3--); /* Remove leading zeros */
  540.    stacknum(workptr+n3,l3,e1,m1^m2);         /* Stack the answer */
  541. }
  542.  
  543. void bindiv(op) /* OPdiv,  the binary /  operator;
  544.                    OPidiv, the binary %  operator, and
  545.                    OPmod,  the binary // operator  are all handled here */
  546. char op;
  547. {
  548.    int n1,n2,m1,m2,e1,e2,z1,z2,l1,l2;
  549.    int n3,l3;
  550.    int i,j;
  551.    int c,d,mul;
  552.    if((n2=num(&m2,&e2,&z2,&l2))<0)die(Enum);
  553.    delete(&l3);
  554.    if((n1=num(&m1,&e1,&z1,&l1))<0)die(Enum);
  555.    delete(&l3);
  556.    if(z2)die(Edivide);           /* anything divided by zero */
  557.    if(z1){stack("0",1);return;}  /* zero divided by anything */
  558.    if(l1>precision+2)l1=precision+2;
  559.    if(l2>precision+2)l2=precision+2;
  560.    l3=precision+2;               /* The number of digits in the quotient */
  561.    if(op!=OPdiv)l3=e1-e2+1;      /* For % and //, the number of digits in
  562.                                     the integer quotient. */
  563.    if(l3<=0){                    /* The integer result is a fraction */
  564.       if(op==OPidiv)stack("0",1);       /* integer quotient is zero */
  565.       else {
  566.          while(l1>0&&workptr[n1+l1-1]=='0')l1--; /* remove trailing zeros */
  567.          stacknum(workptr+n1,l1,e1,m1); /* remainder result is n1 */
  568.       }
  569.       return;
  570.    }
  571.    if(l3>precision+2)l3=precision+2;
  572.    if(op==OPmod&&l3>precision){
  573.       stack("0",1);
  574.       return;/* if l3>precision, return remainder 0 */
  575.    }
  576.    /* Now extend n1 to length l2+l3-1 with zeros */
  577.    mtest(workptr,worklen,eworkptr+l3+l3+l2,l3+l3+l2+256);
  578.    if(l1<l2+l3)n3=eworkptr+l2+l3-l1;
  579.    else n3=eworkptr;
  580.    for(i=l1;i<l2+l3-1;i++)workptr[n1+i]='0';
  581.    for(i=0;i<l3;i++){ /* loop for each digit of result */
  582.       workptr[n3+i]='0'; /* Start each result digit at zero */
  583.       while(1){
  584.          c=0;
  585.          z1=1;
  586.          if(i)d=workptr[n1+i-1]*10+workptr[n1+i]-'0'*11;
  587.             else d=workptr[n1+i]-'0';
  588.          mul=d/(workptr[n2]-'0'+1);/* The next digit can't be lower than this*/
  589.          if(mul==0)mul=1;          /* continue until subtraction fails */
  590.          for(j=l2-1;j>= -i;j--){   /* do a subtraction */
  591.             if(j>=0)d=workptr[n2+j]-'0';
  592.             else d=0;
  593.             d=workptr[n1+i+j]-d*mul-c-'0';
  594.             if(d)z1=0;
  595.             c=0;
  596.             while(d<0)d+=10,c++;
  597.             workptr[n1+i+j]=d+'0';
  598.          }
  599.          if(z1){workptr[n3+i]+=mul;break;}    /* Exactly zero resulted */
  600.          if(!c){workptr[n3+i]+=mul;continue;} /* A positive value resulted */
  601.          c=0;
  602.          for(j=l2-1;j>= -i;j--){          /* add back a failed subtraction */
  603.             if(j>=0)d=workptr[n2+j]-'0';
  604.             else d=0;
  605.             d+=workptr[n1+i+j]+c;
  606.             if(d>'9')d-=10,c=1;
  607.             else c=0;
  608.             workptr[n1+i+j]=d;
  609.          }
  610.          break; /* This result digit is found */
  611.       }
  612.       if(z1&&i>=l1-l2) { /* exact division */
  613.          l3=i+1;
  614.          if(op==OPmod){stack("0",1);return;} /* zero remainder */
  615.          break; /* The entire result is found */
  616.       }
  617.    }/* End of division: the result can be stacked */
  618.    if(op==OPmod){ /* stack the remainder */
  619.       if(l1<l2+l3)l1=l2+l3-1;
  620.       for(;l1&&workptr[n1]=='0';l1--,e1--,n1++);
  621.       for(;l1>0&&workptr[n1+l1-1]=='0';l1--);
  622.       stacknum(workptr+n1,l1,e1,m1);
  623.    }
  624.    else { /* stack the quotient */
  625.       for(;l3>0&&workptr[n3]=='0';e2++,n3++,l3--);
  626.       while(l3>0&&workptr[n3+l3-1]=='0')l3--;
  627.       if(abs(e1-=e2)>maxexp)die(Eoflow);
  628.       stacknum(workptr+n3,l3,e1,m1^m2);
  629.    }
  630. }
  631.  
  632. void binexp(op) /* OPpower, the binary ** operator */
  633. char op;
  634. {
  635.    int pow,n,m,e,z,l,pm=0,c=four*8-1; /* Ahem! 8 bits per byte here */
  636.    char *ptr;
  637.    pow=getint(1);           /* The exponent must be an integer. */
  638.    if(pow<0)pow= -pow,pm=1; /* find x**(abs(y)) first, then calculate x**y */
  639.    if((n=num(&m,&e,&z,&l))<0)die(Enum);  /* A copy of the first operand */
  640.    if(pow==0){
  641.       delete(&l);
  642.       stack("1",1);  /* x ** 0 is 1 */
  643.       return;
  644.    }
  645.    if(z)return;      /* 0 ** x is 0 - note the zero operand is still stacked */
  646.    while(pow>0)pow<<=1,c--;/* Get the MSB of the num into the MSB of the int */
  647.    precision+=2;           /* Temporarily increase precision for good result */
  648.    while((c--)>0){         /* For each bit of the exponent */
  649.       rxdup(),             /* Square the intermediate result */
  650.       binmul(op);
  651.       if((pow<<=1)<0)      /* If the next bit of the exponent is set,        */
  652.          stacknum(workptr+n,l,e,m),binmul(op);  /* multiply the number in    */
  653.    }
  654.    if(pm){ /* The exponent was negative, so invert the number */
  655.       mtest(cstackptr,cstacklen,ecstackptr+2*four,256);
  656.       ptr=cstackptr+ecstackptr-four,
  657.       l= align(*(int *)ptr),
  658.       ptr-=l,   /* ptr points to the stack entry containing the result */
  659.       l+=four,  /* l contains its whole length */
  660.       n=four+align(1);
  661.       for(c=l-1;c>=0;c--)ptr[c+n]=ptr[c]; /* Make two ints-worth of space */
  662.       ptr[0]='1',
  663.       *(int *)(ptr+align(1))=1, /* Store the stack entry "1" in the space */
  664.       ecstackptr+=n,
  665.       bindiv(2);            /* Now divide 1 by the result. */
  666.    }
  667.    precision-=2;            /* Restore the old precision */
  668.    n=num(&m,&e,&z,&l),      /* Prepare to reformat the number to the new */
  669.    delete(&c),              /* precision by unstacking and restacking */
  670.    eworkptr=0;
  671.    while(l>0&&workptr[n+l-1]=='0')l--;  /* first remove trailing zeros */
  672.    stacknum(workptr+n,l,e,m);
  673. }
  674.  
  675. void rxdup() /* Duplicate the top stack entry */
  676. {
  677.    char *mtest_old;
  678.    long mtest_diff;
  679.    char *ptr=cstackptr+ecstackptr;
  680.    int len= align(*((int *)ptr-1))+four;
  681.    if dtest(cstackptr,cstacklen,ecstackptr+len,len+256)
  682.       ptr+=mtest_diff;
  683.    memcpy(ptr,ptr-len,len), /* Simple, really... */
  684.    ecstackptr+=len;
  685. }
  686.  
  687. void binrel(op) /* Implements all the comparison operators. */
  688. char op;
  689. {
  690.    int len1,len2;
  691.    int i;
  692.    int ans=0;
  693.    unsigned char *ptr1,*ptr2;
  694.    int n,m,m2,e1,e2,z,l;
  695.    n=num(&m2,&e2,&z,&l),  /* Test to see whether the top value is a number */
  696.    ptr2=(unsigned char *)delete(&len2), /* Delete the top value */
  697.    n=(n<0||num(&m,&e1,&z,&l)<0);  /* Test to see whether both are numbers */
  698.    if(op==OPeequ||op>=OPnneq){    /* The strict comparison operators */
  699.       ptr1=(unsigned char *)delete(&len1);
  700.    /* Now see which one is greater, before calculating the required result */
  701.       if(op>OPnneq||len1==len2){
  702.          for(i=0;i<len1&&i<len2&&ptr1[i]==ptr2[i];i++);
  703.          if(i==len1)ans= -!(i==len2); /* string1 is a prefix of string2 */
  704.          else if(i==len2)ans=1;       /* string2 is a prefix of string1 */
  705.          else ans=ptr1[i]-ptr2[i];    /* strings differ at this character */
  706.       }
  707.       else ans=1; /* for == and \== with lengths different, report not equal */
  708.       switch(op){
  709.          case OPeequ: ans=!ans;    break;
  710.          case OPnneq: ans=(ans!=0);break;
  711.          case OPlless:ans=(ans<0); break;
  712.          case OPggrtr:ans=(ans>0); break;
  713.          case OPlleq: ans=(ans<=0);break;
  714.          case OPggeq: ans=(ans>=0);
  715.       }
  716.    }
  717.    else {
  718.       if (!n) {                       /* both numeric */
  719.          if (!n && (m^m2))            /* different signs: */
  720.             {z=0; delete(&l);}        /* sign of result = sign of num1 */
  721.          else {
  722.             ecstackptr+=align(len2)+four;/* restack string2 */
  723.             i=precision,precision=fuzz,  /* add fuzz */
  724.             binmin(op),                  /* compare using binary - */
  725.             precision=i,
  726.             n=num(&m,&i,&z,&l),          /* get flags, then discard the result */
  727.             delete(&l);
  728.          }
  729.       }
  730.       else { /* string comparison; first strip spaces */
  731.          ecstackptr+=align(len2)+four;/* restack string2 */
  732.          strip(),
  733.          ptr2=(unsigned char *)delete(&len2), /* Get pointers and lengths of */
  734.          strip(),                             /* the stripped strings and    */
  735.          ptr1=(unsigned char *)delete(&len1); /* delete them from the stack. */
  736.          for(i=0;i<len1&&i<len2&&ptr1[i]==ptr2[i];i++); /* Compare */
  737.          if(i==len1)while(i<len2&&ptr2[i]==' ')i++; /* Act as if the shorter */
  738.          if(i==len2)while(i<len1&&ptr1[i]==' ')i++; /* were padded wth spaces*/
  739.          if(i>=len1)           /* now set flags as for numeric comp. */
  740.             if(i>=len2)z=1,m=0;
  741.             else z=0,m=(ptr2[i]>' ');
  742.          else if(i>=len2)z=0,m=(ptr1[i]<' ');
  743.          else z=0,m=(ptr1[i]<ptr2[i]);
  744.       }
  745.       if(z){if(op==OPequ||op==OPleq||op==OPgeq)ans=1;} /* This gives the     */
  746.       else if(op==OPgrtr&&!m || op==OPneq)ans=1;       /* correct result for */
  747.       if(m){if(op==OPless||op==OPleq)ans=1;}           /* the required op    */
  748.       else if(op==OPgeq)ans=1;
  749.    }
  750.    ptr1=(unsigned char *)(cstackptr+ecstackptr), /* The result is stacked */
  751.    ecstackptr+=align(1)+four;
  752.    (*ptr1)='0'+ans,
  753.    (*(int *)(ptr1+align(1)))=1;
  754. }
  755. void binbool(op)  /* OPand, OPxor, OPor - binary &, |, && operators */
  756. char op;
  757. {
  758.    int z1;
  759.    int minus,exp,zero,len;
  760.    if(num(&minus,&exp,&z1,&len)<0)die(Enum);  /* Get the two numbers and */
  761.    delete(&len);                              /* delete the second */
  762.    if(num(&minus,&exp,&zero,&len)<0)die(Enum);
  763.    switch(op){
  764.       case OPand:if(z1)delete(&len),stack("0",1);
  765.          break;
  766.       case OPxor:if(!z1)unnot(op);
  767.          break;
  768.       case OPor:if(!z1)delete(&len),stack("1",1);
  769.    }
  770. }
  771. void bincat(op) /* OPcat, OPspc - concatenation without/with a space */
  772. char op;
  773. {
  774.    int len1,len2,alen1,alen2,count;
  775.    char *ptr=cstackptr+ecstackptr-four;
  776.    char *aptr;
  777.    char *ptr1,*ptr2;
  778.    alen1=align(len1= *(int *)ptr);
  779.    ptr1=ptr-alen1;
  780.    ptr2=ptr1-four;
  781.    alen2=align(len2= *(int*)ptr2);
  782.    ptr2-=alen2;
  783.    aptr=ptr2+len2;
  784.    if(op==OPspc)*(aptr++)=' ',len2++;
  785.    for(count=len1;count--;aptr++[0]=ptr1++[0]);
  786.    ptr2+=align(len1+len2);
  787.    *(int *)ptr2=len1+len2;
  788.    ecstackptr=ptr2-cstackptr+four;
  789. }
  790.  
  791. void unnot(op) /* OPnot, unary \ operator */
  792. char op;
  793. {
  794.    int minus,exp,zero,len;
  795.    if(num(&minus,&exp,&zero,&len)<0)die(Enum);
  796.    delete(&len);
  797.    if(zero)stack("1",1);
  798.    else stack("0",1);
  799. }
  800. void unmin(op) /* OPneg, unary - */
  801. char op;
  802. {
  803.    int a,b;
  804.    int minus,exp,zero,len;
  805.    if((a=num(&minus,&exp,&zero,&len))<0)die(Enum);
  806.    delete(&b);
  807.    if(zero)stack("0",1);
  808.    else stacknum(workptr+a,len,exp,!minus); /* restack with opposite sign */
  809. }
  810. void unplus(op) /* OPplus, unary +  -just unstack and restack, thus checking */
  811. char op;       /*                  that it is numeric and reformatting it   */
  812. {
  813.    int a,b;
  814.    int minus,exp,zero,len;
  815.    if((a=num(&minus,&exp,&zero,&len))<0)die(Enum);
  816.    delete(&b);
  817.    if(zero)stack("0",1);
  818.    else stacknum(workptr+a,len,exp,minus);
  819. }
  820.  
  821. void strip() /* Strip leading and trailing spaces from the top stack value */
  822. {
  823.    char *ptr=cstackptr+ecstackptr-four;
  824.    char *ptr1;
  825.    int len= *(int *)ptr;
  826.    int i;
  827.    ptr-=align(len),        /* Point to the value */
  828.    ptr1=ptr,               /* save the original pointer */
  829.    ecstackptr-=align(len); /* discount the original length */
  830.    for(;len>0&&ptr[0]==' ';len--,ptr++);  /* Skip leading spaces */
  831.    for(;len>0&&ptr[len-1]==' ';len--);    /* Remove trailing spaces */
  832.    if(ptr==ptr1)ptr1+=len;  /* If no leading spaces leave the value in place */
  833.    else for(i=0;i<len;i++,(*(ptr1++))=(*(ptr++)));   /* else move it back */
  834.    (*(int *)(ptr1+toalign(len)))=len,
  835.    ecstackptr+=align(len);
  836. }
  837.  
  838. int num(minus,exp,zero,len)
  839. int *minus,*exp,*zero,*len;
  840. { /* examines the `last value' on the calculator stack to determine whether
  841.      it is numeric (always leaves the number stacked). If not, then the answer
  842.      is -1, otherwise the answer is an offset within the workspace where a
  843.      sequence of digits is to be found. In this case, the sequence of digits,
  844.      when a decimal point is added between the 1st and 2nd digits and the
  845.      result is multiplied by 10**exp, is equal to the magnitude of the number.
  846.      `minus' is 1 if the number is negative; `zero' is 1 if the number is zero,
  847.      and `len' is the length of the sequence of digits. */
  848.    register char *ptr1=cstackptr+ecstackptr-four;
  849.    register int ptr2=eworkptr;
  850.    int ans=ptr2;
  851.    register int len1= *(int *)ptr1;
  852.    int dot=0;
  853.    int etmp,emin;
  854.    register int myzero=1; /* fast-access copy of "*zero" */
  855.    register int myexp=-1; /* and of *exp */
  856.    register int ch;
  857.    if(len1<0)die(Ecall); /* doing any numeric operation whatsoever on a 'null'
  858.                          is strictly forbidden! */
  859.    ptr1-=align(len1);    /* ptr1 points to the value, len1 holds its length */
  860.    mtest(workptr,worklen,ptr2+len1,len1+256);
  861.    (*minus)=0;           /* Assume positive; set negative if '-' found */
  862.    for(;ptr1[0]==' '&&len1>0;len1--,ptr1++); /* Skip leading spaces */
  863.    for(;len1>0&&ptr1[len1-1]==' ';len1--);   /* and trailing spaces */
  864.    if((ch=ptr1[0])=='-')ptr1++,len1--,(*minus)=1; /* Deal with leading sign */
  865.    else if(ch=='+')ptr1++,len1--;
  866.    for(;ptr1[0]==' '&&len1>0;len1--,ptr1++); /* and spaces after it */
  867.    if(len1<=0||(ch=ptr1[0])>'9'||ch=='.'&&(len1==1||ptr1[1]>'9'))
  868.       return -1;  /* initial check for validity */
  869.    for(;len1>0;ptr1++,len1--){ /* Now, examine each character of the number */
  870.       if((ch=ptr1[0])=='0'&&myzero){
  871.          if(dot)myexp--;       /* Each leading 0 after the dot divides by 10 */
  872.          continue;
  873.       }
  874.       if(ch>='0'&&ch<='9'){
  875.          myzero=0;  /* Either zero was false already, or a non-zero digit was
  876.                        found. */
  877.          if(!dot)myexp++;  /* Each figure before the dot multiplies by 10 */
  878.          workptr[ptr2++]=ch;
  879.       }
  880.       else if(ch=='.'){
  881.          if(dot)return -1;     /* Count the number of dots */
  882.          dot=1;
  883.       }
  884.       else if((ch&0xdf)=='E'){ /* Now deal with an exponent */
  885.          ptr1++,len1--;
  886.          emin=etmp=0;
  887.          if((ch=ptr1[0])=='-')emin=1,ptr1++,len1--;
  888.          else if(ch=='+')ptr1++,len1--;
  889.          if(len1<=0)return -1;
  890.          for(;len1>0;ptr1++,len1--){
  891.             if((ch=ptr1[0]-'0')<0||ch>9)return -1; /* Must contain digits */
  892.             etmp=etmp*10+ch;
  893.             if(etmp>maxexp)die(Eoflow);
  894.          }
  895.          *len=ptr2-ans;
  896.          eworkptr=ptr2;
  897.          if(*zero=myzero) return *exp=*minus=0,ans; /* No exponent if zero */
  898.          if(emin)etmp= -etmp;    /* Otherwise set the exponent and return. */
  899.          (*exp)=myexp+etmp;
  900.          return ans;
  901.       }
  902.       else return -1; /* Each character must be a digit or "E" or "." */
  903.    }
  904.    *len=ptr2-ans;
  905.    if(*zero=myzero) *exp=*minus=0; /* no exponent or sign if zero */
  906.    else *exp=myexp;
  907.    eworkptr=ptr2;  /* Protect this number from being overwritten, */
  908.    return ans;     /* and return it. */
  909. }
  910.  
  911. int getint(flg)
  912. int flg;
  913. { /* get an integer from the calculator stack. Error if overflow.
  914.      if flg=1 and the number was non-integral an error is raised */
  915.    int n,minus,exp,zero,len,d;
  916.    unsigned ans=0;
  917.    if((n=num(&minus,&exp,&zero,&len))<0)die(Enum); /* First get the number  */
  918.    delete(&d);                                     /* and delete it         */
  919.    if(zero)return 0;
  920.    for(;len>0&&workptr[n+len-1]=='0';len--);       /* remove trailing zeros */
  921.    if(flg&&len>exp+1)die(Enonint);                 /* not an integer        */
  922.    for(;len>0&&exp>=0;exp--,len--,n++){       /* now collect all the digits */
  923.       ans=ans*10+workptr[n]-'0';
  924.       if((int)ans<0)die(Erange);
  925.    }                                       /* Take account of the exponent. */
  926.    for(;exp>=0;exp--,ans*=10)if((int)ans<0)die(Erange);
  927.    if(minus)ans= -ans;               /* and finally, give the correct sign. */
  928.    return ans;
  929. }
  930.  
  931. int isint(num,len,exp) /* Given components of a number obtained by num(), */
  932. int num,len,exp;       /* tell whether it represents an integer.          */
  933. {
  934.    for(;len>0&&workptr[num+len-1]=='0';len--);
  935.    return len<=exp+1&&exp<precision&&(exp<9||exp==9&&workptr[num]<'2');
  936. }
  937.  
  938. char *delete(len)  /* Delete an item from the calculator stack, returning */
  939. int *len;          /* its position and setting "len" to its length.  The  */
  940. {                  /* item is not actually deleted from memory, so it can */
  941.                    /* still be examined, but it will probably soon be     */
  942.                    /* overwritten by new values on the stack.             */
  943.    char *ptr=cstackptr+ecstackptr-four;
  944.    (*len)= *(int *)ptr;
  945.    if(*len>=0)ptr-= align(*len),
  946.               ecstackptr-= align(*len);
  947.    else ptr=(char *)-1;     /* I don't think this value is ever used */
  948.    ecstackptr-=four;
  949.    return ptr;
  950. }
  951.  
  952. int isnull() /* Tell whether the top value on the stack is null, i.e. */
  953. {            /* has length = -1                                       */
  954.    char *ptr=cstackptr+ecstackptr-four;
  955.    return (*(int *)ptr)<0;
  956. }
  957.  
  958. void stacknum(num,len,exp,minus)
  959. char *num;
  960. int exp,len,minus;
  961. { /* stack the number given by sequence of digits `num' of length `len' 
  962.      and exponent `exp'. minus=0 if the number is positive, 1 if negative. */
  963.    char *ptr1;
  964.    int len1=0;
  965.    int i;
  966.    mtest(cstackptr,cstacklen,ecstackptr+len+30,len+256);
  967.    ptr1=cstackptr+ecstackptr;
  968.    if(len<=0)num="0",len=1,exp=0,minus=0;
  969.    if(len>precision)   /* Round to the correct number of digits */
  970.       if(num[len=precision]>='5'){
  971.          for(i=len-1;i>=0;i--){
  972.             if(++num[i]<='9')break;
  973.             num[i]='0';
  974.          }
  975.          if(i<0){      /* change 999995 to 10000E+1 (or whatever) */
  976.             for(i=len-2;i>=0;i--)num[i+1]=num[i];
  977.             num[0]='1',
  978.             exp++;
  979.          }
  980.       }  /* Now stack the digits, starting with a sign if negative */
  981.    if(minus)ptr1[len1++]='-';
  982.    if(len-exp-1<=2*precision&&exp<precision){ /* stack with no exponent */
  983.       if(exp<0){                       /* begin with 0.00...0    */
  984.          ptr1[len1++]='0',
  985.          ptr1[len1++]='.';
  986.          for(i= -1;i>exp;i--)ptr1[len1++]='0';
  987.       }
  988.       while(len>0){                    /* stack the digits */
  989.          ptr1[len1++]=num[0],
  990.          num++,
  991.          len--,
  992.          exp--;
  993.          if(len&&exp==-1)ptr1[len1++]='.'; /* remembering the decimal point  */
  994.       }
  995.       while(exp>-1)ptr1[len1++]='0',exp--; /* Add zeros up to the decimal pt */
  996.    }
  997.    else{       /* stack floating point in appropriate form with exponent */
  998.       ptr1[len1++]=num++[0],len--;   /* The (first) digit before the "." */
  999.       if(numform)while(exp%3)        /* For engineering, up to two more  */
  1000.             exp--,                   /* digits are required before "."   */
  1001.             ptr1[len1++]=(len-->0 ? (num++)[0] : '0');
  1002.       if(len>0){                     /* Now the "." and the rest of the  */
  1003.          ptr1[len1++]='.';           /* digits.                          */
  1004.          while(len--)ptr1[len1++]=(num++)[0];
  1005.       }
  1006.       if(exp){                       /* Add the exponent                 */
  1007.          ptr1[len1++]='E',
  1008.          ptr1[len1++]= exp<0 ? '-' : '+',
  1009.          exp=abs(exp);
  1010.          if(exp>maxexp)die(Eoflow);
  1011.          for(i=1;i<=exp;i*=10);
  1012.          i/=10;
  1013.          for(;i>=1;i/=10)
  1014.             ptr1[len1++]=exp/i+'0',
  1015.             exp%=i;
  1016.       }
  1017.    }
  1018.    *(int *)(ptr1+align(len1))=len1; /* Finish off the stack entry.       */
  1019.    ecstackptr+=align(len1)+four;
  1020. }
  1021.  
  1022. void getvarname(line,ptr,varname,namelen,maxlen) /* Go along a program line,
  1023.                          accumulating characters to form a variable name.  If
  1024.                          it is a compound symbol, the substitution in the tail
  1025.                          is performed here also.  If the character pointer
  1026.                          does not point to a valid symbol, then on exit
  1027.                          varname[0]=namelen=0. */
  1028. char *line;     /* the program line */
  1029. int *ptr;       /* the current character pointer */
  1030. char *varname;  /* where to put the variable name */
  1031. int *namelen;   /* the length of the returned variable name */
  1032. int maxlen;     /* the amount of space allocated to varname */
  1033. {
  1034.    char *exp,*exp1,*vg;
  1035.    char c;
  1036.    int expn;
  1037.    int explen;
  1038.    int disp=trcflag&Tintermed; /* whether to trace compound symbols */
  1039.    char quote;
  1040.    maxlen-=2;                  /* a safety margin :-) */
  1041.    if(rexxsymbol(line[*ptr])<1) /* Test the starting character */
  1042.       {varname[0]=0;(*namelen)=0;return;}
  1043.    for(exp=varname;rexxsymbol(line[*ptr]);exp++,(*ptr)++){
  1044.       if(exp-varname>maxlen)die(Elong);  /* Copy the stem or simple symbol */
  1045.       (*exp)=line[*ptr];
  1046.    }
  1047.    if(line[*ptr]=='.'){
  1048.       varname[0]|=128;                   /* flag: not a simple symbol */
  1049.       if((c=line[*ptr+1])<=' '||!(rexxsymboldot(c)||c=='('||c=='\''||c=='\"'))
  1050.          (*ptr)++;                       /* stem - step past the final dot */
  1051.       else disp|=4;                      /* compound symbol (so display it) */
  1052.    }
  1053.    while(line[*ptr]=='.'){/* Loop to interpret the qualifiers of a comp.symb.*/
  1054.       (*ptr)++,
  1055.       (*(exp++))='.';     /* Step past and copy the dot */
  1056.       if(line[*ptr]<=' ')break; /* Stop if at a space, terminator, or token */
  1057.       switch(line[*ptr]){ /* What kind of qualifier is it? */
  1058.          case '.':break;  /* null qualifier */
  1059.          case '(':(*ptr)++, /* parenthesised expression e.g. stem.(a+b) */
  1060.             exp1=scanning(line,ptr,&explen),  /* Get the expression    */
  1061.             ecstackptr=exp1-cstackptr;        /* delete the expression */
  1062.             if(exp+explen-varname>maxlen)die(Elong);
  1063.             memcpy(exp,exp1,explen),          /* Copy to the varname */
  1064.             exp+=explen;
  1065.             if(line[(*ptr)++]!=')')die(Elpar);/* Expect ')' */
  1066.             break;
  1067.          case '\'': /* Quoted expression e.g. stem.'tail' */
  1068.          case '\"':quote=line[(*ptr)++];
  1069.             for(expn= *ptr;(line[expn++])!=quote;);/*Find the matching quote */
  1070.             if(exp+expn-*ptr-varname>maxlen)die(Elong);
  1071.             memcpy(exp,line+*ptr,expn-*ptr-1),     /* Copy the string */
  1072.             exp+=expn-*ptr-1,
  1073.             (*ptr)=expn;
  1074.             break;
  1075.          default: exp1=exp; /* The usual qualifier - a symbol */
  1076.             while(rexxsymbol(line[*ptr])){  /* append the symbol to the name */
  1077.                if(exp-varname>maxlen)die(Elong);
  1078.                (*(exp++))=line[(*ptr)++];
  1079.             }
  1080.             if(exp1!=exp&&rexxsymbol(exp1[0])==1){/* non-null non-constant */
  1081.                (*exp)=0,
  1082.                vg=varget(exp1,exp-exp1,&explen); /* See if the sym has a val */
  1083.                if(vg!=cnull){                    /* if so, substitute */
  1084.                   exp=exp1;
  1085.                   if(exp+explen-varname>maxlen)die(Elong);
  1086.                   memcpy(exp,vg,explen),
  1087.                   exp+=explen;
  1088.                }
  1089.             }
  1090.       }
  1091.    }
  1092.    if(disp==12){                           /* tracing compound symbols */
  1093.       c=varname[0];
  1094.       varname[0]&=0x7f;                    /* Don't print the "stem" flag */
  1095.       traceline(">C>",varname,exp-varname);
  1096.       varname[0]=c;
  1097.    }
  1098.    (*exp)=0,
  1099.    (*namelen)=exp-varname;
  1100. }
  1101.  
  1102. void skipvarname(line,ptr) /* Skip a variable name in a program line */
  1103.                            /* It is guaranteed to start with a valid char */
  1104. char *line;                /* the program line */
  1105. int *ptr;                  /* the current character pointer */
  1106. {
  1107.    char quote;
  1108.    int paren;
  1109.    while(rexxsymbol(line[*ptr])) (*ptr)++;
  1110.    while(line[*ptr]=='.'){/* Loop to skip the qualifiers of a compound symbol*/
  1111.       (*ptr)++;           /* step past the dot */
  1112.       if(line[*ptr]<=' ')break; /* Stop if at a space, terminator, or token */
  1113.       switch(line[*ptr]){ /* What kind of qualifier is it? */
  1114.          case '.':break;  /* null qualifier */
  1115.          case '(':(*ptr)++; /* parenthesised expression e.g. stem.(a+b) */
  1116.             for(paren=1;paren&&line[*ptr]&&line[*ptr]!=-1;(*ptr)++)
  1117.                if(line[*ptr]=='(')paren++;       /* Find matching ')' */
  1118.                else if(line[*ptr]==')')paren--;
  1119.             if(paren)die(Elpar);
  1120.             break;
  1121.          case '\'': /* Quoted expression e.g. stem.'tail' */
  1122.          case '\"':quote=line[(*ptr)++];
  1123.             while((line[(*ptr)++])!=quote); /* Find the matching quote */
  1124.             break;
  1125.          default: /* The usual qualifier - a symbol */
  1126.             while(rexxsymbol(line[*ptr]))(*ptr)++;
  1127.       }
  1128.    }
  1129. }
  1130.  
  1131. int gettoken(line,ptr,varname,maxlen,ex) /* Go along a program line and form
  1132.     a token, i.e. a sequence of characters which are valid in symbols - such
  1133.     as the word coming after SIGNAL. The token may be quoted, in which case
  1134.     the return value is 2, or a symbol, in which case 1 is returned.  If ex
  1135.     is non-zero and the token is obviously not a symbol or a quoted string,
  1136.     then it may be an entire expression, perhaps preceded by VALUE - as in
  1137.     SIGNAL VALUE x.  In that case 0 is returned.  The token is terminated
  1138.     with a null after it has been collected. */
  1139. char *line;    /* the program line */
  1140. int *ptr;      /* the character pointer */
  1141. char *varname; /* where to put the token */
  1142. int maxlen;    /* the amount of space available in varname */
  1143. int ex;        /* whether or not an entire expression is allowed */
  1144. {
  1145.    char *exp;
  1146.    int i;
  1147.    int explen;
  1148.    char quote;
  1149.    if(rexxsymboldot(line[*ptr])){ /* it's just a simple symbol */
  1150.       for(i=0;rexxsymboldot(line[*ptr]);varname[i++]=line[(*ptr)++])
  1151.          if(i>=maxlen-2)die(Elong);
  1152.       varname[i]=0;
  1153.       return 1;
  1154.    }
  1155.    if((quote=line[(*ptr)++])=='\''||quote=='\"'){ /* it's a string constant */
  1156.       for(i=0;(varname[i++]=line[(*ptr)++])!=quote;) if(i>=maxlen-1)die(Elong);
  1157.       varname[--i]=0;
  1158. /*    if(!i)die(Enostring);   We allow null strings except where checked individually */
  1159.       return 2;
  1160.    }
  1161.    if(!ex)die(Enostring);  /* it must be an expression; is that allowed? */
  1162.    if(line[--*ptr]==VALUE)(*ptr)++;  /* VALUE is optional here */
  1163.    if(!line[*ptr])die(Enostring);
  1164.    scanning(line,ptr,&explen);     /* get the expression */
  1165.    exp=delete(&explen);
  1166.    if(explen>maxlen-1)die(Elong);
  1167.    memcpy(varname,exp,explen);     /* and copy it */
  1168.    varname[explen]=0;
  1169.    if(line[*ptr]==')')die(Erpar);  /* save some work by flagging extra ')'s
  1170.                                    now.  This must be the end of a clause. */
  1171.    return 0;
  1172. }
  1173.