【问题标题】:parser with scopes and conditionals具有范围和条件的解析器
【发布时间】:2010-06-11 18:32:13
【问题描述】:

我正在编写一个 C/C++/... 构建系统(我知道这很疯狂 ;)),但我在设计我的解析器时遇到了麻烦。

我的“食谱”如下所示:

global
{
    SOURCE_DIRS src
    HEADER_DIRS include
    SOURCES bitwise.c \
            framing.c
    HEADERS \
            ogg/os_types.h \
            ogg/ogg.h
}
lib static ogg_static
{         
   NAME ogg
}
lib shared ogg_shared
{
    NAME ogg
}

(这是基于超级简单的 libogg 源码树)

# 是 cmets,\ 是“换行符转义”,表示该行在下一行继续(参见 QMake syntac)。 {} 是作用域,就像在 C++ 中一样,全局是适用于每个“目标”的设置。这都是背景,与 无关……我真的不知道如何使用我的示波器。我将需要能够有多个范围,以及一种条件处理形式,如下所示:

win32:DEFINES NO_CRT_SECURE_DEPRECATE

解析函数需要知道它所处的范围级别,并在范围增加时调用自身。大括号的位置也存在问题(global {global{ 或如示例中所示)。

如何使用标准 C++ 和 STL 来解决这个问题?我知道这是一项艰巨的工作,这正是我需要一个好的起点的原因。谢谢!

我已经拥有的是整个 ifstream 和内部字符串/字符串流存储,所以我可以逐字阅读。

【问题讨论】:

标签: c++ parsing


【解决方案1】:

我会建议(这或多或少地出自编译器教科书)您分阶段解决问题。这会分解问题,以便在每个阶段都更易于管理问题。

首先关注词法分析阶段。您的词法分析阶段应该获取原始文本并为您提供一系列标记,例如单词和特殊字符。词法分析器阶段可以处理行延续,并根据需要处理空格或 cmets。通过处理空格,词法分析器可以简化解析器的任务:您可以编写词法分析器,以便 global{global { 甚至

global
{

都会产生两个令牌:一个代表global,一个代表{

另外请注意,词法分析器可以将行号和列号附加到标记上,以便以后遇到错误时使用。

一旦你有一个很好的令牌流,就开始你的解析阶段。解析器应采用该标记序列并构建抽象语法树,该树对文档的语法结构进行建模。此时,您不必担心ifstreamoperator>>,因为词法分析器应该已经为您完成了所有这些读取。

您已表示有兴趣在看到范围后递归调用解析函数。这当然是一种方法。正如您将看到的,您必须反复做出的设计决定是您是否真的想递归调用相同的解析函数 (允许像 global { global { ... } } 这样的结构,您可能希望在语法上禁止),或者您是否要定义适用于范围内的稍微(甚至显着)不同的语法规则集。

一旦你发现自己不得不改变规则:关键是通过重构为函数来重用尽可能多的东西,你可以在不同的语法变体之间重用。如果你继续朝着这个方向前进——使用表示你想要处理的不同语法块的单独函数,并让它们在需要时相互调用(可能是递归的)——你最终会得到我们所说的 递归下降解析器。维基百科条目有一个很好的简单示例;见http://en.wikipedia.org/wiki/Recursive_descent_parser

如果您发现自己真的想更深入地研究词法分析器和解析器的理论和实践,我建议您获得一本好的、可靠的编译器教科书来帮助您。上面 cmets 中提到的 Stack Overflow 主题将帮助您入门:Learning to write a compiler

【讨论】:

  • 这是我试图在脑海中构建的内容。哎呀,维基百科文章(我为什么不看那里:s)肯定会帮助我获得基础知识。谢谢
【解决方案2】:

boost::spirit 是一个很好的递归下降解析器生成器,它使用 C++ 模板作为语言扩展来描述解析器和词法分析器。它适用于原生 C++ 编译器,但无法在托管 C++ 下编译。

Codeproject 有一个 tutorial article 可能会有所帮助。

【讨论】:

    【解决方案3】:

    ANTLR(使用ANTLRWorks),之后你可以寻找FLEX/BISON和其他类似lemon。那里有很多工具,但 ANTLR 和 flex/bison 就足够了。我个人非常喜欢 ANTLRWorks,无法推荐其他东西。

    稍后:使用 ANTLR,您可以为 variety of languages 生成解析器/词法分析器代码。

    【讨论】:

      【解决方案4】:

      除非项目的重点是专门学习如何编写词法分析器和 shift-reduce 解析器,否则我建议使用 Flex 和 Bison,它们将为您处理大部分解析工作。编写语法和语义分析仍然是一大堆工作,别担心;)

      【讨论】:

      • 好吧,如果你明白我的意思的话,我认为这是一个“以艰难的方式学习 C++”的学术自导师试错法:)。我认为这是一个值得的事业,并且肯定会向我展示足够的标准库和 STL,以便很好地掌握 C++ 恕我直言。哎呀,我什至会在这个过程中了解编译器和链接器。
      • @rubenvb: 然后写一个像样的递归解析器。我所知道的最简单的 exaplin-by-doing 参考是 Crenshaw 教程(链接于 1669 年)。
      • @dmckee 对于 OP 在他的帖子中建议的复杂性语法,递归下降是否合理?我认为那是疯狂所在......
      • @user:递归体面会很好。 Crenshaw 的教程为一种类似 pascal 的语言构建了一个递归的体面解析器,它具有相当多的复杂性。
      猜你喜欢
      • 2017-09-14
      • 1970-01-01
      • 1970-01-01
      • 2019-10-12
      • 2022-09-23
      • 1970-01-01
      • 1970-01-01
      • 2022-11-02
      • 2010-09-09
      相关资源
      最近更新 更多