/* jmc JMCN:@<BIT1.PRB.DCa1>GANADO.SNA.SVCS start 07/07/86  */
/* driver module snotc.c */
/* change this  define statement to */
/* #define VC 1 for a PC with MSVC++  */
#ifndef  VC 
#define VC 0
#define getche()  getc(stdin)
#endif
#if VC == 1
#include <conio.h>
#define getche() _getche()
#endif

#include <stdio.h>
#include <setjmp.h>
#include <math.h>
#include <ctype.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#define isnumeric(x)  (x > 44 && x < 58) 
#define zout(x) memset(&x,'\0',sizeof(x) )
#define spcout(x) memset(&x,'\0',sizeof(x) ); memset(&x,' ',sizeof(x) - 1) )
#define iswhite(x) ( x == ' ' || x == '\t' )
#define isdelim(x) ( strchr(" !;,+-<>'/*%^=()", x) || x == 9 || x == '\r' || x == 0) 
#define NUM_FUNC        100
#define NUM_GLOBAL_VARS 100
#define NUM_LOCAL_VARS  200
#define NUM_BLOCK       100
#define ID_LEN          31
#define FUNC_CALLS      31
#define NUM_PARAMS      31
#define PROG_SIZE       10000
#define LOOP_NEST       31
enum token_types {DELIMITER, IDENTIFIER, NUMBER, KEYWORD,
                TEMP, STRING, BLOCK};
/* additional C keyword tokens go in here, exit is not defined for example */

enum tokens {ARG, CHAR, INT, IF, ELSE, FOR, DO, WHILE,
             SWITCH, RETURN, EOL, FINISHED, END};

/* add additional double operators here (such as ->) */

enum double_operators {LT=1, LE, GT, GE, EQ, NE};

/* NOTE: no support for ternary ? : */

/* These are the constants used to call syntax_err() when
   a syntax error occurs.
   GENERIC is a generic error message used 
 
*/
enum error_message
     {GENERIC, UNBALANCED_PARENS, NO_EXP, EQUALS_EXPECTED,
      NOT_VAR, PARAM_ERR, SEMI_EXPECTED,
      UNBALANCED_BRACES, FUNC_UNDEF, TYPE_EXPECTED,
      NEST_FUNC, RET_NOCALL, PAREN_EXPECTED,
      WHILE_EXPECTED, QUOTE_EXPECTED, NOT_TEMP,
      TOO_MANY_LVARS, DIV_BY_ZERO};

char *prog;    /* current location in source code */
char *p_buf;   /* start of program stream */
jmp_buf e_buf; /* pointers for longjmp() from setenv() */

struct intern_func_type {
  char f_name[30]; 	/* function name */
  int (*p)();   	/* pointer to any function */
};

static struct intern_func_type  intern_func[5]; 

struct var_type {
  char var_name[ID_LEN];
  int v_type;
  int value;
}  global_vars[NUM_GLOBAL_VARS];

		/* this makes a stack */

struct var_type local_var_stack[NUM_LOCAL_VARS];

struct func_type {
  char func_name[ID_LEN];
  int ret_type; 
  char *loc;  /* location of entry point in file */
} func_table[NUM_FUNC];

int call_stack[NUM_FUNC];

struct commands { /* keyword lookup table */
  char command[20];
  char tok;
} table[] = {     	/* Commands must be entered lowercase */
  "if", IF, 		/* in this table. */
  "else", ELSE,
  "for", FOR,
  "do", DO,
  "while", WHILE,
  "char", CHAR,
  "int", INT,
  "return", RETURN,
  "end", END,
  "", END  /* mark end of table */
};

char token[80];
char token_type, tok;

int functos;  		/* idx  top of function call stack */
int func_index; 	/* idx  function table */
int gvar_index; 	/* idx  global variable table */
int lvartos; 		/* idx  local variable stack */

int ret_value; /* function return value */

