Here is my code so far:
public class Token {
// Data:
private String type = "";
private String name = "";
private double value = 0;
// Constructors:
public Token() { this( "" ); }
public Token( String t ) { this( t, 0 ); }
public Token( String t, double v ) { this( t, t, v ); }
public Token( String t, String n, double v ) {
type = t; name = n; value = v;
}
// Methods:
public String getType( ) { return type;}
public String getName( ) { return name;}
public double getValue( ) { return value; }
public String toString( ) { return (" type="+type+" name="+name+" value="+value);}
}
import java.util.*;
public class Memory {
private HashMap<String, Double> map;
/** Creates new Memory */
public Memory() {
map = new HashMap<String, Double>();
}
public void store(String name, double value) {
map.put(name, new Double(value));
}
public double fetch(String name) {
Double x = (Double)map.get(name);
if (x == null) return 0;
return x.doubleValue();
}
}
public class Evaluator {
private double value;
private static EvalTokenizer str;
private static Memory mem = new Memory();
public Evaluator( String s ) {
str = new EvalTokenizer( s );
value = evaluate();
}
public double getValue() {
return value;
}
public void storeCurrentValue(int line) {
mem.store("$"+line, value);
}
private double evaluate() {
return evalStatement(str.getToken());
}
private double evalStatement(Token firstToken) {
/* <statement> ::= <var> = <expression>
| <expression>
*/
String s = firstToken.getType();
// if (s.equals("goto")) return 0;
if (s.equals("_id") && (str.peekToken().getType()).equals("=")) {
// <statement> ::= <var> = <expression>
str.getToken();
double x = evalExpression(str.getToken());
mem.store(firstToken.getName(), x);
return x;
}
return evalExpression(firstToken);
}
private double evalExpression(Token firstToken) {
/* <expression> ::= <term>
| <expression> + <term>
| <expression> - <term>
*/
double x = evalTerm(firstToken);
while (true) {
String op = str.peekToken().getType();
if (op.equals("+") || op.equals("-")) {
str.getToken(); // skip "+" or "-"
double y = evalTerm(str.getToken());
if (op.equals("+")) x += y;
else x -= y;
} else
return x;
}
}
private double evalTerm(Token firstToken) {
/* <term> ::= <factor>
| <term> * <factor>
| <term> / <factor>
*/
double x = evalFactor(firstToken);
while (true) {
String op = str.peekToken().getType();
if (op.equals("*") || op.equals("/") {
str.getToken(); // skip "*" or "/"
double y = evalFactor(str.getToken());
if (op.equals("*")) x = x*y;
else x= x/y;
} else return x;
}
}
private double evalFactor(Token firstToken) {
/* <factor> ::= ( <expression> )
| + <factor>
| - <factor>
| <variable>
| ++ <variable>
| -- <variable>
| <number>
*/
String t = firstToken.getType();
if (t.equals("(")) {
// <factor> ::= ( <expression> )
double x = evalExpression(str.getToken());
String nex = str.getToken().getType();
if (!nex.equals(")")) throw new ArithmeticException("bad expression" );
return x;
}
// <factor> ::= + <factor> | - <factor>
if (t.equals("+")) return (evalFactor(str.getToken()));
if (t.equals("-")) return (-evalFactor(str.getToken()));
// <factor> ::= <number>
if (t.equals("_num")) return firstToken.getValue();
// <factor> ::= <variable>
if (t.equals("_id")) return mem.fetch(firstToken.getName());
if (t.equals("++") || t.equals("--")) {
// <factor> ::= ++ <variable> | -- <variable>
firstToken = str.getToken();
if ((firstToken.getType()).equals("_id")) {
double x = mem.fetch(firstToken.getName());
if (t.equals("++")) {
mem.store(firstToken.getName(), x+1);
return x+1;
} else {
mem.store(firstToken.getName(), x-1);
return x-1;
}
}
}
throw new ArithmeticException("bad expression" );
}
}
import java.util.StringTokenizer;
public class EvalTokenizer {
// Data:
private StringTokenizer str;
private Token nextToken = new Token();
public EvalTokenizer( String line ) {
str = new StringTokenizer(line, "+*-/().<>!=%,|& ", true);
getToken();
}
public Token peekToken() { return nextToken; }
/**
* A token is either a number literal (integer or double), an identifier, or special symbols
* getToken finds the next token, skipping blanks, and return it.
* For _int or _double token, place the processed value in value.
* For _id, place the name of the identifier in name.
* Throw ArithmeticException if input is unrecognized.
*/
public Token getToken( ) throws ArithmeticException {
static boolean isVariable(String id) {
}
Token result = nextToken;
nextToken = getNextToken();
String t1 = result.getType();
String t2 = nextToken.getType();
// handle floating numbers
if (t1.equals("_num") && t2.equals(".")) {
nextToken = getNextToken();
t2 = nextToken.getType();
if (!t2.equals("_num")) throw new ArithmeticException("number format error" );
t2 = nextToken.getName();
double x = result.getValue()+nextToken.getValue()*Math.pow(10.0, -t2.length());
nextToken = getNextToken();
return new Token("_num", "", x);
}
if (t1.equals("$")) {
if (t2.equals("_int")) {
double x = nextToken.getValue();
nextToken = getNextToken();
return new Token("_dollar", x);
} else
throw new ArithmeticException("dollar variable format error" );
}
if (t1.equals("+")) {
if (t2.equals("+")) { nextToken = getNextToken(); return new Token("++"); }
}
if (t1.equals("-")) {
if (t2.equals("-")) { nextToken = getNextToken(); return new Token("--"); }
}
if (t2.equals("=")) {
if (t1.equals(">")) { nextToken = getNextToken(); return new Token(">="); }
if (t1.equals("<")) { nextToken = getNextToken(); return new Token("<="); }
if (t1.equals("=")) { nextToken = getNextToken(); return new Token("=="); }
}
System.out.println("token = "+result);
return result;
}
private Token getNextToken() throws ArithmeticException {
long theValue;
// Return a default empty token when no more tokens in str.
if( !str.hasMoreTokens()) return new Token();
String s = str.nextToken( );
if( s.equals( " " ) ) return getNextToken();
char c = s.charAt(0);
if ('0' <= c && c <= '9') { // numbers
try { theValue = Long.parseLong( s ); }
catch( NumberFormatException e ) {
throw new ArithmeticException("number format error" );
}
return new Token( "_num", s, theValue);
}
if ('A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || c == '$') // identifiers
return new Token( "_id", s, 0);
return new Token( s, s, 0 );
}
}
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class Calculator {
/**
* Simple main to exercise Evaluator class.
*/
public static void main( String [ ] args )
{
String str;
BufferedReader in = new BufferedReader( new InputStreamReader( System.in ) );
int line = 1;
System.out.print( "Enter expressions, one per line:\nline 1: " );
while (true) {
try {
str = in.readLine( );
if (str == null) continue;
if (str.equals("quit")) break;
Evaluator ev = new Evaluator( str );
System.out.println( "line " + line + " result >>> " + ev.getValue( ) );
ev.storeCurrentValue(line);
line++;
System.out.print( "line "+line+": " );
}
catch( IOException e ) {
System.err.println( e );
System.out.print( "line "+line+": " );
}
catch (ArithmeticException e) {
System.err.println( e );
System.out.print( "line "+line+": " );
}
} // end while
System.out.println("Goodbye.");
} // end main
}
I need to edit this block of the code to implement the % operator:
private double evalTerm(Token firstToken) {
/* <term> ::= <factor>
| <term> * <factor>
| <term> / <factor>
*/
double x = evalFactor(firstToken);
while (true) {
String op = str.peekToken().getType();
if (op.equals("*") || op.equals("/") {
str.getToken(); // skip "*" or "/"
double y = evalFactor(str.getToken());
if (op.equals("*")) x = x*y;
else x= x/y;
} else return x;
}
}
I have tried this, but for some reason it isn't working even though % is part of my tokens:
private double evalTerm(Token firstToken) {
/* <term> ::= <factor>
| <term> * <factor>
| <term> / <factor>
*/
double x = evalFactor(firstToken);
while (true) {
String op = str.peekToken开发者_如何学Python().getType();
if (op.equals("*") || op.equals("/") || op.equals("%")) || {
str.getToken(); // skip "*" or "/"
double y = evalFactor(str.getToken());
if (op.equals("*")) x = x*y;
if (op.equals("/")) x= x/y;
else x = x%y;
} else return x;
}
}
What am I doing wrong and how can I fix it?
in your code you have
if (op.equals("*")) x = x*y;
if (op.equals("/")) x= x/y;
else x = x%y;
i think you mean to have an else if
on the second line ie
if (op.equals("*")) x = x*y;
else if (op.equals("/")) x= x/y;
else x = x%y;
The code below should work for you:
private double evalTerm(Token firstToken) {
/* <term> ::= <factor>
| <term> * <factor>
| <term> / <factor>
| <term> % <factor>
*/
double x = evalFactor(firstToken);
while (true) {
String op = str.peekToken().getType();
if (op.equals("*") || op.equals("/") || op.equals("%")) {
str.getToken(); // skip "*" or "/"
double y = evalFactor(str.getToken());
if (op.equals("*")) {
x = x*y;
} else if (op.equals("/")) {
x = x/y;
}
else x= x%y;
} else return x;
}
}
There were two issues. Firstly you had a syntax error in the outer if statement. Secondly, the inner if statement had a logic error. Without the else before if (op.equals("/")) it would be match twice for '*' first as x*y and then as x%y giving '(x*y)%y'.
The code works fine for me once all the (four or so) syntax errors are fixed. However, you will want to chain those if statements, otherwise the * operator matches also the % operator:
if (op.equals("*")) x = x * y;
**else** if (op.equals("/")) x = x / y;
else x = x % y;
Here is the output of finding 11 % 4, which is 3 (11 = 2 * 4 + 3).
Enter expressions, one per line:
line 1: 11 % 4
token = type= name= value=0.0
token = type=_num name=11 value=11.0
token = type=% name=% value=0.0
token = type=_num name=4 value=4.0
line 1 result >>> 3.0
line 2:
精彩评论