Skip to content

Instantly share code, notes, and snippets.

@ezksd
Created June 27, 2020 09:20
Show Gist options
  • Save ezksd/fc3da994c668abbabebb6a08e2fa1e9a to your computer and use it in GitHub Desktop.
Save ezksd/fc3da994c668abbabebb6a08e2fa1e9a to your computer and use it in GitHub Desktop.
package com.company;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
record Tuple<A,B>(A a,B b){}
interface Token { }
record Number(int i) implements Token{ }
enum Operator implements Token{
ADD,MINUS,MULTIPLY,DIVIDED
}
enum Bracket implements Token{
LEFT,RIGHT;
}
public class Caculator {
static Optional<List<Token>> parseAll(String s) {
var i = 0;
var list = new LinkedList<Token>();
while (i < s.length()) {
var r = parse(s, i);
if (r.isPresent()) {
list.add(r.get().a());
i = r.get().b();
} else {
return Optional.empty();
}
}
return Optional.of(list);
}
static Optional<Tuple<Token, Integer>> parse(String s, int p) {
var c = s.charAt(p);
return switch (c) {
case '(' -> Optional.of(new Tuple<>(Bracket.LEFT, p + 1));
case ')' -> Optional.of(new Tuple<>(Bracket.RIGHT, p + 1));
case '*' -> Optional.of(new Tuple<>(Operator.MULTIPLY, p + 1));
case '/' -> Optional.of(new Tuple<>(Operator.DIVIDED, p + 1));
case '+' -> Optional.of(new Tuple<>(Operator.ADD, p + 1));
case '-' -> Optional.of(new Tuple<>(Operator.MINUS, p + 1));
default -> parseNumber(s, p);
};
}
static Optional<Tuple<Token, Integer>> parseNumber(String s, int p) {
int i = 0;
if (!Character.isDigit(s.charAt(p))){
return Optional.empty();
}
while (p < s.length() && Character.isDigit(s.charAt(p))) {
i = i * 10 + (s.charAt(p++) - '0');
}
return Optional.of(new Tuple<>(new Number(i), p));
}
static Optional<Double> caculate(List<Token> tokens) {
var list = new ArrayList<Token>(tokens.size());
list.addAll(tokens);
return expr(list,0).map(Tuple::a);
}
static Optional<Tuple<Double,Integer>> expr(List<Token> list,int p){
var term = term(list, p);
return term.flatMap(x ->{
var tuples = expr1(list, x.b());
return tuples.map(xs -> {
double s = x.a();
for (var tuple : xs.a()) {
switch (tuple.a()) {
case ADD -> s += tuple.b();
case MINUS -> s -= tuple.b();
default -> throw new UnsupportedOperationException();
}
}
return new Tuple<>(s, xs.b());
});
});
}
static Optional<Tuple<List<Tuple<Operator, Double>>, Integer>> expr1(List<Token> list, int p){
var result = new LinkedList<Tuple<Operator,Double>>();
while (p < list.size()) {
var token = list.get(p);
var term = term(list, p + 1);
if(term.isPresent() && (token == Operator.ADD || token == Operator.MINUS)){
result.add(new Tuple<>((Operator)token, term.get().a()));
p = p + 2;
}else {
break;
}
}
return Optional.of(new Tuple<>(result, p));
}
static Optional<Tuple<Double,Integer>> term(List<Token> list,int p){
var digit = digit(list, p);
return digit.flatMap(x -> {
var tuples = term1(list, x.b());
return tuples.map(xs -> {
double s = x.a();
for (Tuple<Operator, Double> tuple : xs.a()) {
switch (tuple.a()) {
case MULTIPLY -> s *= tuple.b();
case DIVIDED -> s /= tuple.b();
default -> throw new UnsupportedOperationException();
}
}
return new Tuple<>(s,xs.b());
});
});
}
static Optional<Tuple<List<Tuple<Operator,Double>>,Integer>> term1(List<Token> list,int p){
var result = new LinkedList<Tuple<Operator,Double>>();
while (p < list.size()) {
var token = list.get(p);
var term = digit(list, p + 1);
if(term.isPresent() && (token == Operator.MULTIPLY || token == Operator.DIVIDED)){
result.add(new Tuple<>((Operator)token, term.get().a()));
p = p + 2;
}else {
break;
}
}
return Optional.of(new Tuple<>(result, p));
}
static Optional<Tuple<Double, Integer>> digit(List<Token> list, int p) {
if (p < list.size()){
var t = list.get(p);
if (t instanceof Number)
return Optional.of(new Tuple<>(((double) ((Number) list.get(p)).i()), p + 1));
else if(t == Bracket.LEFT){
return expr(list, p + 1).flatMap(x -> {
if (x.b() < list.size() && list.get(x.b()) == Bracket.RIGHT) {
return Optional.of(new Tuple<>(x.a(), x.b() + 1));
}else {
return Optional.empty();
}
});
}
}
return Optional.empty();
}
public static void main(String[] args) {
Optional<List<Token>> tokens1 = parseAll("123+(456+312)*2");
Optional<Double> aDouble = tokens1.flatMap(Caculator::caculate);
aDouble.ifPresent(System.out::println);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment