我正在尝试使用最简单的解析器来处理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...)
。通过将我的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());
}
});
然而,这还没有完全点击给我。我怀疑有更好的方法可以做到这一点,所以我仍然对任何想法都很感兴趣。
答案 0 :(得分:0)
你正在混合2种不同类型的“解析器”:字符串解析器aka。 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
。但是我认为这不会像你期望的那样工作,因为这会匹配任何类型的令牌,而不仅仅是常量。
这肯定是JParsec中记录较少的部分之一,并没有真正记录完毕!