From 2fd496f28f1ef0483eac9a37d649a170618da6ab Mon Sep 17 00:00:00 2001 From: Kraemerd <Dominic_Daniel.Kraemer@Student.Reutlingen-University.de> Date: Sun, 8 Jan 2023 17:50:55 +0100 Subject: [PATCH] fixed a bug in lexer.java, implemented whole parser(except brackets) --- expressions.txt | 4 +- src/Application.java | 28 ++++-- src/Lexer.java | 3 + src/Parser.java | 201 ++++++++++++++++++++++--------------------- 4 files changed, 126 insertions(+), 110 deletions(-) diff --git a/expressions.txt b/expressions.txt index e06786f..f46bda3 100644 --- a/expressions.txt +++ b/expressions.txt @@ -1,3 +1 @@ -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 diff --git a/src/Application.java b/src/Application.java index dedb78a..f8ac1ee 100644 --- a/src/Application.java +++ b/src/Application.java @@ -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(); } } } diff --git a/src/Lexer.java b/src/Lexer.java index a61e4cc..a65c71b 100644 --- a/src/Lexer.java +++ b/src/Lexer.java @@ -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)); diff --git a/src/Parser.java b/src/Parser.java index 6f2e753..85c780c 100644 --- a/src/Parser.java +++ b/src/Parser.java @@ -10,13 +10,17 @@ public class Parser { private class BinaryOperation extends Expression { Expression leftExpression; - char operator; + 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; } @@ -27,9 +31,9 @@ public class Parser { } private class Number extends Value { - public String original; + public String digits; public Number(String i) { - this.original = i; + this.digits = i; } } @@ -54,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; } @@ -64,145 +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 null; - //return parseValue(ts).orElseGet(() -> parseVariable(ts).orElseGet(() -> null)); + return ast; } //checks if a String only contains an allowed operator with parseCharacter(...) private Boolean parseOperator(String operator) throws ParserException { if(operator.length()>1) { - throw new ParserException("RuntimeException: invalid length for an operator: " + 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); + throw new ParserException("SyntaxError: invalid length for an operator: " + operator); } - if(data.isEmpty()) { - throw new ParserException("RuntimeException: empty String"); + if(!parseCharacter(operator, "+-*/^")) { + throw new ParserException("SyntaxError: invalid operator character: " + operator); } return true; } - private Optional<BinaryOperation> parseBinaryOperation(List<Lexer.Token> ts) throws ParserException { - if(ts.get(0).getType()!=Lexer.TokenType.SPECIAL) { - throw new ParserException("SyntaxError: expected bracket, got " + ts.get(0).getData() + " instead"); + private BinaryOperation parseBinaryOperation(List<Lexer.Token> ts) throws ParserException { + if(ts.isEmpty()) { + throw new ParserException("SyntaxError: empty token list"); } - String lbracket = ts.remove(0).getData(); - parseCharacter(lbracket, "("); - int i; - boolean found = false; - //check for bracket - /* - for(i=0; i<ts.size(); i++) { - if(ts.get(0).getType() == Lexer.TokenType.SPECIAL) { - int rightBrackets = 0; - int leftBrackets = 0; - if(parseCharacter(ts.get(0).getData(),"(")) { - leftBrackets += 1; - } - else if(parseCharacter(ts.get(0).getData(),")")) { - rightBrackets += 1; - if(rightBrackets>leftBrackets) { - found = true; - break; - } - } - - } + if(ts.size()==1) { + return null; } - if(!found) { - throw new ParserException("SyntaxError: no matching bracket was found"); + 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<>(); - //check for operator - for(i=0; i<ts.size(); i++) { - leftList.add(ts.remove(i)); - if(parseOperator(ts.get(i).getData())) { - break; - } - } - ts.remove(0); - if(ts.size()==0) { - throw new ParserException("SyntaxError: could not find a matching operator"); - } - + leftList.add(ts.remove(0)); Expression leftExpression = parseExpression(leftList); + String operator = ts.remove(0).getData(); + parseOperator(operator); Expression rightExpression = parseExpression(ts); - return null; + return new BinaryOperation(leftExpression, operator, rightExpression); } - private Optional<Variable> parseVariable(List<Lexer.Token> ts) throws ParserException { + private Variable parseVariable(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.VARIABLE) { - return Optional.empty(); + return null; } String data = ts.remove(0).getData(); if (data.isEmpty()) { - throw new ParserException("RuntimException: empty token"); + throw new ParserException("SyntaxError: empty token"); } - parseCharacter(data,"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"); - return Optional.of(new Variable(data)); + 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<Value> 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 Decimal 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); @@ -231,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); + } } } @@ -239,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)); } } -- GitLab