生成与解析是完全不同的工作。
解析消除冗余并规范化数据。生成增加了冗余并根据一些目标(风格指南、效率目标等)选择(通常是许多中的一种)表示。
如果让自己偏离 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”中剥离了整个引用字符串文字的概念已经。
一个干净的解决方案是忘记与 BNF 的误导性相似性,而只是从头开始设计自己的语法。
如果目标只是拥有一个(递归)宏/模板扩展引擎,那么它确实应该比您目前拥有的要简单得多。也许您可以描述您的实际任务(输入、期望的输出和所需的行为),以便我们帮助您实现这一目标?