diff --git a/expressions.txt b/expressions.txt index ba3d6148e53d59ee0444357ada31b3a4c16ce1bd..7177c93c0417e33d9dac40d8bff6d4bd7039fb10 100644 --- a/expressions.txt +++ b/expressions.txt @@ -4,4 +4,5 @@ 2+5*2 2*(5+2) 20*(5^2) -(x^2)+50*x+2 \ No newline at end of file +(x^2)+50*x+2 +5*(2-5)+(4+2)+x \ No newline at end of file diff --git a/src/main/ASTPrinter.java b/src/main/ASTPrinter.java index 2b7c72b951031b7a2a33f2b075d4faee227cf15c..546b116c78e1abc333029b7058f2fc9218150cae 100644 --- a/src/main/ASTPrinter.java +++ b/src/main/ASTPrinter.java @@ -1,11 +1,9 @@ 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) - * 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 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 @@ -19,7 +17,7 @@ public class ASTPrinter implements Visitor<String>{ * recursive call) and combines them into one String together with the operator * * @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 public String visit(final Parser.BinaryOperation binaryOP) { @@ -49,7 +47,6 @@ public class ASTPrinter implements Visitor<String>{ return sb.toString(); } - /** * 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) @@ -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) */ @Override @@ -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) */ @Override @@ -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) */ @Override diff --git a/src/main/Application.java b/src/main/Application.java index dd30e0237d237ddb4514d4ba8396be7c6dfa9078..510bf3e0940b1edfddb2f4c068cf0e354a1bcb1a 100644 --- a/src/main/Application.java +++ b/src/main/Application.java @@ -6,6 +6,23 @@ import java.io.IOException; import java.util.LinkedList; 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 static void main(String[] args) { //A list that will contain a String for each line of the "expressions.txt" file @@ -27,6 +44,7 @@ public class Application { e.printStackTrace(); } + LinkedList<String> stringsForPlotter = new LinkedList<>(); //Iterate through every String for (String expressionString: expressions) { System.out.println("Expression: " + expressionString); @@ -36,33 +54,26 @@ public class Application { List<Lexer.Token> tokens = Lexer.lex(expressionString); System.out.println("Lexer created tokens:"); //prints out each token to the console - int i = 0; + int index = 0; for(Lexer.Token token: tokens) { - System.out.println("[" + i + "]" + token.toString()); - i++; + System.out.println("[" + index + "]" + token.toString()); + index++; } //Parse all tokens with the parser and saves the result into the variable 'ast' Parser parser = new Parser(); Parser.Expression ast = parser.parse(tokens); + //Prints the ast out with an ASTPrinter //the result can later be used to show the ast in a function plotter ASTPrinter printer = new ASTPrinter(); System.out.println("Printing: '" + printer.visit(ast) + "'"); - Evaluator evaluator = new Evaluator(); - System.out.println(evaluator.visit(ast, 20)); - System.out.println(); + stringsForPlotter.add(printer.visit(ast)); + System.out.println("\n"); } catch (Exception e) { e.printStackTrace(); } - } - - /* - Evaluator evaluator = new Evaluator(); - String s = printer.visit(exp); - System.out.println("Evaluating: '" + evaluator.visit(exp) + "'"); - SwingFunctionPlotter.plotFunction(s); - }*/ + SwingFunctionPlotter.plotFunction(stringsForPlotter); } } diff --git a/src/main/Evaluator.java b/src/main/Evaluator.java index 62a37d883ebde622fb6df7821f1b14ac1d18e262..729ad83e1d19ea290b0ff1c4aac0bdc383e81dd3 100644 --- a/src/main/Evaluator.java +++ b/src/main/Evaluator.java @@ -3,10 +3,26 @@ package main; import java.util.LinkedList; import java.util.List; +/** + * <h1>Evaluator</h1> + * + * The Evaluator class calculates the value of an expression with a given value for its + * variables. With the visitor pattern it visits each node of the AST(Abstract Syntax Tree) and returns its values + * or performs a recursive call it its a BinaryOperation + * + * @version 1.0 + * @since 09.01.2023 + */ public class Evaluator implements Visitor<Double>{ + //This value will be used for all variables private int x; + /** + * + * @param binaryOP + * @return + */ @Override public Double visit(final Parser.BinaryOperation binaryOP) { @@ -34,8 +50,7 @@ public class Evaluator implements Visitor<Double>{ result *= rOperand; } else { - //*************************************************************************************** - result = ((Parser.BinaryOperation) binaryOP.rightExpression).accept(this, result, "*"); + } } else { @@ -50,8 +65,6 @@ public class Evaluator implements Visitor<Double>{ result /= rOperand; } else { - //*************************************************************************************** - result = ((Parser.BinaryOperation) binaryOP.rightExpression).accept(this, result, "/"); } } else { @@ -76,21 +89,42 @@ public class Evaluator implements Visitor<Double>{ return result; } + /** + * + * @param variable + * @return + */ @Override public Double visit(final Parser.Variable variable) { return variable.value * x; } + /** + * + * @param number + * @return + */ @Override public Double visit(final Parser.Number number) { return Double.valueOf(number.digits); } + /** + * + * @param decimal + * @return + */ @Override public Double visit(final Parser.Decimal decimal) { return Double.valueOf(decimal.afterDot.digits + "." + decimal.beforeDot.digits); } + /** + * Visits each node of a given expression + * @param ast A given expression that should be evaluated + * @param x This value will be used for all tokens of type Variable + * @return Returns the calculated value of the expression + */ public Double visit(final Parser.Expression ast, int x) { this.x = x; return ast.accept(this); diff --git a/src/main/Lexer.java b/src/main/Lexer.java index b76e27d8a754b223e06351de59391893e1b6b3a1..f3e5accfc52960c0eb58f828970dee61fb274ba9 100644 --- a/src/main/Lexer.java +++ b/src/main/Lexer.java @@ -6,16 +6,20 @@ import java.util.LinkedList; import java.util.List; /** - * <h1>The Lexer</h1> + * <h1>Lexer</h1> * The Lexer class crates a List of Token objects out of a String * * @version 1.0 * @since 09.01.2023 + * @see TokenType + * @see Token + * @see #lex(String) */ public class Lexer { /** * enum TokenType that can either be a number, variable or a special character (like * or / etc.) + * @see Lexer */ public static enum TokenType { NUMBER, VARIABLE, SPECIAL @@ -24,6 +28,7 @@ public class Lexer { /** * 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 + * @see Lexer */ public static class Token { protected TokenType type; @@ -50,8 +55,9 @@ public class Lexer { /** * creates a list of tokens from a given String * @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 + * @see Lexer */ public static List<Token> lex(String input) throws Exception{ if(input.isEmpty()) { diff --git a/src/main/Parser.java b/src/main/Parser.java index 73327dd15d8f99895299add833b2a35bcd6a1af6..85afada8dc675189672d5aa9d46a4e4673a24b69 100644 --- a/src/main/Parser.java +++ b/src/main/Parser.java @@ -6,7 +6,7 @@ import java.util.LinkedList; 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 * * @version 1.0 @@ -22,7 +22,6 @@ public class Parser { */ public abstract class Expression { public abstract <T> T accept(Visitor<T> visitor); - public abstract <T> T accept(Visitor<T> visitor, double leftValue, String operator); } /** @@ -41,15 +40,11 @@ public class Parser { this.rightExpression = rightExpression; this.capsuled = capsuled; } + @Override public <T> T accept(Visitor<T> visitor) { return visitor.visit(this); } - - public <T> T accept(Visitor<T> visitor, double leftValue, String operator) { - leftExpression.accept(visitor, leftValue, operator); - return visitor.visit(this); - } } /** @@ -66,15 +61,6 @@ public class Parser { public <T> T accept(Visitor<T> visitor) { 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); - } } /** @@ -89,22 +75,13 @@ public class Parser { * This class represents a number, it contains a String 'digits' that holds it value */ public class Number extends Value { - public String digits; + String digits; public Number(String i) { this.digits = i; } public <T> T accept(Visitor<T> visitor) { 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); - } } /** @@ -121,11 +98,6 @@ public class Parser { public <T> T accept(Visitor<T> visitor) { 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); - } } /** diff --git a/src/main/SwingFunctionPlotter.java b/src/main/SwingFunctionPlotter.java index d433aee2fe88e0274d6a01bbcb5e7ecea9a31d41..cd805de72294a090810159c0fd730c45c0a0969a 100644 --- a/src/main/SwingFunctionPlotter.java +++ b/src/main/SwingFunctionPlotter.java @@ -5,11 +5,27 @@ import com.mindfusion.charting.swing.LineChart; import javax.swing.*; 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 { 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() { public void run() { try { @@ -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); 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),2), 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(); FunctionSeries series1; try { series1 = new FunctionSeries(function,1000, -20, 20); - series1.setTitle("Current function"); + series1.setTitle("Function: " + function + "[" + index + "]"); lineChart.getSeries().add(series1); } catch(Exception e) {