C language interpreter-14 Functions

Source: Internet
Author: User

The function is implemented as follows:

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;      ...

The FindByName search method requires a list of parameters:

public override Context FindByName(string str)        {            if (ArgumentDefinitions != null)            {                foreach (FunctionArgumentDefine arg in ArgumentDefinitions)                {                    if (arg.Name == str)                        return arg;                }            }                        return base.FindByName(str);        }

The running method is as follows:

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": ""); // preparation BeforeRun (ctx, parameters); Run (ctx); // cleaning AfterRun (ctx );}

Preparations include:

1. initialize function parameters.

2. Set the function parameters using the input parameters (it seems like the logging interface ).

3. initialize the parameter stack for recursion.

 

Read the Code:

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

The parameter initialization is performed only when the first call is made. In this case, apart from variable parameter functions, fixed parameter functions need to release these parameters at the end of the interpreter program. Please refer to the previous article ~ Context () code.

Before and After always appear in pairs:

IteratorCount--;            if (IteratorCount > 0)            {                if (m_parameterStack.Count > 0)                {                    RestoreParameter(ctx);                }            }            else            {                // Clean variable arguments                if (IsVariableArgument)                {                    FreeVariableArgument(ctx);                }            }

Note that the previous parameter must be restored from recursive return.

 

Now, reload the Context. Run () method. Note: Because Forward Declaration is supported, the function body may be empty:

public override void Run(Context ctx)        {            if (Body != null)            {                Body.Run(this);            }        }

Now, the function structure has begun to take shape.

The following uses malloc as an example to illustrate how to implement an internal function:

Public class Malloc: FunctionDefine {public Malloc () {// init name Name = "malloc"; // Init return type ReturnType = new DataTypeInfo () {Type = PrimitiveDataType. voidType | PrimitiveDataType. pointerType, PointerCount = 1}; // initialize the parameter list ArgumentDefinitions. add (new FunctionArgumentDefine () {Name = "size", TypeInfo = new DataTypeInfo () {Type = PrimitiveDataType. intType | PrimitiveDataType. unsignedType}); // register to the global directory so that the analyzer can access the Context. registerInternalFunction (Name);} public override void Run (Context ctx) {FunctionArgumentDefine arg = ArgumentDefinitions. first () as FunctionArgumentDefine; ReturnValue = new Expression. operand. value () {DataType = PrimitiveDataType. intType, // allocate memory, with the address DataField = Context. memory. allocate (arg. getValue (). asInt )};}}

 

Let's look at the complicated print () method for printing output (). Note: This is a variable parameter function:

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; // indicates IsVariableArgument = true; Context. registerInternalFunction (Name);} public override void Run (Context ctx) {if (ArgumentDefinitions. count <1) return; // The first parameter should be of the string pointer type. It is the output template 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; // format the output 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; // output percentage case 'F': // floating point {if (argIdx <ArgumentDefinitions. count) {sb. append (ArgumentDefinitions [argIdx ++] as FunctionArgumentDefine ). getValue (). asFloat. toString () ;}} break; case 'I': // output INTEGER {if (argIdx <ArgumentDefinitions. count) {sb. append (ArgumentDefinitions [argIdx ++] as FunctionArgumentDefine ). getValue (). asInt. toString () ;}} break; case's ': // output string {if (argIdx <ArgumentDefinitions. count) {sb. append (Context. memory. getString (ArgumentDefinitions [argIdx ++] as FunctionArgumentDefine ). pointerAddress) ;}} break; case 'U': // The output unsigned integer {if (argIdx <ArgumentDefinitions. count) {sb. append (ArgumentDefinitions [argIdx ++] as FunctionArgumentDefine ). getValue (). asInt. toString ("{u}") ;}} break; case 'X': // output hexadecimal number 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: // unsupported format {sb. append ('%'); sb. append (ch);} break;} I ++;} else {// escape characters and other 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 ());}}}

 

The more complex one is the input () method. See its definition:

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

Six parameters are required, all of which are pointer types, and a return value is added. The execution process is as follows:

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

The following is a part of the execution of internal functions in C code:

         int iVal = 0;if (input("Test Input", "Please input a string", "0", "%i", "Integer required", &iVal)){print("result=%i \n", iVal);}

 

 

 

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

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.