JavaCC(Java Compiler Compiler)是一个用JAVA开发的语法分析生成器。
特点如下:

  • LL(k)
  • 支持指定长度的 look-ahead
  • look-ahead可以内嵌表达式
  • 类似YACC,在模板文件中嵌套代码
  • 生成后的代码不再依赖任何第三方库

四则运算的语法如下:

1
2
3
expr : term | expr ('+' | '-') term
term : pri  | term ('*' | '/') pri
pri  : INT | '(' expr ')' | -INT 

上面的语法是左递归的,改成非左递归的如下:

1
2
3
4
5
expr : term expr' 
expr': ('+' | '-') term expr' | ε
term : pri term'
term': ('*' | '/') pri term'  | ε
pri  : INT  | '(' expr ')' | -INT

Calculator.jj 代码如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
options {
    STATIC = false;
    DEBUG_PARSER = true;
    UNICODE_INPUT = true;
    JDK_VERSION = "1.8";
}

PARSER_BEGIN(Calculator)

package com.test;
import java.io.*;

public class Calculator {

    public Calculator(String expr){
         this(new StringReader(expr));
    }
}

PARSER_END(Calculator)

SPECIAL_TOKEN : {" "}

TOKEN : {
        <ADD : "+" >
    |   <SUB : "-" >
    |   <MUL : "*" >
    |   <DIV : "/" >
}

TOKEN : {
        < NUMBER : < DIGITS> | < DIGITS> "." < DIGITS>  >
    |   < #DIGITS : ([ "0"-"9" ])+ >
}

TOKEN : {
        < LEFT_PAR : "(">
     |  < RIGHT_PAR : ")">
}
SPECIAL_TOKEN : { < EOL : "\n" | "\r" | "\r\n"> }

double expr() : {
	double left;
	double right;
}
{
	left = term()
	(
	  < ADD > right = term() { left = left + right; }
	| < SUB > right = term() { left = left - right; }
	)*
	{ return left; }
}

double term() : {
	double left = 0D;
	double right = 0D;
}
{
	left = pri()
	(
	  < MUL > right = pri() { left = left * right;}
	| < DIV > right = pri() { left = left / right;}
	)*
	{ return left;}
}

double pri() : {
	Token t;
	double val;
}
{
  try {
	  t = < NUMBER > { return Double.parseDouble(t.image); }
    |  < LEFT_PAR> val = expr() < RIGHT_PAR> { return val;}
    |  < SUB > val = pri() { return -val;}
  } catch(Exception e) {
    e.printStackTrace();
  }
}

编译上述 语法文件,命令如下:

1
javacc Calculator.jj

打印输出:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
Java Compiler Compiler Version 7.0.10 (Parser Generator)
(type "javacc" with no arguments for help)
Reading from file Calculator.jj . . .
Note: UNICODE_INPUT option is specified. Please make sure you create the parser/lexer using a Reader with the correct ch
aracter encoding.
File "TokenMgrError.java" is being rebuilt.
File "ParseException.java" is being rebuilt.
File "Token.java" is being rebuilt.
File "SimpleCharStream.java" is being rebuilt.
Parser generated successfully.

测试代码:

1
2
3
4
5
6
    public static void main(String[] args)throws Exception {
        String str = "1 + 2 * 3 - (4 + 5 / 6 - 7 * 8) + 9 - 10  \n";
        Calculator c = new Calculator(str);
        double d = c.expr();
        System.out.println("res -> " + d);
    }

执行结果: res -> 57.16666666666666