Obligatorisk uppgift: Numerisk kalkylator
Följande klasser skall ingå
I Calculator
Till stor del given. Kompletteras bara med exception- hantering.
I Stokenizer
Given - skall användas (i oförändrat skick)!
I Parser
En mall (”
ParserTemplate”) given
I SyntaxException
I EvaluationException
Klassen Calculator
”Huvudklass” för kalkylatorn. Innehåller konstruktor,
statement(med en hjälpmetod) samt
main-metoden.
public class Calculator { private Parser parser;
private Stokenizer tokenizer;
private Map<String, Double> variables;
public Calculator(Stokenizer tokenizer) { this.tokenizer = tokenizer;
variables = new TreeMap<String, Double>();
variables.put("PI", Math.PI);
variables.put("E", Math.E);
variables.put("ans", new Double(0.));
parser = new Parser(tokenizer, variables);
}
(12 september 2018 – OU2 2 )
Kalylatorns main-metod
public static void main(String[] args) throws IOException
{
System.out.println("Numerical calculator version 2018-09-11");
Calculator calc = new Calculator(new Stokenizer());
while (true) { statement();
} }
Kalylatorns statement-metod
public void statement() { try {
calc.line();
} catch (SyntaxException syntaxException) { throw syntaxException;
} catch (EvaluationException evaluationException) { throw evaluationException;
} }
Röd kod
ska ersättas med kod som ger felutskrift och ser till att tokenizern positioneras till slutet på raden
(12 september 2018 – OU2 4 )
Hjälpmetod till statement
EOL EOL
file quit vars statement
assignment filename
private void line() {
do { // Skip empty lines
System.out.print("> ");
tokenizer.nextToken();
} while (tokenizer.isEOL());
String command = tokenizer.getToken(); // First token if (command.equals("quit") || tokenizer.isEOS()) {
System.out.println("Bye!");
System.exit(0);
} else if (command.equals("vars")) { System.out.println(variables);
tokenizer.nextToken();
} else {
double parsed = parser.assignment();
System.out.println(parsed);
variables.put("ans", new Double(parsed));
}
if (!tokenizer.isEOL()) {
throw new SyntaxException("Expected EOL");
}
Syntaxdiagram: Specifikation för Parser-klassen
Obs: Hette tidigare factor
eller
eller
number
) expression
= word
function name
term
+ −
expression
* term
factor /
primary
function name
word
sin cos exp log
( assignment
primary
− primary
assignment
factor
(12 september 2018 – OU2 6 )
Parser-mallen
public class ParserTemplate { private Stokenizer tokenizer;
private Map<String, Double> variables;
private TreeSet<String> functions;
public ParserTemplate(Stokenizer tokenizer,
Map<String,Double> variables) {
this.tokenizer = tokenizer;
this.variables = variables;
functions = new TreeSet<String>();
functions.add("sin");
functions.add("cos");
functions.add("exp");
functions.add("log");
}
Parser-mallen
public double assignment() { double result = expression();
return result;
}
public double expression() { double sum = term();
return sum;
}
public double term() { double prod = factor();
return prod;
}
public double factor() { return primary();
}
(12 september 2018 – OU2 8 )
Parser-mallen
public double primary() { double result = 99999;
if (tokenizer.isNumber()) {
result = tokenizer.getNumber();
tokenizer.nextToken();
} else {
throw new SyntaxException("primary not complete yet: " + tokenizer.getToken());
}
return result;
} }
Tips om hantering av funktionsanropen
Funktionsanropen har alla samma syntax:
funktionsnamn(assignment)
log function
name (
word
) function name
sin cos exp
primary
−
assignment
number
primary
(12 september 2018 – OU2 10 )
Tips om hantering av funktionsanropen
Hanteringen av argumentet (syntaxkontroll av och evaluering) bör alltså göras gemensamt på ett ställe. Inget ”klipp och klistrande” av kod, alltså!
För att underlätta det har parsern försetts med ett
TreeSet<String> functionssom innehåller funktionsnamnen.
Följande kod passar då in någonstans i
primary ...else if (funtions.contains(tokenizer.getToken()) { result = functionHandler(tokenizer.getToken()) } else if {
...
Hjälpmetoden functionHandler
double functionHandler(String functionName) {
tokenizer.nextToken(); // Pass the function name if (tokenizer.getChar()!=’(’)
throw new SyntaxException(...);
double argument = primary(); // Handles the parentheses if (functionName.equals("exp"))
return Math.exp(argument);
else if ( ... ) ...
else if ( ... ) ...
...
}
Metoden utnyttjar alltså
primaryför kontrollen av högerparentesen.
(12 september 2018 – OU2 12 )
Var kan syntaxfel upptäckas?
eller
eller
number
) expression
= word
function name
term
+ −
expression
* term
factor /
primary
function name
word
sin cos
( assignment
primary
− primary
assignment
factor
Var kan syntaxfel upptäckas?
eller
− eller
/ expression
=
term expression
function name sin cos exp log primary term
factor (
function name
*
word
+
) word
primary
primary
− assignment
number factor
assignment
(12 september 2018 – OU2 14 )
Var kan syntaxfel upptäckas?
EOL EOL
file quit
vars statement
assignment filename
Var kan syntaxfel upptäckas?
quit
file filename vars
statement
assignment EOL
EOL
(12 september 2018 – OU2 16 )
Tips
Lägg in undantagshanteringen från början!
Se till att följande skrivs ut:
I
Vilken/vilka tokar som förväntades
I
Vilken tok som hittades (
getToken())
I