C語言解譯器-14 函數

來源:互聯網
上載者:User

函數的實現如下:

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

 

 

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.