我正在尝试使用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命令。
帮助我弄清楚我的语法?
答案 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/