2

私はジソンを使おうとしています。

これが私の文法です:

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 コマンドが返されることを期待しています。

文法を理解するのに何か助けはありますか?

4

2 に答える 2

1

この目的のために本格的なパーサーが必要であることに異議を唱えます。たとえば、レクサーと手書きの再帰降下パーサーを使用するだけで同じことができます。

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/

于 2014-02-23T05:45:49.570 に答える