如下是使用递归下降方法解析基本四则运算的parser
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
public class Main {
public static void main(String[] args) {
String source = "3 + 4 * 5";
Lexer lexer = new Lexer(source.toCharArray());
Token token = lexer.read();
while (token != EOL) {
System.out.println("=> " + token);
System.out.println("peek => " + lexer.peek(0));
token = lexer.read();
}
Parser parser = new Parser(source);
Node ast = parser.expression();
System.out.println("ast: " + ast);
int ret = eval(ast);
System.out.println("ret:" + ret);
}
static class Token {
String value;
int type; // 1 number 2 op
public Token(String value, int type) {
this.value = value;
this.type = type;
}
public Token(char ch, int type) {
this.value = Character.toString(ch);
this.type = type;
}
@Override
public String toString() {
return "Token{" +
"value='" + value + '\'' +
", type=" + type +
'}';
}
}
public static Token EOL = new Token("EOL", 0);
static class Lexer {
char[] chars;
int len;
int index;
boolean hasMore;
List queue;
public Lexer(char[] chars) {
this.chars = chars;
this.len = chars.length;
this.index = 0;
hasMore = true;
this.queue = new ArrayList<>();
}
public Token read() {
fillQueue(1);
if (this.queue.isEmpty()) {
return EOL;
}
return this.queue.remove(0);
}
public Token peek(int i) {
fillQueue(i + 1);
if (i >= this.queue.size()) {
return EOL;
}
return this.queue.get(i);
}
private void fillQueue(int i) {
while (hasMore && this.queue.size() < i) {
addToken();
}
}
private void addToken() {
if (index >= chars.length) {
hasMore = false;
return;
}
// 跳过空白字符
while (isSpace(chars[index])) {
index++;
}
Token token = null;
char lookaheadChar = chars[index];
if (isDigit(lookaheadChar)) {
StringBuilder sb = new StringBuilder();
while (index < this.len && isDigit(chars[index])) {
sb.append(chars[index++]);
}
token = new Token(sb.toString(), 1);
} else if (isOperator(lookaheadChar)) {
token = new Token(chars[index++], 2);
} else if (isParenthesis(lookaheadChar)) {
token = new Token(chars[index++], 2);
} else {
throw new RuntimeException("unknown token");
}
queue.add(token);
}
public boolean isDigit(char ch) {
return '0' <= ch && ch <= '9';
}
public boolean isSpace(char ch) {
return ch == ' ';
}
public boolean isOperator(char ch) {
return ch == '+' || ch == '-' || ch == '*' || ch == '/';
}
public boolean isParenthesis(char ch) {
return ch == '(' || ch == ')';
}
}
static abstract class Node {
}
static int eval(Node ast) {
if (ast instanceof Number) {
return ((Number) ast).num;
} else if (ast instanceof Expression) {
Expression exp = (Expression) ast;
int left = eval(exp.left);
int right = eval(exp.right);
switch (exp.op) {
case '+':
return left + right;
case '-':
return left - right;
case '*':
return left * right;
case '/':
return left / right;
default:
throw new RuntimeException("unknown operator");
}
} else {
throw new RuntimeException("don't support eval " + ast);
}
}
static class Number extends Node {
int num;
public Number(int num) {
this.num = num;
}
@Override
public String toString() {
return Integer.toString(num);
}
}
static class Expression extends Node {
Node left;
char op;
Node right;
public Expression(Node left, char op, Node right) {
this.left = left;
this.op = op;
this.right = right;
}
@Override
public String toString() {
String ret = "(";
if (left instanceof Number) {
ret += left;
} else if (left instanceof Expression) {
Expression leftExp = (Expression) left;
ret += "(" + leftExp.left + " " + leftExp.op + " " + leftExp.right + ")";
}
ret += " " + op + " ";
if (right instanceof Number) {
ret += right;
} else if (right instanceof Expression) {
Expression rightExp = (Expression) right;
ret += "(" + rightExp.left + " " + rightExp.op + " " + rightExp.right + ")";
}
return ret + ")";
}
}
static class Parser {
Lexer lexer;
public Parser(String source) {
lexer = new Lexer(source.toCharArray());
}
public Node expression() {
Node left = term();
if (isToken("+") || isToken("-")) {
String op = lexer.read().value; // read +/-
Node right = term();
return new Expression(left, op.charAt(0), right);
}
return left;
}
public Node term() {
Node left = factor();
if (isToken("*") || isToken("/")) {
String op = lexer.read().value; // read *//
Node right = factor();
return new Expression(left, op.charAt(0), right);
}
return left;
}
public Node factor() {
if (isToken("(")) {
lexer.read(); // skip left (
Node exp = expression();
lexer.read(); // skip right )
return exp;
} else {
Token token = lexer.read();
if (token.type == 1) {
int val = Integer.parseInt(token.value);
return new Number(val);
} else {
throw new RuntimeException("syntax error: " + token);
}
}
}
public boolean isToken(String name) {
Token token = lexer.peek(0);
return token.type == 2 && token.value.equals(name);
}
}
}
程序运行结果如下: