Created
September 30, 2012 03:40
-
-
Save freshwater/3805768 to your computer and use it in GitHub Desktop.
Reversible state machine for a calculator application.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.hudcalc.hudcalc; | |
import com.hudcalc.hudcalc.SymbolList.Symbol; | |
public class StateMachine | |
{ | |
// maximum input length for each number, in digits | |
int maxLength = 8; | |
enum State { | |
S1, D, S1MINUS, SN1, SNDOTD, | |
SN2, S2DOTD, S2, S2N1, S2N2, DONE, | |
NOTRANSFER, ERROR | |
} | |
private Symbol[] symbolStack = new Symbol[30]; | |
private State[] stateStack = new State[30]; | |
int[] numberSize = new int[] { 0, 0 }; | |
int currentNumber = 0; | |
int arithmeticSymbolLocation = 0; | |
boolean secondNumberHasDot = false; | |
int pointer = 0; | |
public StateMachine( String initial ) | |
{ | |
this(); | |
char[] chars = initial.toCharArray(); | |
for (int i = 0; i < chars.length; i++) { | |
processToken(chars[i]); | |
} | |
} | |
public StateMachine() | |
{ | |
// initialize stacks | |
stateStack[0] = State.S1; | |
for (int i = 0; i < symbolStack.length; i++) { | |
symbolStack[i] = Symbol.EMPTY; | |
} | |
} | |
/** returns symbols in string form **/ | |
@Override | |
public String toString() | |
{ | |
return new SymbolList(symbolStack).toString(); | |
} | |
public State transferState( State state, Symbol sym ) | |
{ | |
//- | |
switch(state) | |
{ | |
case S1: switch(sym) { | |
case MINUS: return State.S1MINUS; | |
case DOT: return State.S2N1; | |
case DIGIT: return State.SNDOTD; | |
} | |
break; | |
case S1MINUS: switch(sym) { | |
case DOT: return State.SN1; | |
case DIGIT: return State.SNDOTD; | |
} | |
break; | |
case SNDOTD: switch(sym) { | |
case DOT: return State.SN2; | |
case DIGIT: return State.SNDOTD; | |
case PLUS: | |
case MINUS: | |
case TIMES: | |
case DIVIDE:return State.S2; | |
} | |
break; | |
case SN1: switch(sym) { | |
case DIGIT: return State.SN2; | |
} | |
break; | |
case SN2: switch(sym) { | |
case DIGIT: return State.SN2; | |
case PLUS: | |
case MINUS: | |
case TIMES: | |
case DIVIDE:return State.S2; | |
} | |
break; | |
case S2: switch(sym) { | |
case DOT: return State.S2N1; | |
case DIGIT: return State.S2DOTD; | |
case PLUS: | |
case MINUS: | |
case TIMES: | |
case DIVIDE:return State.S2; | |
} | |
break; | |
case S2DOTD: switch(sym) { | |
case DOT: return State.S2N1; | |
case DIGIT: return State.S2DOTD; | |
case PLUS: | |
case MINUS: | |
case TIMES: | |
case DIVIDE:return State.S2DOTD; | |
} | |
break; | |
case S2N1: switch(sym) { | |
case DIGIT: return State.S2N2; | |
case PLUS: | |
case MINUS: | |
case TIMES: | |
case DIVIDE:return State.S2N1; | |
} | |
break; | |
case S2N2: switch(sym) { | |
case DIGIT: return State.S2N2; | |
case EQUAL: return State.DONE; | |
case PLUS: | |
case MINUS: | |
case TIMES: | |
case DIVIDE:return State.S2N2; | |
} | |
} | |
//- | |
return State.NOTRANSFER; | |
} | |
// second number has digits? | |
public boolean isCalculable() | |
{ | |
return numberSize[1] > 0; | |
} | |
public String getFirstNumber() | |
{ | |
if (currentNumber == 0) { | |
return new SymbolList(symbolStack).toString().substring(0, pointer); | |
} else { | |
return new SymbolList(symbolStack).toString().substring(0, arithmeticSymbolLocation - 1); | |
} | |
} | |
public String getSecondNumber() | |
{ | |
if (arithmeticSymbolLocation > 0 && pointer > arithmeticSymbolLocation) { | |
return new SymbolList(symbolStack).toString().substring(arithmeticSymbolLocation, pointer); | |
} else { | |
return ""; | |
} | |
} | |
public String getArithmeticSymbol() | |
{ | |
if (arithmeticSymbolLocation > 0) { | |
return symbolStack[arithmeticSymbolLocation].toString(); | |
} else { | |
return ""; | |
} | |
} | |
public String getAnswer() | |
{ | |
if( isCalculable() ) { | |
return Arithmetic.getAnswer( | |
getFirstNumber(), getSecondNumber(), getArithmeticSymbol()); | |
} else { | |
return ""; | |
} | |
} | |
public void processToken( char token ) | |
{ | |
State nextState = State.ERROR; | |
Symbol sym = Symbol.ERROR; | |
switch(token) | |
{ | |
// D | |
case '0':case '1':case '2':case '3':case '4': | |
case '5':case '6':case '7':case '8':case '9': | |
nextState = transferState(stateStack[pointer], Symbol.DIGIT); | |
// transition exists? | |
if (nextState != State.NOTRANSFER) | |
{ | |
if (numberSize[currentNumber] < maxLength) | |
{ | |
pointer++; | |
stateStack[pointer] = nextState; | |
symbolStack[pointer] = Symbol.toSymbol(token); | |
numberSize[currentNumber]++; | |
} | |
} | |
break; | |
// . | |
case '.': | |
nextState = transferState(stateStack[pointer], Symbol.DOT); | |
if (nextState != State.NOTRANSFER) | |
{ | |
if (numberSize[currentNumber] < maxLength) | |
{ | |
pointer++; | |
stateStack[pointer] = nextState; | |
symbolStack[pointer] = Symbol.toSymbol(token); | |
if (currentNumber == 1) | |
{ | |
secondNumberHasDot = true; | |
} | |
} | |
} | |
break; | |
// - | |
case '-': | |
nextState = transferState(stateStack[pointer], Symbol.MINUS); | |
if (nextState != State.NOTRANSFER) | |
{ | |
// first number is negatable | |
if (pointer == 0) | |
{ | |
pointer++; | |
stateStack[pointer] = nextState; | |
symbolStack[pointer] = Symbol.toSymbol(token); | |
} | |
else | |
{ | |
if (currentNumber == 0) | |
{ | |
currentNumber = 1; | |
pointer++; | |
stateStack[pointer] = nextState; | |
symbolStack[pointer] = Symbol.toSymbol(token); | |
arithmeticSymbolLocation = pointer; | |
} | |
if (currentNumber == 1) | |
{ | |
symbolStack[arithmeticSymbolLocation] = Symbol.toSymbol(token); | |
} | |
} | |
} | |
break; | |
// + x / | |
case '+': sym = Symbol.PLUS; | |
case 'x': sym = Symbol.TIMES; | |
case '/': sym = Symbol.DIVIDE; | |
nextState = transferState(stateStack[pointer], sym); | |
if (nextState != State.NOTRANSFER) | |
{ | |
// in first number | |
if (currentNumber == 0) | |
{ | |
currentNumber = 1; | |
pointer++; | |
stateStack[pointer] = nextState; | |
symbolStack[pointer] = Symbol.toSymbol(token); | |
arithmeticSymbolLocation = pointer; | |
} | |
// in second number | |
if (currentNumber == 1) | |
{ | |
symbolStack[arithmeticSymbolLocation] = Symbol.toSymbol(token); | |
} | |
} | |
break; | |
// < | |
case '<': | |
if (pointer > 0) | |
{ | |
switch(symbolStack[pointer].toChar()) | |
{ | |
case '0':case '1':case '2':case '3':case '4': | |
case '5':case '6':case '7':case '8':case '9': | |
numberSize[currentNumber]--; | |
break; | |
case '+':case '-':case 'x':case '/': | |
currentNumber = 0; | |
arithmeticSymbolLocation = 0; | |
case '.': | |
if (currentNumber == 1) | |
{ | |
secondNumberHasDot = false; | |
} | |
} | |
symbolStack[pointer] = Symbol.EMPTY; | |
pointer--; | |
} | |
break; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment