/*
 * llex.c -- lexical analysis routines.
 */

#ifdef CRAY
#include <stdlib.h>
#endif					/* CRAY */

#include <math.h>
#include "..\h\config.h"
#include "general.h"
#include "tproto.h"
#include "link.h"
#include "opcode.h"
#include <ctype.h>

int nlflag = 0;		/* newline last seen */

#if MACINTOSH
#if MPW
#include <CursorCtl.h>
#define CURSORINTERVAL 100
#endif					/* MPW */
#endif					/* MACINTOSH */

#if !EBCDIC
#define tonum(c)	(isdigit(c) ? (c - '0') : ((c & 037) + 9))
#endif					/* !EBCDIC */

#if !EBCDIC
/*
 * getopc - get an opcode from infile, return the opcode number (via
 *  binary search of opcode table), and point id at the name of the opcode.
 */
int getopc(id)
char **id;
   {
   register char *s;
   register struct opentry *p;
   register int test;
   int low, high, cmp;
   extern char *getstr();

   s = getstr();
   if (s == NULL)
      return EOF;
   low = 0;
   high = NOPCODES;
   do {
      test = (low + high) / 2;
      p = &optable[test];
      if ((cmp = strcmp(p->op_name, s)) < 0)
         low = test + 1;
      else if (cmp > 0)
         high = test;
      else {
         *id = p->op_name;
         return (p->op_code);
         }
      } while (low < high);
   *id = s;
   return 0;
   }
#else					/* !EBCDIC */
/*
 * getopc - get an opcode from infile, return the opcode number (via
 * sequential search of opcode table) and point id at the name of the opcode.
 */
 
int getopc(id)
char **id;
   {
   register char *s;
   register struct opentry *p;
   register int test;
 
   s = getstr();
   if (s == NULL)
      return EOF;
   for(test=0;test < NOPCODES; test++) {
       p = &optable[test];
       if( strcmp(p->op_name, s) == 0) {
           *id = p->op_name;
           return (p->op_code);
       }
   }
   *id = s;
   return 0;
   }
#endif					/* !EBCDIC */

/*
 * getid - get an identifier from infile, put it in the identifier
 *  table, and return a pointer to it.
 */
char *getid()
   {
   register char *s;

   s = getstr();
   if (s == NULL)
      return NULL;
   return putident((int)strlen(s)+1);
   }

/*
 * getstr - get an identifier from infile and return a pointer to it.
 */
char *getstr()
   {
   register int c;
   register char *p;

#if MACINTOSH
#if MPW
   {
   static short cursorcount = CURSORINTERVAL;
   if (--cursorcount == 0) {
      RotateCursor(-32);
      cursorcount = CURSORINTERVAL;
      }
   }
#endif					/* MPW */
#endif					/* MACINTOSH */

   p = lsfree;
   while ((c = getc(infile)) == ' ' || c == '\t') ;
   if (c == EOF)
      return NULL;
   while (c != ' ' && c != '\t' && c != '\n' && c != ',' && c != EOF) {
      if (p >= lsend)
         quit("out of string space");
      *p++ = c;
      c = getc(infile);
      }
   *p = 0;
   nlflag = (c == '\n');
   return lsfree;
   }

/*
 * getrest - get the rest of the line from infile, put it in the identifier
 *  table, and return a pointer to it.
 */
char *getrest()
   {
   register int c;
   register char *p;

   p = lsfree;
   while ((c = getc(infile)) != '\n' && c != EOF) {
      if (p >= lsend)
         quit("out of string space");
      *p++ = c;
      }
   *p = 0;
   nlflag = (c == '\n');
   return putident((int)strlen(lsfree)+1);
   }

/*
 * getdec - get a decimal integer from infile, and return it.
 */
int getdec()
   {
   register int c, n;
   int sign = 1;

   n = 0;
   while ((c = getc(infile)) == ' ' || c == '\t') ;
   if (c == EOF)
      return 0;
   if (c == '-') {
      sign = -1;
      c = getc(infile);
      }
   while (c >= '0' && c <= '9') {
      n = n * 10 + (c - '0');
      c = getc(infile);
      }
   nlflag = (c == '\n');
   return n*sign;
   }

