Created
June 27, 2020 09:20
-
-
Save ezksd/fc3da994c668abbabebb6a08e2fa1e9a 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
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