1

我会编写一个简单的词法分析器,它可以识别没有数字的单词和忽略空格的数字。

我使用 jparsec v3.0 编写了以下代码:

final Parser<String> words = Patterns.isChar(CharPredicates.IS_ALPHA).many1().toScanner("word").source();
final Parser<String> nums = Patterns.isChar(CharPredicates.IS_DIGIT).many1().toScanner("num").source();
final Parser<Tokens.Fragment> tokenizer = Parsers.or(
        words.map(it -> Tokens.fragment(it, "WORD")),
        nums.map(it -> Tokens.fragment(it, "NUM")));
final Parser<List<Token>> lexer = tokenizer.lexer(Scanners.WHITESPACES);

但以下测试失败,但有异常org.jparsec.error.ParserException: line 1, column 7: EOF expected, 1 encountered。相反,使用字符串“abc cd 123”解析成功。

final List<Token> got = lexer.parse("abc cd123");
final List<Token> expected = Arrays.asList(
        new Token(0, 3, Tokens.fragment("abc", "WORD")),
        new Token(4, 2, Tokens.fragment("cd", "WORD")),
        new Token(6, 3, Tokens.fragment("123", "NUM")));
assertEquals(expected, got);

在您看来有什么问题?

4

2 回答 2

1

以下测试通过:

public class SOTest {
  final Parser<String> words = Patterns.isChar(CharPredicates.IS_ALPHA).many1().toScanner("word").source();
  final Parser<String> nums = Patterns.isChar(CharPredicates.IS_DIGIT).many1().toScanner("num").source();
  final Parser<Tokens.Fragment> tokenizer = Parsers.or(
    words.map(it -> Tokens.fragment(it, "WORD")),
    nums.map(it -> Tokens.fragment(it, "NUM")));
  final Parser<List<Token>> lexer = tokenizer.lexer(Scanners.WHITESPACES);


  @Test public void test(){
    final List<Token> got = lexer.parse("abc cd 123");
    Asserts.assertArrayEquals(got.toArray(new Token[0]),
      new Token(0, 3, Tokens.fragment("abc", "WORD")),
      new Token(4, 2, Tokens.fragment("cd", "WORD")),
      new Token(7, 3, Tokens.fragment("123", "NUM")));
  }      
}

您的标记要么只是ALPHA字符,要么只是DIGITS,因此您无法解析是正常的abc cd123

文档中说“在每次出现之前或之后都忽略分隔符”这一事实应该被解释为在被解析的s列表Token之前或之后出现的分隔符被忽略。但是分隔符不会被忽略以分隔标记,除非是运算符(Terminals有关更多信息,请参见类)。

于 2017-01-10T04:07:58.603 回答
0

只需将分隔符设为可选即可解决该问题:

tokenizer.lexer(Scanners.WHITESPACES.optional(null))
于 2017-01-10T22:36:38.380 回答