Clang-Repl 概述:
- 是一个交互式 C++ 解释器,支持增量编译,以读取-求值-打印循环(REPL)风格进行交互式编程。
- 使用 Clang 库将高级编程语言编译为 LLVM IR,再由 LLVM 即时(JIT)基础设施执行。
- 适合探索性编程和对洞察时间要求高的场合,受Cling启发,可将其部分内容向上游推进。
基本数据流:
- 由交互式提示符或允许增量处理输入的接口控制输入基础设施。
- 将输入发送到 Clang 基础结构中的底层增量设施。
- 编译为 AST 表示,可进一步转换以附加特定行为。
- 降低为 LLVM IR,作为 LLVM JIT 编译基础设施的输入格式,将指定函数转换为目标架构的机器代码并执行。
构建指令:
cd llvm-project
,mkdir build
,cd build
,cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DLLVM_ENABLE_PROJECTS=clang -G "Unix Makefiles"../llvm
(注意这里的 RelWithDebInfo - 调试/发布)。cmake --build. --target clang clang-repl -j n
或cmake --build. --target clang clang-repl
。Clang-repl
构建在llvm-project/build/bin
下,进入该目录运行./clang-repl
进入交互模式。
使用方法:
- 基本用法:可包含头文件,定义函数,进行输入输出等操作。
- 函数定义和调用:定义并调用函数,如
int sum(int a, int b){ return a+b; }; int c = sum(9,10); std::cout << c << std::endl;
。 - 迭代结构:如
for
和while
循环。 - 类和结构:定义类并进行操作,
class Rectangle {int width, height; public: void set_values (int,int); int area() {return width*height;}};
等。 - Lambda 表达式:
auto welcome = []() { std::cout << "Welcome to REPL" << std::endl;}; welcome();
。 - 使用动态库:
%lib print.so
,包含头文件并调用函数,如print(9);
。生成动态库的命令为clang++-17 -c -o print.o print.cpp
,clang-17 -shared print.o -o print.so
。
关闭或终止:%quit
。
执行结果处理:
捕获执行结果:通过
Value
对象捕获程序执行结果,可存储在LastValue
中,用于连接解释器和编译代码,实现语言互操作性,如cppyy
项目利用此功能在 C++ 和 Python 之间传输值。- 值合成:选择要合成的表达式,根据类型决定是否分配内存。
- 存储位置:
LastValue
是类成员,可在后续输入中访问,无值打印时为无效状态。 - 提高效率和用户体验:
Value
对象用于创建类型和内存的映射,实现高效的类型转换,提高用户体验。
转储捕获的执行结果:创建临时转储以显示所需数据的值和类型,方便交互式编程,类似于 Python 的工作方式,使用
Automatic Printf
扩展libclangInterpreter
库实现,无需多次使用printf
函数。- 解析机制:
Interpreter.cpp
中的ParseAndExecute()
函数可接受Value
参数捕获结果,若省略则验证并推送最后一个值到dump()
函数。 - 注释令牌:使用
annot_repl_input_end
令牌处理缺少分号的情况,识别用户输入的结束位置,存储并返回表达式语句以便自动打印。 - AST 转换:Sema 遇到该令牌时进行 AST 转换,在 CodeGen 过程前设置相关标记,在 AST 消费者中遍历顶级声明以合成表达式。
- 解析机制:
更多技术细节可访问RFC on LLVM Discourse。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。