import java.io.IOException;
public class RdCalcInterpreter implements CalcParser {
private CalcLexer lexer;
public RdCalcInterpreter() {
this.lexer = new DFACalcLexer();
}
private void error(String rule) throws IOException {
throw new IOException("Parse error in %s on token %s"
.formatted(rule, lexer.peek()));
}
@Override
public void prog() throws IOException {
switch (lexer.peek().getType()) {
case NUM:
case LP:
stmt();
prog();
break;
case EOF:
break;
default:
error("prog");
}
}
void stmt() throws IOException {
int result = exp();
System.out.println(result);
lexer.match(CalcToken.Type.STOP);
}
int exp() throws IOException {
int lhs = term();
return exptail(lhs);
}
int exptail(int accumulate) throws IOException {
switch (lexer.peek().getType()) {
case OPA:
CalcToken oper = lexer.match(CalcToken.Type.OPA);
int rhs = term();
if (oper.getText().equals("+")) accumulate += rhs;
else accumulate -= rhs;
return exptail(accumulate);
case RP:
case STOP:
return accumulate;
default:
error("exptail");
return -1;
}
}
int term() throws IOException {
int lhs = factor();
return termtail(lhs);
}
int termtail(int accumulate) throws IOException {
switch (lexer.peek().getType()) {
case OPM:
CalcToken oper = lexer.match(CalcToken.Type.OPM);
int rhs = factor();
if (oper.getText().equals("*")) accumulate *= rhs;
else accumulate /= rhs;
return termtail(accumulate);
case RP:
case STOP:
case OPA:
return accumulate;
default:
error("termtail");
return -1;
}
}
int factor() throws IOException {
switch (lexer.peek().getType()) {
case NUM:
CalcToken tok = lexer.match(CalcToken.Type.NUM);
return Integer.valueOf(tok.getText());
case LP:
lexer.match(CalcToken.Type.LP);
int result = exp();
lexer.match(CalcToken.Type.RP);
return result;
default:
error("factor");
return -1;
}
}
}