c++ - 如何从用户输入修改 C++ 代码

标签 c++ clang root-framework

我目前正在编写一个位于 C++ 解释器之上的程序。用户在运行时输入 C++ 命令,然后将其传递给解释器。对于某些模式,我想将给出的命令替换为修改后的形式,以便提供额外的功能。

我想替换任何形式的东西

A->Draw(B1, B2)

MyFunc(A, B1, B2).

我的第一个想法是正则表达式,但这很容易出错,因为 AB1B2 中的任何一个都可以是任意 C++ 表达式。由于这些表达式本身可能包含带引号的字符串或括号,因此很难用正则表达式匹配所有情况。此外,这个表达式可能有多种嵌套形式

我的下一个想法是将 clang 作为子进程调用,使用“-dump-ast”获取抽象语法树,对其进行修改,然后将其重建为要传递给 C++ 解释器的命令。但是,这需要跟踪任何环境更改,例如包含文件和前向声明,以便为 clang 提供足够的信息来解析表达式。由于解释器不公开这些信息,这似乎也不可行。

第三个想法是使用 C++ 解释器自己的内部解析来转换为抽象语法树,然后从那里构建。然而,这个解释器并没有以我能找到的任何方式暴露 ast。

是否有关于如何继续前进的任何建议,无论是沿着规定的路线之一,还是完全沿着不同的路线?

最佳答案

你想要的是 Program Transformation System . 这些工具通常可以让您表达对源代码的更改,以源代码级别的模式编写,基本上说:

 if you see *this*, replace it by *that*

但在抽象语法树上运行,因此匹配和替换过程是 比你通过字符串黑客获得的更值得信赖。

此类工具必须具有用于感兴趣的源语言的解析器。 源语言是 C++ 使得这相当困难。

Clang 有点资格;毕竟它可以解析C++。操作对象 如果没有所有环境上下文,它就无法做到这一点。的程度 OP 正在输入(格式良好的)程序片段(语句等)。 进入解释器,Clang可能[我没有太多经验 我自己] 无法专注于片段是什么(语句?表达式?声明?...)。最后,Clang 并不是真正的 PTS。它的树修改过程不是源到源的转换。这对方便很重要,但可能不会阻止 OP 使用它;表面语法重写规则很方便,但您总是可以更加努力地替换程序树黑客。当规则多于几条时,这开始变得很重要。

GCC with Melt有点像 Clang 那样符合条件。 我的印象是 Melt 最多使 GCC 少一点 不能容忍这种工作。 YMMV。

我们的DMS Software Reengineering Toolkit及其full C++14 [EDIT July 2018: C++17] front end绝对合格。 DMS已被用于进行大规模改造 在大规模 C++ 代码库上。

DMS 可以 parse arbitrary (well-formed) fragments of C++无需事先告知语法类别是什么,并使用其模式解析机制返回正确语法非终结符类型的 AST。 [您可能会得到多个解析,例如歧义,您将决定如何解决,请参阅 Why can't C++ be parsed with a LR(1) parser?更多讨论] 如果您愿意在解析时不使用宏扩展,并且坚持预处理器指令(它们也被解析)相对于代码片段(#if foo{#endif not allowed) 但对于交互式输入的代码片段来说,这不太可能是一个真正的问题。

DMS 然后提供一个完整的程序 AST 库来操作解析树(搜索、检查、修改、构建、替换),然后可以从修改后的树重新生成表面源代码,提供 OP 文本 提供给解释器。

在这种情况下,它的亮点在于 OP 可以将他的大部分修改直接写为源到源语法规则。对于他的 例如,他可以为 DMS 提供重写规则(未经测试但非常接近正确):

rule replace_Draw(A:primary,B1:expression,B2:expression):
        primary->primary
    "\A->Draw(\B1, \B2)"     -- pattern
rewrites to
    "MyFunc(\A, \B1, \B2)";  -- replacement

并且 DMS 将采用任何包含左侧“...绘制...”模式的已解析 AST,并在将匹配项替换为 A、B1 和 B2 之后用右侧替换该子树。引号是 metaquotes,用于区分 C++ 文本和规则语法文本;反斜杠是在元引号内用于命名元变量的元转义。有关您可以在规则语法中表达的更多详细信息,请参阅 DMS Rewrite Rules .

如果 OP 提供了一个集合这样的规则,则可以要求 DMS 应用整个集合。

所以我认为这对 OP 来说效果很好。这是一个相当重量级的机制,可以“添加”到他想要提供给第 3 方的包中; DMS 及其 C++ 前端几乎不是“小”程序。但是现代机器拥有大量资源,所以我认为这是一个问题,即 OP 需要做到这一点。

关于c++ - 如何从用户输入修改 C++ 代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31814263/

相关文章:

c - 适用于 gcc c11,但在 Clang 3.6 c11 上我得到 malloc() : memory corruption (fast): 0x0000000000fb8620

objective-c - 铿锵警告 : Value stored to 'pool' during its initialization is never read

c++ - CERN 根目录 : generate streamer for an extern "C" struct in a namespace

c++ - 从文件中读取会产生意外的输出

c++ - 分解 D3DXMatrixLookAtLH 矩阵

c++ - 使用 clang 获取类中的方法列表

c++ - 如何防止将 TTree 写入 TFile

c++ - C++ 实现代码中的字符串不应出现在输出二进制文件中。怎么修

c++ - 未调用库中的 ESP32 函数

c++ - 如何为类生成字典(vector<vector<short>>)