/* 
   Copyright 1994-2003 Free Software Foundation, Inc.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
   02111-1307, USA.  

   You may contact the author at:

   mailto::camille@bluegrass.net

   or by snail mail at:

   David Lindauer
   850 Washburn Ave Apt 99
   Louisville, KY 40222
*/
/* scanner
 */
/* Trigraphs implemented, won't work for token pasting though */
#include        <stdio.h>
#include				<ctype.h>
#include				<string.h>
#include       <float.h>
#include       <limits.h>
#include       <math.h>
#include				"lists.h"
#include        "expr.h"
#include        "c.h"
#include        "errors.h"
#include "utype.h"
#include "interp.h"

/* #define DEMO */

extern int prm_errfile;
extern char version[];
extern LIST *clist;
extern FILE *cppFile, *listFile, *inputFile;
extern int prm_cplusplus,prm_cmangle,prm_ansi;
extern int ifskip,elsetaken;
extern IFSTRUCT *ifs;
extern char *errfile;
extern int errlineno;
extern int phiused, prm_trigraph;

extern int currentfile ;
extern char *infile;
extern short            *lptr;          /* shared with preproc */
extern FILE            *inclfile[20];  /* shared with preproc */
extern char            *inclfname[20];  /* shared with preproc */
extern IFSTRUCT             *ifshold[70];
extern int             inclline[20];   /* shared with preproc */
extern int							inclcurrent[10] ;
extern int             incldepth;      /* shared with preproc */
extern int						prm_listfile;

int sym_charindex ;
int lineno;
int laststrlen;
short     inputline[4100], unalteredline[4100];
int             lastch;
enum e_sym      lastst;
char            lastid[101] = "";
char            laststr[MAX_STRLEN + 1] = "";
LLONG_TYPE      ival = 0;
long double     rval = 0.0;
char            *linstack[20];  /* stack for substitutions */
char            chstack[20];    /* place to save lastch */
int             lstackptr = 0;  /* substitution stack pointer */
int cantnewline = FALSE;
int incconst = FALSE;

int backupchar = -1;

int demolines;

static int phiputcpp,phiputlist,phiputerror;
static int commentlevel;
static int phifirst = FALSE ;
static ULLONG_TYPE llminus1 ;
void initsym(void)
{       lptr = inputline;
        inputline[0] = 0;
        lineno = 0; errlineno = 1;
				lastid[0] = 0;
				laststr[0] = 0;
				ival = 0;
				rval = 0.0;
				cantnewline=FALSE;
				incconst = FALSE;
				backupchar = -1;
				phiputcpp=phiputlist = phiputerror = FALSE;
            phifirst = TRUE ;
            llminus1= 0 ;
            llminus1--; // done at run-time so I don't have to compile twice
}

