函数的实现如下:
public class FunctionDefine : Context { private Stack<List<Expression.Operand.Value>> m_parameterStack; public DataTypeInfo ReturnType; public Expression.Operand.Operand ReturnValue; public bool IsVariableArgument; public int ReferenceCount; public int IteratorCount = 0; public List<Context> ArgumentDefinitions; public Block Body; ...
其查找方法FindByName需要搜索参数列表:
public override Context FindByName(string str) { if (ArgumentDefinitions != null) { foreach (FunctionArgumentDefine arg in ArgumentDefinitions) { if (arg.Name == str) return arg; } } return base.FindByName(str); }
其运行方法实现如下:
public virtual void Run(Context ctx, List<Expression.Operand.Operand> parameters) { Debug.WriteLine(string.Format("Call function \"{0}\" with [{1}] parameter{2}", Name, parameters.Count, parameters.Count > 0 ? "s" : "")); // 准备工作 BeforeRun(ctx, parameters); Run(ctx); // 清场工作 AfterRun(ctx); }
准备工作包括:
1. 初始化函数参数。
2. 使用传入的参数设置函数参数(好像很拗口)。
3. 初始化参数栈,以备递归。
不多说,看代码:
private void BeforeRun(Context ctx, List<Expression.Operand.Operand> parameters) { if (IsFirstRunning) { ConfigReturnEvent(ctx); AllocateFixedArguments(ctx); IsFirstRunning = false; } if (IsVariableArgument) { FreeVariableArgument(ctx); AllocateVariableArguments(ctx, parameters); } SavePreviousParameters(ctx); InitArguments(ctx, parameters); IteratorCount++; }
出效率计,仅在第一调用时进行参数初始化工作。这样导致一个副作用就是除变参函数外,固定参数函数需要在解释程序运行到最后时释放这些参数。请参考前面的文章之~Context()代码。
Before和After总是成对出现:
IteratorCount--; if (IteratorCount > 0) { if (m_parameterStack.Count > 0) { RestoreParameter(ctx); } } else { // Clean variable arguments if (IsVariableArgument) { FreeVariableArgument(ctx); } }
注意,从递归返回时要恢复前次的参数。
现在,重载Context.Run()方法。注意:由于支持前向申明,所以函数体可能为空:
public override void Run(Context ctx) { if (Body != null) { Body.Run(this); } }
现而今,函数的结构已经初具。
下面,以malloc为例,看看怎么实现一个内部函数:
public class Malloc : FunctionDefine { public Malloc() { // init name Name = "malloc"; // Init return type ReturnType = new DataTypeInfo() { Type = PrimitiveDataType.VoidType | PrimitiveDataType.PointerType, PointerCount = 1 }; // 初始化参数列表 ArgumentDefinitions.Add(new FunctionArgumentDefine() { Name = "size", TypeInfo = new DataTypeInfo() { Type = PrimitiveDataType.IntType | PrimitiveDataType.UnsignedType } }); // 注册到全局,使得分析器能够访问 Context.RegisterInternalFunction(Name); } public override void Run(Context ctx) { FunctionArgumentDefine arg = ArgumentDefinitions.First() as FunctionArgumentDefine; ReturnValue = new Expression.Operand.Value() { DataType = PrimitiveDataType.IntType, // 分配内存,给出地址 DataField = Context.Memory.Allocate(arg.GetValue().AsInt) }; } }
再看看复杂一点的用于打印输出的方法print()。注意,这是个变参函数:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Diagnostics; namespace SharpC.Grammar.Function.InternalFunction { public class Print : FunctionDefine { public Print() { Name = "print"; ReturnType.Type = PrimitiveDataType.VoidType; //表明变参身份 IsVariableArgument = true; Context.RegisterInternalFunction(Name); } public override void Run(Context ctx) { if (ArgumentDefinitions.Count < 1) return; // 第一个参数应该是字符串指针类型,为输出模板 FunctionArgumentDefine argFormat = ArgumentDefinitions.First() as FunctionArgumentDefine; string formatStr = Context.Memory.GetString(argFormat.PointerAddress); #if DEBUG Debug.Write(string.Format("print(\"{0}\"", formatStr)); for (int m = 1; m < ArgumentDefinitions.Count; m++) Debug.Write("," + (ArgumentDefinitions[m] as FunctionArgumentDefine).GetValue().ToString()); Debug.Write(")"); #endif StringBuilder sb = new StringBuilder(); int len = formatStr.Length; int i = 0; int argIdx = 1; int argLen = ArgumentDefinitions.Count; // 格式化输出 while(i < len) { char ch = formatStr[i]; if (ch == '%') { i++; if (i >= len) { sb.Append('%'); break; } ch = formatStr[i]; switch (ch) { case '%': sb.Append('%'); break;//输出百分号 case 'f': //浮点数 { if (argIdx < ArgumentDefinitions.Count) { sb.Append((ArgumentDefinitions[argIdx++] as FunctionArgumentDefine).GetValue().AsFloat.ToString()); } } break; case 'i': // 输出整数 { if (argIdx < ArgumentDefinitions.Count) { sb.Append((ArgumentDefinitions[argIdx++] as FunctionArgumentDefine).GetValue().AsInt.ToString()); } } break; case 's': // 输出字符串 { if (argIdx < ArgumentDefinitions.Count) { sb.Append(Context.Memory.GetString((ArgumentDefinitions[argIdx++] as FunctionArgumentDefine).PointerAddress)); } } break; case 'u': // 输出无符号整数 { if (argIdx < ArgumentDefinitions.Count) { sb.Append((ArgumentDefinitions[argIdx++] as FunctionArgumentDefine).GetValue().AsInt.ToString("{u}")); } } break; case 'x': // 输出16进制数 case 'X': { if (argIdx < ArgumentDefinitions.Count) { int res = (ArgumentDefinitions[argIdx++] as FunctionArgumentDefine).GetValue().AsInt; if (ch == 'x') sb.Append(res.ToString("{x}")); else sb.Append(res.ToString("{X}")); } } break; default: // 不支持的格式 { sb.Append('%'); sb.Append(ch); } break; } i++; } else { // 转义字符及其它 switch (ch) { case '\\': { i++; if (i >= len) { // Invalid escape character break; } ch = formatStr[i]; switch (ch) { case 'a': sb.Append('\a'); break; case 'b': sb.Append('\b'); break; case 'f': sb.Append('\f'); break; case 'n': sb.Append('\n'); break; case 't': sb.Append('\t'); break; case 'v': sb.Append('\v'); break; case '"': sb.Append('"'); break; case '\\': sb.Append('\\'); break; default: { sb.Append('\\'); sb.Append(ch); } break; } i++; } break; default: sb.Append(ch); i++; break; } } } // while Debug.WriteLine(" output:{{" + sb.ToString() + "}}"); Console.Write(sb.ToString()); } } }
更复杂一点的,是input()方法。看其定义:
public class Input : FunctionDefine { public Input() { Name = "input"; ReturnType.Type = PrimitiveDataType.IntType; ArgumentDefinitions.Add(new FunctionArgumentDefine() { Name = "title", TypeInfo = new DataTypeInfo() { Type = PrimitiveDataType.CharType | PrimitiveDataType.PointerType, PointerCount = 1 } }); ArgumentDefinitions.Add(new FunctionArgumentDefine() { Name = "message", TypeInfo = new DataTypeInfo() { Type = PrimitiveDataType.CharType | PrimitiveDataType.PointerType, PointerCount = 1 } }); ArgumentDefinitions.Add(new FunctionArgumentDefine() { Name = "defValue", TypeInfo = new DataTypeInfo() { Type = PrimitiveDataType.CharType | PrimitiveDataType.PointerType, PointerCount = 1 } }); ArgumentDefinitions.Add(new FunctionArgumentDefine() { Name = "format", TypeInfo = new DataTypeInfo() { Type = PrimitiveDataType.CharType | PrimitiveDataType.PointerType, PointerCount = 1 } }); ArgumentDefinitions.Add(new FunctionArgumentDefine() { Name = "errMsg", TypeInfo = new DataTypeInfo() { Type = PrimitiveDataType.CharType | PrimitiveDataType.PointerType, PointerCount = 1 } }); ArgumentDefinitions.Add(new FunctionArgumentDefine() { Name = "result", TypeInfo = new DataTypeInfo() { Type = PrimitiveDataType.CharType | PrimitiveDataType.PointerType, PointerCount = 1 } }); Context.RegisterInternalFunction(Name); }
需要6个参数,全部是指针类型,再加一个返回值。其执行处理如下:
public override void Run(Context ctx) { Function.FunctionArgumentDefine argTitle = ArgumentDefinitions[0] as Function.FunctionArgumentDefine; Function.FunctionArgumentDefine argMsg = ArgumentDefinitions[1] as Function.FunctionArgumentDefine; Function.FunctionArgumentDefine argDefVal = ArgumentDefinitions[2] as Function.FunctionArgumentDefine; Function.FunctionArgumentDefine argFormat = ArgumentDefinitions[3] as Function.FunctionArgumentDefine; Function.FunctionArgumentDefine argErrMsg = ArgumentDefinitions[4] as Function.FunctionArgumentDefine; Function.FunctionArgumentDefine argResult = ArgumentDefinitions[5] as Function.FunctionArgumentDefine; if (argResult.Address == 0) throw new RuntimeException(string.Format("Parameter \"{0}\" is invalid: {1}.", argResult.Name, argResult.Address)); InputForm inputFrm = new InputForm(); inputFrm.Title = argTitle.Address != 0 ? Context.Memory.GetString(argTitle.PointerAddress) : string.Empty; inputFrm.Message = argMsg.Address != 0 ? Context.Memory.GetString(argMsg.PointerAddress) : string.Empty; inputFrm.DefaultValue = argDefVal.Address != 0 ? Context.Memory.GetString(argDefVal.PointerAddress) : string.Empty; inputFrm.Format = argFormat.Address != 0 ? Context.Memory.GetString(argFormat.PointerAddress) : string.Empty; inputFrm.ValidationMessage = argErrMsg.Address != 0 ? Context.Memory.GetString(argErrMsg.PointerAddress) : string.Empty; int resVal = 0; if (inputFrm.ShowDialog() == System.Windows.Forms.DialogResult.OK) { int address = argResult.PointerAddress; switch (inputFrm.Format) { case "%f": Context.Memory.SetFloat(address, float.Parse(inputFrm.Result)); break; case "%i": Context.Memory.SetInt(address, int.Parse(inputFrm.Result)); break; case "%u": Context.Memory.SetInt(address, (int)uint.Parse(inputFrm.Result)); break; case "%x": Context.Memory.SetInt(address, (int)uint.Parse(inputFrm.Result)); break; case "%c": Context.Memory.SetChar(address, (byte)inputFrm.Result[0]); break; case "%s": default: Context.Memory.SetString(address, inputFrm.Result); break; } resVal = 1; } ReturnValue = new Expression.Operand.Value() { DataType = PrimitiveDataType.IntType, DataField = resVal }; }
另附在C代码中执行内部函数的片断:
int iVal = 0; if (input("Test Input", "Please input a string", "0", "%i", "Integer required", &iVal)) { print("result=%i \n", iVal); }