Skip to content

Instantly share code, notes, and snippets.

@iamcsharper
Last active February 24, 2020 17:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save iamcsharper/7eb34c41561d688c444dae26f74f1040 to your computer and use it in GitHub Desktop.
Save iamcsharper/7eb34c41561d688c444dae26f74f1040 to your computer and use it in GitHub Desktop.
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;
}
}
@iamcsharper
Copy link
Author

iamcsharper commented Feb 24, 2020

This is my simple implementation of recursive descent parser in terms of basic math functions.

Now you can use it with that code:

public class Main {

	public static void main(String[] args) {
		Parser parser = new Parser();
		String function = "exp(-x)";
		double x = 1.2;

		try {
			parser.setVariable("x", x);

			double f = parser.eval(function);

			System.out.println("x=" + x + " f(x) = " + f);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment