为什么这个简单的 jparsec 词法分析器失败了?
Why this simple jparsec lexer fails?
我会编写一个简单的词法分析器来识别 没有数字 的单词和忽略空格的数字。
我使用 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);
您认为哪里不对?
以下测试通过:
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
.
是正常的
文档说 "delimiters are ignored before or after each occurence" 的事实应该被解释为忽略出现在 Token
s 的 列表之前或之后的分隔符。但是分隔符不会被忽略以分隔标记,运算符除外(有关更多信息,请参阅 Terminals
class)。
只需将定界符设为可选即可解决问题:
tokenizer.lexer(Scanners.WHITESPACES.optional(null))
我会编写一个简单的词法分析器来识别 没有数字 的单词和忽略空格的数字。
我使用 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);
您认为哪里不对?
以下测试通过:
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
.
文档说 "delimiters are ignored before or after each occurence" 的事实应该被解释为忽略出现在 Token
s 的 列表之前或之后的分隔符。但是分隔符不会被忽略以分隔标记,运算符除外(有关更多信息,请参阅 Terminals
class)。
只需将定界符设为可选即可解决问题:
tokenizer.lexer(Scanners.WHITESPACES.optional(null))