杰森忽略了我的一条规则

时间:2014-02-23 01:13:46

标签: javascript lexical-analysis jison

我正在尝试使用Jison。

这是我的语法:

var grammar = {
lex:{
    rules:[
        ["\\s+",            ""],
        ["then",            "return 'newline';"],
        ["goto",            "return 'goto';"],
        ["http[^\\s]*",     "return 'url';"],
        ["search",          "return 'search';"],
        ["should_exist",    "return 'exist';"],
        //["#(.)*",           "return 'elementById';"],
        //["$",               "return 'EOF';"]
    ]
},
bnf:{
    lines:[
        ['lines line',          "console.log('big expression is ',$3);  return ['l2',$1, $2];"],
        ['line',                "console.log('expression is ',$1); return ['l1',$1]"],
    ],
    line:[
        ["line newline",        "console.log('line newline', $1); $$ = $1"],
        ["goto url",            "console.log('goto', $2); $$ = {cmd:'goto', url: $2 } "],
        ["elementById exist",   "$$ = {cmd:'assert', elId: $1} "]
    ]
}
};

当我尝试解析goto http://www.google.com then goto http://www.bing.com时,我只会返回[ 'l1', { cmd: 'goto', url: 'http://www.google.com' } ]

我期待返回两个goto命令。

帮助我弄清楚我的语法?

2 个答案:

答案 0 :(得分:3)

代码中的主要问题是过早使用return。使用return将在那里结束解析 。因此,如果您在不打算终止解析的规则中使用它,那么您就遇到了麻烦。我喜欢有一条规则,这是整个系统的切入点,其工作只是用一些明智的东西来呼叫return

这里的东西更像你想要的东西。我没有改变任何内容到lex

    bnf:{
        top: [
            ['lines', "console.log('top is ', $1);  return $1;"]
        ],
        lines:[
            ['lines line',          "console.log('big expression is ', $1);  $$ = ['l2', $1, $2];"],
            ['line',                "console.log('expression is ',$1); $$ = ['l1',$1]"],
        ],
        line:[
            ["line newline",        "console.log('line newline', $1); $$ = $1"],
            ["goto url",            "console.log('goto', $2); $$ = {cmd:'goto', url: $2 } "],
            ["elementById exist",   "$$ = {cmd:'assert', elId: $1} "]
        ]
    }

我得到的输出是:

goto http://www.google.com
line newline { cmd: 'goto', url: 'http://www.google.com' }
expression is  { cmd: 'goto', url: 'http://www.google.com' }
goto http://www.bing.com
big expression is  [ 'l1', { cmd: 'goto', url: 'http://www.google.com' } ]
top is  [ 'l2',
  [ 'l1', { cmd: 'goto', url: 'http://www.google.com' } ],
  { cmd: 'goto', url: 'http://www.bing.com' } ]

这是你最初拥有的和我的建议之间的差异:

--- original.js 2014-02-23 08:10:37.605989877 -0500
+++ parser.js   2014-02-23 08:35:06.674952990 -0500
@@ -14,9 +14,12 @@
         ]
     },
     bnf:{
+        top: [
+            ['lines', "console.log('top is ', $1);  return $1;"]
+        ],
         lines:[
-            ['lines line',          "console.log('big expression is ',$3);  return ['l2',$1, $2];"],
-            ['line',                "console.log('expression is ',$1); return ['l1',$1]"],
+            ['lines line',          "console.log('big expression is ', $1);  $$ = ['l2', $1, $2];"],
+            ['line',                "console.log('expression is ',$1); $$ = ['l1',$1]"],
         ],
         line:[
             ["line newline",        "console.log('line newline', $1); $$ = $1"],

答案 1 :(得分:1)

为了达到这个目的,我认为你需要一个完整的解析器。例如,您可以使用lexer和手写递归下降解析器执行相同的操作:

var lexer = new Lexer;

lexer.addRule(/\s+/, function () {
    // skip whitespace
});

lexer.addRule(/then|goto|search/, function (lexeme) {
    return lexeme.toUpperCase();
});

lexer.addRule(/https?:\/\/[^\s]+/, function (lexeme) {
    this.yytext = lexeme;
    return "URL";
});

lexer.addRule(/$/, function () {
    return "EOF";
});

现在我们有了一个词法分析器,我们将创建递归下降解析器:

function parse(input) {
    lexer.setInput(input);
    return statement();
}

function statement() {
    var condition = command();
    match("THEN");
    var branch = command();
    match("EOF");

    return {
        condition: condition,
        branch: branch
    };
}

function command() {
    match("GOTO");
    var url = match("URL");

    return {
        command: "GOTO",
        url: url
    };
}

function match(expected) {
    var token = lexer.lex();
    if (token === expected) return lexer.yytext;
    else throw new Error("Unexpected token: " + token);
}

现在您需要做的就是致电parse

var output = parse("goto http://www.google.com/ then goto http://www.bing.com/");

alert(JSON.stringify(output, null, 4));

自己查看演示:http://jsfiddle.net/r4RH2/1/

相关问题