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
1 + x^2 - (3 * x)
2x + 0,5x^2 - 1
\ No newline at end of file
x+2/5223+y+44+4+2^12/222
\ No newline at end of file
......@@ -2,36 +2,50 @@ import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
public class Application {
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;
String datapath = "expressions.txt";
try {
System.out.println("Reading the file:");
System.out.println("Reading the file...\n");
reader = new BufferedReader(new FileReader(datapath));
String line = reader.readLine();
while(line != null) {
System.out.println(line);
expressions.add(line);
line = reader.readLine();
}
System.out.println();
reader.close();
}
catch (IOException e ) {
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
for (String value: test) {
//Iterates through every String and parses them into multiple tokens
for (String value: expressions) {
System.out.println(value);
//creates a list of tokens out of the String
List<Lexer.Token> tokens = Lexer.lex(value);
//prints each token out (with .toString())
for(Lexer.Token singleToken: tokens) {
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 {
if(endIndex<input.length()) {
while(Character.isDigit(input.charAt(endIndex)) && endIndex<input.length()) {
endIndex += 1;
if(endIndex==input.length()) {
break;
}
}
}
Token token = new Token(TokenType.NUMBER, input.substring(index,endIndex));
......
......@@ -4,29 +4,45 @@ import java.util.Optional;
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 {
public String original;
public String digits;
public Number(String i) {
this.original = i;
this.digits = i;
}
}
private class Decimal extends Value {
public Number beforeDot;
public char dot;
public Number afterDot;
public Decimal(Number i1, Number i2) {
this.beforeDot = i1;
dot = '.';
this.afterDot = i2;
}
}
......@@ -42,9 +58,8 @@ public class Parser {
Expression ast = parseExpression(ts);
if(!ts.isEmpty()) {
throw new ParserException("SyntaxError: " + ts.size() + " Token(s) left");
throw new ParserException("RuntimeError: " + ts.size() + " token(s) left");
}
return ast;
}
......@@ -52,75 +67,111 @@ public class Parser {
//parses a list of tokens into an expression
private Expression parseExpression(List<Lexer.Token> ts) throws ParserException {
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 parseValue(ts).orElseGet(() -> null);
return ast;
}
//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) {
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(...)
//checks if a certain string can be found in a string of allowed character
//if yes: return true
//if not: a ParserException is thrown
private Boolean parseCharacter(String data, String allowedCharacters) throws ParserException {
if(!allowedCharacters.contains(data)) {
throw new ParserException("SyntaxError: Invalid character: " + data);
private BinaryOperation parseBinaryOperation(List<Lexer.Token> ts) throws ParserException {
if(ts.isEmpty()) {
throw new ParserException("SyntaxError: empty token list");
}
if(ts.size()==1) {
return null;
}
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()) {
throw new ParserException("RuntimeException: empty String");
if (ts.get(0).getType() != Lexer.TokenType.VARIABLE) {
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(...)
//parses a list of tokens into a value
private Optional<Expression> parseValue(List<Lexer.Token> ts) throws ParserException {
//parses a token/list of tokens into a value
private Value parseValue(List<Lexer.Token> ts) throws ParserException {
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) {
return Optional.empty();
return null;
}
String data = ts.remove(0).getData();
String data = ts.get(0).getData();
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 it is, create a decimal
if(ts.get(0).getType() == Lexer.TokenType.SPECIAL) {
if(ts.size()>1) {
if(parseComma(ts.get(0).getData())) {
return Optional.of(parseDecimal(ts, data));
}
if(parseComma(ts)) {
value = parseDecimal(ts);
}
}
}
//if the next token wasn't a comma, create a number
return Optional.of(parseNumber(data));
if(value==null) {
value = parseNumber(ts.remove(0).getData());
}
return value;
}
//called by method parseValue(...)
//parses a decimal of a list of tokens & a string
private Expression parseDecimal(List<Lexer.Token> ts, String data) throws ParserException {
if(ts.size()<1) {
throw new ParserException("RuntimeException: empty token list");
}
if(ts.get(0).getType() != Lexer.TokenType.SPECIAL) {
throw new ParserException("SyntaxException: expected a comma");
private Decimal parseDecimal(List<Lexer.Token> ts) throws ParserException {
String data = ts.remove(0).getData();
if(data.isEmpty()) {
throw new ParserException("SyntaxError: empty data");
}
if(ts.get(1).getType() != Lexer.TokenType.NUMBER) {
throw new ParserException("SyntaxException: expected a number after a comma");
if(ts.size()==0) {
throw new ParserException("SyntaxError: no tokens left to create Decimal");
}
Number beforeDot = (Number) parseNumber(data);
ts.remove(0);
......@@ -131,7 +182,7 @@ public class Parser {
//called by method parseValue(...)
//parses a String into a number
private Expression parseNumber(String data) throws ParserException{
private Number parseNumber(String data) throws ParserException{
if (data.isEmpty()) {
throw new ParserException("RuntimeException: empty token");
}
......@@ -149,7 +200,10 @@ public class Parser {
//checks if a String only contains numbers(including zero) with parseCharacter(...)
private void parseDigit(String data) throws ParserException {
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 {
//checks if a String only contains numbers(excluding zero) with parseCharacter(...)
private void parseDigitWithoutZero(String data) throws ParserException {
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 {
return true;
private Boolean parseComma(List<Lexer.Token> ts) throws ParserException {
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