zaach / jison

Bison in JavaScript.
http://jison.org
4.35k stars 448 forks source link

How to parse Variable #379

Open felixfrtz opened 5 years ago

felixfrtz commented 5 years ago

Hey,

I am trying to parse variables within the calculator example. My Code is as follows:

var grammar = {
    "comment": "JSON Math Parser",
    "lex": {
        "rules": [
            ["\\s+", "/* skip whitespace */"],
            ["[0-9]+(?:\\.[0-9]+)?\\b", "return 'NUMBER'"],
            ["\\*", "return '*'"],
            ["\\/", "return '/'"],
            ["-", "return '-'"],
            ["\\+", "return '+'"],
            ["\\^", "return '^'"],
            ["!", "return '!'"],
            ["%", "return '%'"],
            ["\\(", "return '('"],
            ["\\)", "return ')'"],
            ["PI\\b", "return 'PI'"],
            ["E\\b", "return 'E'"],
            ["$", "return 'EOF'"]
        ]
    },

    "operators": [
        ["left", "+", "-"],
        ["left", "*", "/"],
        ["left", "^"],
        ["right", "!"],
        ["right", "%"],
        ["left", "UMINUS"]
    ],

    "bnf": {
        "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 !", "$$ = (function(n) {if(n==0) return 1; return arguments.callee(n-1) * n})($1)"],
            ["e %", "$$ = $1/100"],
            ["- e", "$$ = -$2", { "prec": "UMINUS" }],
            ["( e )", "$$ = $2"],
            ["NUMBER", "$$ = Number(yytext)"],
            ["VARIABLE", "$$ = yy.data[text]"], // this is what I've added
            ["E", "$$ = Math.E"],
            ["PI", "$$ = Math.PI"]
        ]
    }
};

var parser = new Parser(grammar);

var parserSource = parser.generate();
parser.yy = { data: { m: 4 } };
console.log(parser.parse("m")); 

This leads to the following:

Error: Lexical error on line 1. Unrecognized text. m

I used this post to accomplish this, but it isn't working. Any idea what is wrong with the example?

blackshadev commented 5 years ago

Hi,

Well you don't have a lex rule for variables. The post you mentioned doesn't include this rule, neither does the calculator example.

An example would be:

["\w+", "return 'VARIABLE'"]

You need to define this rule after all your constants and before your EOF rule. It is a but more permissive than required, but it works and it is easy to read.

ps. I can really suggest using a .jison file and use the cmd like (jison grammer.jison) to generate a ,js file instead of creating your own, I find it easier to read, maintain and write. But that is just my opinion.

AnuragVasanwala commented 2 years ago

Hi @felixfrtz 👋🏻

It is a really old question but I came across this today and would like to share my thoughts.

As per @blackshadev suggestion, it would be good to use .jison and compile ito to generate .js. For your need, you can use official example calculator.jison and add following highlighted lines:


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

/* 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'
+[a-zA-Z_][a-zA-Z0-9_]*    return 'NAME'
+\'[^\']*\'                return 'STRING'
+\"[^\"]*\"                return 'STRING'
+"TRUE"                    return 'TRUE'
+"true"                    return 'TRUE'
+"FALSE"                   return 'FALSE'
+"false"                   return 'FALSE'
+"NULL"                    return 'NULL'
<<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;}
    | NUMBER
        {$$ = Number(yytext);}
+    | NAME
+       { $$ = yy[yytext]; }
+   | STRING
+     {$$ = yytext.substring(1, yytext.length - 1);}
+   | TRUE
+     {$$ = true}
+   | FALSE
+       {$$ = false}
+   | NULL
+       {$$ = null}  
    | E
        {$$ = Math.E;}
    | PI
        {$$ = Math.PI;}
    ;