/* f(x) protos */
static int getnum(void);
static int call_puts(void);
static int call_putch(void);
static int print(void);
static int call_getche(void);
int internal_func(char *s);
void prescan(void);
void decl_global(void);
void decl_local(void);
void call(void);
void putback(void);
void decl_local(void);
void local_push(struct var_type i);
void eval_exp(int *value), syntax_err(int error);
void exec_if(void);
void find_eob(void);
void exec_for(void);
void get_params(void);
void get_args(void);
void exec_while(void);
int look_up(char *value);
void func_push(int i);
void exec_do(void);
void assign_var(char *var_name, int value);
int load_program(char *p, char *fname);
int find_var(char *s);
void init_Ifunc(void);
void eval_exp0(int *value);
void eval_exp(int *value);
void eval_exp1(int *value);
void eval_exp2(int *value);
void eval_exp3(int *value);
void eval_exp4(int *value);
void eval_exp5(int *value);
void atom(int *value);
void interpret_block(void);
void func_ret(void);
int func_pop(void);
int is_var(char *s);
int get_token(void);
char *find_func(char *name);
/* end prototypes */

void main(int argc, char *argv[] ) {
	
  if(argc != 2) {
    printf("Usage: \n \t snotc <filename>\n");
    exit(1);
  }
		  /* allocate memory for the program */
  if((p_buf = (char *) malloc(PROG_SIZE))==NULL) {
    printf("Allocation failure\n");
    exit(EXIT_FAILURE);
  }
  init_Ifunc();
  /* load the program to execute */
  if(!load_program(p_buf, argv[1])) exit(1);
  if(setjmp(e_buf)) exit(1); /* initialize long jump buffer */

  gvar_index = 0;  /* initialize global variable index */

  /* set program pointer to start of program buffer */
  prog = p_buf;
  prescan(); 			/* find the location of all functions
                			and global variables in the program */
  lvartos = 0;     		/* initialize local variable stack index */
  functos = 0;     		/* initialize the CALL stack index */
  prog = find_func("main"); 	/* find program starting point */

  if(!prog) { 			/* incorrect or missing main() function in program */
    printf("main() not found.\n");
    exit(1);
  }

  prog--; 			/* back up to opening ( */
  strcpy(token, "main");
  call(); 			/* call main() to start interpreting */
  return;
}

/* Interpret a single statement or block of code. When
   interpret_block() returns the end of main() has been encountered.
*/

int load_program(char *p, char *fname){  /* load */
  FILE *fp;
  int i=0;
  if((fp=fopen(fname, "rb"))==NULL) 
  	return 0;
  i = 0;
  do {
    *p = getc(fp);
    p++; i++;
  } while(!feof(fp) && i<PROG_SIZE);

  if(*(p-2) == 0x1a) {
  	*(p-2) = '\0'; /* null terminate the program */
  }
  else {
  	*(p-1) = '\0';
  }
  fclose(fp);
  return 1;
}

/* get all functions,  store global variables. */
void prescan(void){
  char *p, *tp;
  char temp[32];
  int datatype; 
  int brace = 0;  	/* When 0,
                     		current source position is outside
                     		of any function. */
  p = prog;
  func_index = 0;
  do {
    	while(brace) {  /* bypass code inside functions */
      		get_token();
      		if(*token == '{') 
      			brace++;
      		if(*token == '}') 
      			brace--;
    	}
    	tp = prog; 		/* save current position */
    	get_token();
    				/* global var type or function return type */
    	if(tok==CHAR || tok==INT) { 
      		datatype = tok; /* save data type */
      		get_token();
      		if(token_type == IDENTIFIER) {
        		strcpy(temp, token);
        	get_token();
        	if(*token != '(') { 	/* global  */
          	prog = tp; 		/* goto start of decl */
          	decl_global();
        }
        else if(*token == '(') {  /* assume a function */
          	func_table[func_index].loc = prog;
          	func_table[func_index].ret_type = datatype;
          	strcpy(func_table[func_index].func_name, temp);
          	func_index++;
          	while(*prog != ')') prog++;
          		prog++;
          /* prog is opening curly brace of function */
        }
        else putback();
      }
    }
    else if(*token == '{') 
    		brace++;
  } while(tok != FINISHED);
  prog = p;
}

/* Return the entry to specified function.*/
char *find_func(char *name){
  register int i;
  for(i=0; i < func_index; i++){
    	if(!strcmp(name, func_table[i].func_name))
      		return func_table[i].loc;
  }
  return NULL;
 }

void decl_global(void){  /*set global */
  int vartype;
  get_token();  	/* get type */
  vartype = tok; 	/* save var type */

  do { 				/* process comma-separated list */
    	global_vars[gvar_index].v_type = vartype;
    	global_vars[gvar_index].value = 0;  /* init to 0 */
    	get_token();  		/* get name */
    	strcpy(global_vars[gvar_index].var_name, token);
    	get_token();
    	gvar_index++;
  } while(*token == ',');
  if(*token != ';') 
  	syntax_err(SEMI_EXPECTED);
}


