[cexpr] Support array indexing

The index is currently limited to ints, and is bounds checked (the array
type has a size field indicating the number of elements).
This commit is contained in:
Bill Currie 2021-12-04 10:04:58 +09:00
parent c73e4efcb7
commit c8846f8007
3 changed files with 63 additions and 0 deletions

View file

@ -87,6 +87,11 @@ typedef struct exprtab_s {
struct hashtab_s *tab;
} exprtab_t;
typedef struct exprarray_s {
exprtype_t *type;
unsigned size;
} exprarray_t;
typedef struct exprctx_s {
exprval_t *result;
exprtab_t *symtab; // directly accessible symbols
@ -111,6 +116,8 @@ exprval_t *cexpr_value_reference (exprtype_t *type, void *data, exprctx_t *ctx);
int cexpr_eval_string (const char *str, exprctx_t *context);
void cexpr_error(exprctx_t *ctx, const char *fmt, ...) __attribute__((format(PRINTF,2,3)));
void cexpr_array_getelement (const exprval_t *a, const exprval_t *b,
exprval_t *c, exprctx_t *ctx);
void cexpr_struct_getfield (const exprval_t *a, const exprval_t *b,
exprval_t *c, exprctx_t *ctx);
void cexpr_struct_pointer_getfield (const exprval_t *a, const exprval_t *b,
@ -137,6 +144,7 @@ extern exprtype_t cexpr_field;
extern exprtype_t cexpr_function;
extern exprtype_t cexpr_plitem;
extern binop_t cexpr_array_binops[];
extern binop_t cexpr_struct_binops[];
extern binop_t cexpr_struct_pointer_binops[];

View file

@ -37,6 +37,29 @@
#include "libs/util/cexpr-parse.h"
VISIBLE void
cexpr_array_getelement (const exprval_t *a, const exprval_t *b, exprval_t *c,
exprctx_t *ctx)
{
__auto_type array = (exprarray_t *) a->type->data;
unsigned index = *(const unsigned *) b->value;
exprval_t *val = 0;
if (index < array->size) {
val = cmemalloc (ctx->memsuper, sizeof (exprval_t));
val->type = array->type;
val->value = a->value + array->type->size * index;
} else {
cexpr_error (ctx, "index %d out of bounds for %s", index,
a->type->name);
}
*(exprval_t **) c->value = val;
}
VISIBLE binop_t cexpr_array_binops[] = {
{ '[', &cexpr_int, &cexpr_exprval, cexpr_array_getelement },
{}
};
VISIBLE void
cexpr_struct_getfield (const exprval_t *a, const exprval_t *b, exprval_t *c,
exprctx_t *ctx)

View file

@ -32,17 +32,31 @@
#include "QF/cmem.h"
#include "QF/hash.h"
#include "QF/mathlib.h"
#include "QF/va.h"
#include "QF/simd/vec4f.h"
int a = 5;
int b = 6;
int c;
int array[4] = { 9, 16, 25, 36 };
vec4f_t point = { 2, 3, 4, 1 }; // a point, so w = 1
vec4f_t normal = { 1, 2, 3, 0 }; // a vector, so w = 0
vec4f_t direction = { 4, 5, 6, 0 }; // a vector, so w = 0
vec4f_t plane;
vec4f_t intercept;
exprarray_t int_array_4_data = {
&cexpr_int,
sizeof (array) / sizeof (array[0]),
};
exprtype_t int_array_4 = {
"int[4]",
4 * sizeof (int),
cexpr_array_binops,
0,
&int_array_4_data,
};
exprtype_t *vector_params[] = {
&cexpr_vector,
&cexpr_vector,
@ -117,6 +131,7 @@ exprfunc_t double_func[] = {
exprsym_t symbols[] = {
{ "a", &cexpr_int, &a },
{ "b", &cexpr_int, &b },
{ "array", &int_array_4, &array },
{ "point", &cexpr_vector, &point },
{ "normal", &cexpr_vector, &normal },
{ "plane", &cexpr_vector, &plane },
@ -147,6 +162,7 @@ exprctx_t context = { &test_result, &symtab };
#define TEST_BINOP(op) \
do { \
c = -4096; \
context.result = &test_result; \
cexpr_eval_string ("a " #op " b", &context); \
printf ("c = a %s b -> %d = %d %s %d\n", #op, c, a, #op, b); \
if (c != (a op b)) { \
@ -154,6 +170,17 @@ exprctx_t context = { &test_result, &symtab };
} \
} while (0)
#define TEST_ARRAY(ind) \
do { \
c = -4096; \
context.result = &test_result; \
cexpr_eval_string (va (0, "array[%d]", ind), &context); \
printf ("c = array[%d] -> %d = %d\n", ind, c, array[ind]); \
if (c != array[ind]) { \
ret |= 1; \
} \
} while (0)
int
main(int argc, const char **argv)
{
@ -173,6 +200,11 @@ main(int argc, const char **argv)
TEST_BINOP (^);
TEST_BINOP (%);
TEST_ARRAY (0);
TEST_ARRAY (1);
TEST_ARRAY (2);
TEST_ARRAY (3);
context.result = &plane_result;
cexpr_eval_string ("point.wzyx", &context);
if (plane[0] != point[3] || plane[1] != point[2]