1

Jison 解析器返回计算结果:

calculator.parse("2^3"); // returns 8
calculator.parse("x^2"); // gives a parse err

我希望它返回符号表达式:

calculator.parse("x^2");
// should return
// "Math.pow(x,2)"

calculator.parse("x^(x+1)");
// should return
// "Math.pow(x,x+1)"

calculator.parse("cos(x)");
// should return
// "Math.cos(x)"
4

3 回答 3

2

如果你需要的东西足够简单,你可以通过修改计算器来解决。例如:

  1. IDENTIFIER在令牌列表之后添加一个令牌NUMBER

    [a-z]                 return 'IDENTIFIER'
    

    这允许单个小写字母用作标识。

  2. 修改e '^' e规则以返回字符串而不是计算值:

    | e '^' e
        {$$ = "Math.pow(" + $1 + "," + $3 + ");"}
    
  3. 将新规则添加到规则列表中e

    | IDENTIFIER
    

    (无需明确的操作。)

通过解析这些更改,x^2结果是"Math.pow(x,2);"

为了支持运算符,必​​须修改其他规则,例如e '^' e返回字符串而不是数学结果的规则。

这是非常原始的,不会优化可以优化的东西。例如,1^2将在"Math.pow(1, 2)"可以优化为 时输出1

于 2014-10-01T17:16:17.677 回答
1

(基于@Louis 的回答和评论)

这是使用 jison 的基本符号计算器的代码:

/* description: Parses and executes mathematical expressions. */

/* lexical grammar */
%lex
%%

\s+                   /* skip whitespace */ 
(acos|asin|atan|atan2|cos|log|sin|sqrt|tan) return 'FUNCTION'
[0-9]+("."[0-9]+)?\b  return 'NUMBER'
[a-z]                 return 'IDENTIFIER'
"|"                   return '|'
"*"                   return '*'
"/"                   return '/'
"-"                   return '-'
"+"                   return '+'
"^"                   return '^'
"!"                   return '!'
"%"                   return '%'
"("                   return '('
")"                   return ')'
"PI"                  return 'PI'
"E"                   return 'E'
<<EOF>>               return 'EOF'
.                     return 'INVALID'

/lex

/* operator associations and precedence */

%left '+' '-'
%left '*' '/'
%left '^'
%right '!'
%right '%'
%left UMINUS

%start expressions

%% /* language grammar */

expressions
    : e EOF
        { typeof console !== 'undefined' ? console.log($1) : print($1);
          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 '!'
        {{
          $$ = (function fact (n) { return n==0 ? 1 : fact(n-1) * n })($1);
        }}
    | e '%'
        {$$ = $1/100;}
    | '-' e %prec UMINUS
        {$$ = -$2;}
    | '(' e ')'
        {$$ = $2;}
    | FUNCTION '(' e ')'
        {$$ = "Math." + $1 + "(" + $3 + ")";}
    | '|' e '|'
        {$$ = "Math.abs(" + $2 + ")";}
    | NUMBER
        {$$ = Number(yytext);}
    | E
        {$$ = Math.E;}
    | PI
        {$$ = Math.PI;}
    | IDENTIFIER
    | FUNCTION
    ;
于 2014-10-10T14:26:02.693 回答
0

不。

不是一个简单的方法。取决于你所说的“简单”。您需要定义令牌。然后对这些令牌进行符号操作。和东西。

我不认为计算器会是一个好的起点,而且无论如何它都是一件微不足道的事情,因此将它扔掉并从头开始编写您的 JS 符号解析器语法不会有太大的问题。

只是为了为大家节省一些谷歌时间,这就是我们正在谈论的:http: //zaach.github.io/jison/demos/calc/

于 2014-10-01T12:41:23.587 回答