
import java.io.Reader;
import java.io.InputStreamReader;

/**
 * This class demonstrates how to use a finite state machine within a
 * lexical analyzer.  It parses simple numbers in scientific notation
 * (with no +'s or -'s.  In particular, it recognizes the regular
 * expresssion 
 * [0-9]+ (.[0-9]+)? (E|e[0-9]+)?  */
public class NumReader {
    protected Reader _r;

    /**
     * Try and read one number from system.in
     */
    public static void main(String args[]) {
	Reader r = new InputStreamReader(System.in);
	NumReader nr = new NumReader(r);
	if (nr.read()) {
	    System.out.println("Read a number");
	} else {
	    System.out.println("Did not read a number");
	}
    }

    public NumReader(Reader r) {
	_r = r;
    }

    /**
     * Get the next character from the input stream
     */
    protected char nextChar() {
	try {
	    return (char)_r.read();
	} catch (java.io.IOException e) {
	    System.err.println("Dying!");
	    System.exit(-1);
	}
	return 'c';
    }

    /**
     * Read a pascal-like literal number
     */
    public boolean read() {
	int state = 0;
	while (1 < 2) {
	    char c = nextChar();
	    switch(state) {
	    case 0:
		/* need at least one numerical character */
		if (Character.isDigit(c)) {
		    state = 1;
		} else {
		    return false;
		}
		break;
	    case 1:
		/* we have at least one digit, we may now get decimal or E */
		if (c == '.') {
		    state = 2;
		} else if (c == 'E' || c == 'e') {
		    state = 4;
		} else if (Character.isDigit(c)) {
		    state = 1;
		} else {
		    /* push back this character, we're done */
		    return true;
		}
		break;
	    case 2:
		/* we just got a decimal, now we need at least one digit */
		if (Character.isDigit(c)) {
		    state = 3;
		} else {
		    /* failed! we need at least one digit after decimal  */
		    return false;
		}
		break;
	    case 3:
		/* we've seen number, decimal, number, we could now see E */
		if (c == 'E' || c == 'e') {
		    state = 4;
		} else if (Character.isDigit(c)) {
		    state = 3;
		} else {
		    /* push back this character, we're done */
		    return true;
		}
		break;
	    case 4:
		/* we just got an E, now we need at least one digit */
		if (Character.isDigit(c)) {
		    state = 5;
		} else {
		    /* failed! we need at least one digit after decimal  */
		    return false;
		}
		break;
	    case 5:
		/* we just got an E, now we need at least one digit */
		if (Character.isDigit(c)) {
		    state = 5;
		} else {
		    /* done! push back this character */
		    return true;
		}
		break;
	    default:
		System.err.println("Internal error\n");
		System.exit(-1);
	    }
	}
    }

}
