📄 cslang.txt
字号:
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 }; may be added via if (-1 == SLadd_intrin_var_table (Intrin_Vars, NULL)) exit (EXIT_FAILURE); It should be rather obvious that the arguments to the MAKE_VARIABLE macro correspond to the parameters of the 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. 3.5. Aggregate Data Objects An aggregate data object is an object that can contain more than one data value. The S-Lang interpreter supports several such objects: arrays, structure, and associative arrays. In the following sections, information about interacting with these objects is given. 3.5.1. 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: SLang_create_array SLang_pop_array_of_type SLang_push_array SLang_free_array SLang_get_array_element SLang_set_array_element The use of these functions will be illustrated via a few simple exam- ples. 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: 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); } This example illustrates several points. First of all, the SLang_cre- ate_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 SLang_set_array_element function was used to set the elements of the newly created array. Note that the address con- taining the value of the array element was passed and not the value of the array element itself. That is, SLang_set_array_element (at, &i, seasons[i]) 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 1. When it was pushed, the reference count was bumped up to 2. Then since it was nolonger needed by the function, SLang_free_array was called to decrement the reference count back to 1. For convenience, the second argument to SLang_push_array deter- mines whether or not it is to also free the array. So, instead of the two function calls: (void) SLang_push_array (at, 0); SLang_free_array (at); it is preferable to combine them as (void) SLang_push_array (at, 1); The second example returns a diagonal array of a specified size to the stack. A diagonal array is a 2-d array with all elements zero except for those along the diagonal, which have a value of one: void make_diagonal_array (int n) { SLang_Array_Type *at; int dims[2]; int i, one; dims[0] = dims[1] = n; at = SLang_create_array (SLANG_INT_TYPE, 0, NULL, dims, 2); if (at == NULL) return; one = 1; for (i = 0; i < n; i++) { dims[0] = dims[1] = i; if (-1 == SLang_set_array_element (at, dims, &one)) { SLang_free_array (at); return; } } (void) SLang_push_array (at, 1); } In this example, only the diagonal elements of the array were set. This is bacause when the array was created, all its elements were set to zero. Now consider an example that acts upon an existing array. In particular, consider one that computes the trace of a 2-d matrix, i.e., the sum of the diagonal elements: double compute_trace (void) { SLang_Array_Type *at; double trace; int dims[2]; if (-1 == SLang_pop_array_of_type (&at, SLANG_DOUBLE_TYPE)) return 0.0; /* We want a 2-d square matrix. If the matrix is 1-d and has only one element, then return that element. */ trace = 0.0; if (((at->num_dims == 1) && (at->dims[0] == 1)) || ((at->num_dims == 2) && (at->dims[0] == at->dims[1]))) { double dtrace; int n = at->dims[0]; for (i = 0; i < n; i++) { dims[0] = dims[1] = i; (void) SLang_get_array_element (at, &dims, &dtrace); trace += dtrace; } } else SLang_verror (SL_TYPE_MISMATCH, "Expecting a square matrix"); SLang_free_array (at); return trace; } In this example, SLang_pop_array_of_type was used to pop an array of doubles from the stack. This function will make implicit typecasts in order to return an array of the requested type. 3.5.2. Structures For the purposes of this section, we shall differentiate structures according to whether or not they correspond to an application defined C structure. Those that do are called intrinsic structures, and those do not are called S-Lang interpreter structures. 3.5.2.1. Interpreter Structures The following simple example shows one method that may be used to create and return a structure with a string and integer field to the interpreter's stack: int push_struct_example (char *string_value, int int_value) { char *field_names[2]; unsigned char field_types[2]; VOID_STAR field_values[2]; field_names[0] = "string_field"; field_types[0] = SLANG_STRING_TYPE; field_values[0] = &string_value; field_names[1] = "int_field"; field_types[1] = SLANG_INT_TYPE; field_values[1] = &int_value; if (-1 == SLstruct_create_struct (2, field_names, field_types, field_values)) return -1; return 0; } Here, SLstruct_create_struct is used to push a structure with the specified field names and values onto the interpreter's stack. A simpler mechanism exists provided that one has already defined a C structure with a description of how the structure is laid out. For example, consider a C structure defined by typedef struct { char *s; int i; } SI_Type; Its layout may be specified via a table of SLang_CStruct_Field_Type entries: SLang_CStruct_Field_Type SI_Type_Layout [] = { MAKE_CSTRUCT_FIELD(SI_Type, s, "string_field", SLANG_STRING_TYPE, 0), MAKE_CSTRUCT_FIELD(SI_Type, i, "int_field", SLANG_INT_TYPE, 0), SLANG_END_CSTRUCT_TABLE }; Here, MAKE_CSTRUCT_FIELD is a macro taking 5 arguments: MAKE_CSTRUCT_FIELD(C-structure-type, C-field-name, slang-field-name, slang-data-type, is-read-only) The first argument is the structure type, the second is the name of a field of the structure, the third is a string that specifies the name of the corresponding field of the S-Lang structure, the fourth argu- ment specifies the field's type, and the last argument specifies whether or not the field should be regarded as read-only. Once the layout of the structure has been specified, pushing a S-Lang version of the structure is trival: int push_struct_example (char *string_value, int int_value) { SI_Type si; si.s = string_value; si.i = int_value; return SLang_push_cstruct ((VOID_STAR)&si, SI_Type_Layout); } This mechanism of structure creation also permits a S-Lang structure to be passed to an intrinsic function through the use of the SLang_pop_cstruct routine, e.g., void print_si_struct (void) { SI_Type si; if (-1 == SLang_pop_cstruct ((VOID_STAR)&si, SI_Type_Layout)) return; printf ("si.i=%d", si.i); printf ("si.s=%s", si.s); SLang_free_cstruct ((VOID_STAR)&si, SI_Type_Layout); } Assuming print_si_struct exists as an intrinsic function, the S-Lang code variable s = struct {string_field, int_field}; s.string_field = "hello"; s.int_field = 20; print_si_struct (s); would result in the display of si.i=20; si.s=hello Note that the SLang_free_cstruct function was called after the con- tents of si were nolonger needed. This was necessary because SLang_pop_cstruct allocated memory to set the char *s field of si. Calling SLang_free_cstruct frees up such memory. Now consider the following: typedef struct { pid_t pid; gid_t group; } X_t; How should the layout of this structure be defined? One might be tempted to use: SLang_CStruct_Field_Type X_t_Layout [] = { MAKE_CSTRUCT_FIELD(X_t, pid, "pid", SLANG_INT_TYPE, 0), MAKE_CSTRUCT_FIELD(X_t, group, "group", SLANG_INT_TYPE, 0), SLANG_END_CSTRUCT_TABLE }; However, this assumes pid_t and gid_t have been typedefed as ints. But what if gid_t is a short? In such a case, using MAKE_CSTRUCT_FIELD(X_t, group, "group", SLANG_SHORT_TYPE, 0), would be the appropriate entry for the group field. Of course, one has no way of knowing how gid_t is declared on other systems. For this reason, it is preferable to use the MAKE_CSTRUCT_INT_FIELD macro in cases involving integer valued fields, e.g., SLang_CStruct_Field_Type X_t_Layout [] = { MAKE_CSTRUCT_INT_FIELD(X_t, pid, "pid", 0), MAKE_CSTRUCT_INT_FIELD(X_t, group, "group", 0), SLANG_END_CSTRUCT_TABLE }; Before leaving this section, it is important to mention that access to character array fields is not permitted via this interface. That is, a structure such as typedef struct { char name[32];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -