使用 boost-spirit 解析词素之间的空格

问题描述

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

<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。这是因为重写系统对空格敏感。

解决方法

生成与解析完全不同。

解析去除冗余并规范化数据。生成会添加冗余并根据某些目标(风格指南、效率目标等)选择(通常是许多中的一种)表示。

让自己偏离 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 具有误导性的相似之处,从头开始设计自己的语法。

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

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...