Last active
February 24, 2020 17:31
-
-
Save iamcsharper/7eb34c41561d688c444dae26f74f1040 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.ArrayList; | |
import java.util.HashMap; | |
import java.util.List; | |
import java.util.Map; | |
import java.util.Random; | |
import java.util.regex.Matcher; | |
import java.util.regex.Pattern; | |
/** | |
RDP calculator (function evaluator) | |
@author Yurchenko Ilya | |
@date 24.02.2020 | |
**/ | |
public class Parser { | |
public class Result { | |
Double num; | |
String rest; | |
public Result(Double num, String rest) { | |
this.num = num; | |
this.rest = rest; | |
} | |
} | |
Map<String, Double> vars = new HashMap<String, Double>(); | |
public Parser() { | |
} | |
public void setVariable(String var, Double value) { | |
this.vars.put(var, value); | |
} | |
public Double getVariable(String var) { | |
return this.vars.get(var); | |
} | |
public Result add(String s) throws Exception { | |
Result current = this.sub(s); | |
Double num = current.num; | |
while (current.rest.length() > 0) { | |
if (!current.rest.substring(0, 1).equals("+")) { | |
break; | |
} | |
String next = current.rest.substring(1); | |
current = this.sub(next); | |
num = num + current.num; | |
} | |
return new Result(num, current.rest); | |
} | |
public Result sub(String s) throws Exception { | |
Result current = this.mul(s); | |
Double num = current.num; | |
while (current.rest.length() > 0) { | |
if (!current.rest.substring(0, 1).equals("-")) { | |
break; | |
} | |
String next = current.rest.substring(1); | |
current = this.mul(next); | |
num = num - current.num; | |
} | |
return new Result(num, current.rest); | |
} | |
public Result mul(String s) throws Exception { | |
Result current = this.div(s); | |
Double num = current.num; | |
while (current.rest.length() > 0) { | |
if (!current.rest.substring(0, 1).equals("*")) { | |
break; | |
} | |
String next = current.rest.substring(1); | |
current = this.div(next); | |
num = num * current.num; | |
} | |
return new Result(num, current.rest); | |
} | |
public Result div(String s) throws Exception { | |
Result current = this.exp(s); | |
Double num = current.num; | |
while (current.rest.length() > 0) { | |
if (!current.rest.substring(0, 1).equals("/")) { | |
break; | |
} | |
String next = current.rest.substring(1); | |
current = this.exp(next); | |
num = num / current.num; | |
} | |
return new Result(num, current.rest); | |
} | |
public Result exp(String s) throws Exception { | |
Result current = this.brackets(s); | |
Double num = current.num; | |
while (current.rest.length() > 0) { | |
if (!current.rest.substring(0, 1).equals("^")) { | |
break; | |
} | |
String next = current.rest.substring(1); | |
current = this.brackets(next); | |
num = Math.pow(num, current.num); | |
} | |
return new Result(num, current.rest); | |
} | |
public Result brackets(String s) throws Exception { | |
if (s.charAt(0) == '(') { | |
Result result = this.add(s.substring(1)); | |
if (result.rest.length() > 0 && result.rest.charAt(0) == ')') { | |
result.rest = result.rest.substring(1); | |
} else { | |
throw new Exception("Missed right parenthesis " + s); | |
} | |
return result; | |
} | |
return this.sin(s); | |
} | |
public Result sin(String s) throws Exception { | |
Matcher matcher = Pattern.compile("^[sin]+[\\(]+.+").matcher(s); | |
if (matcher.find()) { | |
// System.out.println("Functions: " + s); | |
// System.out.println("Functions found: " + matcher.group()); | |
Result result = this.add(s.substring(4)); //length("sin(") = 4 | |
if (result.rest.length() > 0 && result.rest.charAt(0) == ')') { | |
result.rest = result.rest.substring(1); | |
} else { | |
throw new Exception("Missed right parenthesis " + s); | |
} | |
result.num = Math.sin(result.num); | |
return result; | |
} | |
return this.cos(s); | |
} | |
public Result cos(String s) throws Exception { | |
Matcher matcher = Pattern.compile("^[cos]+[\\(]+.+").matcher(s); | |
if (matcher.find()) { | |
// System.out.println("Functions: " + s); | |
// System.out.println("Functions found: " + matcher.group()); | |
Result result = this.add(s.substring(4)); //length("sin(") = 4 | |
if (result.rest.length() > 0 && result.rest.charAt(0) == ')') { | |
result.rest = result.rest.substring(1); | |
} else { | |
throw new Exception("Missed right parenthesis " + s); | |
} | |
result.num = Math.cos(result.num); | |
return result; | |
} | |
return this.expFunc(s); | |
} | |
public Result expFunc(String s) throws Exception { | |
Matcher matcher = Pattern.compile("^[exp]+[\\(]+.+").matcher(s); | |
if (matcher.find()) { | |
// System.out.println("Functions: " + s); | |
// System.out.println("Functions found: " + matcher.group()); | |
Result result = this.add(s.substring(4)); //length("sin(") = 4 | |
if (result.rest.length() > 0 && result.rest.charAt(0) == ')') { | |
result.rest = result.rest.substring(1); | |
} else { | |
throw new Exception("Missed right parenthesis " + s); | |
} | |
result.num = Math.exp(result.num); | |
return result; | |
} | |
return this.rand(s); | |
} | |
public Result rand(String s) throws Exception { | |
Matcher matcher = Pattern.compile("^[rand]+[\\(]+[\\\\)]").matcher(s); | |
if (matcher.find()) { | |
// System.out.println("Functions: " + s); | |
// System.out.println("Functions found: " + matcher.group()); | |
Result result = new Result(new Random().nextDouble(), s.substring(6)); | |
return result; | |
} | |
return this.variables(s); | |
} | |
public Result variables(String s) throws Exception { | |
String f = ""; | |
int sign = 1; | |
int i = 0; | |
if (s.charAt(0) == '-') { | |
i = 1; | |
sign = -1; | |
} | |
while (i < s.length()) { | |
char letter = s.charAt(i); | |
if (!this.isLetter("" + letter)) { | |
i--; | |
break; | |
} | |
f += letter; | |
i++; | |
} | |
String sub; | |
if (sign == -1) { | |
sub = s.substring(2); | |
} else { | |
sub = s.substring(1); | |
} | |
if (sub.length() != s.length()) | |
return new Result(sign*this.getVariable(f), sub); | |
return this.constant(s); | |
} | |
public Result constant(String s) throws Exception { | |
String regex = "^((\\+|-)?([0-9]+)(\\.[0-9]+)?)|((\\+|-)?\\.?[0-9]+)"; | |
Matcher matcher = Pattern.compile(regex).matcher(s); | |
if (matcher.find()) { | |
String group = matcher.group(); | |
return new Result(Double.valueOf(group), s.substring(group.length())); | |
} else { | |
return new Result(null, s); | |
} | |
} | |
public List<String> findVariables(String s) { | |
List<String> result = new ArrayList<>(); | |
int i = 0; | |
while (i < s.length()) { | |
String letter = "" + s.charAt(i); | |
if (this.isLetter(letter) && result.indexOf(letter) < 0) { | |
result.add(letter); | |
} | |
i++; | |
} | |
return result; | |
} | |
public boolean isLetter(String c) { | |
c = c.toLowerCase(); | |
return c != c.toUpperCase(); | |
} | |
public Double eval(String str) throws Exception { | |
Result result = this.add(str); | |
if (result.rest.length() > 0) { | |
throw new Exception("Can't parse. Left unclosed: " + result.rest); | |
} | |
return result.num; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is my simple implementation of recursive descent parser in terms of basic math functions.
Now you can use it with that code: