cslang.tm
来自「一个C格式的脚本处理函数库源代码,可让你的C程序具有执行C格式的脚本文件」· TM 代码 · 共 1,759 行 · 第 1/5 页
TM
1,759 行
table via the \cfun{SLadd_intrin_fun_table} function. The table will look like:#v+ SLang_Intrin_Fun_Type My_Intrinsics [] = { /* table entries */ MAKE_INTRINSIC_N(...), MAKE_INTRINSIC_N(...), . . MAKE_INTRINSIC_N(...), SLANG_END_INTRIN_FUN_TABLE };#v- Construction of the table entries may be facilitated using a set of \var{MAKE_INTRINSIC} macros defined in \var{slang.h}. The main macro is called \var{MAKE_INTRINSIC_N} and takes 11 arguments:#v+ MAKE_INTRINSIC_N(name, funct-ptr, return-type, num-args, arg-1-type, arg-2-type, ... arg-7-type)#v- Here \var{name} is the name of the intrinsic function that the interpreter is to give to the function. \var{func-ptr} is a pointer to the intrinsic function taking \var{num-args} and returning \var{ret-type}. The final \exmp{7} arguments specifiy the argument types. For example, the \var{intrin_exit} intrinsic described above may be added to the table using#v+ MAKE_INTRINSIC_N("exit", intrin_exit, SLANG_VOID_TYPE, 1, SLANG_INT_TYPE, 0,0,0,0,0,0)#v- While \var{MAKE_INTRINSIC_N} is the main macro for constructing table entries, \var{slang.h} defines other macros that may prove useful. In particular, an entry for the \var{intrin_exit} function may also be created using any of the following forms:#v+ MAKE_INTRINSIC_1("exit", intrin_exit, SLANG_VOID_TYPE, SLANG_INT_TYPE) MAKE_INTRINSIC_I("exit", intrin_exit, SLANG_VOID_TYPE)#v- See \var{slang.h} for related macros. You are also encouraged to look at, e.g., \var{slang/src/slstd.c} for a more extensive examples. The table may be added via the \cfun{SLadd_intrin_fun_table} function, e.g.,#v+ if (-1 == SLadd_intrin_fun_table (My_Intrinsics, NULL)) { /* an error occurred */ }#v- Please note that there is no need to load a given table more than once, and it is considered to be an error on the part of the application it adds the same table multiple times. For performance reasons, no checking is performed by the library to see if a table has already been added. Earlier it was mentioned that intrinsics may be added to a specified namespace. To this end, one must first get a pointer to the namespace via the \cfun{SLns_create_namespace} function. The following example illustrates how this function is used to add the \var{My_Intrinsics} table to a namespace called \exmp{my}:#v+ SLang_NameSpace_Type *ns = SLns_create_namespace ("my"); if (ns == NULL) return -1; return SLns_add_intrin_fun_table (ns, My_Intrinsics, "__MY__"));#v-#%}}}\sect1{More Complicated Intrinsics} #%{{{ The intrinsic functions described in the previous example were functions that took a fixed number of arguments. In this section we explore more complex intrinsics such as those that take a variable number of arguments. Consider a function that takes two double precision numbers and returns the lesser: #v+ double intrin_min (double *a, double *b) { if (*a < *b) return *a; return *b; }#v- This function may be added to a table of intrinsics using#v+ MAKE_INTRINSIC_2("vmin", intrin_min, SLANG_DOUBLE_TYPE, SLANG_DOUBLE_TYPE, SLANG_DOUBLE_TYPE)#v- It is useful to extend this function to take an arbitray number of arguments and return the lesser. Consider the following variant:#v+ double intrin_min_n (int *num_ptr) { double min_value, x; unsigned int num = (unsigned int) *num_ptr; if (-1 == SLang_pop_double (&min_value, NULL, NULL)) return 0.0; num--; while (num > 0) { num--; if (-1 == SLang_pop_double (&x, NULL, NULL)) return 0.0; if (x < min_value) min_value = x; } return min_value; }#v- Here the number to compare is passed to the function and the actual numbers are removed from the stack via the \cfun{SLang_pop_double} function. A suitable table entry for it is#v+ MAKE_INTRINSIC_I("vmin", intrin_min_n, SLANG_DOUBLE_TYPE)#v- This function would be used in an interpreter script via a statement such as#v+ variable xmin = vmin (x0, x1, x2, x3, x4, 5);#v- which computes the smallest of \exmp{5} values. The problem with this intrinsic function is that the user must explicitly specify how many numbers to compare. It would be more convenient to simply use#v+ variable xmin = vmin (x0, x1, x2, x3, x4);#v- An intrinsic function can query the value of the variable \var{SLang_Num_Function_Args} to obtain the necessary information:#v+ double intrin_min (void) { double min_value, x; unsigned int num = SLang_Num_Function_Args; if (-1 == SLang_pop_double (&min_value, NULL, NULL)) return 0.0; num--; while (num > 0) { num--; if (-1 == SLang_pop_double (&x, NULL, NULL)) return 0.0; if (x < min_value) min_value = x; } return min_value; }#v- This may be declared as an intrinsic using:#v+ MAKE_INTRINSIC_0("vmin", intrin_min, SLANG_DOUBLE_TYPE) #v-#%}}}#%}}}\sect{Intrinsic Variables} #%{{{ It is possible to access an application's global variables from within the interpreter. The current implementation supports the access of variables of type \var{int}, \var{char *}, and \var{double}. There are two basic methods of making an intrinsic variable available to the interpreter. The most straight forward method is to use the function \cfun{SLadd_intrinsic_variable}:#v+ int SLadd_intrinsic_variable (char *name, VOID_STAR addr, unsigned char data_type, int read_only);#v- For example, suppose that \var{I} is an integer variable, e.g.,#v+ int I;#v- One can make it known to the interpreter as \var{I_Variable} via a statement such as #v+ if (-1 == SLadd_intrinsic_variable ("I_Variable", &I, SLANG_INT_TYPE, 0)) exit (EXIT_FAILURE);#v- Similarly, if \var{S} is declared as#v+ char *S;#v- then #v+ if (-1 == SLadd_intrinsic_variable ("S_Variable", &S, SLANG_STRING_TYPE, 1)) exit (EXIT_FAILURE);#v- makes \var{S} available as a \em{read-only} variable with the name \var{S_Variable}. Note that if a pointer variable is made available to the interpreter, its value is managed by the interpreter and not the application. For this reason, it is recommended that such variables be declared as \em{read-only}. It is important to note that if \var{S} were declared as an array of characters, e.g.,#v+ char S[256];#v- then it would not be possible to make it directly available to the interpreter. However, one could create a pointer to it, i.e.,#v+ char *S_Ptr = S;#v- and make \var{S_Ptr} available as a read-only variable. One should not make the mistake of trying to use the same address for different variables as the following example illustrates:#v+ int do_not_try_this (void) { static char *names[3] = {"larry", "curly", "moe"}; unsigned int i; for (i = 0; i < 3; i++) { int value; if (-1 == SLadd_intrinsic_variable (names[i], (VOID_STAR) &value, SLANG_INT_TYPE, 1)) return -1; } return 0; }#v- Not only does this piece of code create intrinsic variables that use the same address, it also uses the address of a local variable that will go out of scope. The most convenient method for adding many intrinsic variables to the interpreter is to create an array of \var{SLang_Intrin_Var_Type} objects and then add the array via \cfun{SLadd_intrin_var_table}. For example, the array#v+ static SLang_Intrin_Var_Type Intrin_Vars [] = { MAKE_VARIABLE("I_Variable", &I, SLANG_INT_TYPE, 0), MAKE_VARIABLE("S_Variable", &S_Ptr, SLANG_STRING_TYPE, 1), SLANG_END_TABLE };#v- may be added via#v+ if (-1 == SLadd_intrin_var_table (Intrin_Vars, NULL)) exit (EXIT_FAILURE);#v- It should be rather obvious that the arguments to the \var{MAKE_VARIABLE} macro correspond to the parameters of the \cfun{SLadd_intrinsic_variable} function. Finally, variables may be added to a specific namespace via the SLns_add_intrin_var_table and SLns_add_intrinsic_variable functions.#%}}}\sect{Aggregate Data Objects} #%{{{ An aggregate data object is an object that can contain more than one data value. The \slang interpreter supports several such objects: arrays, structure, and associative arrays. In the following sections, information about interacting with these objects is given.\sect1{Arrays} #%{{{ An intrinsic function may interact with an array in several different ways. For example, an intrinsic may create an array and return it. The basic functions for manipulating arrays include:#v+ SLang_create_array SLang_pop_array_of_type SLang_push_array SLang_free_array SLang_get_array_element SLang_set_array_element#v- The use of these functions will be illustrated via a few simple examples. The first example shows how to create an return an array of strings to the interpreter. In particular, the names of the four seasons of the year will be returned:#v+ void months_of_the_year (void) { static char *seasons[4] = { "Spring", "Summer", "Autumn", "Winter" }; SLang_Array_Type *at; int i, four; four = 4; at = SLang_create_array (SLANG_STRING_TYPE, 0, NULL, &four, 1); if (at == NULL) return; /* Now set the elements of the array */ for (i = 0; i < 4; i++) { if (-1 == SLang_set_array_element (at, &i, &seasons[i])) { SLang_free_array (at); return; } } (void) SLang_push_array (at, 0); SLang_free_array (at); }#v- This example illustrates several points. First of all, the \cfun{SLang_create_array} function was used to create a 1 dimensional array of 4 strings. Since this function could fail, its return value was checked. Then the \cfun{SLang_set_array_element} function was used to set the elements of the newly created array. Note that the address containing the value of the array element was passed and not the value of the array element itself. That is,#v+ SLang_set_array_element (at, &i, seasons[i])#v- was not used. The return value from this function was also checked because it too could also fail. Finally, the array was pushed onto the interpreter's stack and then it was freed. It is important to understand why it was freed. This is because arrays are reference-counted. When the array was created, it was returned with a reference count of \var{1}. When it was pushed, the reference count was bumped up to \var{2}. Then since it was nolonger needed by the function, \cfun{SLang_free_array} was called to decrement the reference count back to \var{1}. For convenience, the second argument to \cfun{SLang_push_array} determines whether or not it is to also free the array. So, instead of the two function calls:#v+ (void) SLang_push_array (at, 0); SLang_free_array (at);#v- it is preferable to combine them as#v+ (void) SLang_push_array (at, 1);#v- The second example returns a diagonal array of a specified size to
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?