void call(void)
{
  char *loc, *temp;
  int lvartemp;
  loc = find_func(token); 	/* find  function */
  if(loc == NULL)
    	syntax_err(FUNC_UNDEF); /* function not defined */
  else {
    	lvartemp = lvartos;  	/* save local variable stack idx */
    	get_args();  		/* get function arguments */
    	temp = prog; 		/* save return location */
    	func_push(lvartemp);  	/* save local var stack index */
    	prog = loc;  		/* reset prog to top of function */
    	get_params(); 		/* load the function's parameters with
                     			the values of the arguments */
    	interpret_block(); 	/* interpret the function */
    	prog = temp; 		/* reset the program pointer */
    	lvartos = func_pop(); 	/* reset the local var stack */
  }
}

/* Push the arguments to a function onto the local variable stack. */
void get_args(void){
  int value, count, temp[NUM_PARAMS];
  struct var_type i;
  count = 0;
  get_token();
  if(*token != '(') 
  	syntax_err(PAREN_EXPECTED);
  do {		 /* process csv */
    	eval_exp(&value);
    	temp[count] = value;  /* save temp */
    	get_token();
    	count++;
  }while(*token == ',');
  count--;
  for(; count>=0; count--) {               /* push local_var_stack in reverse order */
    	i.value = temp[count];
    	i.v_type = ARG;
    	local_push(i);
  }
}

		/* find & store function parameters. */
void get_params(void){
  struct var_type *p;
  int i;
  i = lvartos-1;
  do { 			/* look thru csv of parameters */
    	get_token();
    	p = &local_var_stack[i];
        if(*token != ')' ) {
      		if(tok != INT && tok != CHAR)
        		syntax_err(TYPE_EXPECTED);
      		p->v_type = token_type;
      		get_token();
      /* connect  parm with argument on local var stack already */
      strcpy(p->var_name, token);
      get_token();
      i--;
    }
    else break;
  } while(*token == ',');
  if(*token != ')') syntax_err(PAREN_EXPECTED);
}

void func_ret(void){          		/* function Return  */
  int value;
  value = 0;
  eval_exp(&value);			/* get return value*/
  ret_value = value;
}


void local_push(struct var_type i){	/* Push  local var */
  if(lvartos > NUM_LOCAL_VARS)
    	syntax_err(TOO_MANY_LVARS);
  local_var_stack[lvartos] = i;
  lvartos++;
}
				

void func_push(int i){  		/* Push idx local function stack. */
  if(functos>NUM_FUNC)
   	syntax_err(NEST_FUNC);
  call_stack[functos] = i;
  functos++;
}
void assign_var(char *var_name, int value){ /* Assign a value to a variable. */
  register int i;
  for(i=lvartos-1; i >= call_stack[functos-1]; i--)  {   /*  local variable ? */
    	if(!strcmp(local_var_stack[i].var_name, var_name)) {
      		local_var_stack[i].value = value;
      		return;
    }
  }
  if(i < call_stack[functos-1]){     	/* use global var table */
    	for(i=0; i < NUM_GLOBAL_VARS; i++){
      		if(!strcmp(global_vars[i].var_name, var_name)) {
        		global_vars[i].value = value;
        		return;
      		}
      	}
  }
  syntax_err(NOT_VAR); 		/* variable not defined oops */
}

int find_var(char *s){		/* value of var */
  register int i; 
  for(i=lvartos-1; i >= call_stack[functos-1]; i--){  /* local? */
    	if(!strcmp(local_var_stack[i].var_name, token))
      		return local_var_stack[i].value;
  }
  for(i=0; i < NUM_GLOBAL_VARS; i++){             /* global */
    	if(!strcmp(global_vars[i].var_name, s))
      		return global_vars[i].value;
  }
  syntax_err(NOT_VAR); 				/* oops  not found */
  return -1; 
}

		/* if a variable, return 1 else 0*/
int is_var(char *s){
  register int i;
  for(i=lvartos-1; i >= call_stack[functos-1]; i--){  /* local ? */
    	if(!strcmp(local_var_stack[i].var_name, token))
      		return 1;
  }
  for(i=0; i < NUM_GLOBAL_VARS; i++){		/* global */
    	if(!strcmp(global_vars[i].var_name, s))
      		return 1;
  }
  return 0;
}

