繁体   English   中英

python 解析器找到定义宏的位置

[英]python parser find where macros are defined

我有一个名为 header2.h 的测试 header 文件,它只有

#define ford 15

然后另一个 header 称为 header1.h 定义

#include "myheader2.h"
#define make ford
#define car_age 10

我正在尝试使用 Pyparsing 库自动执行 Python 脚本,以便我可以解析 C header 文件。 假设我想验证 define car_age 是否存在,然后我将解析 header1.h 并使用 Python 脚本检查 print car_age 是否存在。 假设我想验证 #define make ford 是否存在,那么我将不得不解析 header.2 以确保“ford”首先存在。

我的 python 脚本有效,但我的问题是我有几个 header 文件使用其他 header 文件中的定义,因此该过程变得非常麻烦。

我认为 pyparsing 库没有帮助我解决问题的功能。 我想知道是否有另一个 Python 解析库或具有可以验证宏定义的功能的不同工具/软件可能在同一个 header 文件或另一个 c header 文件中定义,就像我的示例中一样? 谢谢

这个设计的关键是使用解析动作来维护所有宏的翻译表; 并动态更新查找它们的 pyparsing Forward表达式,并在引用它们时替换它们。

从 macroExpander.py 示例开始,我们添加了另一个表达式来检测#include ,一个解析操作来处理它们,以及一个堆栈来防止循环包含。

macroInclude = "#include" + pp.quoted_string("include_file_reference").add_parse_action(pp.remove_quotes)

# global stack for include processing (to guard against cyclic includes)
include_stack = []

def process_include(s, l, t):
    filename = t.include_file_reference
    if filename in include_stack:
        raise ValueError(f"cyclic reference to {filename!r}")

    # print(f"processing file {filename!r}")
    include_stack.append(filename)

    resolved_file = resolve_file(filename)
    if resolved_file is not None:
        # searching for matches will update the macros dict
        macroExpander.search_string(resolved_file.read_text())

    # all done with this include file, pop from the stack
    include_stack.pop()
    return " ".join(t)

macroInclude.add_parse_action(process_include)

macroInclude添加到 macroExpander 表达式:

# define pattern for scanning through the input string
macroExpander = macroExpr | macroDef | macroInclude

我还添加了这一行,这样我们就可以注释掉示例代码,解析器将足够聪明地跳过它们:

# ignore comments
macroExpander.ignore(pp.c_style_comment)

下面是一些测试代码,用于在使用 stdlib 的 tempfile 模块创建的临时目录中创建示例文件:

from tempfile import TemporaryDirectory
from pathlib import Path
from textwrap import dedent

# header1.h contents
file1 = dedent("""\
/* change to header1.h to see handling of cyclic include */
#include "header2.h"
#define make ford
#define car_age 10
""")

# header2.h contents
file2 = dedent("""\
#define ford 15
""")

# program.c contents
file3 = dedent("""\
#include "header1.h"
#include <stdio.h>

printf("My car is a ", make, " it is ", car_age, " years old!\\n");
""")

# create a temporary dir for header files
with TemporaryDirectory() as tmpdir_str:
    tmpdir = Path(tmpdir_str)

    def resolve_file(fname):
        ret = tmpdir / fname
        if ret.exists():
            return ret
        else:
            return None

    (tmpdir / "header1.h").write_text(file1)
    (tmpdir / "header2.h").write_text(file2)
    (tmpdir / "program.c").write_text(file3)

    expanded = macroExpander.transform_string((tmpdir / "program.c").read_text())
    print(expanded)
    print(macros)

运行这个,我得到以下信息:

#include header1.h
#include <stdio.h>

printf("My car is a ", 15, " it is ", 10, " years old!\n");

{'ford': '15', 'make': '15', 'car_age': '10'}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM