上一篇文章通过分割字符串来进行表达式运算,感觉灵活性太差,比如要添加对变量的支持,需要修改很多地方。下边介绍采用javacc对运算表达式进行语义分析。---JavaCC主要是通过配置文件(xx.jj)生成分析代码的框架。
ExpressionParser.jj配置文件:
---支持变量x、函数(sin,cos...)、简洁乘法(如 3sin(x) 表示3乘以sin(x))
/**
*分析计算公式
* Saber
*/
options
{
IGNORE_CASE=true;//忽略大小写
STATIC =false;
}
PARSER_BEGIN(ExpressionParser)
package myexample;
/** New line translator. */
public class ExpressionParser
{
private static double x;
public ExpressionParser(String expression)
{
this(new java.io.StringReader(expression));
}
public ExpressionParser(String expression,double x)
{
this(new java.io.StringReader(expression));
this.x=x;
}
/** Main entry point. */
public static void main(String args []) throws ParseException
{
ExpressionParser parser = new ExpressionParser(new java.io.StringReader("sin(3.15/2)"));
System.out.println("解析结果="+parser.parse());
}
}
PARSER_END(ExpressionParser)
SKIP :
{
" "
| "\t"
| "\n"
| "\r"
}
TOKEN :
{
/*计算符号*/
< PLUS : "+" >
| < MINUS : "-" >
| < TIMES : "*" >
| < DIVIDE : "/" >
}
TOKEN : { < NUMBER : <DIGITS> | <DIGITS> "." <DIGITS> | <DIGITS>"." | "."<DIGITS> > }
TOKEN : { < #DIGITS : (["0"-"9"])+ > }
TOKEN : { < OPEN_PAR : "(" > |< CLOSE_PAR:")" >}
/*次方*/
TOKEN : { < POW_PAR : "^" > }
TOKEN : {
/*函数*/
< ABS : "abs" >
| < SIN : "sin" >
| < COS : "cos" >
| < LOG : "log" >
| < LOG10 : "log10" >
| < SQRT : "sqrt" >
| < TAN : "tan" >
| < POW : "pow" >
}
TOKEN:{< X :"x" >/**变量**/}
/** 解析表达式 */
double parse() :
{
Token t;
double result=0;
double i=0;
}
{
result=timesAndDivide()
(
< PLUS >
i=timesAndDivide()
{
result+=i;
}
| < MINUS >
i=timesAndDivide()
{
result-=i;
}
)*
{
return result;
}
}
/**基本运算单元**/
double primary():
{
Token t;
double d;
}
{
d=doNumber()
{
return d;
}
|d=calculatorPar()
{
return d;
}
| < MINUS >d=primary()
{
return d;
}
| d=doFunction()
{
return d;
}
}
/**乘法运算**/
double timesAndDivide():
{
double result=0;
double i=0;
}
{
result=primary()
(
< TIMES >
i=primary()
{
result*=i;
}
| < DIVIDE >
i=primary()
{
result/=i;
}
)*
{
return result;
}
}
/**函数计算**/
double doFunction():
{
double arg=0;
}
{
< SIN > arg=calculatorPar()
{
return Math.sin(arg);
}
| < COS >
arg=calculatorPar()
{
return Math.cos(arg);
}
}
/**
* 遇到数字,有4种情况:
* a. 数字后紧跟着圆弧,如3(3-2),标识3乘以(3-2)
* b. 数字后是函数,如3sin(3.14),表示3乘以sin(3.14)
* c. 数字后是变量X,如3X,表示3乘以X变量
* d. 其他情况,则直接返回当前数字
*/
double doNumber():
{
Token t;
double d;
double result;
}
{
result= getNumber()
(
d=calculatorPar()
{
result=d*result;
}
| d=doFunction()
{
result=d*result;
}
)*
{
return result;
}
{
return result;
}
}
/**
* 如果是数字则直接返回数字,否则,是变量则返回变量的次方
**/
double getNumber():
{ Token t;
double result=1;
}
{
t= < NUMBER >
{
result= Double.parseDouble(t.image);
}
(
< X >
{
result*=x;
}
)*
{
return result;
}|
(
< X >
{
result*=x;
}
)*
{
return result;
}
}
/*计算圆弧内的表达式*/
double calculatorPar():
{
double d;
}
{
< OPEN_PAR >d=parse()< CLOSE_PAR >
{
return d;
}
}