void lineToCpp(void)
/*
 * line has been preprocessed, dump it to a file
 */
{
		if (cppFile) {
			char buf[1000],*q=buf;
			short *p = inputline;
			*q = 0;
			if (!phiputcpp) {
				phiputcpp = TRUE;
				if (phiused)
					fputc('\x1f',cppFile);
            fprintf(cppFile,"/* LADsoft C compiler Version %s */\n\n",version);
			}
			while (*p) {
				int i;
				if (*q) {
					buf[0] = *q;
					i = 1;
				}
				else
					i = 0;
				i+=installphichar(*p++,buf,i);
				buf[i] = 0;
				q = buf;
				while (*q && (*(q+1) || ((*q &0xf0) != 0x90)))
					fputc(*q++,cppFile);
			}
		}				
}
/* Strips comments and also the newline char at the end of the line */
static void stripcomment (char *line)
{
   char *s = line, *e = s, instr = FALSE;
	while (*e) {
		if (!instr && *e == '/' && (!commentlevel || !prm_ansi || prm_cplusplus)) {
				if (*(e+1) == '*') {
					e++;
					commentlevel++;
				}
            else if (*(e+1) == '/' && !commentlevel) {
					*s++ = '\n';
					*s++ = 0;
					return;
				}
				else if (!commentlevel)
					*s++ = *e;
		}
		else if (!instr && commentlevel && *e == '*' && *(e+1) == '/') {
			commentlevel--;
			e++;
			if (commentlevel == 0) {
				*s++ = ' ';		/* Comments are whitespace */
			}
		}
		else if (!commentlevel) {
			if (instr) {
				if (*e == instr)
					instr = 0;
				else if (*e == '\\')
					*s++ = *e++;
			}
			else if (*e == '"')
				instr = '"';
			else if (*e == '\'')
				instr = '\'';
			*s++ = *e;
		}
    e++;
	}
	*s = 0;
}
static void stripcommentwide(short *line)
{
   int i, quote = 0 ;
   if (prm_ansi)
      return ;
      for (i=0; i < pstrlen(inputline); i++)
         
         if (quote) {
            if (quote == line[i])
               quote = 0 ;
            continue ;
         } else if (line[i] == '\'' || line[i] == '"')
            quote = line[i] ;
         else if (line[i] == '/' && line[i+1] == '/') {
            line[i] = ' ' ;
            line[i+1] = 0 ;
            break ;
         }
}
/* strip trigraphs */
void striptrigraph(short *buf)
{
	short *cp = buf;
	while (*cp) {
		if (*cp == '?' && *(cp+1) == '?') {
			cp +=2;
			switch (*cp++) {
				case '=':
					*buf++='#';
					break;
				case '(':
					*buf++='[';
					break;
				case '/':
					*buf++='\\';
					break;
				case ')':
					*buf++=']';
					break;
				case '\'':
					*buf++='^';
					break;
				case '<':
					*buf++='{';
					break;
				case '!':
					*buf++='|';
					break;
				case '>':
					*buf++='}';
					break;
				case '-':
					*buf++='~';
					break;
				default:
					cp-=2;
					break;
			}
		}
		else *buf++ = *cp++;
	}
	*buf = 0;
}
int     getline(int listflag)
/*
 * Read in a line, preprocess it, and dump it to the list and preproc files
 * Also strip comments and alter trigraphs
 */
{       int     rv,rvc,i,prepping,temp;

		char ibuf[4096],xbuf[4096],*xptr ;
      int *ptr = ibuf,dcrv;
		short *uptr;
		if (cantnewline) {
			return(0);
		}
repeatit:
		do {
				rv = FALSE;
				prepping = FALSE;
				rvc = 0;
        if( lineno > 0 && listflag && prm_listfile) {
					if (!phiputlist) {
						if (phiused) {
							fputc('\x1f',listFile);
						}
						phiputlist = TRUE;
					}
        }
        if( lineno > 0 && prm_errfile) {
					if (!phiputerror) {
						if (phiused) {
							fputc('\x1f',listFile);
						}
						phiputerror = TRUE;
					}
        }
				lferror();
add:
				while(rvc +131 < 4096 && !rv) {
           ++lineno;
#ifdef DEMO
					if (++demolines > 100)
						fatal("Demo restricted to 100 lines of input");
#endif
         rv = (philine(ibuf+rvc,4096-132-rvc,inputFile,phifirst) == NULL);
         phifirst = FALSE ;
					if (rv)
						break;
               stripcomment(ibuf+rvc);
					rvc = strlen(ibuf);
					if (ibuf[rvc-1] != '\n') {
						ibuf[rvc++] = '\n';
						ibuf[rvc] = 0;
					}
					rvc-=2;
               if (rvc < 0)
                  rvc = 0 ;
               while (rvc && ibuf[rvc]==' ')
						rvc--;
					if (ibuf[rvc] != '\\')
						break;
				}
				if (rvc)
					rv = FALSE;
        if( rv) {
								if (ifs)
									generror(ERR_PREPROCMATCH,0,0);
								if (commentlevel)
									generror(ERR_COMMENTMATCH,0,0);
								if (incldepth > 0) {
	                fclose(inputFile);
  	              inputFile = inclfile[--incldepth];
    	            lineno = inclline[incldepth];
									infile = inclfname[incldepth];
									currentfile = inclcurrent[incldepth] ;
									errlineno = lineno;
									errfile = infile;
									ifs = ifshold[incldepth];
									commentlevel = 0;
									popif();
                           browse_startfile(infile) ;
									goto repeatit;
								}
								currentfile = 0 ;
        }
        if( rv )
                return 1;
				lptr = inputline;
				ptr = ibuf;
				xptr = xbuf ;
				uptr = unalteredline ;
				while((temp = parsechar(&ptr)) != 0) {
					*lptr++ = temp;
					*xptr++ = temp ;
					*uptr++ = temp ;
				}
				*lptr = 0;
				*xptr = 0 ;
				*uptr = 0 ;
//            stripcomment(inputline);
				if (prm_trigraph)
					striptrigraph(inputline);
        lptr = inputline;
				while (iswhitespacechar(*lptr))
					lptr++;			
        if(lptr[0] == '#') {
          listflag = preprocess();
					prepping = TRUE;
				}
		} while (ifskip || prepping);
		rvc = strlen(ibuf) ;
      if (defcheck(inputline) == -10 &&  rvc + 131 < 4096) {
			if (ibuf[rvc-1] == '\n')
				ibuf[rvc-1] = ' ';
			goto add ;
		}
      stripcommentwide(inputline) ;
//      for (i=0; i < pstrlen(inputline); i++)
//         if (inputline[i] == '/' && inputline[i+1] == '/') {
//            inputline[i] = ' ' ;
//            inputline[i+1] = 0 ;
//            break ;
//         }
    if(prm_listfile) {
			if (!phiputlist) {
				if (phiused) {
					fputc('\x1f',listFile);
				}
            fprintf(listFile,"LADsoft C compiler Version %s - %s\n\n",version,clist->data);
				phiputlist = TRUE;
			}
			fprintf(listFile,"%5d: %s",lineno, xbuf);
    }
		lineToCpp();
    return 0;
}

