SharpC-A-C-Interpreter-In-C-1000

50次阅读

共计 8230 个字符,预计需要花费 21 分钟才能阅读完成。

函数的实现如下:

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

正文完
 0