在 Perl 中解析多嵌套条件 C 预处理器语句

Posted

技术标签:

【中文标题】在 Perl 中解析多嵌套条件 C 预处理器语句【英文标题】:Parse multi-nested conditional C-preprocessor statements in Perl 【发布时间】:2014-09-08 23:09:08 【问题描述】:

我正在尝试想出一种方法来轻松解析一些 C 头文件。我有三个头文件,File_A1、File_A2 和 File_B。 File_A* 仅包含 #defines#defines 本身可以映射到布尔值、数字数据或像(E && F) 这样的条件语句,其中EF 在文件的前面定义。例如:

FILE_A1

#define TRUE 1
#define FALSE 0
#define USERWARE                                TRUE
#define SECTION_SIZE                            2
#define ENGR2_LOAD_ADDRESS                      0x6FF020
#define INTEGER_ONLY_SUPPORT                    FALSE
#define PRESSURE_SENSOR_MIN_KPA_DELTA           -50
#define DUMMY_ENGR2_LOAD_ADDRESS                0x92059020
#define FAST_FLUSH_SUPPORT                      USERWARE

FILE_A2 非常相似。

File_B 在定义方面有点复杂。它包含嵌套的#define 语句,其中许多都被#if...#elif...#endif 包围,因此类似于:

文件_B

#include "File_A1.h"
#include "File_A2.h"

#if (FAST_FLUSH_SUPPORT )
#define MEMORY_BUDGET_FLASH_DIR                   (12 * 256)
#define MEMORY_BUDGET_FLASH_CFG                   (15 * 256)
#else //(FAST_FLUSH_SUPPORT )
#define MEMORY_BUDGET_FLASH_DIR                   (0)
#define MEMORY_BUDGET_FLASH_CFG                   (0)
#endif //(FAST_FLUSH_SUPPORT )

#define DRAM_OFFSET_FLASH_DIR                   (DUMMY_ENGR2_LOAD_ADDRESS)
#define DRAM_OFFSET_FLASH_CFG                    (DRAM_OFFSET_FLASH_DIR            + MEMORY_BUDGET_FLASH_DIR)
#define DRAM_OFFSET_FLASH_LOG                   (DRAM_OFFSET_FLASH_CFG             + MEMORY_BUDGET_FLASH_CFG)

#define DRAM_FLASH_CFG_BASE              (DRAM_OFFSET_FLASH_CFG + ENGR2_LOAD_ADDRESS)
#define DRAM_FLASH_CFG_SIZE              (MEMORY_BUDGET_FLASH_CFG)

如您所见,它可能会有点毛。我想做的是将所有 FILE_B 的#defines 解析为一个评估级别。此外,所有条件都将被处理和删除。 (假设用户软件为 TRUE),

#define MEMORY_BUDGET_FLASH_DIR                   (12 * 256)
#define MEMORY_BUDGET_FLASH_CFG                   (15 * 256)

#define DRAM_OFFSET_FLASH_DIR                   (0x92059020)
#define DRAM_OFFSET_FLASH_CFG                   (0x92059020            + (12 * 256))
#define DRAM_OFFSET_FLASH_LOG                   ((0x92059020            + (12 * 256))             + (15 * 256))

#define DRAM_FLASH_CFG_BASE              ((0x92059020            + (12 * 256)) + 0x6FF020)
#define DRAM_FLASH_CFG_SIZE              ((15 * 256))

如果我能达到这样的程度,那么我可以研究下一步,即评估宏的所有右侧。例如,MEMORY_BUDGET_FLASH_DIR 的计算结果为 3,072。

这些的构建过程漫长而繁琐,涉及数千个文件,因此使用 -E 运行 gcc 并不是最好的解决方案。事实上,它可能是最糟糕的解决方案之一,因为我相信“-E”可以解析所有宏声明,所以我失去了最初的定义。此外,我真正需要的文件只有 File_A1、File_A2 和 File_B,这意味着其他数千个文件在此范围内毫无意义。

我希望找到一种简单的方法来解析这些语句。 我不太清楚如何评估扩展的表达式,也不知道存储所有这些信息的结构是什么。我希望用 Perl 写这个,因为我对它有一些小的经验,比 Python 更多。

任何帮助将不胜感激。

编辑:更新了问题描述以反映真实价值。稍微澄清一下。

【问题讨论】:

这不是很清楚。您在寻找什么最终输出?为什么不能将这三个标头打包成一个简单的 C 测试工具,然后直接调用 gcc -E 呢? @OliCharlesworth 无意义的约束通常表示作业!这实际上是一个有点牵强的小项目。 @soplu:我看到你已经编辑了你的问题,但我仍然读到“FILE_A2 非常相似”。看起来你没有编写规范的习惯。请解释一下这整件事是为了什么,因为我可以想象现实生活中的 C 预处理器可以解决所有这些问题的几种方法。 关键问题是,如果 OP 要处理真正的 C 代码的“数千个文件”,他的头文件中很可能有各种预处理器地狱。 OP 需要强烈说服我们,他需要的东西要少得多,以获得比“获得完整的预处理器”更少的建议,或者可以以比 C 更复杂的方式解析处理器文件的东西。 不确定这是否有帮助,但您可能想看看Coan 【参考方案1】:

在 Perl 中,您可以使用 Marpa::R2 — 一个通用的 BNF 解析器。

This gist 将 FILE_B 的开头从您的 qiestion 解析为一棵树(请参阅评论中的输出)。

希望这会有所帮助。

【讨论】:

这看起来是我收到的两个选项中最有希望的,谢谢。我需要摆弄它,但我认为这应该可行。并感谢您提供一个让我开始的例子。

以上是关于在 Perl 中解析多嵌套条件 C 预处理器语句的主要内容,如果未能解决你的问题,请参考以下文章

在批处理文件中,如果满足一个条件而不是周围的 for 循环,如何突破嵌套的 if 语句?

你可以嵌套 C 预处理器指令吗?

预指令

求一些C语言if嵌套语句算法题

C语言中程序的编译(预处理操作)+链接详解(详细介绍程序预编译过程)

javascript预解析