/*
 *      getch - basic get character routine.
 */
int     getch(void)
{       while( (lastch = *lptr++) == '\0') {
                if( lstackptr > 0 ) {
                        lptr = linstack[--lstackptr];
                        lastch = chstack[lstackptr];
                        return lastch;
                        }
								if (cantnewline) {
									lptr--;
									return lastch = ' ';
								}
                if(getline(incldepth == 0))
                        return lastch = -1;
                }
        return lastch;
}
 
/*
 *      getid - get an identifier.
 *
 *      identifiers are any isidch conglomerate
 *      that doesn't start with a numeric character.
 *      this set INCLUDES keywords.
 */
void     getid()
{       register int    i;
        i = 0;
				if (prm_cmangle)
					lastid[i++] = '_';		/* Mangling */
				if (lastch == 'L') {
					lastid[i++] = 'L';
					getch();
					if (lastch == '\"') {
												getch();
												i=0;
												while (lastch != '\"' && lastch) {
													*(((short*)(laststr))+i++) = lastch;
													getch();
												}
												if ((lastch & 0x7f) != '\"')
        	                        generror(ERR_NEEDCHAR,'\"',0);
          	              else
            	                    getch();
													*(((short*)(laststr))+i) = 0;
												laststrlen = i;
												lastst = lsconst;
												return;
					}
				}
				while(issymchar(lastch)) {
					if (i < 100)
						i+=installphichar(lastch,lastid,i);
					getch();
        }
				if ((lastid[i-1] & 0xf0) == 0x90)
					lastid[i-1] = 0x90;
        lastid[i] = '\0';
        lastst = id;
}
 
/*
 *      getsch - get a character in a quoted string.
 *
 *      this routine handles all of the escape mechanisms
 *      for characters in strings and character constants.
 */