/* Execute an if statement. */
void exec_if(void)
{
  int cond;

  eval_exp(&cond); /* get if expression */

  if(cond) { /* is true so process target of IF */
    interpret_block();
  }
  else { 		/* otherwise skip around IF block and
            			process the ELSE, if present */
    find_eob(); 	/* find start of next line */
    get_token();

    if(tok != ELSE) {
      putback();  	/* goback to start of token if no ELSE */
      return;
    }
    interpret_block();
  }
}

void exec_while(void){
  int cond;
  char *temp;
  putback();
  temp = prog;  	/* save location of top of while loop */
  get_token();
  eval_exp(&cond);  		/*  check loop control */
  if(cond) 
  	interpret_block();  	/* run it */
  else {  		/* jump over loop*/
    	find_eob();
    	return;
  }
  prog = temp;  /* loop back to top */
}


void exec_do(void){
  int cond;
  char *temp;
  putback();
  temp = prog;  /* save location of top of do loop */
  get_token(); /* get start of loop */
  interpret_block(); /* interpret loop */
  get_token();
  if(tok != WHILE) syntax_err(WHILE_EXPECTED);
  eval_exp(&cond); /* check the loop condition */
  if(cond) prog = temp; /* if true loop; otherwise,
                           continue on */
}

void find_eob(void){
  int brace;
  get_token();
  brace = 1;
  do {
    	get_token();
    	if(*token == '{') 
    		brace++;
    	else if(*token == '}') 
    		brace--;
  } while(brace);
}

void exec_for(void){
  int cond;
  char *temp;
  char *temp2;
  int brace ;
  get_token();
  eval_exp(&cond);  		/* initialization expression */
  if(*token != ';') syntax_err(SEMI_EXPECTED);
  prog++; /* get past the ; */
  temp = prog;
  while (1){
    eval_exp(&cond);  		/* check the condition */
    if(*token != ';') 
    	syntax_err(SEMI_EXPECTED);
    prog++;
    temp2 = prog;
    brace = 1;
    while(brace) {
      	get_token();
      	if(*token == '(') 
      		brace++;
      	if(*token == ')') 
      		brace--;
    }
    if(cond) 
    	interpret_block();  	/* interpret */
    else {  			/* skip loop */
      	find_eob();
      	return;			/* EXIT LOOP */
    }
    prog = temp2;
    eval_exp(&cond); /* do the increment */
    prog = temp;  /* loop back to top */
  }
}
			/* input console char */
static int call_getche(){
  char ch;
  ch = getche();      /* note define for this f(x) */
#if VC == 0           /* handle most C vs  VC++ */
  printf("%d",ch);
#endif
  while(*prog!=')') prog++;
  prog++;   		/* goto end of line that evoked getche */
  return ch;
}
			
static int call_putch(){	/* display a char */
  int vchar;
  eval_exp(&vchar);
  printf("%c", vchar);
  return vchar;
}

			/* put a string */
static int call_puts(void){
  get_token();
  if(*token!='(') 
  	syntax_err(PAREN_EXPECTED);
  get_token();
  if(token_type!=STRING) 
  	syntax_err(QUOTE_EXPECTED);
  puts(token);
  get_token();
  if(*token!=')') 
  	syntax_err(PAREN_EXPECTED);
  get_token();
  if(*token!=';') 
  	syntax_err(SEMI_EXPECTED);
  putback();
  return 0;
}
				/* basic console output */
static int print(void){
  int i;
  get_token();
  if(*token!='(')  
     syntax_err(PAREN_EXPECTED);

  get_token();
  if(token_type==STRING) { 	/* we have a string, write it*/
    	printf("%s ", token);
  }
  else {  			/* we have a number, write it */
   	putback();
   	eval_exp(&i);
   	printf("%d ", i);
  }
  get_token();
  if(*token!=')') 
  	syntax_err(PAREN_EXPECTED);
  get_token();
  if(*token!=';') 
  	syntax_err(SEMI_EXPECTED);
  putback();
  return 0;
}

			/* keyboard input for integers */
