我正在从单独的词法分析器和解析器转移到对字符数组进行操作的组合解析器。一个问题是如何正确处理空白。
问题
采用由一系列字符“a”和“b”组成的语言。输入中允许使用空格,但不会影响程序的含义。
我目前解析这种语言的方法是:
var token = function(p) {
return attempt(next(
parse.many(whitespace),
p));
};
var a = token(char('a'));
var b = token(char('b'));
var prog = many(either(a, b));
这可行,但需要不必要的回溯。对于诸如 ' _ __ba_alb' 之类的程序(在帖子中空格被剥离,所以让 _ 成为一个空格),在匹配 'b' 时,空格被解析两次,第一次解析失败a
时a
,再次解析b
. 简单地删除attempt
是行不通的,因为如果消耗了任何空格,either
则永远不会达到。b
尝试
我的第一个想法是将token
呼叫移到either
:
var a = char('a');
var b = char('b');
var prog = many(token(either(a, b)));
这可行,但现在prog
不能轻易重用。在构建解析器库时,这似乎需要定义解析器两次:一个版本实际使用“a”或“b”并且可以在其他解析器中使用,另一个版本可以正确处理空格。它还要求解析器明确了解每个解析器的操作方式以及它如何处理空白,从而使解析器定义变得混乱。
问题
预期的行为是可以在令牌之前使用任意数量的空格。如果解析令牌失败,它会回溯到令牌的开头而不是空格的开头。
如果不对输入进行预处理以生成令牌流,如何表达这一点?有什么好的,真实世界的代码示例吗?我发现最接近的是用于解析的高阶函数,但这似乎并没有解决我的具体问题。