#include        <stdio.h>
#include        "c.h"
#include        "expr.h"
#include        "gen.h"
#include        "cglbdec.h"

/*
 *68000 C compiler
 *
 *Copyright 1984, 1985, 1986 Matthew Brandt.
 *  all commercial rights reserved.
 *
 *This compiler is intended as an instructive tool for personal use. Any
 *use for profit without the written consent of the author is prohibited.
 *
 *This compiler may be distributed freely for non-commercial use as long
 *as this notice stays intact. Please forward any enhancements or questions
 *to:
 *
 *Matthew Brandt
 *Box 920337
 *Norcross, Ga 30092
 */

static int      errno[80];
static int      numerrs;
static char     inline[132];
char		curfile[41];
int             total_errors = 0;
extern char     *lptr;          /* shared with preproc */
extern FILE     *inclfile[10];  /* shared with preproc */
extern int      inclline[10];   /* shared with preproc */
extern int      incldepth;      /* shared with preproc */
char            *linstack[20];  /* stack for substitutions */
char            chstack[20];    /* place to save lastch */
int             lstackptr = 0;  /* substitution stack pointer */
extern SYM	*search();
char 		*fgets();

#define MAXERR 28
static char *errmsg[] =
 {"Syntax",
  "Bad Character",
  "Floating Point Error",
  "Bad Type",
  "Undefined Symbol",
  "Duplicate Symbol",
  "Punctuation",
  "Identifier expected",
  "Not initialized",
  "Incomplete",
  "Bad initialization",
  "Init size",
  "Bad Class statement",
  "Bad Block",
  "No Pointer",
  "No Fuction",
  "No Member",
  "L-Value expected",
  "Dereferencing error",
  "Mismatch",
  "Expression expected",
  "While expected",
  "No case",
  "Duplicate case",
  "Label error",
  "Preprocessor error",
  "Include file error",
  "Can't open",
  "Define error"};

int     isalnum(c)
char    c;
{       return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
                (c >= '0' && c <= '9');
}

int     isidch(c)
char    c;
{       return isalnum(c) || c == '_' || c == '$';
}

int     isspace(c)
char    c;
{       return c == ' ' || c == '\t' || c == '\n';
}

int     isdigit(c)
char    c;
{       return (c >= '0' && c <= '9');
}

initsym()
{       lptr = inline;
        inline[0] = 0;
        numerrs = 0;
        total_errors = 0;
        lineno = 0;
}

int     getline(listflag)
int     listflag;
{
        int	err, i;
	char    rv, *s;

	if ( Options.List && listflag && lineno > 0)
          fprintf(list,"%6d\t%s",lineno,inline);
	if ( numerrs )
	  {
	    if ( !(Options.List && listflag && lineno > 0) )
	       printf( "%6d\t%s\n", lineno, inline);
            for ( i = 0; numerrs--; ++i )
	      {
		err = errno[i];
		if ( err <= MAXERR )
		  s = (char *) " *** error %d %s\n";
		else
		  s = (char *) " *** error %d\n";
		printf( s, err, errmsg[err]);
		if ( Options.List && listflag && lineno > 0)
                   fprintf(list, s, err, errmsg[err]);
	      }
	   }  
        numerrs = 0;
        ++lineno;
        (void) fgets(inline,131,input);
	rv = feof( input );
        if( rv && incldepth > 0 ) {
                fclose(input);
                input = inclfile[--incldepth];
                lineno = inclline[incldepth];
                return getline(0);
                }
        if( rv )
                return 1;
        lptr = inline;
        if(inline[0] == '#')
                return preprocess();
        return 0;
}

/*
 *      getch - basic get character routine.
 */
int     getch()
{       while( (lastch = *lptr++) == '\0') {
                if( lstackptr > 0 ) {
                        lptr = linstack[--lstackptr];
                        lastch = chstack[lstackptr];
                        return lastch;
                        }
                if(getline(incldepth == 0))
                        return lastch = -1;
                }
        return lastch;
}
 
/*
 *      error - print error information
 */
error(n)
int     n;
{       errno[numerrs++] = n;
        ++total_errors;
}

/*
 *      getid - get an identifier.
 *
 *      identifiers are any isidch conglomerate
 *      that doesn't start with a numeric character.
 *      this set INCLUDES keywords.
 */
