我正在编写一个编译器,真正用于教育目的。我已经从我的输入中生成了令牌并想生成一个 AST。我有一个函数,它接受令牌列表并递归生成 ast。在大多数解析器中,您都有一个指向词法分析器的指针,因此每次处理树中的标记时,您都会推进词法分析器。当您遇到需要在树中生成更深节点的部分时,我不知道如何推进词法分析器,因为您无法修改词法分析器列表的结构。
以这样的 clojure 程序为例(+ 1 2 (+ 1 1))。它会前进到 + 然后递归并正确生成节点,但是词法分析器在生成节点返回后重新处理 + 1 1 ,因此您最终会得到这样的树:
Root
---> +
---> 1
---> 2
-----> +
-----> 1
-----> 1
---> +
---> 1
---> 1
Run Code Online (Sandbox Code Playgroud) 文档中写道:
ast.parse(source, filename='<unknown>', mode='exec')
Equivalent to compile(source, filename, mode, ast.PyCF_ONLY_AST).
compile(source, filename, mode[, flags[, dont_inherit]])
The filename argument should give the file from which the code was read;
pass some recognizable value if it wasn’t read from a file
('<string>' is commonly used).
Run Code Online (Sandbox Code Playgroud)
但它并没有告诉我如何从 AST 节点取回这个文件名。或者如何使用此文件名参数。它只是一个存根吗?
我正在 github 上使用来自 Zach Carter 的reflect.js(一个不错的Javascript 解析器);我正在尝试修改他的解析器的行为,以将注释作为应该像其他任何东西一样被解析的普通标记来处理。reflect.js 的默认行为是跟踪所有注释(词法分析器将它们作为标记抓取),然后将它们的列表附加到它创建的 AST(抽象语法树)的末尾。
但是,我希望将这些注释就地包含在 AST 中。我相信此更改将涉及向这里的grammar.y 文件添加语法规则。目前没有评论规则——如果我的理解是正确的,这就是为什么它们被主要解析代码忽略的原因。
您如何编写规则以在 AST 中包含注释?
在网络上找到的 clang 工具示例总是在玩具示例上运行,这些示例通常都是非常简单的 C 程序。
我正在构建一个对 C++ 代码执行源到源转换的工具,这显然是一项非常非常具有挑战性的任务,但 clang 可以胜任这项任务。
我现在面临的问题是,clang 为任何使用 STL 的 C++ 代码生成的 AST 是巨大的。例如,我有一些 C++ 代码,其中clang++ -ast-dump ... | wc -l67,018 行令人毛骨悚然的 AST gobbledygook!
其中 99% 是标准库的东西,我的目标是在我的源到源元编程任务中忽略它们。所以,为了实现这一点,我想简单地过滤掉文件。假设我只想查看我正在分析的项目标头中的类定义(并忽略所有标准库标头的内容),我只需要弄清楚我CXXRecordDecl的每个标头来自哪个标头!
这能做到吗?
编辑:希望这是一种解决方法。现在试试这个......重要的是它必须告诉我decls来自的标题,而不是对应于翻译单元的cpp文件。
使用 pythonsinspect模块,我已经隔离了一个方法对象,我现在需要遍历方法中的源代码以查找对某些其他方法的调用并获取它们的参数。
例如,假设在以下类中:
def my_method():
print('hello')
foobar('apple', 'pear', 6)
print('world')
foobar(1, 2, 3)
return foobar('a', 'b')
Run Code Online (Sandbox Code Playgroud)
我需要提取传递给的参数列表foobar():
[('apple', 'pear', 6), (1, 2, 3), ('a', 'b', None)]
Run Code Online (Sandbox Code Playgroud)
可以假设所有参数都是硬编码的而不是动态的。
给定inspect包中的方法对象,我如何检查所述方法中的方法调用?
inspect.getsourcelines(method)但是如果参数语法发生变化,这会中断。ast模块的抽象语法树,但还没有找到任何解决方案。inspect但我再次没有找到任何解决方案。我正在以函数式风格编写编译器。类型检查器目前相当简单:它(大部分)只是一个函数 from Exprto Type。
现在,我想在工作流中添加一个步骤,为后续阶段保留类型信息。有很多方法可以做到这一点(符号表等),但一个简单的方法是将其转换为一个看起来像 AST 但包含类型信息的 IR。例如,如果 AST 数据类型是:
datatype Expr = Literal of int
| Add of Expr * Expr
| ...
Run Code Online (Sandbox Code Playgroud)
然后键入的 IR 将是:
type TExpr = Type * TExpr'
datatype TExpr' = TLiteral of int
| TAdd of TExpr * TExpr
| ...
Run Code Online (Sandbox Code Playgroud)
所以我现在的目标是将我的类型检查器转换为类型注释器:一个函数Expr -> TExpr而不是Expr -> Type. 这是我的问题:如果不向类型检查器功能添加一堆样板混乱,您将如何做到这一点?
天真地,我需要到处添加包装和解包代码,破坏了类型检查器功能的简单易读性。也就是说,Add类型检查器中的情况目前看起来像:
let lhs_t = check lhs in
let rhs_t = check rhs in
case (lhs_t, rhs_t) of
(Int, …Run Code Online (Sandbox Code Playgroud) compiler-construction functional-programming abstract-syntax-tree typechecking
我正在尝试使用带有标志的 Swift 编译器从 Swift 文件中打印抽象语法树 (AST)-print-ast。这是没有 Xcode & 的xcodebuild。
我一直在处理通过 Carthage 构建的 3rd 方框架的导入。给定一个包含以下代码的源文件:
import Foundation
import BrightFutures // 3rd party framework
class MyAsyncService {
func asyncFunc() -> Future<String, NSError> {
return Promise<String, NSError>().future
}
}
Run Code Online (Sandbox Code Playgroud)
通过指定框架搜索路径 ( -F) 以下命令:
swiftc -print-ast Source.swift -F Carthage/Build/Mac
Run Code Online (Sandbox Code Playgroud)
产生预期的输出:
import Foundation
import BrightFutures
internal class MyAsyncService {
internal func asyncFunc() -> Future<String, NSError>
@objc deinit
internal init()
}
Run Code Online (Sandbox Code Playgroud)
我需要为仅针对 iOS 的项目打印 AST,并为 …
我想在编译时向某些类添加通用字段。为了这个目标,我按照官方文档实现了我自己的 AST 注释和转换类,并使用 AST 注释来注释所需的类。
但我在编译时收到此错误:
org.codehaus.groovy.control.MultipleCompilationErrorsException:启动失败:/home/.../groovy/Sample.groovy:-1:转换直接使用包含 ClassNode java.util.HashSet 的泛型作为字段 x。你不应该这样做。请参考旧的 ClassNode 创建一个新的 ClassNode,并使用新的 ClassNode 代替旧的 ClassNode。否则,编译器将在 OpenJDK 的 TypeResolver 中创建错误的描述符和潜在的 NullPointerException。如果这不是您自己做的,请将此错误报告给转换的作者。@ 第 -1 行,第 -1 列。
我做错了吗?
示例代码
例如,假设我想向每个通过注释进行注释的类添加一个HashSet<Long>名为的字段。xMyAST
我的 AST 注释类:
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
@GroovyASTTransformationClass(classes = [MyASTTransformation.class])
public @interface MyAST {
}
Run Code Online (Sandbox Code Playgroud)
我的 AST 转换类:
@CompileStatic
@GroovyASTTransformation(phase = CompilePhase.SEMANTIC_ANALYSIS)
public class MyASTTransformation implements ASTTransformation {
@Override
public void visit(ASTNode[] nodes, SourceUnit sourceUnit) {
ClassNode clazz = (ClassNode) nodes[1];
ClassNode longHashSetClass = new ClassNode(HashSet.class); …Run Code Online (Sandbox Code Playgroud) 我正在寻找一种工具,可以从某些给定的输入生成方法存根。我已经看到 了astpackage,但它似乎代表了一个已经解析的 AST,它包含有关源文件中所有位置的信息。重要的是,您需要提供源信息
我正在考虑以编程方式生成源文件,所以我不知道我的 AST 节点将在最终文件中的哪个位置结束。
我很好奇:
ast包裹中的位置提供虚拟信息,它是否会正确打印(即忽略位置信息)?我意识到我可以通过文本生成来完成这一切,但这似乎不安全且难以处理。
我正在使用基于示例Clang ASTFrontendActions 示例的LibTooling 为 clang 4.0 编写工具。给定当前语句 stmt,我想在 AST 中获取它的直接父级。因此,我尝试使用以下代码转储 stmt 的所有父级(用于测试目的):
bool VisitStmt(Stmt *s) {
cout <<"Trying to get parents \n";
const Stmt currentStmt = *s;
const auto& parents = Context->getParents(currentStmt);
auto it = Context->getParents(currentStmt).begin();
if(it == Context->getParents(currentStmt).end())
cout<< "parents not found\n";
cout<<"parents size "<< parents.size() <<": \n";
if (!parents.empty()){
for (int i = 0; i< parents.size(); i++ ){
cout<<"parent at "<< i <<": \n";
const Stmt* parentStmt = parents[i].get<Stmt>();
parentStmt->dump();
}
}
}
Run Code Online (Sandbox Code Playgroud)
Context在ASTContext …
c++ ×2
clang ×2
python ×2
bytecode ×1
clojure ×1
generics ×1
go ×1
grammar ×1
groovy ×1
groovyc ×1
inspect ×1
ios ×1
javascript ×1
libtooling ×1
llvm ×1
pretty-print ×1
python-2.7 ×1
swift ×1
typechecking ×1