漫談IronPython 編譯器講述說明
自 IronPython 正式發布以來,由于對 Python 語言的喜愛所驅使,同時我想藉此去了解一下編程語言的IronPython 編譯器,分析器等程序是什么原理,如何運作的,于是就開始進行IronPython 編譯器的學習了。
但代碼也看了有一段時間了,之前是看一些實現細節,結果越看越糊涂。現在我發現需要改變一下策略了,因為我們了解一個系統總是從對它的使用方法去開始了解,如果直接去了解底層的運作原理,則可能會迷失在代碼海洋里面。所以我也準備采取自頂而下的分析方法,撿軟柿子捏,從簡單的,宏觀的入手。至于具體的實現細節,可以慢慢再深入研究。
直奔主題,我們看到 Compile() 方法,這是負責編譯的主控制方法。這個方法不難理解,我讀了一遍,注釋如下:
- /// <summary>
- /// 編譯
- /// </summary>
- public void Compile() {
- string fullPath = Path.GetFullPath(outputAssembly);
- string outDir = Path.GetDirectoryName(fullPath);
- string fileName = Path.GetFileName(outputAssembly);
- // Python 編譯器的接受池
- PythonCompilerSink sink = new PythonCompilerSink(compilerSink);
- // 程序集產生器
- assemblyGen = new AssemblyGen(
- Path.GetFileNameWithoutExtension(outputAssembly),
- outDir, fileName, includeDebugInformation, staticTypes, executable, machine
- );
- // 是否以設定入口點(entry point)
- bool entryPointSet = false;
- // 設定默認的主文件(對非 DLL 的輸出文件類型而言)
- if (mainFile == null && sourceFiles.Count == 1 && targetKind != PEFileKinds.Dll) {
- mainFile = sourceFiles[0];
- }
- // 對每個源文件依次編譯
- foreach (string sourceFile in sourceFiles) {
- // 是否產生 Main 方法
- bool createMainMethod = sourceFile == mainFile;
- // 每個源代碼文件編譯為一個模塊
- CompilePythonModule(sourceFile, sink, createMainMethod);
- if (sink.Errors > 0) return;
- if (createMainMethod) {
- entryPointSet = true;
- }
- }
這段代碼中,調用到了 IronPython 編譯器自身的私有方法 CompilePythonModule() 來完成編譯模塊的功能。下面我們來看一下這個方法在做什么:
- // 依次將所有資源文件添加到程序集中
- if (resourceFiles != null) {
- foreach (ResourceFile rf in resourceFiles) {
- assemblyGen.AddResourceFile(rf.Name, rf.File, rf.PublicResource ? ResourceAttributes.Public : ResourceAttributes.Private);
- }
- }
- // 對非 DLL 的目標文件,必須要求有一個入口點
- if (targetKind != PEFileKinds.Dll && !entryPointSet) {
- sink.AddError("", string.Format("Need an entry point for target kind {0}", targetKind), String.Empty, CodeSpan.Empty, -1, Severity.Error);
- }
- // 最終產生輸出的程序集
- assemblyGen.Dump();
- }
- 本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/inelm/archive/2006/10/09/4612996.aspx
在上述兩個方法中,我們看到,出現了幾個重要的類,它們將是我們下面接著分析的重點線索:
- // 編譯模塊
- private void CompilePythonModule(string fileName, PythonCompilerSink sink, bool createMain) {
- // 設定當前要編譯的源文件
- assemblyGen.SetPythonSourceFile(fileName);
- // 創建編譯器環境對象
- CompilerContext context = new CompilerContext(fileName, sink);
- // 創建分析器
- Parser p = Parser.FromFile(state, context);
- // 調用分析器的分析方法,得到一個語句對象(語句應該是利用了組合模式的一個嵌套的概念,這個語句代表整個文件里的一個大語句)
- Statement body = p.ParseFileInput();
- if (sink.Errors > 0) return;
- // 創建一個全局套件??有可能是指 globals() 這個字典對象。有待分析。。。
- // 這里面的 Binder 是干什么的也有待研究。
- GlobalSuite gs = Compiler.Ast.Binder.Bind(body, context);
- string moduleName = GetModuleFromFilename(fileName);
- // 這里看到了 TypeGen,該類代表一個類型產生器
- // tg 指向了一個模塊類型(IronPython 中,每一個模塊產生為一個對應的類。)
- TypeGen tg = OutputGenerator.GenerateModuleType(moduleName, assemblyGen);
- // 編譯模塊的 __init__ 方法??(猜測)
- CodeGen init = CompileModuleInit(context, gs, tg, moduleName);
到這里為止,我們大致上看到了 IronPython 編譯器的工作流程,從一系列源代碼文件,資源文件,以及其他一些配置屬性出發,經過 Parser, 各種 Generator 的運作,最終到達 AssemblyGenerator 的 Dump() 方法,輸出編譯結果程序集。
【編輯推薦】