/* Code of Figure 4.12, pages 105-107 from
   Kenneth C. Louden, Programming Languages
   Principles and Practice 2nd Edition
   Copyright (C) Brooks-Cole/ITP, 2003
*/
/* 
   Modified by B.-M. Chang 2011 for Interpreter of Lang S
*/

#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include "global.h"  

int token; /* holds the current input token for the parse */
int declaration = 0;
int inmatchfun = 0;
int inmatchstmt = 0;

/* declarations to allow arbitrary recursion */
void stmt(void); 
void matchstmt(void); 
void matchfun(void);   /* match function declaration */
void command(void);
int expr(void);
int term(void);
int factor(void);
int number(void);
int digit(void);

... 

void stmt(void)
{  
   int loc, result, whilestart, type, n;
   switch(token) 
   {
	case ID: 	// stmt -> id '=' expr
		loc = tokenval; 
		match(ID); 
		if (token == '=') {
			match('=');
			result = expr( ); 
			symtable[loc].val = result; 
		}
		break;

	...


// stmt -> 'let' type id = expr {, type id = expr} 'in' stmt {; stmt} 'end' 
	case LET:      
		match(LET);
		n = 0;
		while (token == INT || token == BOOL || token == FUN) {

		    if (token == FUN) { // fun t f(t x {,t x}) : S  



			...



		    }

		    if (token == INT || token == BOOL) {



			...


		    }

		    if (token == ',') match(',');
		    else break;
		}
		match(IN);
		stmt();
		while (token == ';') {
			match(token);
			stmt();
		}
		pop(n);
		match(END);
		break;

	case RETURN:
		match(RETURN);
		result = expr();
		symtable[ep-1].val = result;
		break;    
   	}
}

void matchfun(void)   // match f(t x {, t x}) : S
{
    inmatchfun = 1;
    match(ID);
    match('(');

    while (token == INT | token == BOOL) {
       	match(token);
       	match(ID);
       	if (token == ',') match(',');
	else break;
    }

    match(')');
    match(':');
    matchstmt();
    inmatchfun = 0;
}

void matchstmt(void)
{  
   inmatchstmt = 1;
   switch(token) 
   {
	case ID: 
		match(ID); 
		if (token == '=') {
			match('=');
			expr( ); 
		}
		break;

	case '(':
		match('(');
		matchstmt();
		while(token == ';') {
			match(';');
			matchstmt();
		}
		if (token == ')') 
			match(')');
		break;

	case IF:
		match(IF);
		expr();
		match(THEN);
		matchstmt();
		match(ELSE); 
		matchstmt();
		break;

	case WHILE:
		match(WHILE);
		expr();
		match(DO);
		matchstmt();
		break;

	case READ:
		match(READ);
		match(ID);
		break;

	case PRINT: 
		match(PRINT); 
		expr();
		break;

	case LET:
		match(LET);
		while (token == INT || token == BOOL) {
			match(token);
			if (token == ID) {
				match(ID);
				match('=');
				expr();
			} else error();
			if (token == ',') match(',');
			else break;
		}
		match(IN);
		matchstmt();
		while (token == ';') {
			match(token);
			matchstmt();
		}
		match(END);
		break;
	case RETURN:
		match(RETURN);
		expr();
		break;
   }
   inmatchstmt = 0;
}

... 

int factor(void)
/* factor -> '(' expr ')' | number | id  | f(expr {, expr}) */
{   int loc, result, funstart, args[10], i = 0;

    switch(token) 
    {

	...

  	case FUNID:   			// function call 
     		if (inmatchfun || inmatchstmt) {
	   	   match(FUNID); 
		   match('('); 
	   	   if (token != ')') 
		      expr();
	   	   while (token == ',') { 		
		      match(',');
		      expr();
	    	   }
	    	   match(')');
   	    	   result = -1; 
		   break;
		}

    	loc = tokenval;
    	funstart = symtable[loc].val; // start of function 
    	token = getToken();

	/* evaluating arguments */
	if (token == '(') {
	    match('(');
	    ...

	}

	
	/* set up activation record */

	...

	match(')');

	/* goto callee */
	pc = funstart;
	token = getToken();
	match('(');
	i = 0;

	/* set up parameters and passing */

	...

	match(')');
	match(':');
	stmt();

	/* pop AR */ 
	pc = symtable[ep+1].val;
	token = getToken();
	lastentry = ep - 1;
	ep = symtable[ep].val;
	result = symtable[lastentry].val;  // return value
	break;
    }
    return result;
}
