我有一个网络应用程序。我的任务是增加执行动态(或从服务器端加载)数学公式的能力,例如在 Excel 中。是的,我可以使用 JavaScript 沙箱,但它确实不安全,我不需要太多功能,只需要数学(求和、乘法等)和“如果”短语。我希望你们知道实现数学处理器的最佳方法。
问候保罗
我有一个网络应用程序。我的任务是增加执行动态(或从服务器端加载)数学公式的能力,例如在 Excel 中。是的,我可以使用 JavaScript 沙箱,但它确实不安全,我不需要太多功能,只需要数学(求和、乘法等)和“如果”短语。我希望你们知道实现数学处理器的最佳方法。
问候保罗
您可以使用 jison ( http://zaach.github.io/jison/ ) 或 PEGjs ( https://github.com/dmajda/pegjs )编写自己的解析器。
至于语法规范,您应该查看 ECMA-376 ( http://www.ecma-international.org/publications/standards/Ecma-376.htm ) 和 MS-XLS ( http://msdn.microsoft.com /en-us/library/cc313154%28v=office.12%29.aspx)。两者都有公式语言的高级描述(带有伪 ABNF)。
这是我的解决方案:
/* description: Parses end executes mathematical expressions with IF THEN ELSE statments. */
/* generated from http://zaach.github.io/jison/try/ */
/* The example IF(1>2) THEN 5 ELSE 1 */
/* lexical grammar */
%lex
%%
\s+ /* skip whitespace */
[0-9]+("."[0-9]+)?\b return 'NUMBER'
"*" return '*'
"/" return '/'
"-" return '-'
"+" return '+'
"^" return '^'
"(" return '('
")" return ')'
"<" return '<'
">" return '>'
"PI" return 'PI'
"E" return 'E'
"IF" return 'IF';
"THEN" return 'THEN'
"ELSE" return 'ELSE'
"==" return '=='
<<EOF>> return 'EOF'
. return 'INVALID'
/lex
/* operator associations and precedence */
%left '+' '-'
%left '*' '/'
%left '^'
%left UMINUS
%left 'IF'
%left '<'
%left '>'
%left '=='
%start expressions
%% /* language grammar */
expressions
: e EOF
{return $1;}
;
e
: e '+' e
{$$ = $1+$3;}
| e '-' e
{$$ = $1-$3;}
| e '*' e
{$$ = $1*$3;}
| e '/' e
{$$ = $1/$3;}
| e '^' e
{$$ = Math.pow($1, $3);}
| '-' e %prec UMINUS
{$$ = -$2;}
| '(' e ')'
{$$ = $2;}
| NUMBER
{$$ = Number(yytext);}
| E
{$$ = Math.E;}
| PI
{$$ = Math.PI;}
| e '<' e
{$$ = $1<$3;}
| e '>' e
{$$ = $1>$3;}
| e '==' e
{$$ = $1==$3;}
| IF '(' e ')' THEN e ELSE e
{
if($3 == true){
$$ = $6;
}
else{
$$ = $8;
}
}
;
}
我不确定,这是正确的方法,但它对我有用。您可以在http://zaach.github.io/jison/try/尝试一下
您可以使用 math.js 中包含的表达式解析器:
示例用法:
math.eval('1.2 / (2.3 + 0.7)'); // 0.4
math.eval('5.08 cm in inch'); // 2 inch
math.eval('sin(45 deg) ^ 2'); // 0.5
math.eval('9 / 3 + 2i'); // 3 + 2i
math.eval('det([-1, 2; 3, 1])'); // -7