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 应该将其输入作为来自 CONSTANT_LEXER 的标记流,并以 IGNORED 作为分隔符。问题是 CONSTANT_PARSER 是由“映射” CONSTANT_LEXER 定义的,这意味着它使用词法分析器解析其输入,而不是映射结果。这会引发以下错误:

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

通过定义 CONSTANT_PARSER 正如Parsers.tokenType(Token.class, "constant")您所说的那样,解析器使用令牌流,将它们命名为constant。但是,我认为这并不像您期望的那样起作用,因为这将匹配任何类型的 Token,而不仅仅是常量。

这当然是 JParsec 中记录较少的部分之一,也没有很好的记录!

于 2012-10-31T05:04:42.807 回答