使用 boost-spirit 解析词位之间的空白

Parsing white-spaces in between lexemes using boost-spirit

我想使用 boost::spirit 解析 bnf 语法。这个 工作正常。但是,我也希望能够读取出现在词素之间的 white-spaces。例如,假设我有这样的语法:

<name> ::= <firtname> <surname>
<firtname> ::= <char><char> | <firstname><char>
<surname> ::= <char><char> | <surname><char>
<char>   ::= a | b | c ... | z

假设我有一个使用上述语法的重写系统,我应该在最后为 <name> 输出类似 David Harvey 的内容。但是如果<name>规则是这样写的<name> ::= <firtname><surname>。重写系统应该给出这样的输出 DavidHarvey。这是因为重写系统是white-space敏感的。

生成与解析完全不同。

解析删除冗余并规范化数据。 Generation 添加冗余并根据某些目标(风格指南、效率目标等)选择(通常是许多)表示。

由于 BNF 相似性而让自己偏离轨道,您已经忘记了自己的目标。因为,在 BNF 中,许多空格实例根本不重要。

直接观察表明 AST 不包含空格。

破解它

最简单的方法是在 AST 中将跳过的空格表示为“字符串文字”:

    _term       = _literal | _rule_name | _whitespace;

    _whitespace = +blank;

然后使 _list 规则也成为一个词位(因此 to not skip blanks):

    // lexemes
    qi::rule<Iterator, Ast::List()>   _list;
    qi::rule<Iterator, std::string()> _literal, _whitespace;

看到了Live On Compiler Explorer

清洁解决方案

上面留下了一些“缺陷”:有些地方的空格仍然不重要(即 | 左右,特别是在列表属性数字之前):

<code>   ::=  <letter><digit> 34 | <letter><digit><code> 23
<letter> ::= "a" 1 | "b" 2 | "c" 3 | "d" 4 | "e" 5 | "f" 6 | "g" 7 | "h" 8 | "i" 9
<digit>  ::= "9" 10 | "1" 11 | "2" 12 | "3" 13 | "4" 14

我看不出它在那里有什么用处,当然除非你的输入看起来不像你一直在使用的输入。例如。如果它看起来像这样:

<code>::=<letter><digit>34|<letter><digit><code>23
<letter>::="a"1|"b"2|"c"3|"d"4|"e"5|"f"6|"g"7|"h"8|"i"9
<digit>::="9"10|"1"11|"2"12|"3"13|"4"14

你可以把所有的规则都变成词位。但是,这根本不会与引号字符串的存在相加。引用字符串的整个概念是标记暂停正常空白(和注释)跳过的区域。

我有一种挥之不去的感觉,你离你的实际问题(见 https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem)比我们目前所能看到的要远得多,你甚至可能已经从中剥离了整个引用字符串文字的概念已经是“BNF”了。

A clean solution would be to forget about misleading similarities with BNF and just devise your own grammar from the ground up.

如果目标只是拥有一个(递归)macro/template 扩展引擎,那么它应该比您目前拥有的简单得多。也许您可以描述您的实际任务(输入、期望的输出和所需的行为),以便我们帮助您实现目标?