gpt4 book ai didi

c++ - 使用 Boost.Spirit 解析标记化的自由形式语法

转载 作者:行者123 更新时间:2023-11-30 02:55:45 25 4
gpt4 key购买 nike

我一直在尝试为 callgrind 工具的输出创建一个 Boost.Spirit 解析器,这是 valgrind 的一部分。 Callgrind 输出一种领域特定的嵌入式编程语言 (DSEL),它可以让您做各种很酷的事情,例如合成计数器的自定义表达式,但它不容易解析。

我在 https://gist.github.com/ned14/5452719#file-sample-callgrind-output 放置了一些示例 callgrind 输出.我已经将我目前最好的尝试放在 Boost.Spirit 词法分析器和解析器上 https://gist.github.com/ned14/5452719#file-callgrindparser-hpphttps://gist.github.com/ned14/5452719#file-callgrindparser-cxx . Lexer 部分很简单:它对标记值、非空白文本、注释、行尾、整数、十六进制、 float 和运算符进行标记(忽略示例代码中的标点符号,它们未被使用)。跳过空白。

到目前为止一切顺利。问题是解析标记化的输入流。我什至还没有尝试过主要节,我仍在尝试解析可能出现在文件中任何 点的标记值。标记值如下所示:

tagtext: unknown series of tokens<eol>

它可以是自由格式的文本,例如

desc: I1 cache: 32768 B, 64 B, 8-way associative, 157 picosec hit latency

在这种情况下,您希望将标记集转换为字符串,即转换为 iterator_range 并提取。

它也可以是一个表达式,例如

event: EPpsec = 316 Ir + 1120 I1mr + 1120 D1mr + 1120 D1mw + 1362 ILmr + 1362 DLmr + 1362 DLmw

这表示从现在开始,事件 EPpsec 将被合成为 Ir 乘以 316 加到 I1mr 乘以 1120 加到...等。

我想在这里强调的一点是,标签-值对需要作为任意标记集累积,并进行后处理,以便我们稍后将它们变成任何东西。

为此,Boost.Spirit 的 utree() 类看起来正是我想要的,这就是示例代码所使用的。但是在 VS2012 上使用带有可变参数模板的 November CTP 编译器我目前看到这个编译错误:

1>C:\Users\ndouglas.RIMNET\documents\visual studio 2012\Projects\CallgrindParser\boost\boost/range/iterator_range_core.hpp(56): error C2440: 'static_cast' : cannot convert from 'boost::spirit::detail::list::node_iterator<const boost::spirit::utree>' to 'base_iterator_type'
1> No constructor could take the source type, or constructor overload resolution was ambiguous
1> C:\Users\ndouglas.RIMNET\documents\visual studio 2012\Projects\CallgrindParser\boost\boost/range/iterator_range_core.hpp(186) : see reference to function template instantiation 'IteratorT boost::iterator_range_detail::iterator_range_impl<IteratorT>::adl_begin<const Range>(ForwardRange &)' being compiled
1> with
1> [
1> IteratorT=base_iterator_type
1> , Range=boost::spirit::utree
1> , ForwardRange=boost::spirit::utree
1> ]

... 这表明我的 base_iterator_type 是 istreambuf_iterator 的 Boost.Spirit multi_pass<> 包装,用于前向迭代器性质,Boost.Spirit 的 utree() 实现无法理解。问题是,我不确定这是我的错误代码还是错误的 Boost.Spirit 代码,因为 line_pos_iterator<> 未能正确指定其 forward_iterator 概念标签。

感谢过去的 Stackoverflow 帮助,我可以编写一个纯非标记化语法,但它会很脆弱。正确的解决方案是标记化并使用能够相当任意输入的自由格式语法。令人遗憾的是,让 Boost.Spirit 的 Lex 和 Grammar 在现实世界的例子中一起工作来实现这一点的例子比玩具例子少得多。因此,我们将不胜感激任何帮助。

尼尔

最佳答案

token 属性公开了一个变体,除了基本迭代器范围之外,它还可以_assume 在 token_type typedef 中声明的类型:

typedef lex::lexertl::token<base_iterator_type, mpl::vector<std::string, int, double>> token_type;

因此:stringintdouble。但是请注意,当解析器实际 使用该值时,强制 到其中一种可能的类型只会延迟发生。

utree 是一个非常通用的容器[1]。因此,当您在规则上公开 spirit::utree 属性,并且标记 value variant 包含 iterator_range 时,它​​会尝试将其分配到 utree 对象(这失败了,因为迭代器是......'funky')。

获得所需行为的最简单方法是强制 Qi 将tag 标记的属性解释为字符串,并让that 分配给 utree。因此,以下行构成了使编译成功的修复:

    unknowntagvalue = qi::as_string[tok.tag] >> restofline;

注意事项

说了这么多,我确实会提出以下建议

  • 考虑使用 Nabialek Trick 根据匹配的 tag 分派(dispatch)不同的惰性规则 - 这样就没有必要处理原始 utree 稍后

  • 您可能已经成功地专门化了 boost::spirit::traits::assign_to_XXXXXX 特征(参见 documentation)

  • 考虑使用纯 Qi 解析器。虽然我可以“感觉到”你的情绪“它会变脆”[2],但你似乎已经证明它会把复杂性 boost 到这样的程度,以至于它可能没有净值(value):

    • 属性实现的意想不到的方式(这个问题)
    • line-pos 迭代器的问题(这是一个常见问题,而且 AFAIR 它主要有hardinelegant 解决方案)
    • 关于例如临时调试(访问 SA 中的源数据)、切换/禁用 skipper 等。
    • 我的个人经验是,查看词法分析器状态来驱动这些并没有帮助,因为切换词法分析器状态只能通过词法分析器标记语义操作可靠地工作,而通常, 消歧会发生在Qi 阶段

但我发散了:)


[1] 例如它们具有非常轻量级的迭代器范围“引用”功能(例如符号,或者避免将字符从源缓冲区复制到属性中,除非需要)

[2] 实际上,只是因为使用顺序词法分析器(扫描器)大大减少了回溯机会的数量,所以它简化了解析器的心智模型。但是,您可以使用 期望点 来达到几乎相同的效果。

关于c++ - 使用 Boost.Spirit 解析标记化的自由形式语法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16196065/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com