Since IronPython officially released, because of the love of the Python language driven, and I want to understand the programming language compiler, parser and other programs are how the principle, how to operate, so I started the IronPython source code of the learning process. But the code has been watching for some time, before looking at some implementation details, the result is more confused. Now I find that I need to change my strategy, because we understand that a system always starts with the way it is used, and if you go directly to the underlying workings, you may get lost in the code ocean. So I also prepare to take the top-down analysis method, pick soft persimmon pinch, from the simple, macro-start. As for the specific implementation details, you can study it slowly and further.
OK, the one I caught today looks like a soft persimmon:
Ironpython/hosting/pythoncompiler.cs
First, let's take a look at the main class in this file: Pythoncompiler (Python compiler)
In this class, there is a bunch of properties that do not have to go to the tube, which means that the compiler will output the type of the file (DLL or EXE), the output path, the reference to which Assembly AH and so on.
Heading straight to the topic, we see the Compile () method, which is responsible for compiling the master control method.
This method is not difficult to understand, I read it again, the following comments:
/// <summary>
///Compile
/// </summary>
Public voidCompile () {
stringFullPath=Path.GetFullPath (outputassembly);
stringOutDir=Path.getdirectoryname (FullPath);
stringFileName=Path.getfilename (outputassembly);
//Accept pool for Python compiler
Pythoncompilersink Sink= NewPythoncompilersink (Compilersink);
//Assembly Generator
Assemblygen= NewAssemblygen (
Path.getfilenamewithoutextension (outputassembly),
OutDir, FileName, IncludeDebugInformation, Statictypes, executable, machine
);
//whether to set entry points (entry point)
BOOLEntrypointset= false;
//Set the default primary file (for non-DLL output file types)
if(Mainfile== NULL &&Sourcefiles.count== 1 &&Targetkind!=PEFileKinds.Dll) {
Mainfile=sourcefiles[0];
}
//compile each source file in turn
foreach (stringsourcefileinchsourceFiles) {
//whether to produce the Main method
BOOLCreatemainmethod=sourcefile==Mainfile;
//Each source code file is compiled into a single module
Compilepythonmodule (sourcefile, Sink, Createmainmethod);
if(sink. Errors> 0) return;
if(Createmainmethod) {
Entrypointset= true;
}
}
//Add all the resource files to the assembly in turn
if(Resourcefiles!= NULL) {
foreach(Resourcefile RFinchresourcefiles) {
Assemblygen.addresourcefile (RF. Name, RF. File, RF. Publicresource?ResourceAttributes.Public:ResourceAttributes.Private);
}
}
//for non-DLL target files, an entry point must be required
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);
}
//the assembly that eventually produces the output
Assemblygen.dump ();
}
In this code, the Pythoncompiler class itself is called to the Private Method Compilepythonmodule () to complete the function of the compilation module. Let's take a look at what this method does:
//compiling the module
Private voidCompilepythonmodule (stringFileName, Pythoncompilersink sink,BOOLCreatemain) {
//set the current source file to be compiled
Assemblygen.setpythonsourcefile (fileName);
//creating a compiler environment object
Compilercontext Context= NewCompilercontext (fileName, sink);
//Creating analyzers
Parser P=Parser.fromfile (State, context);
//Call the parser parsing method and get a statement object (the statement should be a nested concept that takes advantage of the combined pattern, which represents a large statement in the entire file)
Statement Body=P.parsefileinput ();
if(sink. Errors> 0) return;
//Create a global suite?? It is possible to refer to globals () as the Dictionary object. Pending analysis ...
//What the Binder is doing here is still to be researched.
globalsuite GS=Compiler.Ast.Binder.Bind (body, context);
stringModuleName=Getmodulefromfilename (fileName);
//Here you see Typegen, the class representing a type generator
//TG points to a module type (in IronPython, each module is generated as a corresponding class. )
Typegen TG=Outputgenerator.generatemoduletype (ModuleName, Assemblygen);
//__init__ method of compiling module?? (guessing)
CodeGen Init=Compilemoduleinit (Context, GS, TG, modulename);
//If you need to create the Main method, create the
if(Createmain) {
//Lenovo in front of a CodeGen example, observe the call statement can be thought of, the method of the generator is
//CodeGen, and the type of generator is Typegen
CodeGen Main=Outputgenerator.generatemoduleentrypoint (TG, init, modulename, referencedassemblies);
//notice here that the CodeGen code generator contains an important attribute that represents this method
//the MethodInfo of the reflected information, which can be called by this method.
Assemblygen.setentrypoint (Main. MethodInfo, Targetkind);
}
//because the module class is not an ordinary class, you need to add a special tag to it (Attribute)
Assemblygen.addpythonmoduleattribute (TG, modulename);
//the resulting type of action is complete
TG. Finishtype ();
}
In the above two methods, we see that there are several important classes that will be the key clues that we'll proceed to analyze below:
Parser: Analyzer
Statement: statement
Globalsuite:globals ()??
Typegen: Type generator
CodeGen: Code generator (code to generate the method)
In another private method Compilemoduleunit, the main is to do some module import work, the code is easy to understand, here is not detailed analysis.
Now look back, in Ironpython/hosting/pythoncompiler.cs this file, there are still two classes left to mention:
Resourcefile: Represents a related property of a resource file.
Pythoncompilersink: The Accepted pool of Pythoncompiler compilation results is literally understood. As to how it works, let's leave it behind for analysis.
So far, we have generally seen the workflow of the IronPython compiler, starting with a series of source code files, resource files, and other configuration properties, through Parser, various Generator operations, eventually reaching Assemblygenerator's The Dump () method, which outputs the compiled result assembly.
The above code analysis inevitably has the error, still needs to continue to dig and comb.
Source: http://www.cnblogs.com/RChen/archive/2006/10/09/ipysrcstudy1.html
IronPython Source Profiling Series (1): IronPython compiler