Conversation
| * The Repl class implements a simple REPL. | ||
| * It supports addition and substraction including unary. | ||
| * It calculates the expressions like these: 4 + 6 - 8, 2 - 3 - 4 and so on. | ||
| * \help command explains these operations |
There was a problem hiding this comment.
Hello! Why do you use different types of slashes for different commands? In this project, we suppose to use the forward slash like jshell does.
There was a problem hiding this comment.
Hello, thank you very much for review. Instructions here https://hyperskill.org/projects/1/stages/3 requires to use \help but /exit. I just strictlly followed it) I fixed it in next commit.
There was a problem hiding this comment.
thanks, it is just a typo in the stage description! In this project, we chose slash for commands because it is used by jshell (since Java 9).
| /** | ||
| * The Repl class implements a simple REPL. | ||
| * It supports addition and substraction including unary. | ||
| * It calculates the expressions like these: 4 + 6 - 8, 2 - 3 - 4 and so on. |
There was a problem hiding this comment.
Now, It cannot calculate expressions without spaces: 2+8 -> Unsupported expression.
| if (line.contains("/") || line.contains("\\")) { | ||
| switch (line.trim()) { | ||
| case "/help": | ||
| System.out.println("Program calculates the expressions like these: 4 + 6 - 8, 2 - 3 - 4 and so on. It supports both unary and binary minuses. Enter '/exit' to terminate program."); |
There was a problem hiding this comment.
The terminate command is not /exit in your program, but the text prints it.
| * @param postfix arithmetic expression in postfix notation | ||
| * @return result of calculation | ||
| **/ | ||
| private static int calculatePostfix(String[] postfix) throws IllegalArgumentException { |
There was a problem hiding this comment.
You do not need to specify an unchecked exception in the method declaration. Usually, they are written in the Javadoc section @throws.
| * @param words arithmetic expression in infix notation | ||
| * @return expression in postfix notation | ||
| **/ | ||
| private static String[] infixToPostfix(String[] words) throws IllegalArgumentException { |
There was a problem hiding this comment.
It is a good idea to use postfix notation here. It allows you to support multiplication, division and brackets in future.
| String line = sc.nextLine(); | ||
|
|
||
| if (line != null && line.length() > 0) { | ||
| if (line.contains("/") || line.contains("\\")) { |
There was a problem hiding this comment.
Maybe it would be better to skip lines containing only spaces as well.
|
|
||
| /** | ||
| * Converts operations to unified form. | ||
| * E.g: --- = -, ++++ = +, -- = + etc. |
There was a problem hiding this comment.
Can you process the operations like "++-" like a simple "-"? As an example, the Python REPL does it.
| } | ||
|
|
||
|
|
||
| private static String[] lineToInfix(String line) throws IllegalArgumentException { |
There was a problem hiding this comment.
It is good that you decompose the program into a set of methods. You can also decompose it into a set of classes to make it easy to read and develop.
There was a problem hiding this comment.
I think it is a long line to read it.
There was a problem hiding this comment.
I've tried to decompose, but it is still look like spaghetti code. I would be grateful for the advice on decomposition.
There was a problem hiding this comment.
I would take some of the repetitive logic to a class like Utils. You can either create a separate file containing a public class, or declare it right here if it is not a public class.
public class Repl {
// ...
}
final class Utils {
private Utils() { }
// methods...
}
The class may contain a set of static methods which perform typical transformations of strings using regular expressions. You can also define patterns of regular expressions as static fields of this class. It is a quite popular approach.
You can also try to model the Expression as a class or interface with a single method evaluate(). Then you can extend or implement the class using a PostfixExpression with the overridden method to perform evaluation logic.
So, your main class will contain code only to read/output results.
But this is just one of many ways to decompose it as simple as possible.
By the way, we have added a new stage for this project. It uses the postfix notation like your program.
|
|
||
| for (String word : expr) { | ||
| if ((!word.matches("[0-9+-]+")) || (word.contains("-") && word.contains("+"))) throw new IllegalArgumentException("Unsupported expression: " + word); | ||
| if (word.matches("[\\+]+[0-9]+")) { |
There was a problem hiding this comment.
It may be better to use Pattern and Matcher if you take a regex multiple times because it has a better performance. The matches method of a string is often used when you need just match a string only once.
swsms
left a comment
There was a problem hiding this comment.
Good, but there are small remarks and recommendations.
|
|
||
| if (line != null && line.length() > 0 && line.trim().replace(" ","").length() > 0) { | ||
| //processing commands | ||
| if (line.contains("/")) { |
There was a problem hiding this comment.
It may be better to use startsWith(...) instead of contains(...).
| } | ||
|
|
||
| //This class represents an expression | ||
| class Expression { |
There was a problem hiding this comment.
I see you made a good decomposition! I wrote about it in the previous review.
|
|
||
|
|
||
| /** | ||
| * Evaluates arithmetic expression in postfix notation. |
There was a problem hiding this comment.
Note, there is a new stage describing this algorithm: https://hyperskill.org/projects/1/stages/21.
There was a problem hiding this comment.
We've added a new stage with large arithmetics to REPL.
There is a number of new projects as well:
Encryption-decryption: https://hyperskill.org/projects/12/
Online chat with networking: https://hyperskill.org/projects/13/
| * @return operation in unified form: + or - | ||
| * @throws IllegalArgumentException if operation can not be converted to unified form | ||
| **/ | ||
| private static String convertOperation (String word) throws IllegalArgumentException { |
There was a problem hiding this comment.
Usually, unchecked exceptions are not declared in a method declaration. But you can still catch them.
|
|
||
| //case for "assign" type of expression e.g. "x = ..." | ||
| if (expAssignsValueToVariable) { | ||
| //extract right side of an expression |
There was a problem hiding this comment.
I would hide this code in a separate private method to make this method more readable and concise.
| } | ||
| } else { | ||
| //substitute variables | ||
| substLine = substituteVariables(infixLine, variables); |
There was a problem hiding this comment.
I think, it is the "main" routine of this method and this code is short. You may read this topic.
| if (operator == null) throw new IllegalArgumentException("Unsupported operator NULL"); | ||
|
|
||
| //equals | ||
| Pattern pattern = Pattern.compile("^[=]*$"); |
There was a problem hiding this comment.
You can try to move all patterns to a special class like ExUtils as well as methods that checks/parses/etc strings.
There was a problem hiding this comment.
Partially implemented, thanks.
| private static final Pattern ALLOWED_CHARS = Pattern.compile("^[a-zA-Z0-9+-=*/()^]*$"); | ||
|
|
||
| //operator patterns | ||
| private static final Pattern EQUALS_PATTERN = Pattern.compile("^[=]*$"); |
There was a problem hiding this comment.
There is a set of good regexes!
No description provided.