int     getsch(void)        /* return an in-quote character */
{       register int    i, j;
        if(lastch == '\n')
                return -1;
        if(incconst || lastch != '\\') {
                i = lastch;
                getch();
                return i;
                }
        getch();        /* get an escaped character */
        if(isdigit(lastch)) {
                for(i = 0,j=0;j < 3;++j) {
                        if(lastch <= '7' && lastch >= '0')
                                i = (i << 3) + lastch - '0';
                        else
                                break;
                        getch();
                        }
                return i;
                }
        i = lastch;
        getch();
        switch(i) {
                case '\n':
                        getch();
                        return getsch();
								case 'a':
												return '\a';
                case 'b':
                        return '\b';
                case 'f':
                        return '\f';
                case 'n':
                        return '\n';
                case 'r':
                        return '\r';
                case 'v':
                        return '\v';
								case 't':
												return '\t';
								case '\'':
												return '\'';
								case '\"':
												return '\"';
								case '\\':
												return '\\';
                        case '?':
                                    return '?' ;
								case 'x':
												{
													int n=0,count=0;
												  while (isxdigit(lastch)) {
														count++;
													  lastch-=0x30;
														if (lastch > 10) lastch -=7;
														if (lastch > 15) lastch -=32;
														n*=16;
														n+=lastch;
														getch();
													}
													if (count > 2)
														generror(ERR_CONSTTOOLARGE,0,0);
													return n;
												}
                default:
                        return i;
                }
}

int     radix36(char c)
{       if(isdigit(c))
                return c - '0';
        if(c >= 'a' && c <= 'z')
                return c - 'a' + 10;
        if(c >= 'A' && c <= 'Z')
                return c - 'A' + 10;
        return INT_MAX ;
}
 
/*
 *      getbase - get an integer in any base.
 */
void getbase(int b,char **ptr)
{       LLONG_TYPE    i ;
        int j;
        int errd = 0;
        i = 0;
        while((j=radix36(**ptr)) < b) {
               (*ptr) ++ ;
               if (i > (llminus1-j)/b)
                 if (!errd) {
                   generror(ERR_CONSTTOOLARGE,0,0);
                   errd++;
                 }
               i = i * b + j;
        }
        ival = i;
        lastst = iconst;
}
 
/*
 *      getfrac - get fraction part of a floating number.
 */
void getfrac(int radix, char **ptr)
{       long double  frmul;
        frmul = 1.0/radix ;
        while(radix36(**ptr) < radix) {
                rval += frmul * radix36(*(*ptr)++) ;
                frmul /= radix ;
                }
        lastst = rconst ;
}
 
/*
 *      getexp - get exponent part of floating number.
 *
 *      this algorithm is primative but usefull.  Floating
 *      exponents are limited to +/-255 but most hardware
 *      won't support more anyway.
 */
void getexp(int radix, char **ptr)
{
        int neg = FALSE ;
        if(**ptr == '-') {
                neg = TRUE ;
                (*ptr)++;
                }
        else {
								if (**ptr == '+')
									(*ptr)++;
				}
        getbase(10,ptr);
        if(ival > LDBL_MAX_10_EXP) {
                generror(ERR_FPCON,0,0);
                ival = 0 ;
        } ;
        if (neg)
           ival = -ival ;
        if (radix == 10)
           rval *= pow10l((long double)ival);
        else {
           rval *= powl(2.0,(long double)ival) ;
        }
        lastst = rconst;
}
 
/*
 *      getnum - get a number from input.
 *
 *      getnum handles all of the numeric input. it accepts
 *      decimal, octal, hexidecimal, and floating point numbers.
 */
