Boost.Spirit:解析期间设置子语法

时间:2013-07-22 14:35:47

标签: c++ boost-spirit boost-spirit-qi

为了处理大型编译时间和语法重用,我将语法编写成几个按顺序调用的子语法。其中之一(称之为:SETUP语法)提供了解析器的一些配置(通过符号解析器),因此后来的子语法在逻辑上依赖于那个(再次通过不同的符号解析器)。因此,在解析SETUP之后,需要更改以下子语法的符号解析器。

我的问题是,如何有效地处理这个问题,同时保留子语法之间的松散耦合?

目前我只看到两种可能性:

  • SETUP语法的on_success处理程序,它可以完成工作,但这会引入相当多的耦合。
  • 在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;
}

SetupRealWork本身就是解析器(我上面的子解析器)。在设置部分期间,可能会更改语法的某些关键字,因此设置部分具有qi::symbols<char, keywords>规则。在开始时,这些符号将包含#task1#task2。解析文件的第一部分后,它们包含$$task1$$task2

由于关键字已更改且由于RealWork需要解析I,因此需要了解新关键字。因此,在文件配对过程中,我必须将符号从Setup转移到RealWork

我看到的两种方法是:

  • Setup了解RealWork,并将符号从Setup转移到RealWork的{​​{1}}处理程序qi::on_success。 (坏,耦合)
  • 切换到两个解析步骤。 Setup的{​​{1}}看起来像

    start

    并且将会有MainParser的第二个解析器。示意性地:

    start = setup >> unparsed_rest
    

    几个解析步骤的开销。

所以,到目前为止,属性还没有发挥作用。只需在解析时更改解析器即可处理多种输入文件。

我的希望是像MainParser这样的处理程序SymbolTable Table; string Unparsed_Rest; MainParser.parse(Input, (Unparsed_Rest, Table)); RealWordParser.setupFromAlteredSymbolTable(Table); RealWorkParser.parse(Unparsed_Rest); 。根据这个想法,每次解析器开始解析输入时都会触发此处理程序。从理论上讲,只是在解析开始时进行拦截,就像我们有拦截qi::on_before_parseqi::on_success一样。

1 个答案:

答案 0 :(得分:3)

可悲的是,你没有显示任何代码,你的描述有点......粗略。所以这是一个相当通用的答案,它解决了我能够从你的问题中提炼出来的一些观点:

关注点分离

这听起来非常像您需要将AST构建与转换/处理步骤分开。

分析器组合

当然你可以编写语法。简单地按照规则编写语法,并以任何传统的方式隐藏这些语法的实现(pImpl成语,const静态内部规则,无论什么符合条件)。

然而,构图通常不需要“事件”驱动元素:如果您觉得需要分两个阶段解析,听起来我只是在努力保持概述但是,递归下降或PEG语法自然非常适合在一个 swoop 中描述类似的语法(或者如果你愿意,可以一次传递)。

但是,如果你找到了

(a)你的语法变得复杂了  (b)或者您希望能够根据运行时功能选择性地插入子程序

你可以考虑

  1. Nabialek的伎俩(我在[tag:boost-spirit] answers on this site
  2. 中多次展示/提到过这个伎俩
  3. 您可以动态构建规则(这不是很容易推荐的,因为您将运行与复制Proto表达式树相关的致命陷阱,这会导致悬空引用)。我偶尔也会给出一些答案:

    REPEAT:除非你知道如何检测UB并使用Proto解决问题,否则不要尝试这个

  4. 希望这些东西可以帮助你走上正轨。如果没有,我建议你回来一个具体的问题。我在家里的代码比“想法”要多得多,因为经常对你而言意味着别的东西而不是我。