如何使用tokenizer构建解析器?

时间:2017-02-09 10:23:24

标签: java parsing jparsec

我使用来解析字符串,如:

[1,2, 3]
[ 3, 4]
[3   ,4,56, 7 ]
[]

我已经实现了一些类(继承自我的Token接口)来表示标记:

final class OpenListToken
final class CommaToken
final class CloseListToken
final class NumberToken // Has a public final property "value" that contains the int

我还为每个人实现了标记器:

static final Parser<OpenListToken> openListTokenParser
static final Parser<CommaToken> commaTokenParser
static final Parser<CloseListToken> closeListTokenParser
static final Parser<NumberToken> numberTokenParser

这些都在角色级别工作。例如:

final NumberToken t = numberTokenParser.parse("123");
// t.value == 123

final OpenListToken u = openListToken.parse("[");
// Succeeds

现在我想把它们组合成一个ListExpression的解析器,它是一个代表数字列表的类。我尝试过类似的东西:

openListTokenParser
    .next(numberTokenParser.sepBy(commaTokenParser))
    .followedBy(closeListTokenParser)

这适用于像[1,2,3]这样的字符串,但显然不适用于像[ 1, 2 ]这样的字符串。

是否有一个运算符需要一些解析器并在它们之间放置whitespace*

或者是否可以让我的ListExpression解析器在我的Token接口实例流而不是字符上工作?

1 个答案:

答案 0 :(得分:1)

您可以使用Terminals类中的函数直接构建标记生成器。在您的情况下,这将如下所示:

首先定义我们的终端集,例如运营商,关键词,词语......

Terminals terminals = operators("[", "]", ",");

然后我们的令牌由我们的终端或IntegerLiteral令牌化器进行标记:

Parser<?> tokens = Parsers.or(terminals.tokenizer(), IntegerLiteral.TOKENIZER);

我们的最终结果来自整数的句法解析器(由标记为INTEGER的标记构建),由逗号标记分隔,位于括号标记之间。我们忽略所有标记之间的任何空格(这是from的第二个参数:

Parser<?> parser = IntegerLiteral.PARSER.sepBy(terminals.token(",")).between(terminals.token("["), terminals.token("]"))
  .from(tokens, Scanners.WHITESPACES.many().cast());

Etvoilà:

System.out.println(parser.parse( "[1,2,3]"));
System.out.println(parser.parse( "[ 1, 2 , 3 ]   "));
System.out.println(parser.parse( "   [1,2,3   ]"));
System.out.println(parser.parse( "[1, 2   ,    3]"));