void getnum(void)
{
   char buf[200], *ptr = buf ;
   int hasdot = FALSE ;
   int radix=10 ;
   int floatradix = 0 ;

   if (lastch == '0') {
      getch() ;
      if (lastch == 'x' || lastch == 'X') {
         getch() ;
         radix = 16 ;
      } else 
         radix = 8 ;
   }
   while (radix36(lastch) < radix) {
      *ptr++ = lastch ;
      getch() ;
   }
   if (lastch == '.') {
      if (radix == 8)
         radix = 10 ;
      *ptr++ = lastch ;
      getch() ;
      while(radix36(lastch) < radix) {
         *ptr++ = lastch ;
         getch() ;
      }
   }
   if ((lastch == 'e' || lastch == 'E') && radix != 16)
      radix = floatradix = 10 ;
   else if ((lastch == 'p' || lastch == 'P') && radix == 16)
      floatradix = 2 ;

   if (floatradix) {
      *ptr++ = lastch ;
      getch() ;
      if (lastch == '-' || lastch == '+') {
         *ptr++=lastch ;
         getch() ;
      }
      while (radix36(lastch) < 10) {
         *ptr++ = lastch ;
         getch() ;
      }
   }

   *ptr = 0 ; 
	ptr = buf;
   // at this point the next char is any qualifier after the number

   if (radix36(*ptr) < radix)
      getbase(radix,&ptr) ;
   else {
      ival = 0 ;
      lastst = iconst ;
   }
   if (*ptr == '.') {
      ptr++ ;
      rval = ival ;
      getfrac(radix,&ptr) ;
   }
   if (*ptr == 'e' || *ptr == 'E' || *ptr == 'p' || *ptr == 'P') {
      if (lastst != rconst) {
         rval = ival ;
      }
      ptr++ ;
      getexp(floatradix,&ptr) ;
   }
   if (lastst != rconst) {
      if (lastch == 'i') {
         if (!prm_ansi && *lptr == '6' && *(lptr +1) == '4') {
            getch() ;
            getch() ;
            getch() ;
            lastst = llconst ;
         }
      }
      else if (lastch == 'U' || lastch == 'u') {
			lastst = iuconst;
			getch();
			if (lastch == 'L' || lastch == 'l') {
            getch() ;
            if (lastch == 'L' || lastch == 'l') {
               lastst = lluconst;
               getch();
            } else
               lastst = luconst;
			}
		}
		else if (lastch == 'L' || lastch == 'l') {
         lastst = lconst;
			getch();
         if (lastch == 'L' || lastch == 'l') {
               getch();
            if (lastch == 'U' || lastch == 'u') {
               getch();
               lastst = lluconst;
            } else
               lastst = llconst ;
         }
         
         else if (lastch == 'U' || lastch == 'u') {
            lastst = iuconst;
				getch();
			}
		}
   } else {
									if (lastch == 'F' || lastch == 'f') {
											if (lastst != rconst) {
												rval = ival;
											}
											lastst = fconst;
											getch();
									}
									else if (lastch == 'L' || lastch == 'l') {
											if (lastst != rconst) {
												rval = ival;
											}
											lastst = lrconst;
											getch();
									}
   }
   if (isstartchar(lastch) || isdigit(lastch)) {
      generror(ERR_INVCONST,0,0) ;
      while ((isstartchar(lastch) || isdigit(lastch))  && lastch != eof)
         getch() ;
   }
}
 