static int getnum(void){
  char tmp[20];
  int i;
  zout(tmp);
  gets(tmp);
  for(i=0;i< (int)strlen(tmp);i++){
      if (!isnumeric(tmp[i]) ){
          printf("Integer expected  \n");
          exit(EXIT_FAILURE);   
      }
  }
  while(*prog != ')') prog++;
  prog++;  /* to EOL */
  return atoi(tmp);
}
void decl_local(void){          /* local variable */
  struct var_type i;
  get_token();  		/* get type */
  i.v_type = tok;
  i.value = 0;  		/* init to 0 */
  do { 				/* process comma-separated list */
    	get_token(); 		/* get var name */
    	strcpy(i.var_name, token);
    	local_push(i);
    	get_token();
  } while(*token == ',');
  if(*token != ';') 
  	syntax_err(SEMI_EXPECTED);
}

			/* pop idx of variable stack */
int func_pop(void)
{
  functos--;
  if(functos < 0) 
  	syntax_err(RET_NOCALL);
  return  call_stack[functos];
}


void interpret_block(void){
  int value;
  char block = 0;
  do {
    token_type = get_token();
    /* If interpreting single statement, return on  first semicolon.
      first - what kind of token is up */		
    if(token_type == IDENTIFIER) {  /* Not a keyword, so process expression. */
      putback();  		/* restore token to input stream for
                     			further processing by eval_exp() */
      eval_exp(&value);  	/* process the expression */
      if(*token!=';') syntax_err(SEMI_EXPECTED);
    }
    else if(token_type==BLOCK) { 	/* if block delimiter */
      if(*token == '{') 		/*  block */
        block = 1; 			/* interpreting block, not statement */
      else return; 			/* is endblock, so return */
    }
    else 			/* is keyword */
      switch(tok) {
        	case CHAR:
        	case INT:     /* declare local variables */
          		putback();
          		decl_local();
          		break;
        	case RETURN:  /* return from function call */
          		func_ret();
          		return;
        case IF:      /* process an if statement */
          	exec_if();
          	break;
        case ELSE:    /* process an else statement */
          	find_eob(); /* find else block end then  go on*/
          	break;
        case WHILE:   /* process a while loop */
          	exec_while();
          	break;
        case DO:      /* process a do-while loop */
          	exec_do();
          	break;
        case FOR:     /* process a for loop */
          	exec_for();
          	break;
        case END:
          	exit(0);
      }
  } while (tok != FINISHED && block);
}
	/* begin parser, start at eval_exp() */
	/* we step down into each eval_expN() - a descending parser */
	
void eval_exp(int *value){
  get_token();
  if(!*token) {
    	syntax_err(NO_EXP);
    	return;
  }
  if(*token == ';') {
    	*value = 0; 			/* found an  empty expression */
    	return;
  }
  eval_exp0(value);
  putback(); 				/* stream gets last token restored */
}

	/* Process an assignment expression */
	
void eval_exp0(int *value){
  char temp[ID_LEN];  			/* variable getting assignemnt */
  register int temp_tok;
  if(token_type == IDENTIFIER) {
    if(is_var(token)) {  		/* see if assignment */
      	strcpy(temp, token);
      	temp_tok = token_type;
      	get_token();
      	if(*token == '=') {  		/* assignment */
        	get_token();
        	eval_exp0(value);  	/* get value to assign */
        	assign_var(temp, *value);  	/* put it in there */
        	return;
      }
      else {  				/* not assignment */
        	putback();  		/* restore original token */
        	strcpy(token, temp);
        	token_type = temp_tok;
      }
    }
  }
  eval_exp1(value);			/* step down one more */
}

	/* relational operators. */

void eval_exp1(int *value){
  int partial_value;
  register char op;
  char relops[7] = {
    	LT, LE, GT, GE, EQ, NE, 0
  };

  eval_exp2(value);
  op = *token;
  if(strchr(relops, op)) {
    	get_token();
    	eval_exp2(&partial_value); 
    	switch(op) {               /* do boolean operation */
      		case LT:
        		*value = *value < partial_value;
        		break;
      		case LE:
        		*value = *value <= partial_value;
        		break;
      		case GT:
        		*value = *value > partial_value;
        		break;
      		case GE:
        		*value = *value >= partial_value;
        		break;
      		case EQ:
        		*value = *value == partial_value;
        		break;
      		case NE:
        		*value = *value != partial_value;
        		break;
    	}
  }
}

		/*  add, subtract */
void eval_exp2(int *value){
  register char  op;
  int partial_value;
  eval_exp3(value);
  while((op = *token) == '+' || op == '-') {
    	get_token();
    	eval_exp3(&partial_value);
    	switch(op) { 			/* add or subtract */
      		case '-':
        		*value = *value - partial_value;
        		break;
      		case '+':
        		*value = *value + partial_value;
        		break;
    }
  }
}

		/* multiply & divide */
