2014-02-23 63 views
2

我正在嘗試使用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命令返回。

任何幫助我搞清楚我的語法?

回答

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

爲了達到這個目的,我想爭取一個完整的解析器。例如,你可以做簡單的使用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/

+0

嚴重的是,這是一個下一級響應。感謝您爲此付出了時間。 – Micah