clang - Clang RecursiveASTVisitor
问题描述
我正在开发一个 c++ 到无类 c 的翻译器。
基于 LLVM 中的 Kaleidoscope 示例,AST 树的每个节点都有一个 codeGen() 函数,该函数将生成适当的代码并将其返回给父节点。
我正在尝试使用访问者模式实现类似的行为,但我需要访问者返回对象。
关于如何使用RecursiveASTVisitor
?
作为程序的示例输入:
void DrawToLayout(std::string, double, double, double, double) {}
class PCellRect {
private:
double bottomX, bottomY, topX, topY;
public:
PCellRect(double bX, double bY, double tX, double ty)
: bottomX(bX), bottomY(bX), topX(bX), topY(bX) {}
void Draw() { DrawToLayout("Rect", bottomX, bottomY, topX, topY); }
};
void Test() {
PCellRect rectangle(1.0, 1.0, 2.0, 2.0);
rectangle.Draw();
}
会产生这个输出:
void DrawToLayout(std::string, double, double, double, double) {}
void PCellRect_Constructor(double &bottomX, double &bottomY, double &topX,
double &topY, double bX, double bY, double tX,
double tY) {
bottomX = bX;
bottomY = bY;
topX = bY;
topY = bY;
}
void PCellRect_Draw(double &bottomX, double &bottomY, double &topX,
double &topY) {
DrawToLayout("Rect", bottomX, bottomY, topX, topY);
}
void Test() {
double rectangle_PCellRect_bottomX;
double rectangle_PCellRect_bottomY;
double rectangle_PCellRect_topX;
double rectangle_PCellRect_topY;
PCellRect_Constructor(rectangle_PCellRect_bottomX,
rectangle_PCellRect_bottomY, rectangle_PCellRect_topX,
rectangle_PCellRect_topY, 1.0, 1.0, 2.0, 2.0);
PCellRect_Draw(rectangle_PCellRect_bottomX, rectangle_PCellRect_bottomY,
rectangle_PCellRect_topX, rectangle_PCellRect_topY);
}
解决方案
正如您所注意到的,RecursiveASTVisitor
访问函数返回bool
并且无法更改。这些返回值在用户定义的遍历行为中起着至关重要的作用。因此,在此限制中,我为您提供了两种不同的选择。
解决方案 1
该解决方案基于RecursiveASTVisitor
. 您可以将std::stringstream
(或任何用于按顺序收集结果的容器)保留为访问者的成员对象,并在遍历树时编写修改后的语句/声明。
class Translator : public RecursiveASTVisitor<Translator> {
public:
bool VisitCXXConstructExpr(clang::CXXConstructExpr *ConstructorCall) {
auto *Constructor = ConstructorCall->getConstructor();
auto *ConstructedClass = Constructor->getParent();
for (auto &Member : getMembers(ConstructedClass)) {
SS << declareMember(Member) << "\n";
}
SS << "\n";
SS << callPseudoConstructor(Constructor) << "\n";
}
// other visit functions
private:
std::stringstream SS;
};
解决方案 2
这个解决方案有点复杂,但提供了更多的自由。它基于实现您自己的RecursiveASTVisitor
. 您可以通过使用StmtVisitor、DeclVisitor、TypeVisitor和TypeLocVisitor来做到这一点。这些只是访问者,因此它们为一个节点调用正确的访问函数,而不是为其子节点调用正确的访问函数。为了实现您自己的遍历,您需要调用Visit
您想要遍历的所有子节点。
在以下代码段中,我并未使用所有Visitor
类(const
实际上是这些类的版本):
/// Some custom object to be constructed for each AST node
class TranslatedNode {
// ...
};
class Translator : public ConstStmtVisitor<Translator, TranslatedNode>,
public ConstDeclVisitor<Translator, TranslatedNode> {
public:
TranslatedNode VisitCXXConstructExpr(clang::CXXConstructExpr *ConstructorCall) {
TranslatedNode Result;
auto *Constructor = Constructor->getConstructor();
auto *ConstructedClass = Constructor->getParent();
for (auto &Member : getMembers(ConstructedClass)) {
Result.declareMember(Member);
}
Result.startCall(getPseudoConstructor(Constructor);
for (auto &Member : getMembers(ConstructedClass)) {
Result.addArgument(Member);
}
for (auto *Argument : ConstructorCall->arguments()) {
Result.addArgument(Visit(Argument));
}
return Result;
}
// other visit functions
};
这在某种程度上是一个伪代码,但我希望你能明白。
第一种方法更容易,只要您可以按照自己的方式实现某些东西,就RecursiveASTVisitor
应该这样做。但是,在像您这样的情况下,我确实认为迟早需要对遍历进行更多控制。
我希望这些信息对您的项目有用。与 Clang 一起愉快地黑客攻击!
推荐阅读
- amazon-dynamodb - 使用 DynamoDBMapper 注释映射 Java 可选
- linkedin - Linkedin 广告报告返回给定广告系列的空“元素”数组
- excel - Excel 图表:有一种方法可以更改 Y 轴值,将“掩码”文本放在数字位置?
- java - 致命异常尝试在空对象引用上调用虚拟方法“java.lang.String java.lang.Object.toString()”
- r - 为什么即使我没有使用 list()、key<-、names<- 或 attr<-,我也会收到“检测到无效的 .internal.selfref”警告(但没有输出)?
- python - 列出索引超出范围的读取文件
- jsp - 如何使用 html 文件连接服务器?
- java - 一组数字的共同值
- c# - 新的 Xamarin.Forms CollectionView 不允许多预选
- javascript - 如何在 JavaScript 中 getParent().getNode().getProperty("jcr:title")?