void eval_exp3(int *value){
  register char  op;
  int partial_value, t;
  eval_exp4(value);
  while((op = *token) == '*' || op == '/' || op == '%') {
    	get_token();
    	eval_exp4(&partial_value);
    	switch(op) {          /* mul, div, % */
      		case '*':
        		*value = *value * partial_value;
        		break;
      		case '/':
        		if(partial_value == 0)   /* always check before divide */
        		   	syntax_err(DIV_BY_ZERO);       
        		*value = (*value) / partial_value;
        		break;
      		case '%':
        		t = (*value) / partial_value;
        		*value = *value-(t * partial_value);
        		break;
    	}
  }
}

	/* handle unary + or - */
void eval_exp4(int *value){
  register char  op;
  op = '\0';
  if(*token == '+' || *token == '-') {
    	op = *token;
    	get_token();
  }
  eval_exp5(value);
  if(op) {                 		/* can't do a compare on null */
  	if(op == '-') 
    		*value = -(*value);
  }
}

			/* expression in parens  */
void eval_exp5(int *value){
  if((*token == '(')) {
    get_token();
    eval_exp0(value);   		/* get nested expression  */
    if(*token != ')') syntax_err(PAREN_EXPECTED);
    get_token();
  }
  else
    atom(value);
}

		/* Find a value  */
void atom(int *value){
  int i;
  switch(token_type) {
  	case IDENTIFIER:
    		i = internal_func(token);
    		if(i!= -1) {           /* call library function */
		      *value = (*intern_func[i].p)();
    		}
    		else
    			if(find_func(token)) { 
      				call();        /* invoke user function */
      				*value = ret_value;
    			}
    			else {
    				*value = find_var(token); /*  get the value of var */
    			}
    		get_token();
    		return;
  	case NUMBER: 			/*  constant */
    		*value = atoi(token);
    		get_token();
    		return;
  	case DELIMITER: 			/* const char */
    		if(*token == '\'') {
      			*value = *prog;
      			prog++;
      			if(*prog!='\'') 
      				syntax_err(QUOTE_EXPECTED);
      			prog++;
      			get_token();
      			return ;
    		}
    		if(*token==')') 
    			return; 		/* empty expression */
    		else 
    			syntax_err(GENERIC); 	/* generic syntax error */
  	default:
    		syntax_err(GENERIC); 		/* syntax error */
  }
}

		/* Display an error message. */
void syntax_err(int error){
  char *p, *temp;
  int linecount = 0;
  register int i;
  static char *e[]= {  /* text for the errors we trap */
    "syntax or other error",
    "unbalanced parentheses",
    "no expression present",
    "equals sign expected",
    "not a variable",
    "parameter error",
    "semicolon expected",
    "unbalanced braces",
    "function undefined",
    "type specifier expected",
    "too many nested function calls",
    "return without call",
    "parentheses expected",
    "while expected",
    "closing quote expected",
    "not a string",
    "too many local variables",
    "division by zero"
  };
  printf("\n%s: ", e[error]);
  p = p_buf;                    /* roll back to beginning to find where we bombed */
  while(p != prog) {  		/* get line number of error */
    p++;
    if(*p == '\r') {
      linecount++;
    }
  }
  printf(" in line %d\n", linecount);

  temp = p;
  for(i=0; i < 20 && p > p_buf && *p != '\n'; i++, p--);  
                                /* print the offender */
  for(i=0; i < 30 && p <= temp; i++, p++) printf("%c", *p);
  longjmp(e_buf, 1); 		/* return to known point */
}

		/* main processing - look for a token */