/*
 * getoct - get an octal number from infile, and return it.
 */
int getoct()
   {
   register int c, n;

   n = 0;
   while ((c = getc(infile)) == ' ' || c == '\t') ;
   if (c == EOF)
      return 0;
   while (c >= '0' && c <= '7') {
      n = (n << 3) | (c - '0');
      c = getc(infile);
      }
   nlflag = (c == '\n');
   return n;
   }

/*
 *  Get integer, but if it's too large for a long, put the string via cp
 *   and return -1.
 */
long getint(j,cp)
   int j;
   char **cp;
   {
   register int c;
   int over = 0;
   register char *p;
   double result = 0;
   long lresult = 0;
   double radix;

   if (lsfree + j > lsend)
      quit("out of string space");
   p = lsfree;
   
   while ((c = getc(infile)) >= '0' && c <= '9') {
      *p++ = c;
      result = result * 10 + (c - '0');
      lresult = lresult * 10 + (c - '0');
      if (result <= MinLong || result >= MaxLong) {
         over = 1;			/* flag overflow */
         result = 0;			/* reset to avoid fp exception */
         }
      }
   if (c == 'r' || c == 'R') {
      *p++ = c;
      radix = result;
      lresult = 0;
      result = 0;
      while (c = getc(infile)) {
         *p++ = c;
         if (isdigit(c) || isalpha(c))
            c = tonum(c);
         else
            break;
         result = result * radix + c;
         lresult = lresult * radix + c;
         if (result <= MinLong || result >= MaxLong) {
            over = 1;			/* flag overflow */
            result = 0;			/* reset to avoid fp exception */
            }
         }
      }
   nlflag = (c == '\n');
   if (!over)
      return lresult;			/* integer is small enough */
   else {				/* integer is too large */
      *p++ = 0;
      *cp = putident((int)(p - lsfree));/* convert integer to string */
      return -1;			/* indicate integer is too big */
      }
   }

/*
 * getreal - get an Icon real number from infile, and return it.
 */
double getreal()
   {
   double n;
   register int c, d, e;
   int esign;
   register char *s, *ep;
   char cbuf[128];

   s = cbuf;
   d = 0;
   while ((c = getc(infile)) == '0')
      ;
   while (c >= '0' && c <= '9') {
      *s++ = c;
      d++;
      c = getc(infile);
      }
   if (c == '.') {
      if (s == cbuf)
         *s++ = '0';
      *s++ = c;
      while ((c = getc(infile)) >= '0' && c <= '9')
         *s++ = c;
      }
   ep = s;
   if (c == 'e' || c == 'E') {
      *s++ = c;
      if ((c = getc(infile)) == '+' || c == '-') {
         esign = (c == '-');
         *s++ = c;
         c = getc(infile);
         }
      e = 0;
      while (c >= '0' && c <= '9') {
         e = e * 10 + c - '0';
         *s++ = c;
         c = getc(infile);
         }
      if (esign) e = -e;
      e += d - 1;
      if (abs(e) >= LogHuge)
         *ep = '\0';
      }
   *s = '\0';
   n = atof(cbuf);
   nlflag = (c == '\n');
   return n;
   }

/*
 * getlab - get a label ("L" followed by a number) from infile,
 *  and return the number.
 */

int getlab()
   {
   register int c;

   while ((c = getc(infile)) != 'L' && c != EOF && c != '\n') ;
   if (c == 'L')
      return getdec();
   nlflag = (c == '\n');
   return 0;
   }

/*
 * getstrlit - get a string literal from infile, as a string
 *  of octal bytes, and return it.
 */
char *getstrlit(l)
register int l;
   {
   register char *p;

   if (lsfree + l > lsend)
      quit("out of string space");
   p = lsfree;
   while (!nlflag && l--)
      *p++ = getoct();
   *p++ = 0;
   return putident((int)(p-lsfree));
   }

/*
 * newline - skip to next line.
 */
novalue newline()
   {
   register int c;

   if (!nlflag) {
      while ((c = getc(infile)) != '\n' && c != EOF) ;
      }
   nlflag = 0;
   }
