BoostSpirit:在解析过程中设置子语法
Boost.Spirit: Setup sub-grammar during parsing
为了处理大量的编译时间和语法的重用,我将语法组成了几个按顺序调用的子语法。其中一个子语法(称之为SETUP语法)提供了解析器的一些配置(通过符号解析器),因此后面的子语法在逻辑上依赖于该子语法(同样通过不同的符号解析器)。因此,在解析SETUP之后,需要更改以下子语法的符号解析器。
我的问题是,如何有效地处理这一问题,同时保持子语法之间的松散耦合?
目前我只看到两种可能性:
- SETUP语法的on_ccess处理程序可以完成这项工作,但这会引入一些耦合
- SETUP之后,将所有内容解析为一个字符串,构建一个新的解析器(根据修改后的符号),并在第二步中解析该字符串。这将留下相当多的开销
我想要的是一个on_before_parse处理程序,它可以由任何需要在每次解析之前做一些工作的语法来实现。从我的角度来看,这将减少耦合,并且解析器的一些设置在其他情况下也可以派上用场。这样的事情可能发生吗?
更新:
抱歉说得太粗略了,那不是我的本意。
任务是用一些关键字(如#task1
和#task2
)解析输入I。但在某些情况下,这些关键字需要不同,比如$$task1
和$$task2
。
因此,解析后的文件将以开头
setup {
#task1=$$task1
#task2=$$task2
}
realwork {
...
}
一些代码草图:Given是一个主解析器,由几个(至少两个)解析器组成。
template<typename Iterator>
struct MainParser: qi::grammar<Iterator, Skipper<Iterator>> {
MainParser() : MainParser::base_type(start) {
start = setup >> realwork;
}
Setup<Iterator> setup;
RealWork<Iterator> realwork;
qi::rule<Iterator, Skipper<Iterator> > start;
}
CCD_ 5和CCD_。在设置部分,语法中的一些关键字可能会被更改,因此设置部分具有qi::symbols<char, keywords>
规则。在开头,这些符号将包含#task1
和#task2
。在解析文件的第一部分之后,它们包含$$task1
和$$task2
。
由于关键字已经更改,并且RealWork
需要解析I,因此它需要了解新的关键字。因此,在文件的配对过程中,我必须将符号从Setup
传输到RealWork
。
我看到的两种方法是:
- 使
Setup
知道RealWork
,并在Setup
的qi::on_success
处理程序中将符号从Setup
传输到RealWork
。(坏,耦合) 切换到两个解析步骤。
MainParser
的start
看起来像start = setup >> unparsed_rest
并且在CCD_ 23之后将存在第二解析器。示意图:
SymbolTable Table; string Unparsed_Rest; MainParser.parse(Input, (Unparsed_Rest, Table)); RealWordParser.setupFromAlteredSymbolTable(Table); RealWorkParser.parse(Unparsed_Rest);
几个解析步骤的开销。
因此,到目前为止,属性还没有发挥作用。只是在解析时更改解析器来处理几种类型的输入文件。
我希望是一个像qi::on_success
一样的qi::on_before_parse
处理程序。从这个想法来看,每当解析器开始解析输入时,就会触发这个处理程序。从理论上讲,这只是解析开始时的拦截,就像我们的拦截on_success
和on_error
一样。
遗憾的是,您没有显示任何代码,并且您的描述有点。。。粗略的因此,这里有一个相当通用的答案,它解决了我能够从你的问题中提取的一些要点:
关注点分离
听起来很像是需要将AST构建与转换/处理步骤分开。
分析器组成
当然你可以编写语法。只需按照规则编写语法,并以任何传统方式隐藏这些语法的实现(pImpl
习语、const静态内部规则,任何合适的)。
然而,合成通常不需要"事件"驱动的元素:如果你觉得需要分两个阶段进行解析,在我看来,你只是在努力保持概述,但递归下降或PEG语法自然非常适合一次性描述类似的语法(如果你愿意的话,也可以一次性)。
但是,如果你发现
(a) 你的语法变得复杂
(b) 或者您希望能够根据运行时功能选择性地插件子语法
你可以考虑
- Nabialek技巧(我在这个网站上的[标签:提升精神]回答中多次展示/提到过这一点
-
您可以动态地构建规则(不建议这样做,因为您将在与复制Proto表达式树有关的致命陷阱中运行,这会导致悬空引用)。我偶尔也会展示一些这样做的答案:
- 从替代语法分析器表达式的可变列表生成Spirit语法分析器表达式
- C++Boost qi递归规则构造
- BoostSpirit.Qi:动态创造"差异";解析时的解析器
重复:除非你知道如何检测UB并用Proto 修复问题,否则不要尝试这个
希望这些东西能帮助你走上正轨。如果没有,我建议你提出一个具体的问题。我更喜欢代码而不是"想法",因为想法对你来说往往意味着比我更重要的东西。
- 为不同配置设置MSVC_RUNTIME_LIBRARY的正确方法是什么
- 1d 智能指针不适用于语法 (*)++
- 在C++/Linux中设置单调时钟的一些技巧
- 如何在选项卡视图Qt中设置一个新项目,并保存以前的项目
- 助记符和指向成员语法的指针
- 有人能分解一下这个c++模板的语法吗
- C++避免重复声明的语法是什么
- 嵌套在类中时无法设置成员数据
- QMetaObject invokeMethod的基于函数指针的语法
- 需要帮助设置在C++中使用的Potrace
- 如何在自删除后将对象设置为nullptr
- 将指针设置为"nullptr"并不能防止双重删除?
- 如何在Ubuntu中使用cmake设置qt4
- ld:bind_at_load和-bitcode_bundle(Xcode设置ENABLE_bitcode=YES)不能
- 如何在boost beast http请求中设置http头
- 如何使用 cpp 设置随机数生成器的语法?
- 如何将字符设置为函数?我对语法感到困惑...设置<char>max_freq(映射<字符,整数>频率)
- BoostSpirit:在解析过程中设置子语法
- 用于调用设置为特定变体的成员函数的正确 c++ 变体语法是什么
- 用于将默认参数值设置为默认构造函数的Nicer语法