public class Code
//----- shortcuts to the relevant IL instruction codes of System.Reflection.Emit.OpCodes public static readonly OpCode // loading method arguments LDARG0 = OpCodes.Ldarg_0, LDARG1 = OpCodes.Ldarg_1, LDARG2 = OpCodes.Ldarg_2, LDARG3 = OpCodes.Ldarg_3, LDARG = OpCodes.Ldarg_S, // storing in method argument slots STARG = OpCodes.Starg_S, // loading local variables LDLOC0 = OpCodes.Ldloc_0, LDLOC1 = OpCodes.Ldloc_1, LDLOC2 = OpCodes.Ldloc_2, LDLOC3 = OpCodes.Ldloc_3, LDLOC = OpCodes.Ldloc_S, // storing local variables STLOC0 = OpCodes.Stloc_0, STLOC1 = OpCodes.Stloc_1, STLOC2 = OpCodes.Stloc_2, STLOC3 = OpCodes.Stloc_3, STLOC = OpCodes.Stloc_S, // loading constant values LDNULL = OpCodes.Ldnull, LDCM1 = OpCodes.Ldc_I4_M1, LDC0 = OpCodes.Ldc_I4_0, LDC1 = OpCodes.Ldc_I4_1, LDC2 = OpCodes.Ldc_I4_2, LDC3 = OpCodes.Ldc_I4_3, LDC4 = OpCodes.Ldc_I4_4, LDC5 = OpCodes.Ldc_I4_5, LDC6 = OpCodes.Ldc_I4_6, LDC7 = OpCodes.Ldc_I4_7, LDC8 = OpCodes.Ldc_I4_8, LDC = OpCodes.Ldc_I4, // stack manipulation DUP = OpCodes.Dup, POP = OpCodes.Pop, // method invocation CALL = OpCodes.Call, RET = OpCodes.Ret, // branching BR = OpCodes.Br, BEQ = OpCodes.Beq, BGE = OpCodes.Bge, BGT = OpCodes.Bgt, BLE = OpCodes.Ble, BLT = OpCodes.Blt, BNE = OpCodes.Bne_Un, // arithmetics ADD = OpCodes.Add, SUB = OpCodes.Sub, MUL = OpCodes.Mul, DIV = OpCodes.Div, REM = OpCodes.Rem, NEG = OpCodes.Neg, // field access LDFLD = OpCodes.Ldfld, STFLD = OpCodes.Stfld, LDSFLD = OpCodes.Ldsfld, STSFLD = OpCodes.Stsfld, // object creation NEWOBJ = OpCodes.Newobj, NEWARR = OpCodes.Newarr, // array handling LDLEN = OpCodes.Ldlen, LDELEMCHR = OpCodes.Ldelem_U2, LDELEMINT = OpCodes.Ldelem_I4, LDELEMREF = OpCodes.Ldelem_Ref, STELEMCHR = OpCodes.Stelem_I2, STELEMINT = OpCodes.Stelem_I4, STELEMREF = OpCodes.Stelem_Ref, // exception handling THROW = OpCodes.Throw; |
const FieldAttributes GLOBALATTR = FieldAttributes.Assembly | FieldAttributes.Static; const FieldAttributes FIELDATTR = FieldAttributes.Assembly; const MethodAttributes METHATTR = MethodAttributes.Assembly | MethodAttributes.Static; const TypeAttributes INNERATTR = TypeAttributes.Class | TypeAttributes.NotPublic; const typeattributes progattr = typeattributes.class | typeattributes.public; |
/* quick access to conditional branch instructions */ static readonly OpCode[] brtrue = { BEQ, BGE, BGT, BLE, BLT, BNE }; static readonly OpCode[] brfalse = { BNE, BLT, BLE, BGT, BGE, BEQ }; /* No-arg contructor of class System.Object. */ static readonly ConstructorInfo objCtor = typeof(object).GetConstructor(new Type[0]); /* no-arg constructor of class system.executionengineexception, for functions without return */ internal static readonly ConstructorInfo eeexCtor = typeof(system.executionengineexception).getconstructor(new type[0]); |
//----- System.Reflection.Emit objects for metadata management static AssemblyBuilder assembly; // metadata builder for the program assembly static ModuleBuilder module; // metadata builder for the program module static TypeBuilder program; // metadata builder for the main class static TypeBuilder inner; // metadata builder for the currently compiled inner class internal static MethodBuilder // builders for the basic I/O operations provided by the Z# keywords read and write readChar, readInt, writeChar, writeInt; internal static ILGenerator il; // IL stream of currently compiled method |
//----- metadata generation /* Creates the required metadata builder objects for the given Symbol. * Call this after you inserted you Symbol into the symbol table. // TAB */ internal static void CreateMetadata (Symbol sym) { switch (sym.kind) { case Symbol.Kinds.Global: if (sym.type != Tab.noType) sym.fld = program.DefineField(sym.name, sym.type.sysType, GLOBALATTR); break; case Symbol.Kinds.Field: if (sym.type != Tab.noType) sym.fld = inner.DefineField(sym.name, sym.type.sysType, FIELDATTR); break; case Symbol.Kinds.Local: il.DeclareLocal(sym.type.sysType); break; case Symbol.Kinds.Type: inner = module.DefineType(sym.name, INNERATTR); sym.type.sysType = inner; // define default contructor (calls base constructor) sym.ctor = inner.defineconstructor(methodattributes.public, CallingConventions.Standard, new Type[0]); il = sym.ctor.GetILGenerator(); il.Emit(LDARG0); il.Emit(CALL, objCtor); il.Emit(RET); break; case Symbol.Kinds.Meth: // build argument list Type[] args = new Type[sym.nArgs]; Symbol arg = sym.locals; while (arg != null && arg.kind == Symbol.Kinds.Arg) { args[arg.adr] = arg.type.sysType; arg = arg.next; } sym.meth = program.DefineMethod(sym.name, METHATTR, sym.type.sysType, args); il = sym.meth.GetILGenerator(); if (sym.name == "Main") assembly.SetEntryPoint(sym.meth); break; case Symbol.Kinds.Prog: AssemblyName assemblyName = new AssemblyName(); assemblyName.Name = sym.name; assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Save); module = assembly.DefineDynamicModule(sym.name + "Module", sym.name + ".exe"); program = module.DefineType(sym.name, PROGATTR); // initialize globals inner = null; // build methods for I/O keywords (read, write) BuildReadChar(); BuildReadInt(); BuildWriteChar(); BuildWriteInt(); break; } } /* Completes the system type of an inner class. * Call this at end of class declaration. */ internal static void CompleteClass () { inner.CreateType(); inner = null; } |
// ---------- instruction generation /* Load the operand x onto the expression stack. */ internal static void Load (Item x) { /*---------------------------------*/ /*----- insert your code here -----*/ /*---------------------------------*/ } /* Load an integer constant onto the expression stack. */ internal static void LoadConst (int n) { /*---------------------------------*/ /*----- insert your code here -----*/ /*---------------------------------*/ } /* Generate an assignment x = y. */ internal static void Assign (Item x, Item y) { /*---------------------------------*/ /*----- insert your code here -----*/ /*---------------------------------*/ } /* Generate an increment instruction that increments x by n. */ internal static void Inc (Item x, int n) { /*---------------------------------*/ /*----- insert your code here -----*/ /*---------------------------------*/ } /* Unconditional jump. */ internal static void Jump (Label lab) { /*---------------------------------*/ /*----- insert your code here -----*/ /*---------------------------------*/ } /* True Jump. Generates conditional branch instruction. */ internal static void TJump (Item x) { /*---------------------------------*/ /*----- insert your code here -----*/ /*---------------------------------*/ } /* False Jump. Generates conditional branch instruction. */ internal static void FJump (Item x) { /*---------------------------------*/ /*----- insert your code here -----*/ /*---------------------------------*/ } |
/* Generate an executable .NET-PE-File. */ public static void WritePEFile () { program.CreateType(); if (inner != null) inner.CreateType(); assembly.save(assembly.getname().name + ".exe"); } static void BuildReadChar () { // char read () { readChar = program.DefineMethod("readc", MethodAttributes.Static, typeof(char), new Type[0]); il = readChar.GetILGenerator(); // return (char) System.Console.Read(); il.EmitCall(CALL, typeof(Console).GetMethod("Read", new Type[0]), null); il.Emit(OpCodes.Conv_U2); // } il.Emit(RET); } static void BuildReadInt () { // int readi () readInt = program.DefineMethod("readi", MethodAttributes.Static, typeof(int), new Type[0]); il = readInt.GetILGenerator(); // bool neg = false; LocalBuilder neg = il.DeclareLocal(typeof(bool)); il.Emit(LDC0); il.Emit(STLOC0); // int x = 0; LocalBuilder x = il.DeclareLocal(typeof(int)); il.Emit(LDC0); il.Emit(STLOC1); // char ch = read(); LocalBuilder ch = il.DeclareLocal(typeof(char)); il.EmitCall(CALL, readChar, null); il.Emit(STLOC2); // if (c == '-') { Label ifEnd = il.DefineLabel(); il.Emit(LDLOC2); il.Emit(LDC, (int) '-'); il.Emit(BNE, ifEnd); // neg = true; il.Emit(LDC1); il.Emit(STLOC0); // c = ReadChar(); il.EmitCall(CALL, readChar, null); il.Emit(STLOC2); // } il.MarkLabel(ifEnd); // while ('0' <= c && c <= '9') { Label whileStart = il.DefineLabel(); Label whileEnd = il.DefineLabel(); il.MarkLabel(whileStart); il.Emit(LDC, (int) '0'); il.Emit(LDLOC2); il.Emit(BGT, whileEnd); il.Emit(LDLOC2); il.Emit(LDC, (int) '9'); il.Emit(BGT, whileEnd); // x = 10 * x + (int) (c-'0'); il.Emit(LDC, 10); il.Emit(LDLOC1); il.Emit(MUL); il.Emit(LDLOC2); il.Emit(LDC, (int) '0'); il.Emit(SUB); il.Emit(ADD); il.Emit(STLOC1); // c = ReadChar(); il.EmitCall(CALL, readChar, null); il.Emit(STLOC2); // } il.Emit(BR, whileStart); il.MarkLabel(whileEnd); // return neg ? -x : x; ifEnd = il.DefineLabel(); Label elseBranch = il.DefineLabel(); il.Emit(LDLOC0); il.Emit(OpCodes.Brfalse, elseBranch); il.Emit(LDLOC1); il.Emit(NEG); il.Emit(BR, ifEnd); il.MarkLabel(elseBranch); il.Emit(LDLOC1); il.MarkLabel(ifEnd); // } il.Emit(RET); } static void BuildWriteChar () { // void Write (char c, int width) writeChar = program.DefineMethod("write", MethodAttributes.Static, typeof(void), new Type[] { typeof(char), typeof(int) }); il = writeChar.GetILGenerator(); // System.Console.Write(System.String.Format("{{0,{0}}}", width), c) il.Emit(OpCodes.Ldstr, "{{0,{0}}}"); il.Emit(LDARG1); il.Emit(OpCodes.Box, typeof(int)); il.EmitCall(CALL, typeof(string).GetMethod("Format", new Type[] { typeof(string), typeof(object) }), null); il.Emit(LDARG0); il.Emit(OpCodes.Box, typeof(char)); il.EmitCall(CALL, typeof(Console).GetMethod("Write", new Type[] { typeof(string), typeof(object) }), null); // } il.Emit(RET); } static void BuildWriteInt () { // void write (int x, int width) writeInt = program.DefineMethod("write", MethodAttributes.Static, typeof(void), new Type[] { typeof(int), typeof(int) }); il = writeInt.GetILGenerator(); // System.Console.Write(System.String.Format("{{0,{0}}}", width), x) il.Emit(OpCodes.Ldstr, "{{0,{0}}}"); il.Emit(LDARG1); il.Emit(OpCodes.Box, typeof(int)); il.EmitCall(CALL, typeof(string).GetMethod("Format", new Type[] { typeof(string), typeof(object) }), null); il.Emit(LDARG0); il.Emit(OpCodes.Box, typeof(int)); il.EmitCall(CALL, typeof(Console).GetMethod("Write", new Type[] { typeof(string), typeof(object) }), null); // } il.Emit(RET); } } |
/* Z# Code Item. * An item stores the attributes of an operand during code generation. */ class Item { public enum Kinds { Const, Arg, Local, Static, Field, Stack, Elem, Meth, Cond } public Kinds kind; // Const, Local, Static, Stack, Field, Elem, Method, Cond public Struct type; // item type public int val; // Const: value public int adr; // Arg, Local: offset public int relop; // Cond: token code of relational operator public Symbol sym; // Field, Meth: node from symbol table public Label tLabel, fLabel; // Cond: true jumps, false jumps public Item (Symbol sym) { type = sym.type; this.sym = sym; switch (sym.kind) { case Symbol.Kinds.Const: kind = Kinds.Const; val = sym.val; break; case Symbol.Kinds.Arg: kind = Kinds.Arg; adr = sym.adr; break; case Symbol.Kinds.Local: kind = Kinds.Local; adr = sym.adr; break; case Symbol.Kinds.Global: kind = Kinds.Static; break; case Symbol.Kinds.Field: kind = Kinds.Field; break; case Symbol.Kinds.Meth: kind = Kinds.Meth; break; default: Parser.Errors.Error(ErrorStrings.CREATE_ITEM); break; } } // special constructor for Const Items public Item (int val) { kind = Kinds.Const; type = Tab.intType; this.val = val; } // special constructor for Cond Items public Item (int relop, Struct type) { this.kind = Kinds.Cond; this.type = type; this.relop = relop; tLabel = Code.il.DefineLabel(); fLabel = Code.il.DefineLabel(); } // special constructor for Stack Items internal Item (Struct type) { kind = Kinds.Stack; this.type = type; } } |