📄 generator.cs
字号:
else if(statement is Return)
{
if(((Return)statement).Value != null)
EmitExpression(il,((Return)statement).Value,body.SymbolTable);
il.Emit(OpCodes.Ret);
}
else if(statement is CallStatement)
{
CallStatement call = statement as CallStatement;
Symbol symbol = body.SymbolTable.Find(call.Name,SymbolType.Function);
EmitCallStatement(il,statement as CallStatement,body.SymbolTable);
if(symbol != null)
{
if(((MethodBuilder)symbol.CodeObject).ReturnType != typeof(void))
il.Emit(OpCodes.Pop);
}
else
{
if(call.Name == "Read")
il.Emit(OpCodes.Pop);
}
}
else if(statement is If)
{
//
// Genereate if statement.
//
If ifStatement = statement as If;
// Eval condition
EmitExpression(il,ifStatement.Condition,body.SymbolTable);
if(ifStatement.IfBody != null && ifStatement.ElseBody == null)
{
ifStatement.IfBody.SymbolTable = new SymbolTable(body.SymbolTable);
Label exit = il.DefineLabel();
il.Emit(OpCodes.Brfalse,exit);
EmitBody(il,ifStatement.IfBody,false);
il.MarkLabel(exit);
}
else if(ifStatement.IfBody != null && ifStatement.ElseBody != null)
{
ifStatement.IfBody.SymbolTable = new SymbolTable(body.SymbolTable);
ifStatement.ElseBody.SymbolTable = new SymbolTable(body.SymbolTable);
Label exit = il.DefineLabel();
Label elseLabel = il.DefineLabel();
il.Emit(OpCodes.Brfalse,elseLabel);
EmitBody(il,ifStatement.IfBody,false);
il.Emit(OpCodes.Br,exit);
il.MarkLabel(elseLabel);
EmitBody(il,ifStatement.ElseBody,false);
il.MarkLabel(exit);
}
}
else if(statement is While)
{
//
// Generate while statement.
//
While whileStatement = statement as While;
whileStatement.Body.SymbolTable = new SymbolTable(body.SymbolTable);
Label begin = il.DefineLabel();
Label exit = il.DefineLabel();
il.MarkLabel(begin);
// Eval condition
EmitExpression(il,whileStatement.Condition,body.SymbolTable);
il.Emit(OpCodes.Brfalse,exit);
EmitBody(il,whileStatement.Body,false);
il.Emit(OpCodes.Br,begin);
il.MarkLabel(exit);
}
else if(statement is Do)
{
//
// Generate do statement.
//
Do doStatement = statement as Do;
doStatement.Body.SymbolTable = new SymbolTable(body.SymbolTable);
Label loop = il.DefineLabel();
il.MarkLabel(loop);
EmitBody(il,doStatement.Body,false);
EmitExpression(il,doStatement.Condition,body.SymbolTable);
il.Emit(OpCodes.Brtrue,loop);
}
else if(statement is For)
{
//
// Generate for statement.
//
For forStatement = statement as For;
forStatement.Body.SymbolTable = new SymbolTable(body.SymbolTable);
Label loop = il.DefineLabel();
Label exit = il.DefineLabel();
// Emit initializer
EmitAssignment(il,forStatement.Initializer,body.SymbolTable);
il.MarkLabel(loop);
// Emit condition
EmitExpression(il,forStatement.Condition,body.SymbolTable);
il.Emit(OpCodes.Brfalse,exit);
// Emit body
EmitBody(il,forStatement.Body,false);
// Emit counter
EmitAssignment(il,forStatement.Counter,body.SymbolTable);
il.Emit(OpCodes.Br,loop);
il.MarkLabel(exit);
}
}
}
private void EmitAssignment(ILGenerator il, Assignment assignment, SymbolTable symbolTable)
{
Symbol variable = symbolTable.Find(assignment.Name,SymbolType.Variable);
if(variable == null)
Error("Assignment variable " + assignment.Name + " unknown.");
// Non-indexed assignment
if(assignment.Index == null)
{
if(variable.CodeObject is ParameterBuilder)
{
Parameter p = variable.SyntaxObject as Parameter;
if(p.PassMethod == PassMethod.ByReference)
il.Emit(OpCodes.Ldarg_S,((ParameterBuilder)variable.CodeObject).Position - 1);
}
// Load value
EmitExpression(il,assignment.Value,symbolTable);
// Store
if(variable.CodeObject is LocalBuilder)
il.Emit(OpCodes.Stloc,(LocalBuilder)variable.CodeObject);
else if(variable.CodeObject is FieldBuilder)
il.Emit(OpCodes.Stsfld,(FieldBuilder)variable.CodeObject);
else if(variable.CodeObject is ParameterBuilder)
{
Parameter p = variable.SyntaxObject as Parameter;
if(p.PassMethod == PassMethod.ByReference)
il.Emit(OpCodes.Stind_I4);
else
il.Emit(OpCodes.Starg,((ParameterBuilder)variable.CodeObject).Position - 1);
}
}
else
{
// Load array.
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);
// Load index.
EmitExpression(il,assignment.Index,symbolTable);
// Load value.
EmitExpression(il,assignment.Value,symbolTable);
// Set
il.Emit(OpCodes.Stelem_I4);
}
}
private void EmitCall(ILGenerator il, Call call, SymbolTable symbolTable)
{
Symbol symbol = symbolTable.Find(call.Name,SymbolType.Function);
if(symbol != null)
{
Function function = symbol.SyntaxObject as Function;
//
// Check arguments
//
if(call.Arguments == null && function.Parameters == null)
{
// Ugly hack.
goto Hack;
}
else if(call.Arguments.Count != function.Parameters.Count)
{
Error("Argument mismatch [" + call.Name + "]");
}
else if(call.Arguments.Count != function.Parameters.Count)
{
Error("Argument mismatch [" + call.Name + "]");
}
else
{
for(int x = 0;x<call.Arguments.Count;x++)
{
if(call.Arguments[x].PassMethod != function.Parameters[x].PassMethod)
{
Error("Argument error [" + call.Name + "], argument [" + x + "] is wrong.");
}
}
}
if(call.Arguments != null)
{
foreach(Argument argument in call.Arguments)
{
if(argument.PassMethod == PassMethod.ByReference)
{
// Regular value
if(argument.Value is Name)
{
Symbol variable = symbolTable.Find(((Name)argument.Value).Value,SymbolType.Variable);
if(variable.CodeObject is LocalBuilder)
{
il.Emit(OpCodes.Ldloca,variable.CodeObject as LocalBuilder);
}
else if(variable.CodeObject is FieldBuilder)
{
il.Emit(OpCodes.Ldsflda,variable.CodeObject as FieldBuilder);
}
else if(variable.CodeObject is ParameterBuilder)
{
il.Emit(OpCodes.Ldarga_S,((ParameterBuilder) variable.CodeObject).Position - 1);
}
}
else if(argument.Value is UnaryExpression && ((UnaryExpression)argument.Value).UnaryOperatorType == UnaryOperatorType.Indexer)
{
Symbol variable = symbolTable.Find(((Name)argument.Value).Value,SymbolType.Variable);
if(variable.CodeObject is LocalBuilder)
{
if( ((Variable)variable.SyntaxObject).Type.VariableType == VariableType.PrimitiveArray)
Error("ref cannot be applied to arrays");
il.Emit(OpCodes.Ldloca,variable.CodeObject as LocalBuilder);
}
else if(variable.CodeObject is FieldBuilder)
{
if( ((Variable)variable.SyntaxObject).Type.VariableType == VariableType.PrimitiveArray)
Error("ref cannot be applied to arrays");
il.Emit(OpCodes.Ldsflda,variable.CodeObject as FieldBuilder);
}
else if(variable.CodeObject is ParameterBuilder)
{
if( ((Parameter)variable.SyntaxObject).Type.VariableType == VariableType.PrimitiveArray)
Error("ref cannot be applied to arrays");
il.Emit(OpCodes.Ldarga,((ParameterBuilder) variable.CodeObject).Position - 1);
}
EmitExpression(il,((UnaryExpression)argument.Value).Indexer,symbolTable);
il.Emit(OpCodes.Ldelema);
}
else
{
Error("ref may only be applied to variables");
}
}
else
{
EmitExpression(il,argument.Value,symbolTable);
}
}
}
Hack:
il.Emit(OpCodes.Call,((MethodBuilder)symbol.CodeObject));
}
else
{
if(call.Name == "Read")
{
il.Emit(OpCodes.Ldstr,"Input > ");
MethodInfo write = System.Type.GetType("System.Console").GetMethod("Write",new System.Type [] {typeof(string)});
il.EmitCall(OpCodes.Call,write,null);
MethodInfo read = System.Type.GetType("System.Console").GetMethod("ReadLine");
MethodInfo parse = System.Type.GetType("System.Int32").GetMethod("Parse",new System.Type [] {typeof(string)});
il.EmitCall(OpCodes.Call,read,null);
il.EmitCall(OpCodes.Call,parse,null);
}
else if(call.Name == "Write")
{
EmitExpression(il,call.Arguments[0].Value,symbolTable);
MethodInfo write = System.Type.GetType("System.Console").GetMethod("WriteLine",new System.Type [] {typeof(int)});
il.EmitCall(OpCodes.Call,write,null);
}
else
{
Error("Unknown function name. [" + call.Name + "]");
}
}
}
private void EmitCallStatement(ILGenerator il, CallStatement call, SymbolTable symbolTable)
{
Symbol symbol = symbolTable.Find(call.Name,SymbolType.Function);
if(symbol != null)
{
Function function = symbol.SyntaxObject as Function;
//
// Check arguments
//
if(call.Arguments == null && function.Parameters == null)
{
// Ugly hack.
goto Hack;
}
else if(call.Arguments.Count != function.Parameters.Count)
{
Error("Argument mismatch [" + call.Name + "]");
}
else if(call.Arguments.Count != function.Parameters.Count)
{
Error("Argument mismatch [" + call.Name + "]");
}
else
{
for(int x = 0;x<call.Arguments.Count;x++)
{
if(call.Arguments[x].PassMethod != function.Parameters[x].PassMethod)
{
Error("Argument error [" + call.Name + "], argument [" + x + "] is wrong.");
}
}
}
if(call.Arguments != null)
{
foreach(Argument argument in call.Arguments)
{
if(argument.PassMethod == PassMethod.ByReference)
{
// Regular value
if(argument.Value is Name)
{
Symbol variable = symbolTable.Find(((Name)argument.Value).Value,SymbolType.Variable);
if(variable.CodeObject is LocalBuilder)
{
if( ((Variable)variable.SyntaxObject).Type.VariableType == VariableType.PrimitiveArray)
Error("ref cannot be applied to arrays");
il.Emit(OpCodes.Ldloca,variable.CodeObject as LocalBuilder);
}
else if(variable.CodeObject is FieldBuilder)
{
if( ((Variable)variable.SyntaxObject).Type.VariableType == VariableType.PrimitiveArray)
Error("ref cannot be applied to arrays");
il.Emit(OpCodes.Ldsflda,variable.CodeObject as FieldBuilder);
}
else if(variable.CodeObject is ParameterBuilder)
{
if( ((Parameter)variable.SyntaxObject).Type.VariableType == VariableType.PrimitiveArray)
Error("ref cannot be applied to arrays");
il.Emit(OpCodes.Ldarga,((ParameterBuilder) variable.CodeObject).Position - 1);
}
}
else if(argument.Value is UnaryExpression && ((UnaryExpression)argument.Value).UnaryOperatorType == UnaryOperatorType.Indexer)
{
Symbol variable = symbolTable.Find(((Name)argument.Value).Value,SymbolType.Variable);
if(variable.CodeObject is LocalBuilder)
{
il.Emit(OpCodes.Ldloc,variable.CodeObject as LocalBuilder);
}
else if(variable.CodeObject is FieldBuilder)
{
il.Emit(OpCodes.Ldsfld,variable.CodeObject as FieldBuilder);
}
else if(variable.CodeObject is ParameterBuilder)
{
il.Emit(OpCodes.Ldarga,((ParameterBuilder) variable.CodeObject).Position - 1);
}
EmitExpression(il,((UnaryExpression)argument.Value).Indexer,symbolTable);
il.Emit(OpCodes.Ldelema);
}
else
{
Error("ref may only be applied to variables");
}
}
else
{
EmitExpression(il,argument.Value,symbolTable);
}
}
}
Hack:
il.Emit(OpCodes.Call,((MethodBuilder)symbol.CodeObject));
}
else
{
if(call.Name == "Read")
{
il.Emit(OpCodes.Ldstr,"Input > ");
MethodInfo write = System.Type.GetType("System.Console").GetMethod("Write",new System.Type [] {typeof(string)});
il.EmitCall(OpCodes.Call,write,null);
MethodInfo read = System.Type.GetType("System.Console").GetMethod("ReadLine");
MethodInfo parse = System.Type.GetType("System.Int32").GetMethod("Parse",new System.Type [] {typeof(string)});
il.EmitCall(OpCodes.Call,read,null);
il.EmitCall(OpCodes.Call,parse,null);
}
else if(call.Name == "Write")
{
EmitExpression(il,call.Arguments[0].Value,symbolTable);
MethodInfo write = System.Type.GetType("System.Console").GetMethod("WriteLine",new System.Type [] {typeof(int)});
il.EmitCall(OpCodes.Call,write,null);
}
else
{
Error("Unknown function name. [" + call.Name + "]");
}
}
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -