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

Merge branch 'dominicsbranch' into 'main'

Dominicsbranch

See merge request !7
parents 2aca6157 2fd496f2
No related branches found
No related tags found
1 merge request!7Dominicsbranch
1 + xy^2 - (31 * x)y x+2/5223+y+44+4+2^12/222
1 + x^2 - (3 * x) \ No newline at end of file
2x + 0,5x^2 - 1
\ No newline at end of file
...@@ -2,36 +2,50 @@ import java.io.BufferedReader; ...@@ -2,36 +2,50 @@ import java.io.BufferedReader;
import java.io.FileReader; import java.io.FileReader;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
import java.util.LinkedList;
import java.util.List; import java.util.List;
public class Application { public class Application {
public static void main(String[] args) { public static void main(String[] args) {
//LinkedList<String> expressions = new LinkedList<>()
//LinkedList<String> expressions = new List<>();
List<String> expressions = new LinkedList<>();
//Reads the file "expressions.txt" and adds its values to a list
BufferedReader reader; BufferedReader reader;
String datapath = "expressions.txt"; String datapath = "expressions.txt";
try { try {
System.out.println("Reading the file:"); System.out.println("Reading the file...\n");
reader = new BufferedReader(new FileReader(datapath)); reader = new BufferedReader(new FileReader(datapath));
String line = reader.readLine(); String line = reader.readLine();
while(line != null) { while(line != null) {
System.out.println(line); expressions.add(line);
line = reader.readLine(); line = reader.readLine();
} }
System.out.println();
reader.close(); reader.close();
} }
catch (IOException e ) { catch (IOException e ) {
e.printStackTrace(); e.printStackTrace();
} }
//List with a fitting String to be parsed into multiple tokens
List<String> test = Arrays.asList("1 + xy^2 - (31 * x)y"); //Iterates through every String and parses them into multiple tokens
//Iterates through every String for (String value: expressions) {
for (String value: test) { System.out.println(value);
//creates a list of tokens out of the String //creates a list of tokens out of the String
List<Lexer.Token> tokens = Lexer.lex(value); List<Lexer.Token> tokens = Lexer.lex(value);
//prints each token out (with .toString()) //prints each token out (with .toString())
for(Lexer.Token singleToken: tokens) { for(Lexer.Token singleToken: tokens) {
System.out.println(singleToken.toString()); System.out.println(singleToken.toString());
} }
Parser parser = new Parser();
try {
parser.parse(tokens);
System.out.println();
}
catch (ParserException e) {
System.out.println(e.getMessage());
}
System.out.println();
} }
} }
} }
...@@ -47,6 +47,9 @@ public class Lexer { ...@@ -47,6 +47,9 @@ public class Lexer {
if(endIndex<input.length()) { if(endIndex<input.length()) {
while(Character.isDigit(input.charAt(endIndex)) && endIndex<input.length()) { while(Character.isDigit(input.charAt(endIndex)) && endIndex<input.length()) {
endIndex += 1; endIndex += 1;
if(endIndex==input.length()) {
break;
}
} }
} }
Token token = new Token(TokenType.NUMBER, input.substring(index,endIndex)); Token token = new Token(TokenType.NUMBER, input.substring(index,endIndex));
......
...@@ -4,29 +4,45 @@ import java.util.Optional; ...@@ -4,29 +4,45 @@ import java.util.Optional;
public class Parser { public class Parser {
private abstract interface Expression { private abstract class Expression {
} }
private abstract class Value implements Expression { private class BinaryOperation extends Expression {
Expression leftExpression;
String operator;
Expression rightExpression;
public BinaryOperation(Expression leftExpression, String operator, Expression rightExpression) {
this.leftExpression = leftExpression;
this.operator = operator;
this.rightExpression = rightExpression;
}
}
private class Variable extends Expression {
String variableName;
public Variable(String i) {
this.variableName = i;
}
}
private abstract class Value extends Expression {
} }
private class Number extends Value { private class Number extends Value {
public String original; public String digits;
public Number(String i) { public Number(String i) {
this.original = i; this.digits = i;
} }
} }
private class Decimal extends Value { private class Decimal extends Value {
public Number beforeDot; public Number beforeDot;
public char dot;
public Number afterDot; public Number afterDot;
public Decimal(Number i1, Number i2) { public Decimal(Number i1, Number i2) {
this.beforeDot = i1; this.beforeDot = i1;
dot = '.';
this.afterDot = i2; this.afterDot = i2;
} }
} }
...@@ -42,9 +58,8 @@ public class Parser { ...@@ -42,9 +58,8 @@ public class Parser {
Expression ast = parseExpression(ts); Expression ast = parseExpression(ts);
if(!ts.isEmpty()) { if(!ts.isEmpty()) {
throw new ParserException("SyntaxError: " + ts.size() + " Token(s) left"); throw new ParserException("RuntimeError: " + ts.size() + " token(s) left");
} }
return ast; return ast;
} }
...@@ -52,75 +67,111 @@ public class Parser { ...@@ -52,75 +67,111 @@ public class Parser {
//parses a list of tokens into an expression //parses a list of tokens into an expression
private Expression parseExpression(List<Lexer.Token> ts) throws ParserException { private Expression parseExpression(List<Lexer.Token> ts) throws ParserException {
if(ts.isEmpty()) { if(ts.isEmpty()) {
throw new ParserException("empty token list"); throw new ParserException("SyntaxError: empty token list");
}
Expression ast;
ast = parseBinaryOperation(ts);
if(ast==null) {
ast = parseVariable(ts);
if(ast==null) {
ast = parseValue(ts);
}
if(ast==null) {
throw new ParserException("SyntaxError: invalid character");
}
} }
return ast;
return parseValue(ts).orElseGet(() -> null);
} }
//checks if a String only contains an allowed operator with parseCharacter(...) //checks if a String only contains an allowed operator with parseCharacter(...)
private void parseOperator(String operator) throws ParserException { private Boolean parseOperator(String operator) throws ParserException {
if(operator.length()>1) { if(operator.length()>1) {
throw new ParserException("RuntimeException: invalid length for an operator: " + operator); throw new ParserException("SyntaxError: invalid length for an operator: " + operator);
}
if(!parseCharacter(operator, "+-*/^")) {
throw new ParserException("SyntaxError: invalid operator character: " + operator);
} }
parseCharacter(operator, "+-*/^"); return true;
} }
//called by methods parseOperator(...), parseDigit(...), parseDigitWithoutZero(...) private BinaryOperation parseBinaryOperation(List<Lexer.Token> ts) throws ParserException {
//checks if a certain string can be found in a string of allowed character if(ts.isEmpty()) {
//if yes: return true throw new ParserException("SyntaxError: empty token list");
//if not: a ParserException is thrown }
private Boolean parseCharacter(String data, String allowedCharacters) throws ParserException { if(ts.size()==1) {
if(!allowedCharacters.contains(data)) { return null;
throw new ParserException("SyntaxError: Invalid character: " + data); }
BinaryOperation operation;
if(ts.get(1).getType()!= Lexer.TokenType.SPECIAL) {
throw new ParserException("SyntaxError: unexpected operator: " + ts.get(1).getData());
}
List<Lexer.Token> leftList = new LinkedList<>();
leftList.add(ts.remove(0));
Expression leftExpression = parseExpression(leftList);
String operator = ts.remove(0).getData();
parseOperator(operator);
Expression rightExpression = parseExpression(ts);
return new BinaryOperation(leftExpression, operator, rightExpression);
}
private Variable parseVariable(List<Lexer.Token> ts) throws ParserException {
if (ts.isEmpty()) {
throw new ParserException("SyntaxError: empty token list");
} }
if(data.isEmpty()) { if (ts.get(0).getType() != Lexer.TokenType.VARIABLE) {
throw new ParserException("RuntimeException: empty String"); return null;
} }
return true;
String data = ts.remove(0).getData();
if (data.isEmpty()) {
throw new ParserException("SyntaxError: empty token");
}
if(!parseCharacter(data,"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")) {
throw new ParserException("Invalid variable character: " + data);
}
return new Variable(data);
} }
//called by method parseException(...) //called by method parseException(...)
//parses a list of tokens into a value //parses a token/list of tokens into a value
private Optional<Expression> 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("RuntimeException: empty token list"); throw new ParserException("SyntaxError: empty token list");
} }
if (ts.get(0).getType() != Lexer.TokenType.NUMBER) { if (ts.get(0).getType() != Lexer.TokenType.NUMBER) {
return Optional.empty(); return null;
} }
String data = ts.get(0).getData();
String data = ts.remove(0).getData();
if (data.isEmpty()) { if (data.isEmpty()) {
throw new ParserException("RuntimeException: empty token"); throw new ParserException("SyntaxError: empty token");
} }
if (ts.size()>0) { Value value = null;
if (ts.size()>1) {
//if the next token is of TokenType.SPECIAL, check if it's a comma //if the next token is of TokenType.SPECIAL, check if it's a comma
//if it is, create a decimal //if it is, create a decimal
if(ts.get(0).getType() == Lexer.TokenType.SPECIAL) { if(ts.get(0).getType() == Lexer.TokenType.SPECIAL) {
if(ts.size()>1) { if(parseComma(ts)) {
if(parseComma(ts.get(0).getData())) { value = parseDecimal(ts);
return Optional.of(parseDecimal(ts, data));
}
} }
} }
} }
//if the next token wasn't a comma, create a number if(value==null) {
return Optional.of(parseNumber(data)); value = parseNumber(ts.remove(0).getData());
}
return value;
} }
//called by method parseValue(...) //called by method parseValue(...)
//parses a decimal of a list of tokens & a string //parses a decimal of a list of tokens & a string
private Expression parseDecimal(List<Lexer.Token> ts, String data) throws ParserException { private Decimal parseDecimal(List<Lexer.Token> ts) throws ParserException {
if(ts.size()<1) { String data = ts.remove(0).getData();
throw new ParserException("RuntimeException: empty token list"); if(data.isEmpty()) {
} throw new ParserException("SyntaxError: empty data");
if(ts.get(0).getType() != Lexer.TokenType.SPECIAL) {
throw new ParserException("SyntaxException: expected a comma");
} }
if(ts.get(1).getType() != Lexer.TokenType.NUMBER) { if(ts.size()==0) {
throw new ParserException("SyntaxException: expected a number after a comma"); throw new ParserException("SyntaxError: no tokens left to create Decimal");
} }
Number beforeDot = (Number) parseNumber(data); Number beforeDot = (Number) parseNumber(data);
ts.remove(0); ts.remove(0);
...@@ -131,7 +182,7 @@ public class Parser { ...@@ -131,7 +182,7 @@ public class Parser {
//called by method parseValue(...) //called by method parseValue(...)
//parses a String into a number //parses a String into a number
private Expression parseNumber(String data) throws ParserException{ private Number parseNumber(String data) throws ParserException{
if (data.isEmpty()) { if (data.isEmpty()) {
throw new ParserException("RuntimeException: empty token"); throw new ParserException("RuntimeException: empty token");
} }
...@@ -149,7 +200,10 @@ public class Parser { ...@@ -149,7 +200,10 @@ public class Parser {
//checks if a String only contains numbers(including zero) with parseCharacter(...) //checks if a String only contains numbers(including zero) with parseCharacter(...)
private void parseDigit(String data) throws ParserException { private void parseDigit(String data) throws ParserException {
for(int index=1; index<data.length(); index++) { for(int index=1; index<data.length(); index++) {
parseCharacter(Character.toString(data.charAt(index)), "0123456789"); String character = Character.toString(data.charAt(index));
if(!parseCharacter(character, "0123456789")) {
throw new ParserException("SyntaxError: unexpected character: " + character);
}
} }
} }
...@@ -157,11 +211,40 @@ public class Parser { ...@@ -157,11 +211,40 @@ public class Parser {
//checks if a String only contains numbers(excluding zero) with parseCharacter(...) //checks if a String only contains numbers(excluding zero) with parseCharacter(...)
private void parseDigitWithoutZero(String data) throws ParserException { private void parseDigitWithoutZero(String data) throws ParserException {
for(int index=1; index<data.length(); index++) { for(int index=1; index<data.length(); index++) {
parseCharacter(Character.toString(data.charAt(index)),"123456789"); String character = Character.toString(data.charAt(index));
if(!parseCharacter(character, "123456789")) {
throw new ParserException("SyntaxError: unexpected character: " + character);
}
} }
} }
private Boolean parseComma(String data) throws ParserException { private Boolean parseComma(List<Lexer.Token> ts) throws ParserException {
return true; String data = ts.get(0).getData();
if(parseCharacter(data, ".")) {
if(ts.get(1).getType()!= Lexer.TokenType.NUMBER) {
throw new ParserException("SyntaxError: no number after comma");
}
return true;
}
return false;
}
private Boolean parseBracket(List<Lexer.Token> ts) throws ParserException {
String data = ts.get(0).getData();
if(parseCharacter(data, "(")) {
return true;
}
else {
return false;
}
}
//called by methods parseOperator(...), parseDigit(...), parseDigitWithoutZero(...)
//checks if a certain string can be found in a string of allowed character
private Boolean parseCharacter(String data, String allowedCharacters) throws ParserException {
if(data.isEmpty()) {
throw new ParserException("RuntimeError: empty String");
}
return (allowedCharacters.contains(data));
} }
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment