Next: , Up: Imperative Language Interpreter Usage Outline

4.1.1 Parsing A Program (I)

Parsing a program requires providing the interpreter with the program textual representation and some functions, operators and variables sets. Basic error reporting will also be demonstrated in this section since getting parsing errors with no further details may be quite frustrating.

The parsing of programs very much ressembles parsing expressions.

See Parsing An Expression.

The actual program parsing may be achieved as in:

status = x1f4_init_program(&program, data, flags, &c1);

See x1f4_init_program.

The x1f4_init_program function builds the executable representation of the program from its data textual representation (null terminated string if not otherwise specified) and stores the result in program.

Program executable representations are opaque structures and application wise typeless. Only references to program executable representations are application available. For convenience the C type of program executable representations is void *.

One may declare program as:

void *program;

The rest of x1f4_init_program input is provided via the c1 record. The flags parameter hints x1f4_init_program that it must pay attention to certain c1 fields. In this simple example it is assumed X1f4_C1_BCOLLECT.

See Imperative Language Interpreter Generation Flags.

The C type of the c1 record is struct x1f4_c1_type. The c1 record is thus declared as:

struct x1f4_c1_type c1;

See struct x1f4_c1_type.

The minimal additional input for program parsing is the functions, operators and variables sets in use.

The variables set refers those variables used as state exports from the application toward the executed program. It is specified as a specialized collection (radix tree based). If no state export via variables is required setting the corresponding field in the c1 record to NULL should do fine:

c1.variable_set.context = NULL;

See Variables Collections.

The functions set is specified as for the expression evaluator: a context and a lookup method are to be provided.

In this example the context is a null terminated array of struct x1f4_function_type records (null terminated means here that the name field of the last record in the array is nil). The very unsophisticated lookup method in the expression evaluator crash introduction will apply. The function set fields in the struct x1f4_c1_type record will be set as:

attributes.function_set.get = select_function;
attributes.function_set.context = function_data;

The function_data is declared as:

struct x1f4_function_type *function_data;

and points to the function definitions array aforementioned. It merges the libx1f4i0 trivialities set with a very simple minded standard output printing functions set required by this example.

See x1f4_e4_defaults.

See Generalities Function Set.

See Printing Functions Set.

The two sets may be merged together in some simple fashion like:

static int
merge_sets(struct x1f4_function_type **set)
    int status = 0;
    struct x1f4_function_type *function_data;
    unsigned count, trans;

    x1f4_count_functions(x1f4_e4_defaults, &count);
    x1f4_count_functions(simple_output, &trans);
    function_data = (struct x1f4_function_type *)
	malloc((count + trans + 1) * sizeof(struct x1f4_function_type));
    if (!function_data) {
	status = 1;
    } else {
	*set = function_data;
	memcpy(function_data, x1f4_e4_defaults,
	       count * sizeof(struct x1f4_function_type));
	function_data += count;
	memcpy(function_data, _libx1f4i0_e4_io,
	       (trans + 1) * sizeof(struct x1f4_function_type));

    return status;

where simple_output is the standard output printing functions set and x1f4_count_functions a convenience counting struct x1f4_function_type records until it finds one that has the name field set to NULL.

Set the operators sets to some C like operators sets, as in:


See x1f4_llink_operator1s.

See Prefix Unary Operators.

See C Prefix Unary Operators Set.

See x1f4_llink_operator2s.

See Infix Binary Operators.

See C Infix Binary Operators Set.

Last needed is the parsing error collector. Declare it like:

struct x1f4_c1record_type c1record;

add it in the parsing attributes record as in:

c1.bcollect_set.c1record_data = &c1record;

The X1f4_C1_BCOLLECT bit set in the flags argument of the program parsing function will request the program parser to record whatever parsing error if any in the c1record record.

See Imperative Program Parsing Error Reporting.

The recorded parsing error may be detailed for the benefit of the user. The return of the program parsing function may be examined for processing result, and if not 0 the appropriate error messages may be displayed (there are only two errors: memory allocation and parsing error), so the program parsing may be rewritten as:

status = x1f4_init_program(&program, data, flags, &c1);
if (status) {
    if (status == X1f4_C1_ALLOC_ERROR) {
    } else {
	fprintf(stderr, "%s: cannot parse `%s'\n", ..., ...);
	fprintf(stderr, "%s: ", ...);
	x1f4_stat_program(stderr, ..., data, &c1record, NULL);
	fprintf(stderr, "\n");

See x1f4_stat_program.

See Imperative Language Interpreter Errors.