函数的实现如下:
public class FunctionDefine : Context
{
private Stack> m_parameterStack;
public DataTypeInfo ReturnType;
public Expression.Operand.Operand ReturnValue;
public bool IsVariableArgument;
public int ReferenceCount;
public int IteratorCount = 0;
public List 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 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);
}
准备工作包括:
- 初始化函数参数。
- 使用传入的参数设置函数参数(好像很拗口)。
- 初始化参数栈,以备递归。
不多说,看代码:
private void BeforeRun(Context ctx, List 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);
}