int get_token(void){
  register char *temp;
  token_type = 0; 
  tok = 0;
  temp = token;
  *temp = '\0';
  				/* ignore white space */
  while(iswhite(*prog) && *prog) 
  	++prog;
  if(*prog == '\r') {  		/* jump over cr/lf for VC++ only */
    ++prog;
    ++prog;
    while(iswhite(*prog) && *prog) 
        ++prog;
  }
  if(*prog == '\0') { 		/* EOF */
    *token = '\0';
    tok = FINISHED;
    return (token_type = DELIMITER);
  }
  if(strchr("{}", *prog)) { /* block delimiters */
    *temp = *prog;
    temp++;
    *temp = '\0';
    prog++;
    return (token_type = BLOCK);
  }
  				/* look for comments */
  if(*prog == '/') {
    if(*(prog+1) == '*') { 	/* found one  */
      prog += 2;
      do { 			/* find end of comment */
        while(*prog != '*') 
        	prog++;
        prog++;
      } while (*prog != '/');
      prog++;
    }
  }
  if(strchr("!<>=", *prog)) { 	/* relational operator ? */                              
    switch(*prog) {
      case '=': 
      		if(*(prog+1) == '=') {
          		prog++; 
          		prog++;
          		*temp = EQ;
          		temp++; 
          		*temp = EQ; 
          		temp++;
          		*temp = '\0';
       		}
       		break;
       		
      case '!': 
        	if(*(prog+1) == '=') {
          		prog++; 
          		prog++;
          		*temp = NE;
          		temp++; 
          		*temp = NE; 
          		temp++;
          		*temp = '\0';
       		}
       		break;
       		
      case '<': 
        	if(*(prog+1) == '=') {
          		prog++; 
          		prog++;
          		*temp = LE; 
          		temp++; 
          		*temp = LE;
        	}
        	else {
          		prog++;
          		*temp = LT;
        	}
       		temp++;
       		*temp = '\0';
       		break;
       
      case '>': 
       		if(*(prog+1) == '=') {
          		prog++; 
          		prog++;
          		*temp = GE; 
          		temp++; 
          		*temp = GE;
       		}
       		else {
         		prog++;
         		*temp = GT;
       		}
       		temp++;
       		*temp = '\0';
       		break;
    }
    
    if(*token) 
    	return(token_type = DELIMITER);
  }
  if(strchr("+-*^/%=;(),'", *prog)){ 	/* we found a delimiter */
    *temp = *prog;
    prog++; 
    temp++;
    *temp = '\0';
    return (token_type = DELIMITER);
  }
  if(*prog=='"') { 			/* found a quoted string */
    prog++;
    while(*prog != '"'&& *prog != '\r') 
        *temp++ = *prog++;
    if(*prog == '\r') 
        syntax_err(GENERIC);  		/* we found a esc-r where no one oughta be */
    prog++; 
    *temp = '\0';
    return (token_type = STRING);
  }
  if(isdigit(*prog)) {     		/* do a  number */
    while(!isdelim(*prog)) 
    	*temp++ = *prog++;
    *temp = '\0';
    return (token_type = NUMBER);
  }
  if(isalpha(*prog)) { 		 	/* variable, command, something else ? */
    while(!isdelim(*prog)) 
    	*temp++ = *prog++;
    token_type = TEMP;
  }
  *temp = '\0';
  if(token_type==TEMP) {		/* is it command or variable ? */
    tok = look_up(token);        
    if(tok){ 
       token_type = KEYWORD;
    } 		/* keyword */
    else{ 
       token_type = IDENTIFIER;
    }  					/* assume we can get an only find ID */
  }
  return token_type;
}


void putback(void){  	/* rewind pointer on input stream */
  char *t;
  t = token;
  for(; *t; t++) 
  	prog--;
}

int look_up(char *s)                    /* search for token */
{
  register int i;
  char *p;
  p = s;
  while(*p) {                		/* l_case  every char */
  	*p = tolower(*p); 
  	p++; 
  }
  for(i=0; *table[i].command; i++) {   	/* while not at end of table */
    if(!strcmp(table[i].command, s)) 
        return table[i].tok;            /* success */
  }
  return 0;    	           		/* uh oh we don't know this one */
}
		/* get internal library function name, -1 == not found. */
int internal_func(char *s){
  register int i;
  for(i=0; intern_func[i].f_name[0]; i++) {
     if(!strcmp(intern_func[i].f_name, s))  
     	return i;
  }
  return -1;
}

void init_Ifunc(void){
	/* set up function calls */
	strcpy(intern_func[0].f_name,"putch");
	intern_func[0].p = call_putch;
	strcpy(intern_func[1].f_name,"puts");
	intern_func[1].p = call_puts;
	strcpy(intern_func[2].f_name,"print");
	intern_func[2].p = print;
	strcpy(intern_func[3].f_name,"getnum");
	intern_func[3].p = getnum;
	strcpy(intern_func[4].f_name,"getche");
	intern_func[4].p = call_getche;
	strcpy(intern_func[5].f_name,"");
	intern_func[5].p = NULL;
}
  

