C语言解释器-14 函数

函数的实现如下:

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);
	}



 

 

 

 

你可能感兴趣的:(C#,C语言,解释器,形式语言和自动机)