// Joseph Bergin
// Pace University
// April, 1996


import java.util.*;
import java.lang.Math;
import java.lang.String;
import java.io.*;
import java.awt.*;

public class Scanner 
{	private final int allDone = -1;
	private final int scanningFile = 0;
	private final int scanningString = 1;
	private final int scanningTextField = 2;
	private int state = allDone;
	
	public Scanner(FileInputStream s)
	{	inStream = s;
		state = scanningFile;
	}
	
	public Scanner(String s)
	{	scanString = s;
		state = scanningString;
	}
	
	public Scanner(TextField t)
	{	scanField = t;
		state = scanningTextField;
	}
	
	public void setErrorField(TextField t)
	{	errorField = t;
		errorsToField = true;
	}
	
	static boolean isLetter(char c)
	{	return (c>='a' && c<='z') || (c>='A' && c<='Z');
	}
	
	static boolean isDigit(char c)
	{	return (c>='0' && c<='9');
	}

	static boolean isLetterOrDigit(char c)
	{	return (c>='a' && c<='z') 
			|| (c>='A' && c<='Z') 
			|| (c>='0' && c<='9');
	}

	public int nextToken()
	{	if (!tokenavailable) gettoken();
		return (currenttoken);				
	}

	public void match(int t)
	{	if (!tokenavailable) gettoken();
		if (currenttoken == t) toss();
		else 
		{	parseError(" Match- trying " + t);
		}
	}
	
	public void toss() // Use this to reinitialize a Scanner's in buffer.
	{	tokenavailable = false;
	}
	
	public void parseError(String s)
	{	if(errorsToField)
			errorField.setText(s);
		else
			System.out.println(s);
	}
		
	void scanerror()
	{	if(errorsToField)
			errorField.setText("Scan error.");
		else
			 System.out.println("Scan error.");
	}

	public static final int number = 0;
	public static final int letter = 1;
	public static final int sumfunc = 2;
	public static final int prodfunc = 3;
	public static final int plusop = 4;
	public static final int minusop = 5;
	public static final int timesop = 6;
	public static final int divideop = 7;
	public static final int assignop = 8;
	public static final int rangeop = 9;
	public static final int lparen = 10;
	public static final int rparen = 11;
	public static final int period = 12;
	public static final int semicolon = 13;
	public static final int notoken = -1;
	
	private int currenttoken; // From the list above.
	private int value; // only when currentToken == number
	private  String which; // only when currentToken is letter or function
	
	public String which()
	{	return which;
	}
	
	public int value()
	{	return value;
	}
	
	public int currenttoken()
	{	return currenttoken;
	}
	
	private  boolean tokenavailable = false;
	private  byte [] linebuffer = new byte[81];
	private  int currentchar = 0;
	private  int linelength = -1;
	private  FileInputStream inStream = null;
	private  String scanString = null;
	private  TextField scanField = null;
	private  TextField errorField = null;
	private  boolean errorsToField = false;
	
	void readline()
	{	linelength = 0;
		try
		{	if(state == scanningFile)linelength = inStream.read(linebuffer);
		}
		catch (IOException e)
		{	state = allDone;
		}
		if(state == scanningTextField)
		{	String theText = scanField.getText();
//			System.out.println(theText);
			linelength = theText.length();
			for(int i = 0; i< linelength; i++)
				linebuffer[i] = (byte)theText.charAt(i);
			if(linelength == 0)linebuffer[linelength++] = (byte)';';
		}
		if(state == scanningString)
		{	linelength = scanString.length();
			if(linelength > 0)
			{	state = allDone;
				return;
			}
			for(int i = 0; i< linelength; i++)
				linebuffer[i] = (byte)scanString.charAt(i);
		}
		linebuffer[linelength] = ' ';
		currentchar = 0;
	}
	
	char inspect()
	{	if (currentchar > linelength)	readline();
		return (char)linebuffer[currentchar];
	}
	
	void advance()
	{	currentchar++;
	}

	public final char tab = '\t';
	public final char newline = '\n';
	public final char space = ' ';

	int checkFunctions(String s)
	{	if(s.equals("sum")) return sumfunc;
		if(s.equals("prod")) return prodfunc;
		return letter;
	}

	void gettoken()
	{	char ch, TEMP, TEMP1;
		if(state == allDone) 
		{	currenttoken = notoken;
			return;
		}
		char [] spelling = new char[40];
		String newSpell;
		int loc;
		TEMP = inspect();
		while (TEMP == tab || TEMP == space || TEMP == newline)
		{	advance();
			TEMP = inspect();
		}
		switch (TEMP) 
		{	case '=':
				currenttoken = assignop;
				advance();
				break;	
			case '+':
				currenttoken = plusop;
				advance();
				break;
			case '-':
				currenttoken = minusop;
				advance();
				break;
			case '*':
				currenttoken = timesop;
				advance();
				break;
			case '/':
				currenttoken = divideop;
				advance();
				break;
			case '(':
				currenttoken = lparen;
				advance();
				break;
			case ')':
				currenttoken = rparen;
				advance();
				break;
			case ';':
				currenttoken = semicolon;
				advance();
				break;
			case '.':
				currenttoken = period;
				advance();
				if(inspect()== '.')
				{	currenttoken = rangeop;
					advance();
				}
				break;
			default:
				if (isDigit(TEMP)) 
				{	currenttoken = number;
					value = inspect() - '0';
					advance();
					while (isDigit(inspect())) 
					{	value = value * 10 + inspect() - '0';
						advance();
					}
				} 
				else if (isLetter(TEMP)) 
				{	ch = inspect();
					if (Character.isUpperCase(ch))
						ch = Character.toLowerCase(ch);
					spelling[0] =  ch; loc = 1;
					advance();
					while(isLetterOrDigit(inspect()))
					{	spelling[loc++] = inspect();
						advance();
					}
					loc--; //spelling[loc] = '\0';
				//	newSpell = new char(strlen(spelling) +1);
				//	strcpy(newSpell, spelling);
					which = (new String(spelling)).trim();//newSpell;
					currenttoken = checkFunctions(which);     
				}
				break;
		}
		tokenavailable = true;
	}

	void dumptoken(int t)
	{	System.out.println("<token ");
		switch (t) 
		{	case number:
				System.out.println("num >");
				break;
			case letter:
				System.out.println("let >");
				break;
			case sumfunc:
			case prodfunc:
				System.out.println("fun >");
				break;
			case plusop:
				System.out.println("+ >");
				break;
			case minusop:
				System.out.println("- >");
				break;
			case timesop:
				System.out.println("* >");
				break;
			case divideop:
				System.out.println("/ >");
				break;
			case assignop:
				System.out.println("= >");
				break;
			case rangeop:
				System.out.println(".. >");
				break;
			case lparen:
				System.out.println("( >");
				break;
			case rparen:
				System.out.println(") >");
				break;
			case period:
				System.out.println(". >");
				break;	
			case semicolon:
				System.out.println("; >");
				break;
		}
	}

}

