Files
yallie 9fa3874800 Added the contents of the archive.
Moved the original file to the archive subfolder.
2017-11-20 16:11:42 +03:00

393 lines
9.2 KiB
C#

//------------------------------------------------------------------------------
// <copyright file="codegen.cs" company="Microsoft">
//
// Copyright (c) 2002 Microsoft Corporation. All rights reserved.
//
// The use and distribution terms for this software are contained in the file
// named license.txt, which can be found in the root of this distribution.
// By using this software in any fashion, you are agreeing to be bound by the
// terms of this license.
//
// You must not remove this notice, or any other, from this software.
//
// </copyright>
//------------------------------------------------------------------------------
using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Collections;
using System.Threading;
using Absyn;
class CodeGen : IExpVisitor
{
ExpList expr;
TypeBuilder tb;
MethodBuilder methodb;
Hashtable Functions;
Hashtable GlobalVars;
Hashtable DoVars;
ILGenerator il;
public CodeGen(ExpList ex, Hashtable f, Hashtable g)
{
expr = ex;
Functions = new Hashtable();
GlobalVars = new Hashtable();
DoVars = new Hashtable();
}
void Init()
{
}
public void IntExp(IntExp e)
{
switch(e.Value){
case 0:
il.Emit(OpCodes.Ldc_I4_0);
break;
case 1:
il.Emit(OpCodes.Ldc_I4_1);
break;
case 2:
il.Emit(OpCodes.Ldc_I4_2);
break;
case 3:
il.Emit(OpCodes.Ldc_I4_3);
break;
case 4:
il.Emit(OpCodes.Ldc_I4_4);
break;
case 5:
il.Emit(OpCodes.Ldc_I4_5);
break;
case 6:
il.Emit(OpCodes.Ldc_I4_6);
break;
case 7:
il.Emit(OpCodes.Ldc_I4_7);
break;
case 8:
il.Emit(OpCodes.Ldc_I4_8);
break;
default:
if (e.Value > -128 && e.Value < 127)
il.Emit(OpCodes.Ldc_I4_S, (byte)e.Value);
else if (e.Value > Int32.MinValue && e.Value < Int32.MaxValue)
il.Emit(OpCodes.Ldc_I4, (int)e.Value);
else
il.Emit(OpCodes.Ldc_I8, e.Value);
break;
}
}
public void BinopExp(BinopExp e)
{
e.Left.Visit(this);
e.Right.Visit(this);
switch(e.Oper){
case Operator.ADD:
il.Emit(OpCodes.Add);
break;
case Operator.SUB:
il.Emit(OpCodes.Sub);
break;
case Operator.MUL:
il.Emit(OpCodes.Mul);
break;
case Operator.DIVIDE:
il.Emit(OpCodes.Div);
break;
}
}
public void CompareExp(CompareExp e)
{
Label TrueLabel = il.DefineLabel();
Label EndLabel = il.DefineLabel();
e.Left.Visit(this);
e.Right.Visit(this);
switch(e.Oper){
case Operator.LT:
il.Emit(OpCodes.Blt, TrueLabel);
break;
case Operator.GT:
il.Emit(OpCodes.Bgt, TrueLabel);
break;
case Operator.EQ:
il.Emit(OpCodes.Beq, TrueLabel);
break;
case Operator.LE:
il.Emit(OpCodes.Ble, TrueLabel);
break;
case Operator.GE:
il.Emit(OpCodes.Bge, TrueLabel);
break;
}
il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Br, EndLabel);
il.MarkLabel(TrueLabel);
il.Emit(OpCodes.Ldc_I4_1);
il.MarkLabel(EndLabel);
}
public void CallExp(CallExp e)
{
for(int i = 0; i < e.Params.Length; i++){
e.Params[i].Visit(this);
}
if(e.System){
il.Emit(OpCodes.Call, ((typeof(LispRuntime)).GetMethod(e.FunctionName)));
}
else{
il.Emit(OpCodes.Call, (MethodInfo)Functions[e.FunctionName]);
}
}
public void CarExp(CarExp e)
{
e.Left.Visit(this);
il.Emit(OpCodes.Call, ((typeof(LispRuntime)).GetMethod("Car")));
}
public void IsNullExp(IsNullExp e)
{
}
public void ToIntExp(ToIntExp e)
{
e.Value.Visit(this);
il.Emit(OpCodes.Call, ((typeof(LispRuntime)).GetMethod("ToInt")));
}
public void ToListExp(ToListExp e)
{
e.Value.Visit(this);
il.Emit(OpCodes.Call, ((typeof(LispRuntime)).GetMethod("ToList")));
}
public void StringExp(StringExp e)
{
il.Emit(OpCodes.Ldstr, (e.Value));
il.Emit(OpCodes.Call, ((typeof(LispRuntime)).GetMethod("Init")));
}
public void VarExp(VarExp e)
{
switch(e.Pos){
case 0:
il.Emit(OpCodes.Ldarg_0);
break;
case 1:
il.Emit(OpCodes.Ldarg_1);
break;
case 2:
il.Emit(OpCodes.Ldarg_2);
break;
case 3:
il.Emit(OpCodes.Ldarg_3);
break;
default:
if(e.Pos > -128 && e.Pos < 127)
il.Emit(OpCodes.Ldarg_S, e.Pos);
else
il.Emit(OpCodes.Ldarg, e.Pos);
break;
}
}
public void GlobalVarExp(GlobalVarExp e)
{
il.Emit(OpCodes.Ldsfld, (FieldInfo)GlobalVars[e.Name]);
}
public void IfExp(IfExp e)
{
Label FalseLabel, EndLabel;
FalseLabel = il.DefineLabel();
EndLabel = il.DefineLabel();
e.EvalExp.Visit(this);
il.Emit(OpCodes.Brfalse, FalseLabel);
e.ThenExp.Visit(this);
il.Emit(OpCodes.Br, EndLabel);
il.MarkLabel(FalseLabel);
e.ElseExp.Visit(this);
il.MarkLabel(EndLabel);
}
public void DoExp(DoExp e)
{
Label l1 = il.DefineLabel();
Label l2 = il.DefineLabel();
Label EndLabel = il.DefineLabel();
for (ExpList el = e.Vars; el != null; el = el.Tail){
el.Head.Visit(this);
}
il.Emit(OpCodes.Br, l1);
il.MarkLabel(l2);
for (ExpList el = e.Vars; el != null; el = el.Tail){
DoVarIter((DoVarDef)el.Head);
}
il.MarkLabel(l1);
for (ExpList el = e.Conds; el != null; el = el.Tail){
((DoCondExp)el.Head).EndLabel = EndLabel;
el.Head.Visit(this);
}
il.Emit(OpCodes.Br, l2);
il.MarkLabel(EndLabel);
}
public void DoVarIter(DoVarDef e)
{
e.Iter.Visit(this);
il.Emit(OpCodes.Stloc, (LocalBuilder)DoVars[e.Pos]);
}
public void DoVarExp(DoVarExp e)
{
il.Emit(OpCodes.Ldloc, (LocalBuilder)DoVars[e.Pos]);
}
public void DoCondExp(DoCondExp e)
{
Label FalseLabel;
FalseLabel = il.DefineLabel();
e.Cond.Visit(this);
il.Emit(OpCodes.Brfalse, FalseLabel);
e.Ret.Visit(this);
il.Emit(OpCodes.Br, e.EndLabel);
il.MarkLabel(FalseLabel);
}
public void DoVarDef(DoVarDef e)
{
LocalBuilder lt = il.DeclareLocal(e.Init.ExpType);
DoVars.Add(e.Pos, lt);
e.Init.Visit(this);
il.Emit(OpCodes.Stloc, lt);
}
public void FunctionDef(FunctionDef e)
{
Type[] param = new Type[e.Count];
DoVars = new Hashtable();
for (int i = 0; i < e.Count; i++){
param[i] = (Type)e.Params[i];
}
//DescriptorInfo di = new DescriptorInfo(param);
//di.SetReturnType(e.ExpType);
//di.MethodAttributes = MethodAttributes.Static | MethodAttributes.Public;
methodb = tb.DefineMethod(e.Name, MethodAttributes.Static | MethodAttributes.Public, e.ExpType, param);
Functions.Add(e.Name, methodb);
ILGenerator ilmain = il;
il = methodb.GetILGenerator();
e.Body.Visit(this);
il.Emit(OpCodes.Ret);
il = ilmain;
}
public void GlobalVarDef(GlobalVarDef e)
{
FieldInfo fi = tb.DefineField(e.Name, e.ExpType, FieldAttributes.Static);
GlobalVars.Add(e.Name, fi);
e.Value.Visit(this);
il.Emit(OpCodes.Stsfld, fi);
}
public void Generate(String filename)
{
AppDomain ad = Thread.GetDomain(); //AppDomain.CreateDomain("First", null, null);
AssemblyName an = new AssemblyName();
an.Name = filename + ".exe"; //AssemblyName.CreateSimpleName(filename + ".exe", "LispExe", "Lisp Executable", "default_alias");
AssemblyBuilder ab = ad.DefineDynamicAssembly(an, AssemblyBuilderAccess.RunAndSave);
ModuleBuilder mb = ab.DefineDynamicModule(filename + ".exe", filename + ".exe");
MethodBuilder methodb;
//DescriptorInfo di = new DescriptorInfo(0);
tb = mb.DefineType(filename);
//di.SetReturnType(typeof(void));
//di.MethodAttributes = MethodAttributes.Static | MethodAttributes.Public;
methodb = tb.DefineMethod("Main", MethodAttributes.Static | MethodAttributes.Public, typeof(void), null);
il = methodb.GetILGenerator();
do{
expr.Head.Visit(this);
if (expr.Head is FunctionDef)
GenerateDefStub(((FunctionDef)expr.Head).Name);
else if (expr.Head is GlobalVarDef)
GenerateDefStub(((GlobalVarDef)expr.Head).Name);
else if (expr.Head.ExpType == typeof(int))
GenerateNumericExpStub();
else if (expr.Head.ExpType == typeof(bool))
GenerateBoolExpStub();
else if (expr.Head.ExpType == typeof(CList))
GenerateListExpStub();
expr = expr.Tail;
}while(expr != null);
il.Emit(OpCodes.Ret);
tb.CreateType();
ab.SetEntryPoint((mb.GetType(filename)).GetMethod("Main"));
ab.Save(filename + ".exe");
}
void GenerateNumericExpStub()
{
Type[] type = new Type[1];
type[0] = typeof(System.Int32);
il.Emit(OpCodes.Call, ((typeof(System.Console)).GetMethod("WriteLine", type)));
}
void GenerateListExpStub()
{
il.Emit(OpCodes.Call, ((typeof(LispRuntime)).GetMethod("Print")));
Type[] type = new Type[1];
type[0] = typeof(System.String);
il.Emit(OpCodes.Ldstr, ""); //This is just to do a WriteLine after the Print.
il.Emit(OpCodes.Call, ((typeof(System.Console)).GetMethod("WriteLine", type)));
}
void GenerateDefStub(String Name)
{
Type[] type = new Type[1];
type[0] = typeof(System.String);
il.Emit(OpCodes.Ldstr, Name);
il.Emit(OpCodes.Call, ((typeof(System.Console)).GetMethod("WriteLine", type)));
}
void GenerateBoolExpStub()
{
il.Emit(OpCodes.Call, ((typeof(LispRuntime)).GetMethod("PrintBool")));
}
}