int getsym2(void) 
/*
 * translate character sequences to appropriate token names
 */
{       register int    i, j,k;
				int size;
swlp:
						 switch(lastch) {
                case '+':
                        getch();
                        if(lastch == '+') {
                                getch();
                                lastst = autoinc;
                                }
                        else if(lastch == '=') {
                                getch();
                                lastst = asplus;
                                }
                        else lastst = plus;
                        break;
                case '-':
                        getch();
                        if(lastch == '-') {
                                getch();
                                lastst = autodec;
                                }
                        else if(lastch == '=') {
                                getch();
                                lastst = asminus;
                                }
                        else if(lastch == '>') {
                                getch();
#ifdef CPLUSPLUS
																if (prm_cplusplus && lastch == '*') {
																	getch();
																	lastst = pointstar;
																}
																else
#endif
                                	lastst = pointsto;
                                }
                        else lastst = minus;
                        break;
                case '*':
                        getch();
                        if(lastch == '=') {
                                getch();
                                lastst = astimes;
                                }
                        else lastst = star;
                        break;
                case '/':
                        getch();
                        if(lastch == '=') {
                                getch();
                                lastst = asdivide;
                                }
                        else lastst = divide;
                        break;
                case '^':
                        getch();
                        if(lastch == '=') {
                                getch();
                                lastst = asxor;
                                }
                        else lastst = uparrow;
                        break;
                case ';':
                        getch();
                        lastst = semicolon;
                        break;
                case ':':
                        getch();
#ifdef CPLUSPLUS
												if (prm_cplusplus && lastch == ':') {
													getch();
													if (lastch == '*') {
														getch();
														lastst = classselstar;
													} else
														lastst = classsel;
												}
												else
#endif
                           if (lastch == '>') {
                              getch() ;
                              lastst = closebr ;
                           } else
                             lastst = colon;
                        break;
                case '=':
                        getch();
                        if(lastch == '=') {
                                getch();
                                lastst = eq;
                                }
                        else lastst = assign;
                        break;
                case '>':
                        getch();
                        if(lastch == '=') {
                                getch();
                                lastst = geq;
                                }
                        else if(lastch == '>') {
                                getch();
                                if(lastch == '=') {
                                        getch();
                                        lastst = asrshift;
                                        }
                                else lastst = rshift;
                                }
                        else lastst = gt;
                        break;
                case '<':
                        getch();
												if (incconst) {
                      	  for(i = 0;i < MAX_STRLEN;++i) {
                                if(lastch == '>')
                                        break;
                                if((j = getsch()) == -1)
                                        break;
                                else
                                        laststr[i] = j;
	                              }
  	                      laststr[i] = 0;
    	                    lastst = sconst;
													laststrlen = i;
                           if(lastch != '>')
        	                        generror(ERR_NEEDCHAR,'>',0);
          	              else
            	                    getch();
												} else
                        	if(lastch == '=') {
                                getch();
                                lastst = leq;
                                }
                        	else if(lastch == '<') {
                                getch();
                                if(lastch == '=') {
                                        getch();
                                        lastst = aslshift;
                                        }
                                else lastst = lshift;
                                }
                           else if (lastch == ':') {
                              getch() ;
                              lastst = openbr ;
                           } else if (lastch == '%') {
                              getch() ;
                              lastst = begin ;
                           } else
                              lastst = lt;
                        break;
                case '\'':
                        getch();
												j = 0;
												k = 0;
												ival = 0;
												for (i=0, j=0, k=0; i < 4; i++,k+=8) {
													if (lastch == '\'')
														break;
                        	j = getsch();        /* get a string char */
													ival += j << k;
												}
												if (i == 0) {
														generror(ERR_CHAR4CHAR,0,0);	
			                      getch();
												}
                        else if(lastch != '\'') {
																while (*lptr && *lptr != '\'')
																	lptr++;
																if (*lptr)
																	lptr++;
                                generror(ERR_CHAR4CHAR,0,0);
												}
                        else
                                getch();
                        lastst = cconst;
                        break;
								case 0x2d4:
												getch();
												i=0;
												while (lastch != '\"' && lastch)
													i=installphichar(lastch,laststr,i);
												if ((lastch & 0x7f) != '\"')
        	                        generror(ERR_NEEDCHAR,'\"',0);
          	              else
            	                    getch();
												laststrlen = i;
												size = strlen(laststr);
												lastst = sconst;
												break;
                case '\"':
					 							size = 0;
												while (lastch == '\"') {
                        	getch();
                        	for(i = size;i < MAX_STRLEN;++i) {
                                if(lastch == '\"')
                                        break;
                                if((j = getsch()) == -1)
                                        break;
                                else
                                        laststr[i] = j;
                                }
	                        laststr[i] = 0;
													laststrlen = size = i;
    	                    lastst = sconst;
      	                  if(lastch != '\"')
        	                        generror(ERR_NEEDCHAR,'\"',0);
          	              else
            	                    getch();
												}
                        break;
                case '!':
                        getch();
                        if(lastch == '=') {
                                getch();
                                lastst = neq;
                                }
                        else lastst = not;
                        break;
                case '%':
                        getch();
                        if(lastch == '=') {
                                getch();
                                lastst = asmodop;
                                }
                        else if (lastch == '>') {
                              getch() ;
                              lastst = end ;
                        } else if (lastch == ':') {
                           getch() ;
                           lastst = hash ;      
                        } else lastst = modop;
                        break;
                case '~':
                        getch();
                        lastst = compl;
                        break;
                case '.':
												if (isdigit(*lptr))
													getnum();
												else {	
	                        getch();
#ifdef CPLUSPLUS
													if (prm_cplusplus && lastch == '*') {
														getch();
														lastst = dotstar;
													}
													else 
#endif
													  if (lastch == '.') {
													  	getch();
															if (lastch == '.') {
																getch();
																lastst = ellipse;
																break;
															}
															else {
          	        	      	  generror(ERR_ILLCHAR,lastch,0);
															}
														} else
                        			lastst = dot;
												}
                        break;
                case ',':
                        getch();
                        lastst = comma;
                        break;
                case '&':
                        getch();
                        if( lastch == '&') {
                                lastst = land;
                                getch();
                                }
                        else if( lastch == '=') {
                                lastst = asand;
                                getch();
                                }
                        else
                                lastst = and;
                        break;
                case '|':
                        getch();
                        if(lastch == '|') {
                                lastst = lor;
                                getch();
                                }
                        else if( lastch == '=') {
                                lastst = asor;
                                getch();
                                }
                        else
                                lastst = or;
                        break;
                case '(':
                        getch();
                        lastst = openpa;
                        break;
                case ')':
                        getch();
                        lastst = closepa;
                        break;
                case '[':
                        getch();
                        lastst = openbr;
                        break;
                case ']':
                        getch();
                        lastst = closebr;
                        break;
                case '{':
                        getch();
                        lastst = begin;
                        break;
                case '}':
                        getch();
                        lastst = end;
                        break;
                case '?':
                        getch();
                        lastst = hook;
                        break;
                case '#':
                        getch() ;
                        lastst = hash ;
                        break ;
                case SYM_ASSIGN :
                        getch() ;
                        lastst = assign ;
                        break ;
                case SYM_SHIFTASSIGN :
                        getch() ;
                        lastst = lassign ;
                        break ;
                case '@' :          /* @= is same as above */
                        if (!prm_ansi) {
                           getch() ;
                           if (lastch == '=') {
                              getch() ;
                              lastst = lassign ;
                              break ; 
                           } else
                              lastch = *--lptr ;
                        }
                        // FALL THROUGH
                default:
												if (iscommentchar(lastch)) {
													do {
														getch();
													} while (!iscommentchar(lastch) && lastch != '\n');
												}
												else
                        	generror(ERR_ILLCHAR,lastch,0);
                        getch();
												return 1;
                }
	return 0;
}
/*
 *      getsym - get next symbol from input stream.
 *
 *      getsym is the basic lexical analyzer.  It builds
 *      basic tokens out of the characters on the input
 *      stream and sets the following global variables:
 *
 *      lastch:         A look behind buffer.
 *      lastst:         type of last symbol read.
 *      laststr:        last string constant read.
 *      lastid:         last identifier read.
 *      ival:           last integer constant read.
 *      rval:           last real constant read.
 *
 *      getsym should be called for all your input needs...
 */
void     getsym(void)
{  
         sym_charindex = lptr - inputline ;
         errlineno = lineno ;
				if (backupchar != -1) {
					lastst = backupchar;
					backupchar = -1;
					return;
				}
				if (cantnewline && !*lptr) {
					lastst = eol;
					return;
				}
        while(iswhitespacechar(lastch)) {
          getch();
					if (cantnewline && !*lptr) {
						lastst = eol;
						return;
					}
				}
        if( lastch == -1)
                lastst = eof;
        else if(isdigit(lastch))
                getnum();
        else if(isstartchar(lastch)) {
                getid();
                searchkw();
				}
        else getsym2();
}
/*
 * when we need specific punctuation, call one of these routines
 */
int needpunc(enum e_sym p, int *skimlist)
{       if( lastst == p) {
                getsym();
								return(TRUE);
				}
        else
                expecttoken(p,skimlist);
	return(FALSE);
}
int needpuncexp(enum e_sym p, int *skimlist)
{       if( lastst == p) {
                getsym();
								return(TRUE);
				}
        else
                expecttokenexp(p,skimlist);
	return(FALSE);
}
/*
 * having to back up a character is rare, but sometimes...
 */
void backup(int st)
{
  backupchar = lastst;
  lastst = st;
}