0

JParsec 2.0.1 で動作する最も単純なパーサーを取得しようとしていますが、うまくいきません。次の AST クラスがあります。

public abstract class Node {
}

public final class ConstantNode extends Node {
    private final String value;

    public ConstantNode(String value) {
        this.value = value;
    }

    @Override
    public String toString() {
        return this.value;
    }
}

そして、次のテスト コード:

import junit.framework.Assert;

import org.codehaus.jparsec.Parser;
import org.codehaus.jparsec.Parsers;
import org.codehaus.jparsec.Scanners;
import org.codehaus.jparsec.Terminals;
import org.codehaus.jparsec.Token;
import org.codehaus.jparsec.functors.Map;
import org.junit.Test;

import ast.ConstantNode;
import ast.Node;

public class ParserTest {
    private static final Parser<Token> CONSTANT_LEXER = Parsers
        .or(Terminals.StringLiteral.SINGLE_QUOTE_TOKENIZER,
            Terminals.StringLiteral.DOUBLE_QUOTE_TOKENIZER)
        .token();

    private static final Parser<Node> CONSTANT_PARSER = CONSTANT_LEXER.map(new Map<Token, Node>() {
        @Override
        public Node map(Token from) {
            return new ConstantNode(from.toString());
        }
    });

    private static final Parser<Void> IGNORED = Scanners.WHITESPACES;

    @Test
    public void testParser() {
        Object result = null;

        // this passes
        result = CONSTANT_LEXER.parse("'test'");
        Assert.assertEquals("test org.codehaus.jparsec.Token", result + " " + result.getClass().getName());

        // this fails with exception: org.codehaus.jparsec.error.ParserException: Cannot scan characters on tokens.
        result = CONSTANT_PARSER.from(CONSTANT_LEXER, IGNORED).parse("'test'");
        Assert.assertEquals("test ast.ConstantNode", result + " " + result.getClass().getName());
    }
}

レクサーはトークンへの文字列入力を正常に解析していますが、パーサーは JParsec 例外のためにそれらのトークンを消費できません。私はこのコードを何度も研究してきましたが、これは jparsec のバグであるか、明らかな何かを誤解しているとしか思えません。

ここで私が間違っていることを誰かに教えてもらえますか?

更新:元の問題は再帰参照によるものだと思います。私CONSTANT_PARSERは を使用してCONSTANT_LEXERおり、後で を呼び出しますCONSTANT_PARSER.from(CONSTANT_LEXER...)。my を次のように変更するCONSTANT_PARSERと、テストに合格しました。

private static final Parser<Node> CONSTANT_PARSER = Parsers.tokenType(Token.class, "constant").map(new Map<Token, Node>() {
    @Override
    public Node map(Token from) {
        return new ConstantNode(from.toString());
    }
});

ただし、これはまだ完全にはクリックされていません。これを行うためのより良い方法があると思うので、まだアイデアに非常に興味があります.

4

1 に答える 1

0

2 種類の「パーサー」を混在させています。文字列パーサーとも呼ばれます。JParsec のスキャナーとトークン パーサー:

CONSTANT_PARSER.from(CONSTANT_LEXER, IGNORED).parse("'test'");

基本的に、CONSTANT_PARSER は、セパレータとして IGNORED を使用して、CONSTANT_LEXER からトークンのストリームとして入力を取得する必要があることを示しています。問題は、 CONSTANT_PARSER が「マッピング」 CONSTANT_LEXER によって定義されていることです。これは、結果をマップするよりもレクサーを使用して入力を解析することを意味します。これにより、次のエラーが発生します。

org.codehaus.jparsec.error.ParserException: Cannot scan characters on tokens.

CONSTANT_PARSER を定義することによりParsers.tokenType(Token.class, "constant")、パーサーはトークンのストリームを使用し、名前を付けますconstant。ただし、これは定数だけでなく、あらゆるタイプのトークンに一致するため、期待どおりには機能しないと思います。

これは確かに、JParsec のあまり文書化されていない部分の 1 つであり、十分に文書化されているわけでもありません!

于 2012-10-31T05:04:42.807 に答える