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.
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;
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.
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:
x1f4_llink_operator1s(&c1.operator1s); x1f4_llink_operator2s(&c1.operator2s);
See C Prefix Unary Operators Set.
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) { perror(argv[0]); } 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.