enum e_sym     getid()
{       register int    i;
        i = 0;
        while(isidch(lastch)) {
                if(i < 19)
                        lastid[i++] = lastch;
                getch();
                }
        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()        /* return an in-quote character */
{       register int    i, j;
        if(lastch == '\n')
                return -1;
        if(lastch != '\\') {
                i = lastch;
                getch();
                return i;
                }
        getch();        /* get an escaped character */
        if(isdigit(lastch)) {
                i = 0;
                for(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 'b':
                        return '\b';
                case 'f':
                        return '\f';
                case 'n':
                        return '\n';
                case 'r':
                        return '\r';
		case 't':
			return '\t';
                default:
                        return i;
                }
}

int     radix36(c)
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 -1;
}
 
/*
 *      getbase - get an integer in any base.
 */
getbase(b)
char b;
{       register long    i, j;
        i = 0;
        while(isalnum(lastch)) {
                if((j = radix36(lastch)) < b) {
                        i = i * b + j;
                        getch();
                        }
                else break;
                }
        ival = i;
        lastst = iconst;
}
 
/*
 *      getfrac - get fraction part of a floating number.
 */
getfrac()
{       double  frmul;
        frmul = 0.1;
        while(isdigit(lastch)) {
                rval += frmul * (lastch - '0');
                getch();
                frmul *= 0.1;
                }
}
 
/*
 *      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.
 */
getexp()
{       double  expo, exmul;
        expo = 1.0;
        if(lastst != rconst)
                rval = ival;
        if(lastch == '-') {
                exmul = 0.1;
                getch();
                }
        else
                exmul = 10.0;
        getbase(10);
        if(ival > 255)
                error(ERR_FPCON);
        else
                while(ival--)
                        expo *= exmul;
        rval *= expo;
}
 
/*
 *      getnum - get a number from input.
 *
 *      getnum handles all of the numeric input. it accepts
 *      decimal, octal, hexidecimal, and floating point numbers.
 */
getnum()
{
        if(lastch == '0') {
                getch();
                if(lastch == 'x' || lastch == 'X') {
                        getch();
                        getbase(16);
                        }
                else getbase(8);
                }
        else    {
                getbase(10);
                if(lastch == '.') {
                        getch();
                        rval = ival;    /* float the integer part */
                        getfrac();      /* add the fractional part */
                        lastst = rconst;
                        }
                if(lastch == 'e' || lastch == 'E') {
                        getch();
                        getexp();       /* get the exponent */
                        }
                }
	if ( lastst == iconst && ( lastch == 'l' || lastch == 'L' ))
	  {
		getch();
		/* Should also hame "lastst = iconst;" */
	  }
}
 
/*
 *      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()
{       register int    i, j;
        SYM             *sp;
restart:        /* we come back here after comments */
        while(isspace(lastch))
                getch();
        if( lastch == -1)
                lastst = eof;
        else if(isdigit(lastch))
                getnum();
        else if(isidch(lastch)) {
                getid();
                if( (sp = search(lastid,defsyms.head)) != 0 ) {
                        linstack[lstackptr] = lptr;
                        chstack[lstackptr++] = lastch;
                        lptr = sp->value.s;
                        getch();
                        goto restart;
                        }
                }
        else 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();
                                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 if(lastch == '*') {
                                getch();
                                for(;;) {
                                        if(lastch == '*') {
                                                getch();
                                                if(lastch == '/') {
                                                        getch();
                                                        goto restart;
                                                        }
                                                }
                                        else
                                                getch();
                                        }
                                }
                        else lastst = divide;
                        break;
                case '^':
                        getch();
                        lastst = uparrow;
                        break;
                case ';':
                        getch();
                        lastst = semicolon;
                        break;
                case ':':
                        getch();
                        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(lastch == '=') {
                                getch();
                                lastst = leq;
                                }
                        else if(lastch == '<') {
                                getch();
                                if(lastch == '=') {
                                        getch();
                                        lastst = aslshift;
                                        }
                                else lastst = lshift;
                                }
                        else lastst = lt;
                        break;
                case '\'':
                        getch();
                        ival = getsch();        /* get a string char */
                        if(lastch != '\'')
                                error(ERR_SYNTAX);
                        else
                                getch();
                        lastst = cconst;
                        break;
                case '\"':
                        getch();
                        for(i = 0;i < MAX_STRLEN;++i) {
                                if(lastch == '\"')
                                        break;
                                if((j = getsch()) == -1)
                                        break;
                                else
                                        laststr[i] = j;
                                }
                        laststr[i] = 0;
                        lastst = sconst;
                        if(lastch != '\"')
                                error(ERR_SYNTAX);
                        else
                                getch();
                        break;
                case '!':
                        getch();
                        if(lastch == '=') {
                                getch();
                                lastst = neq;
                                }
                        else lastst = not;
                        break;
                case '%':
                        getch();
                        if(lastch == '=') {
                                getch();
                                lastst = asmodop;
                                }
                        else lastst = modop;
                        break;
                case '~':
                        getch();
                        lastst = compl;
                        break;
                case '.':
                        getch();
                        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;
                default:
                        getch();
                        error(ERR_ILLCHAR);
                        goto restart;   /* get a real token */
                }
        if(lastst == id)
                searchkw();
}

needpunc(p)
enum e_sym      p;
{       if( lastst == p)
                getsym();
        else
                error(ERR_PUNCT);
}

