Skip to content
Snippets Groups Projects
Commit ed3039b3 authored by Dominic Daniel Krämer's avatar Dominic Daniel Krämer
Browse files

Merge branch 'dominicsbranch' into 'main'

Dominicsbranch

See merge request !15
parents a17bb1cb 04f30b3e
No related branches found
No related tags found
1 merge request!15Dominicsbranch
1+1 x
2*4+x x^2
2*5+2 (x^2)-40
2+5*2 (x*40)-(x*20)
2*(5+2) (2*x)+(0.5*x^2)-1
20*(5^2) 1 + (x^2) - (3*x)
(x^2)+50*x+2 \ No newline at end of file
\ No newline at end of file
package main; package main;
import java.util.List;
/** /**
* <h1>The ASTPrinter</h1> * <h1>ASTPrinter</h1>
* The ASTPrinter class creates a String out of an AST(represented through an Expression object) * The ASTPrinter class creates a String out of an AST(represented through an Expression object)
* It prints it in a form the Evaluator class can work with it, it isn't primarily designed for * It prints it in a form the SwingFunctionPlotter class can work with it, it isn't primarily designed
* returning a String that is perfect for human readability (e.g. Pow(x,3) would be printed instead of x^3) * for returning a String that is perfect for human readability (e.g. Pow(x,3) would be printed instead of x^3)
* *
* @version 1.0 * @version 1.0
* @since 09.01.2023 * @since 09.01.2023
...@@ -19,7 +17,7 @@ public class ASTPrinter implements Visitor<String>{ ...@@ -19,7 +17,7 @@ public class ASTPrinter implements Visitor<String>{
* recursive call) and combines them into one String together with the operator * recursive call) and combines them into one String together with the operator
* *
* @param binaryOP The BinaryOperation that should be printed into a String * @param binaryOP The BinaryOperation that should be printed into a String
* @return String Returns the String that was build * @return Returns the String that was build
*/ */
@Override @Override
public String visit(final Parser.BinaryOperation binaryOP) { public String visit(final Parser.BinaryOperation binaryOP) {
...@@ -49,7 +47,6 @@ public class ASTPrinter implements Visitor<String>{ ...@@ -49,7 +47,6 @@ public class ASTPrinter implements Visitor<String>{
return sb.toString(); return sb.toString();
} }
/** /**
* Returns the result of ast.accept(this), which will be the core values of a Value(digits), * Returns the result of ast.accept(this), which will be the core values of a Value(digits),
* Variable(variableName) or BinaryOperation(will lead to a recursive call) * Variable(variableName) or BinaryOperation(will lead to a recursive call)
...@@ -64,6 +61,7 @@ public class ASTPrinter implements Visitor<String>{ ...@@ -64,6 +61,7 @@ public class ASTPrinter implements Visitor<String>{
} }
/** /**
* returns a string-representation of the value stored inside a Variable object
* @see #visit(Parser.Expression) * @see #visit(Parser.Expression)
*/ */
@Override @Override
...@@ -72,6 +70,7 @@ public class ASTPrinter implements Visitor<String>{ ...@@ -72,6 +70,7 @@ public class ASTPrinter implements Visitor<String>{
} }
/** /**
* returns a string-representation of the value stored inside a Number object
* @see #visit(Parser.Expression) * @see #visit(Parser.Expression)
*/ */
@Override @Override
...@@ -80,6 +79,7 @@ public class ASTPrinter implements Visitor<String>{ ...@@ -80,6 +79,7 @@ public class ASTPrinter implements Visitor<String>{
} }
/** /**
* returns a string-representation of the value stored inside a Decimal object
* @see #visit(Parser.Expression) * @see #visit(Parser.Expression)
*/ */
@Override @Override
......
...@@ -6,6 +6,23 @@ import java.io.IOException; ...@@ -6,6 +6,23 @@ import java.io.IOException;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
/** <h1>Application</h1>
* This class contains the main method of this project
* It reads a the file "expressions.txt" line-by-line and saves the value into a String
* The syntax and semantic of the mathematical expression will be tested in multiple steps
* First a Lexer will separate the String into multiple Tokens, then a Parser checks if the
* Tokens can be merged into an AST(Arithmetical Syntax Tree). If not, a ParserException will
* be thrown. If the syntax and semantic of the expression was correct, the expression will
* be calculated by an Evaluator and finally be shown in a FunctionPlotter
*
* @version 1.0
* @since 09.01.2023
* @see Lexer
* @see Parser
* @see ASTPrinter
* @see Evaluator
* @see SwingFunctionPlotter
*/
public class Application { public class Application {
public static void main(String[] args) { public static void main(String[] args) {
//A list that will contain a String for each line of the "expressions.txt" file //A list that will contain a String for each line of the "expressions.txt" file
...@@ -27,6 +44,7 @@ public class Application { ...@@ -27,6 +44,7 @@ public class Application {
e.printStackTrace(); e.printStackTrace();
} }
LinkedList<String> stringsForPlotter = new LinkedList<>();
//Iterate through every String //Iterate through every String
for (String expressionString: expressions) { for (String expressionString: expressions) {
System.out.println("Expression: " + expressionString); System.out.println("Expression: " + expressionString);
...@@ -36,33 +54,37 @@ public class Application { ...@@ -36,33 +54,37 @@ public class Application {
List<Lexer.Token> tokens = Lexer.lex(expressionString); List<Lexer.Token> tokens = Lexer.lex(expressionString);
System.out.println("Lexer created tokens:"); System.out.println("Lexer created tokens:");
//prints out each token to the console //prints out each token to the console
int i = 0; int index = 0;
for(Lexer.Token token: tokens) { for(Lexer.Token token: tokens) {
System.out.println("[" + i + "]" + token.toString()); System.out.println("[" + index + "]" + token.toString());
i++; index++;
} }
//Parse all tokens with the parser and saves the result into the variable 'ast' //Parse all tokens with the parser and saves the result into the variable 'ast'
Parser parser = new Parser(); Parser parser = new Parser();
Parser.Expression ast = parser.parse(tokens); Parser.Expression ast = parser.parse(tokens);
//Prints the ast out with an ASTPrinter //Prints the ast out with an ASTPrinter
//the result can later be used to show the ast in a function plotter //the result can later be used to show the ast in a function plotter
ASTPrinter printer = new ASTPrinter(); ASTPrinter printer = new ASTPrinter();
System.out.println("Printing: '" + printer.visit(ast) + "'"); System.out.println("Printing: '" + printer.visit(ast) + "'");
Evaluator evaluator = new Evaluator(); stringsForPlotter.add(printer.visit(ast));
System.out.println(evaluator.visit(ast, 20));
//Prints the Value of the Expression
System.out.println("Evaluating:");
Evaluator eval = new Evaluator();
//Calculates the expression with values from -20 to 20
for(index=-20;index<=20; index++) {
System.out.print("[" + index + "]" + eval.visit(ast,index) + " ");
if(index%5==0 && index!=-20) {
System.out.println(); System.out.println();
} }
}
System.out.println("\n");
}
catch (Exception e) { catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
SwingFunctionPlotter.plotFunction(stringsForPlotter);
/*
Evaluator evaluator = new Evaluator();
String s = printer.visit(exp);
System.out.println("Evaluating: '" + evaluator.visit(exp) + "'");
SwingFunctionPlotter.plotFunction(s);
}*/
} }
} }
package main; package main;
import java.util.LinkedList; /**
import java.util.List; * <h1>Evaluator</h1>
* This class calculates the value of an expression, using the visitor pattern.
* It visits every element of a given expression and combines them with the matching
* arithmetical operator.
* @version 1.0
* @since 09.01.2023
* @see #visit(Parser.Expression, int)
*/
public class Evaluator implements Visitor<Double> { public class Evaluator implements Visitor<Double> {
private int x; private double value;
/**
* @see #visit(Parser.Expression, int)
*/
@Override @Override
public Double visit(final Parser.BinaryOperation binaryOP) { public Double visit(final Parser.BinaryOperation expression) {
double result = expression.leftExpression.accept(this);
int range = 20; double rOperand = expression.rightExpression.accept(this);
List<Double> results = new LinkedList<>(); switch (expression.operator) {
for(int index=-20; index<=range; index++) { case "+":
}
double result = binaryOP.leftExpression.accept(this);
double rOperand;
switch (binaryOP.operator.charAt(0)) {
case '+':
rOperand = binaryOP.rightExpression.accept(this);
result += rOperand; result += rOperand;
break; break;
case '-': case "-":
rOperand = binaryOP.rightExpression.accept(this);
result -= rOperand; result -= rOperand;
break; break;
case '*': case "*":
if(binaryOP.rightExpression instanceof Parser.BinaryOperation) {;
if(((Parser.BinaryOperation) binaryOP.rightExpression).capsuled) {
rOperand = binaryOP.rightExpression.accept(this);
result *= rOperand;
}
else {
//***************************************************************************************
result = ((Parser.BinaryOperation) binaryOP.rightExpression).accept(this, result, "*");
}
}
else {
rOperand = binaryOP.rightExpression.accept(this);
result *= rOperand; result *= rOperand;
}
break; break;
case '/': case "/":
if (binaryOP.rightExpression instanceof Parser.BinaryOperation) {
if(binaryOP.capsuled) {
rOperand = binaryOP.rightExpression.accept(this);
result /= rOperand;
}
else {
//***************************************************************************************
result = ((Parser.BinaryOperation) binaryOP.rightExpression).accept(this, result, "/");
}
}
else {
rOperand = binaryOP.rightExpression.accept(this);
if (rOperand!=0) { if (rOperand!=0) {
result /= rOperand; result /= rOperand;
} }
else { else {
throw new ArithmeticException("ArithmeticError: division by zero detected"); throw new ArithmeticException("ArithmeticError: division by zero detected");
} }
} result /= rOperand;
break; break;
case '^': case "^":
rOperand = binaryOP.rightExpression.accept(this); for(double index=1.0; index<rOperand; index++) {
for(int i=1; i<rOperand; i++) { result *= result;
result = result*result;
} }
break; break;
default: default:
throw new RuntimeException("SemanticError: unknown operand found in AST: " + binaryOP.operator); throw new RuntimeException("SemanticError: unknown operand found in AST: "
+ expression.operator);
} }
return result; return result;
} }
/**
* @see #visit(Parser.Expression, int)
*/
@Override @Override
public Double visit(final Parser.Variable variable) { public Double visit(final Parser.Variable variable) {
return variable.value * x; return value;
} }
/**
* @see #visit(Parser.Expression, int)
*/
@Override @Override
public Double visit(final Parser.Number number) { public Double visit(final Parser.Decimal decimal) {
return Double.valueOf(number.digits); return Double.parseDouble(decimal.beforeDot.digits + "." + decimal.afterDot.digits);
} }
/**
* @see #visit(Parser.Expression, int)
*/
@Override @Override
public Double visit(final Parser.Decimal decimal) { public Double visit(final Parser.Number number) {
return Double.valueOf(decimal.afterDot.digits + "." + decimal.beforeDot.digits); return Double.parseDouble(number.digits);
} }
public Double visit(final Parser.Expression ast, int x) { /**
this.x = x; * This method is used for visiting every element of an expression
* @param ast The expression in a form of an AST(Abstract Syntax Tree)
* @param value The int value which will be used for the variables
* @return The final value of the expression
*/
public double visit(final Parser.Expression ast, int value) {
this.value = value;
return ast.accept(this); return ast.accept(this);
} }
} }
...@@ -6,16 +6,20 @@ import java.util.LinkedList; ...@@ -6,16 +6,20 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
/** /**
* <h1>The Lexer</h1> * <h1>Lexer</h1>
* The Lexer class crates a List of Token objects out of a String * The Lexer class crates a List of Token objects out of a String
* *
* @version 1.0 * @version 1.0
* @since 09.01.2023 * @since 09.01.2023
* @see TokenType
* @see Token
* @see #lex(String)
*/ */
public class Lexer { public class Lexer {
/** /**
* enum TokenType that can either be a number, variable or a special character (like * or / etc.) * enum TokenType that can either be a number, variable or a special character (like * or / etc.)
* @see Lexer
*/ */
public static enum TokenType { public static enum TokenType {
NUMBER, VARIABLE, SPECIAL NUMBER, VARIABLE, SPECIAL
...@@ -24,6 +28,7 @@ public class Lexer { ...@@ -24,6 +28,7 @@ public class Lexer {
/** /**
* tokens with a TokenType that represents their type and a String with the actual data * tokens with a TokenType that represents their type and a String with the actual data
* has for both values a getter method and overrides toString with its fitting values * has for both values a getter method and overrides toString with its fitting values
* @see Lexer
*/ */
public static class Token { public static class Token {
protected TokenType type; protected TokenType type;
...@@ -50,8 +55,9 @@ public class Lexer { ...@@ -50,8 +55,9 @@ public class Lexer {
/** /**
* creates a list of tokens from a given String * creates a list of tokens from a given String
* @param input The String with the input * @param input The String with the input
* @return result The List of Token objects * @return The List of Token objects
* @throws LexerException If the String was empty, or it couldn't create any result out of it * @throws LexerException If the String was empty, or it couldn't create any result out of it
* @see Lexer
*/ */
public static List<Token> lex(String input) throws Exception{ public static List<Token> lex(String input) throws Exception{
if(input.isEmpty()) { if(input.isEmpty()) {
......
...@@ -6,11 +6,13 @@ import java.util.LinkedList; ...@@ -6,11 +6,13 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
/** /**
* <h1>The Parser</h1> * <h1>Parser</h1>
* The Parser class parses a list of Tokens into an Expression that represents an AST * The Parser class parses a list of Tokens into an Expression that represents an AST
* *
* @version 1.0 * @version 1.0
* @since 09.01.2023 * @since 09.01.2023
* @see #parse(List)
* @see Expression
*/ */
public class Parser { public class Parser {
...@@ -19,16 +21,20 @@ public class Parser { ...@@ -19,16 +21,20 @@ public class Parser {
* It represents an expression in the form of an Abstract Syntax Tree(AST) * It represents an expression in the form of an Abstract Syntax Tree(AST)
* A method 'accept' is implemented, it is used for allowing other classes to interact with it * A method 'accept' is implemented, it is used for allowing other classes to interact with it
* through the visiting pattern * through the visiting pattern
* @see BinaryOperation
* @see Variable
* @see Value
*/ */
public abstract class Expression { public abstract class Expression {
public abstract <T> T accept(Visitor<T> visitor); public abstract <T> T accept(Visitor<T> visitor);
public abstract <T> T accept(Visitor<T> visitor, double leftValue, String operator);
} }
/** /**
* This class represents a binary operation * This class represents a binary operation
* it contains a left expression, an operator, and a right expression * it contains a left expression, an operator, and a right expression
* if this operation is capsuled by brackets, the value of 'capsuled' will be true, else it will be false * if this operation is capsuled by brackets, the value of 'capsuled' will be true, else it will be false
* @see Variable
* @see Value
*/ */
public class BinaryOperation extends Expression { public class BinaryOperation extends Expression {
Expression leftExpression; Expression leftExpression;
...@@ -41,15 +47,11 @@ public class Parser { ...@@ -41,15 +47,11 @@ public class Parser {
this.rightExpression = rightExpression; this.rightExpression = rightExpression;
this.capsuled = capsuled; this.capsuled = capsuled;
} }
@Override @Override
public <T> T accept(Visitor<T> visitor) { public <T> T accept(Visitor<T> visitor) {
return visitor.visit(this); return visitor.visit(this);
} }
public <T> T accept(Visitor<T> visitor, double leftValue, String operator) {
leftExpression.accept(visitor, leftValue, operator);
return visitor.visit(this);
}
} }
/** /**
...@@ -57,29 +59,20 @@ public class Parser { ...@@ -57,29 +59,20 @@ public class Parser {
* of the alphabet * of the alphabet
*/ */
public class Variable extends Expression { public class Variable extends Expression {
double value;
String variableName; String variableName;
public Variable(String i) { public Variable(String i) {
this.value = 1.0;
variableName = i; variableName = i;
} }
public <T> T accept(Visitor<T> visitor) { public <T> T accept(Visitor<T> visitor) {
return visitor.visit(this); return visitor.visit(this);
} }
public <T> T accept(Visitor<T> visitor, double leftValue, String operator) {
if(operator.equals("*")) {
this.value = leftValue;
}
else {
this.value = 1/leftValue;
}
return visitor.visit(this);
}
} }
/** /**
* This abstract class is only used for heredity * This abstract class is only used for heredity
* A value can either be a number or a decimal * A value can either be a number or a decimal
* @see Decimal
* @see Number
*/ */
private abstract class Value extends Expression { private abstract class Value extends Expression {
...@@ -89,26 +82,18 @@ public class Parser { ...@@ -89,26 +82,18 @@ public class Parser {
* This class represents a number, it contains a String 'digits' that holds it value * This class represents a number, it contains a String 'digits' that holds it value
*/ */
public class Number extends Value { public class Number extends Value {
public String digits; String digits;
public Number(String i) { public Number(String i) {
this.digits = i; this.digits = i;
} }
public <T> T accept(Visitor<T> visitor) { public <T> T accept(Visitor<T> visitor) {
return visitor.visit(this); return visitor.visit(this);
} }
public <T> T accept(Visitor<T> visitor, double leftValue, String operator) {
if(operator.equals("*")) {
this.digits = String.valueOf((leftValue * Double.parseDouble(this.digits)));
}
else {
this.digits = String.valueOf((leftValue / Integer.parseInt(this.digits)));
}
return visitor.visit(this);
}
} }
/** /**
* This class represents a decimal, it contains two numbers: the one before- and the one after the dot * This class represents a decimal, it contains two numbers: the one before- and the one after the dot
* @see Number
*/ */
public class Decimal extends Value { public class Decimal extends Value {
public Number beforeDot; public Number beforeDot;
...@@ -121,11 +106,6 @@ public class Parser { ...@@ -121,11 +106,6 @@ public class Parser {
public <T> T accept(Visitor<T> visitor) { public <T> T accept(Visitor<T> visitor) {
return visitor.visit(this); return visitor.visit(this);
} }
public <T> T accept(Visitor<T> visitor, double leftValue, String operator) {
beforeDot.accept(visitor, leftValue, operator);
afterDot.accept(visitor, leftValue, operator);
return visitor.visit(this);
}
} }
/** /**
...@@ -154,6 +134,10 @@ public class Parser { ...@@ -154,6 +134,10 @@ public class Parser {
* @param ts The list of tokens * @param ts The list of tokens
* @return The expression object that got parsed * @return The expression object that got parsed
* @throws ParserException If the list of tokens was empty * @throws ParserException If the list of tokens was empty
* @see #parseBinaryOperation(List)
* @see #parseVariable(List)
* @see #parseDecimal(String)
* @see #parseVariable(List)
*/ */
private Expression parseExpression(List<Lexer.Token> ts) throws ParserException { private Expression parseExpression(List<Lexer.Token> ts) throws ParserException {
if(ts.isEmpty()) { if(ts.isEmpty()) {
...@@ -177,8 +161,9 @@ public class Parser { ...@@ -177,8 +161,9 @@ public class Parser {
* It splits up the tokens into a left and right expression and with a recursive call of parseExpression * It splits up the tokens into a left and right expression and with a recursive call of parseExpression
* each part will be determined, until all BinaryOperations consist of finite left and right expressions * each part will be determined, until all BinaryOperations consist of finite left and right expressions
* @param ts The list of tokens * @param ts The list of tokens
* @return null If the list does not contain a BinaryOperation (anymore) or: BinaryOperation The crated BinaryOP * @return null If the list does not contain a BinaryOperation <br> or: BinaryOperation The crated BinaryOP
* @throws ParserException If the list of tokens was empty * @throws ParserException If the list of tokens was empty
* @see #parseBrackets(List)
* */ * */
private BinaryOperation parseBinaryOperation(List<Lexer.Token> ts) throws ParserException { private BinaryOperation parseBinaryOperation(List<Lexer.Token> ts) throws ParserException {
if(ts.isEmpty()) { if(ts.isEmpty()) {
...@@ -221,6 +206,7 @@ public class Parser { ...@@ -221,6 +206,7 @@ public class Parser {
capsuled = false; capsuled = false;
index = tokensInBracket+1; index = tokensInBracket+1;
} }
//Checks if the operator of this BinaryOperation is permitted //Checks if the operator of this BinaryOperation is permitted
parseOperator(ts.get(index).getData()); parseOperator(ts.get(index).getData());
List<Lexer.Token> leftList = new LinkedList<>(); List<Lexer.Token> leftList = new LinkedList<>();
...@@ -242,6 +228,7 @@ public class Parser { ...@@ -242,6 +228,7 @@ public class Parser {
* @return int The position of the token with the closing bracket or -1 if the first token wasn't a bracket * @return int The position of the token with the closing bracket or -1 if the first token wasn't a bracket
* @throws ParserException If the list of tokens was empty, a bracket never gets closed or there isn't any * @throws ParserException If the list of tokens was empty, a bracket never gets closed or there isn't any
* value between the brackets * value between the brackets
* @see #parseCharacter(String, String)
*/ */
private int parseBrackets(List<Lexer.Token> ts) throws ParserException{ private int parseBrackets(List<Lexer.Token> ts) throws ParserException{
if(ts.isEmpty()) { if(ts.isEmpty()) {
...@@ -285,6 +272,7 @@ public class Parser { ...@@ -285,6 +272,7 @@ public class Parser {
* Checks if a String only contains an allowed operator * Checks if a String only contains an allowed operator
* @param operator The string that represents the operator * @param operator The string that represents the operator
* @throws ParserException If the operator token was too big, small or consisted of invalid characters * @throws ParserException If the operator token was too big, small or consisted of invalid characters
* @see #parseCharacter(String, String)
*/ */
private void parseOperator(String operator) throws ParserException { private void parseOperator(String operator) throws ParserException {
if(operator.isEmpty()) { if(operator.isEmpty()) {
...@@ -301,7 +289,8 @@ public class Parser { ...@@ -301,7 +289,8 @@ public class Parser {
/** /**
* Checks if a token is a variable: * Checks if a token is a variable:
* @param ts List of tokens * @param ts List of tokens
* @return null It the token isn't a variable or: Variable A new Variable that gets created with the received token * @return null It the token isn't a variable <br>or: Variable A new Variable that gets created
* with the received token
* @throws ParserException If the list of tokens was empty or the size of the token was too big * @throws ParserException If the list of tokens was empty or the size of the token was too big
* or too small for a variable * or too small for a variable
*/ */
...@@ -333,13 +322,11 @@ public class Parser { ...@@ -333,13 +322,11 @@ public class Parser {
/** /**
* Checks if a token is a value and if so creates and returns a new Number or Decimal object * Checks if a token is a value and if so creates and returns a new Number or Decimal object
* @param ts The List of the tokens * @param ts The List of the tokens
* @return null If the token isn't a value/number or: Value The created Number or Decimal Object * @return null If the token isn't a value/number <br>or: Value The created Number or Decimal Object
* @throws ParserException If the list of tokens is empty or * @throws ParserException If the list of tokens is empty or
* @see #parseDecimal(String)
* @see #parseNumber(String, boolean)
*/ */
//Checks if a token is a value:
//Yes: returns a new Number or Decimal that gets created with the received token
//No: returns null
private Value parseValue(List<Lexer.Token> ts) throws ParserException { private Value parseValue(List<Lexer.Token> ts) throws ParserException {
if (ts.isEmpty()) { if (ts.isEmpty()) {
throw new ParserException("SyntaxError: empty token list"); throw new ParserException("SyntaxError: empty token list");
...@@ -363,6 +350,7 @@ public class Parser { ...@@ -363,6 +350,7 @@ public class Parser {
* parses a String into a Decimal object that consists of two numbers * parses a String into a Decimal object that consists of two numbers
* @param data The String that contains the value * @param data The String that contains the value
* @return Decimal Returns the new Decimal object * @return Decimal Returns the new Decimal object
* @see #parseVariable(List)
*/ */
private Decimal parseDecimal(String data) throws ParserException { private Decimal parseDecimal(String data) throws ParserException {
if(data.isEmpty()) { if(data.isEmpty()) {
...@@ -382,6 +370,8 @@ public class Parser { ...@@ -382,6 +370,8 @@ public class Parser {
* @param data The String that contains the value * @param data The String that contains the value
* @param afterDot If this Number will be used after a dot in a Decimal object * @param afterDot If this Number will be used after a dot in a Decimal object
* @return Number Returns the new Number object * @return Number Returns the new Number object
* @see #parseDigit(String)
* @see #parseDigitWithoutZero(String)
*/ */
private Number parseNumber(String data, boolean afterDot) throws ParserException{ private Number parseNumber(String data, boolean afterDot) throws ParserException{
if (data.isEmpty()) { if (data.isEmpty()) {
...@@ -411,6 +401,7 @@ public class Parser { ...@@ -411,6 +401,7 @@ public class Parser {
* checks if a String only contains numbers(including zero) * checks if a String only contains numbers(including zero)
* @param data The String that gets checked * @param data The String that gets checked
* @exception ParserException If the data is empty or does contain invalid characters * @exception ParserException If the data is empty or does contain invalid characters
* @see #parseCharacter(String, String)
*/ */
private void parseDigit(String data) throws ParserException { private void parseDigit(String data) throws ParserException {
for(int index=0; index<data.length(); index++) { for(int index=0; index<data.length(); index++) {
...@@ -428,6 +419,7 @@ public class Parser { ...@@ -428,6 +419,7 @@ public class Parser {
* checks if a String only contains numbers(excluding zero) * checks if a String only contains numbers(excluding zero)
* @param data The String that gets checked * @param data The String that gets checked
* @exception ParserException If the data is empty or does contain invalid characters * @exception ParserException If the data is empty or does contain invalid characters
* @see #parseCharacter(String, String)
*/ */
private void parseDigitWithoutZero(String data) throws ParserException { private void parseDigitWithoutZero(String data) throws ParserException {
if(data.isEmpty()) { if(data.isEmpty()) {
......
...@@ -5,11 +5,27 @@ import com.mindfusion.charting.swing.LineChart; ...@@ -5,11 +5,27 @@ import com.mindfusion.charting.swing.LineChart;
import javax.swing.*; import javax.swing.*;
import java.awt.*; import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.LinkedList;
/**
* <h1>SwingFunctionPlotter</h1>
* This class creates a FunctionPlotter Panel using JavaSwing.
* It can display a list of different functions and allows the user to navigate through them
*
* @see #plotFunction(LinkedList)
*/
public class SwingFunctionPlotter extends JFrame { public class SwingFunctionPlotter extends JFrame {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
public static void plotFunction(String function) { /**
* This function is used to display the functions.
* * The LeftArrow Button can be used to navigate to the function shown before, every other
* * Button input will navigate to the next function
* @param function A LinkedList of Strings that contains the function expressions
*/
public static void plotFunction(LinkedList<String> function) {
SwingUtilities.invokeLater(new Runnable() { SwingUtilities.invokeLater(new Runnable() {
public void run() { public void run() {
try { try {
...@@ -22,20 +38,66 @@ public class SwingFunctionPlotter extends JFrame { ...@@ -22,20 +38,66 @@ public class SwingFunctionPlotter extends JFrame {
}); });
} }
protected SwingFunctionPlotter(String function) { /**
* This is the Constructor of the FunctionPlotter
* It will create the FunctionPlotter with all its functions
* @param function A LinkedList of Strings that contains the function expressions
*/
private SwingFunctionPlotter(LinkedList<String> function) {
setDefaultCloseOperation(EXIT_ON_CLOSE); setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(650, 400); setSize(650, 400);
setTitle("Java Swing Library for Charts and Gauges: FunctionSeries"); setTitle("Java Swing Window: Informatik III - Exercise 4");
getContentPane().add(initializeChart(function), BorderLayout.CENTER); //Keeps track of the current shown function
final int[] index = {0};
getContentPane().add(initializeChart(function.get(0),0), BorderLayout.CENTER);
//KeyListener that listens to every KeyInput of the user
addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
//If the user pressed the left arrow this following block will be entered
//The function shown before will be shown again
if(e.getKeyCode() == KeyEvent.VK_LEFT) {
if(index[0]>0) {
index[0]--;
getContentPane().removeAll();
getContentPane().add(initializeChart(function.get(index[0]),index[0]), BorderLayout.CENTER);
validate();
setVisible(true);
}
}
//If any other key got pressed this following block will be entered
//The next function will be shown
else {
index[0]++;
if(index[0]<function.size()) {
getContentPane().removeAll();
getContentPane().add(initializeChart(function.get(index[0]),index[0]), BorderLayout.CENTER);
validate();
setVisible(true);
}
else {
//If the last function was already be shown the FunctionPlotter will close
//and 'destroy' itself
getContentPane().removeAll();
setVisible(false);
dispose();
}
}
}
});
} }
private LineChart initializeChart(String function) { /**
* This function will initialize a FunctionSeries out of the current function that should be shown
*/
private LineChart initializeChart(String function, int index) {
LineChart lineChart = new LineChart(); LineChart lineChart = new LineChart();
FunctionSeries series1; FunctionSeries series1;
try { try {
series1 = new FunctionSeries(function,1000, -20, 20); series1 = new FunctionSeries(function,1000, -20, 20);
series1.setTitle("Current function"); series1.setTitle("Function " + (index+1) + ": " + function);
lineChart.getSeries().add(series1); lineChart.getSeries().add(series1);
} }
catch(Exception e) { catch(Exception e) {
......
package main; package main;
import java.util.List; /**
* This interface is used to implement a visitor pattern
* in other classes. For more information:
* <a href=https://en.wikipedia.org/wiki/Visitor_pattern>Visitor Pattern</a>
*/
public interface Visitor<T>{ public interface Visitor<T>{
public T visit(final Parser.BinaryOperation binOp); public T visit(final Parser.BinaryOperation binOp);
public T visit(final Parser.Variable variable); public T visit(final Parser.Variable variable);
......
package test;
import main.Evaluator;
import main.Lexer;
import main.Parser;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class EvaluatorTest {
@Test
public void testWithString1() {
String s = "1 + (x^2) - (3*x)";
var parser = new Parser();
var evaluator = new Evaluator();
try {
var tokens = Lexer.lex(s);
var ast = parser.parse(tokens);
var value = evaluator.visit(ast, 5);
assertEquals(value,11);
}
catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void testWithString2() {
String s = "(2*x)+(0.5*x^2)-1";
var parser = new Parser();
var evaluator = new Evaluator();
try {
var tokens = Lexer.lex(s);
var ast = parser.parse(tokens);
var value = evaluator.visit(ast, 8);
assertEquals(value,47);
}
catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void testWithString3() {
String s = "(x^2)-40";
var parser = new Parser();
var evaluator = new Evaluator();
try {
var tokens = Lexer.lex(s);
var ast = parser.parse(tokens);
var value = evaluator.visit(ast, 4);
assertEquals(value,-24);
}
catch (Exception e) {
e.printStackTrace();
}
}
}
...@@ -9,7 +9,7 @@ import java.util.List; ...@@ -9,7 +9,7 @@ import java.util.List;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
class LexerTest { public class LexerTest {
@Test @Test
public void disassembleFirstStringWithLexer() { public void disassembleFirstStringWithLexer() {
......
...@@ -7,7 +7,7 @@ import org.junit.Test; ...@@ -7,7 +7,7 @@ import org.junit.Test;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
class ParserTest { public class ParserTest {
@Test @Test
public void testParseVariable() { public void testParseVariable() {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment