📄 generator.cs
字号:
/*
Sharp Compiler
Copyright (C) 2003 Michael Bebenita
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Collections;
namespace Core.Compilation
{
public class Generator
{
private Module m_Module = null;
private SymbolTable m_Globals = null;
public Generator(Module module)
{
m_Module = module;
}
public void Compile(string path)
{
AppDomain domain = System.Threading.Thread.GetDomain();
AssemblyName name = new AssemblyName();
name.Name = "Sharp Code Assembly";
AssemblyBuilder assemblyBuilder = domain.DefineDynamicAssembly(name,AssemblyBuilderAccess.Save);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(m_Module.Name,m_Module.Name + ".exe",true);
//
// Create global variables.
//
TypeBuilder globalBuilder = moduleBuilder.DefineType("Global");
m_Globals = new SymbolTable();
foreach(Statement statement in m_Module.Body.Statements)
{
if(statement is Variable)
{
Variable variable = statement as Variable;
System.Type type = variable.Type.ToSystemType();
FieldBuilder field = globalBuilder.DefineField(variable.Name,type,FieldAttributes.Public | FieldAttributes.Static);
m_Globals.Add(variable.Name,SymbolType.Variable,statement,field);
}
}
globalBuilder.CreateType();
//
// Create functions.
//
m_Module.Body.SymbolTable = m_Globals;
BuildFunctionStubs(m_Module.Body,moduleBuilder);
foreach(Function function in m_Module.Body.Functions)
{
BuildFunction(function);
}
//
// Create entry point.
//
MethodBuilder mainBuilder = moduleBuilder.DefineGlobalMethod("Main",MethodAttributes.Public | MethodAttributes.Static,typeof(void),null);
ILGenerator mainIL = mainBuilder.GetILGenerator();
EmitBody(mainIL,m_Module.Body,true);
moduleBuilder.CreateGlobalFunctions();
assemblyBuilder.SetEntryPoint(mainBuilder.GetBaseDefinition());
assemblyBuilder.Save(m_Module.Name + ".exe");
System.IO.File.Move(m_Module.Name + ".exe",path);
}
private void FindFunction(Body body, ArrayList functions)
{
if(body != null && body.Functions != null)
{
foreach(Function function in body.Functions)
FindFunction(function.Body,functions);
}
}
private void Error(string message)
{
throw new Exception(message);
}
private void EmitExpression(ILGenerator il, Expression expression, SymbolTable symbolTable)
{
if(expression is BinaryExpression)
{
EmitExpression(il,((BinaryExpression)expression).Left,symbolTable);
EmitExpression(il,((BinaryExpression)expression).Right,symbolTable);
switch( ((BinaryExpression)expression).BinaryOperatorType )
{
case BinaryOperatorType.Add:
il.Emit(OpCodes.Add);
break;
case BinaryOperatorType.Subtract:
il.Emit(OpCodes.Sub);
break;
case BinaryOperatorType.Multiply:
il.Emit(OpCodes.Mul);
break;
case BinaryOperatorType.Divide:
il.Emit(OpCodes.Div);
break;
case BinaryOperatorType.Modulo:
il.Emit(OpCodes.Rem);
break;
case BinaryOperatorType.Equal:
il.Emit(OpCodes.Ceq);
break;
case BinaryOperatorType.NotEqual:
il.Emit(OpCodes.Ceq);
il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Ceq);
break;
case BinaryOperatorType.GreaterThen:
il.Emit(OpCodes.Cgt);
break;
case BinaryOperatorType.LessThen:
il.Emit(OpCodes.Clt);
break;
case BinaryOperatorType.GraterOrEqualTo:
il.Emit(OpCodes.Clt);
il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Ceq);
break;
case BinaryOperatorType.LessOrEqualTo:
il.Emit(OpCodes.Cgt);
il.Emit(OpCodes.Ldc_I4_0);
il.Emit(OpCodes.Ceq);
break;
case BinaryOperatorType.And:
il.Emit(OpCodes.And);
break;
case BinaryOperatorType.Or:
il.Emit(OpCodes.Or);
break;
}
}
else if(expression is UnaryExpression)
{
UnaryExpression unaryExpression = expression as UnaryExpression;
switch(unaryExpression.UnaryOperatorType)
{
case UnaryOperatorType.Indexer:
EmitExpression(il,unaryExpression.Value,symbolTable);
EmitExpression(il,unaryExpression.Indexer,symbolTable);
il.Emit(OpCodes.Ldelem_I4);
break;
case UnaryOperatorType.Negative:
EmitExpression(il,unaryExpression.Value,symbolTable);
il.Emit(OpCodes.Neg);
break;
case UnaryOperatorType.Not:
EmitExpression(il,unaryExpression.Value,symbolTable);
il.Emit(OpCodes.Not);
break;
}
}
else if(expression is Literal)
{
Literal literal = expression as Literal;
switch(literal.LiteralType)
{
case LiteralType.Integer:
il.Emit(OpCodes.Ldc_I4,Int32.Parse(literal.Value));
break;
case LiteralType.Real:
il.Emit(OpCodes.Ldc_R4,float.Parse(literal.Value));
break;
case LiteralType.Character:
il.Emit(OpCodes.Ldc_I4,char.GetNumericValue(literal.Value,0));
break;
case LiteralType.Boolean:
if(literal.Value == "true")
il.Emit(OpCodes.Ldc_I4,1);
else if(literal.Value == "false")
il.Emit(OpCodes.Ldc_I4,0);
break;
}
}
else if(expression is Name)
{
Name name = expression as Name;
Symbol variable = symbolTable.Find(name.Value,SymbolType.Variable);
if(variable == null)
Error("Assignment variable " + name.Value + " unknown.");
if(variable.CodeObject is LocalBuilder)
il.Emit(OpCodes.Ldloc,(LocalBuilder)variable.CodeObject);
else if(variable.CodeObject is FieldBuilder)
il.Emit(OpCodes.Ldsfld,(FieldBuilder)variable.CodeObject);
else if(variable.CodeObject is ParameterBuilder)
{
Parameter p = variable.SyntaxObject as Parameter;
il.Emit(OpCodes.Ldarg_S,((ParameterBuilder)variable.CodeObject).Position - 1);
if(p.PassMethod == PassMethod.ByReference)
il.Emit(OpCodes.Ldind_I4);
}
}
else if(expression is Call)
{
EmitCall(il,expression as Call,symbolTable);
}
}
// Used to keep all function names unique.
private SymbolTable m_Functions = new SymbolTable();
private void BuildFunctionStubs(Body body, ModuleBuilder builder)
{
if(body == null || builder == null)
throw new ArgumentNullException();
SymbolTable sibillings = new SymbolTable(m_Globals);
if(body != null && body.Functions != null)
{
foreach(Function function in body.Functions)
{
// Make child visible to sibillings
function.Body.SymbolTable = sibillings;
MethodBuilder method = BuildFunctionStub(function,builder);
// Make child visible to parent.
body.SymbolTable.Add(function.Name,SymbolType.Function,function,method);
sibillings.Add(function.Name,SymbolType.Function,function,method);
BuildFunctionStubs(function.Body,builder);
}
}
}
private MethodBuilder BuildFunctionStub(Function function, ModuleBuilder builder)
{
if(function == null || builder == null)
throw new ArgumentNullException();
//
// Build function stub.
//
// Find an unique name.
string functionName = function.Name;
while(m_Functions.Find(functionName,SymbolType.Function) != null)
functionName += "#";
// Find return type.
System.Type returnType = function.Type.ToSystemType();
// Find parameters.
System.Type [] parameters = null;
if(function.Parameters != null)
{
parameters = new System.Type[function.Parameters.Count];
for(int x = 0; x < function.Parameters.Count; x++)
{
parameters[x] = function.Parameters[x].Type.ToSystemType();
}
}
// Create method.
MethodBuilder method = builder.DefineGlobalMethod(functionName,MethodAttributes.Public | MethodAttributes.Static,returnType, parameters);
if(function.Parameters != null)
{
for(int x = 0; x < function.Parameters.Count; x++)
{
ParameterBuilder p = null;
p = method.DefineParameter(x+1,ParameterAttributes.None,function.Parameters[x].Name);
function.Body.SymbolTable.Add(p.Name,SymbolType.Variable,function.Parameters[x],p);
}
}
function.Builder = method;
m_Functions.Add(functionName,SymbolType.Function,function,method);
return method;
}
private void BuildFunction(Function function)
{
if(function == null)
throw new ArgumentNullException();
//
// Build child functions.
//
if(function.Body.Functions != null)
{
foreach(Function child in function.Body.Functions)
BuildFunction(child);
}
//
// Build function body.
//
ILGenerator il = function.Builder.GetILGenerator();
EmitBody(il,function.Body,false);
return;
}
private void EmitBody(ILGenerator il, Body body, bool root)
{
//
// Declare local variables.
//
foreach(Statement statement in body.Statements)
{
if(statement is Variable)
{
Variable variable = statement as Variable;
LocalBuilder local = null;
FieldBuilder global = null;
if(root)
{
global = (FieldBuilder)body.SymbolTable.Find(variable.Name,SymbolType.Variable).CodeObject;
}
else
{
local = il.DeclareLocal(variable.Type.ToSystemType());
body.SymbolTable.Add(variable.Name,SymbolType.Variable,variable,local);
}
//
// Initialize variable.
//
if(variable.Type.VariableType == VariableType.Primitive)
{
if(variable.Value != null && variable.Value is Expression)
{
EmitExpression(il,(Expression)variable.Value,body.SymbolTable);
if(root)
il.Emit(OpCodes.Stsfld,global);
else
il.Emit(OpCodes.Stloc,local);
}
}
else if(variable.Type.VariableType == VariableType.PrimitiveArray)
{
// Empty array initialization.
if(variable.Value != null && variable.Value is Expression)
{
EmitExpression(il,(Expression)variable.Value,body.SymbolTable);
il.Emit(OpCodes.Newarr,variable.Type.ToSystemType());
if(root)
il.Emit(OpCodes.Stsfld,global);
else
il.Emit(OpCodes.Stloc,local);
}
else if(variable.Value != null && variable.Value is ElementCollection)
{
ElementCollection elements = variable.Value as ElementCollection;
il.Emit(OpCodes.Ldc_I4,elements.Count);
il.Emit(OpCodes.Newarr,variable.Type.ToSystemType());
if(root)
il.Emit(OpCodes.Stsfld,global);
else
il.Emit(OpCodes.Stloc,local);
for(int x = 0;x<elements.Count;x++)
{
// Load array
if(root)
il.Emit(OpCodes.Ldsfld,global);
else
il.Emit(OpCodes.Ldloc,local);
// Load index
il.Emit(OpCodes.Ldc_I4,x);
// Load value
EmitExpression(il,elements[x].Expression,body.SymbolTable);
// Store
il.Emit(OpCodes.Stelem_I4);
}
}
}
}
else if(statement is Assignment)
{
EmitAssignment(il,statement as Assignment,body.SymbolTable);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -