From 4562e0b8760447438b543d2a098838a74d81b3c9 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 4 Jan 2021 00:11:52 +0900 Subject: [PATCH] [util] Implement more of cexpr This adds unary, vector and function expressions. --- include/QF/cexpr.h | 14 +++ libs/util/cexpr-parse.y | 193 +++++++++++++++++++++++++++++++++++----- libs/util/cexpr-type.c | 7 ++ 3 files changed, 194 insertions(+), 20 deletions(-) diff --git a/include/QF/cexpr.h b/include/QF/cexpr.h index e257412d6..77e5b0463 100644 --- a/include/QF/cexpr.h +++ b/include/QF/cexpr.h @@ -62,6 +62,11 @@ typedef struct exprval_s { void *value; } exprval_t; +typedef struct exprlist_s { + struct exprlist_s *next; + exprval_t *value; +} exprlist_t; + typedef struct exprsym_s { const char *name; exprtype_t *type; @@ -69,6 +74,14 @@ typedef struct exprsym_s { struct exprsym_s *next; } exprsym_t; +typedef struct exprfunc_s { + exprtype_t *result; + int num_params; + exprtype_t **param_types; + void (*func) (const exprval_t **params, exprval_t *result, + struct exprctx_s *context); +} exprfunc_t; + typedef struct exprtab_s { exprsym_t *symbols; struct hashtab_s *tab; @@ -116,6 +129,7 @@ extern exprtype_t cexpr_vector; extern exprtype_t cexpr_quaternion; extern exprtype_t cexpr_exprval; extern exprtype_t cexpr_field; +extern exprtype_t cexpr_function; extern binop_t cexpr_struct_binops[]; diff --git a/libs/util/cexpr-parse.y b/libs/util/cexpr-parse.y index eb56ed588..f208f4680 100644 --- a/libs/util/cexpr-parse.y +++ b/libs/util/cexpr-parse.y @@ -43,6 +43,7 @@ #include #include "QF/cmem.h" +#include "QF/dstring.h" #include "QF/hash.h" #include "QF/qfplist.h" #include "QF/sys.h" @@ -55,11 +56,17 @@ static exprval_t *binary_expr (int op, const exprval_t *a, const exprval_t *b, exprctx_t *context); static exprval_t *field_expr (const exprval_t *a, const exprval_t *b, exprctx_t *context); +static exprval_t *unary_expr (int op, const exprval_t *val, + exprctx_t *context); +static exprval_t *vector_expr (exprlist_t *list, exprctx_t *context); +static exprval_t *function_expr (exprsym_t *fsym, exprlist_t *list, + exprctx_t *context); +static exprlist_t *expr_item (exprval_t *val, exprctx_t *context); static void yyerror (void *scanner, exprctx_t *context, const char *s) { - cexpr_error (context, "%s before %s\n", s, cexpr_yyget_text (scanner)); + cexpr_error (context, "%s before %s", s, cexpr_yyget_text (scanner)); } %} @@ -78,19 +85,21 @@ yyerror (void *scanner, exprctx_t *context, const char *s) %left SHL SHR %left '+' '-' %left '*' '/' '%' MOD -%right SIZEOF UNARY INCOP +%right SIZEOF UNARY INCOP %left HYPERUNARY %left '.' '(' '[' %token NAME %token VALUE -%type expr field +%type expr field uexpr +%type opt_arg_list arg_list arg_expr %union { int op; exprsym_t *symbol; exprval_t *value; + exprlist_t *list; const char *string; } @@ -100,20 +109,8 @@ start : expr { assign_expr (context->result, $1, context); } ; -expr - : expr SHL expr { $$ = binary_expr (SHL, $1, $3, context); } - | expr SHR expr { $$ = binary_expr (SHR, $1, $3, context); } - | expr '+' expr { $$ = binary_expr ('+', $1, $3, context); } - | expr '-' expr { $$ = binary_expr ('-', $1, $3, context); } - | expr '*' expr { $$ = binary_expr ('*', $1, $3, context); } - | expr '/' expr { $$ = binary_expr ('/', $1, $3, context); } - | expr '&' expr { $$ = binary_expr ('&', $1, $3, context); } - | expr '|' expr { $$ = binary_expr ('|', $1, $3, context); } - | expr '^' expr { $$ = binary_expr ('^', $1, $3, context); } - | expr '%' expr { $$ = binary_expr ('%', $1, $3, context); } - | expr '.' field { $$ = field_expr ($1, $3, context); } - | expr MOD expr { $$ = binary_expr (MOD, $1, $3, context); } - | NAME +uexpr + : NAME { if ($1) { $$ = (exprval_t *) cmemalloc (context->memsuper, sizeof (*$$)); @@ -125,6 +122,29 @@ expr } } | VALUE + | '[' arg_list ']' { $$ = vector_expr ($2, context); } + | '(' expr ')' { $$ = $2; } + | NAME '(' opt_arg_list ')' { $$ = function_expr ($1, $3, context); } + | uexpr '.' field { $$ = field_expr ($1, $3, context); } + | '+' uexpr %prec UNARY { $$ = $2; } + | '-' uexpr %prec UNARY { $$ = unary_expr ('-', $2, context); } + | '!' uexpr %prec UNARY { $$ = unary_expr ('!', $2, context); } + | '~' uexpr %prec UNARY { $$ = unary_expr ('~', $2, context); } + ; + +expr + : uexpr + | expr SHL expr { $$ = binary_expr (SHL, $1, $3, context); } + | expr SHR expr { $$ = binary_expr (SHR, $1, $3, context); } + | expr '+' expr { $$ = binary_expr ('+', $1, $3, context); } + | expr '-' expr { $$ = binary_expr ('-', $1, $3, context); } + | expr '*' expr { $$ = binary_expr ('*', $1, $3, context); } + | expr '/' expr { $$ = binary_expr ('/', $1, $3, context); } + | expr '&' expr { $$ = binary_expr ('&', $1, $3, context); } + | expr '|' expr { $$ = binary_expr ('|', $1, $3, context); } + | expr '^' expr { $$ = binary_expr ('^', $1, $3, context); } + | expr '%' expr { $$ = binary_expr ('%', $1, $3, context); } + | expr MOD expr { $$ = binary_expr (MOD, $1, $3, context); } ; field @@ -141,6 +161,23 @@ field } ; +opt_arg_list + : { $$ = 0; } + | arg_list { $$ = $1; } + ; + +arg_list + : arg_expr + | arg_list ',' arg_expr + { + $3-> next = $1; + $$ = $3; + } + +arg_expr + : expr { $$ = expr_item ($1, context); } + ; + %% static void @@ -156,7 +193,7 @@ assign_expr (exprval_t *dst, const exprval_t *src, exprctx_t *context) } else { if (dst->type != src->type) { cexpr_error (context, - "type mismatch in expression result: %s = %s\n", + "type mismatch in expression result: %s = %s", dst->type->name, src->type->name); return; } @@ -185,8 +222,9 @@ binary_expr (int op, const exprval_t *a, const exprval_t *b, } exprval_t *result = cexpr_value (rtype, context); if (!binop->op) { - cexpr_error (context, "invalid binary expression: %s %c %s\n", + cexpr_error (context, "invalid binary expression: %s %c %s", a->type->name, op, b->type->name); + memset (result->value, 0, rtype->size); } else { binop->func (a, b, result, context); } @@ -205,11 +243,126 @@ field_expr (const exprval_t *a, const exprval_t *b, exprctx_t *context) } } if (!binop->op) { - cexpr_error (context, "invalid binary expression: %s.%s\n", + cexpr_error (context, "invalid binary expression: %s.%s", a->type->name, b->type->name); + result = cexpr_value (&cexpr_int, context); + *(int *) result->value = 0; } else { exprval_t c = { 0, &result }; binop->func (a, b, &c, context); } return result; } + +static exprval_t * +unary_expr (int op, const exprval_t *val, exprctx_t *context) +{ + unop_t *unop; + + for (unop = val->type->unops; unop->op; unop++) { + if (unop->op == op) { + break; + } + } + exprtype_t *rtype = unop->result; + if (!rtype) { + rtype = val->type; + } + exprval_t *result = cexpr_value (rtype, context); + if (!unop->op) { + cexpr_error (context, "invalid unary expression: %c %s", + op, val->type->name); + } else { + unop->func (val, result, context); + } + return result; +} + +exprval_t * +vector_expr (exprlist_t *list, exprctx_t *context) +{ + exprlist_t *l; + exprval_t *val = cexpr_value (&cexpr_vector, context); + int i; + for (i = 0; i < 4 && list; i++, list = l) { + exprval_t dst = { &cexpr_float, ((float *) val->value) + i }; + exprval_t *src = list->value; + binop_t *cast = cexpr_find_cast (&cexpr_float, src->type); + if (cast) { + cast->func (&dst, src, &dst, context); + } else { + cexpr_error (context, "invalid vector expression type: [%d] %s", + i, val->type->name); + } + l = list->next; + cmemfree (context->memsuper, list); + } + for ( ; i < 4; i++) { + ((float *) val->value)[i] = 0; + } + if (i == 4 && list) { + cexpr_error (context, "excess elements in vector expression"); + } + return val; +} + +static exprval_t *function_expr (exprsym_t *fsym, exprlist_t *list, + exprctx_t *context) +{ + exprlist_t *l; + int num_args = 0; + exprfunc_t *func = 0; + exprval_t *result; + + for (l = list; l; l = l->next) { + num_args++; + } + __auto_type args = (const exprval_t **) alloca (num_args * sizeof (exprval_t *)); + __auto_type types = (exprtype_t **) alloca (num_args * sizeof (exprtype_t *)); + for (num_args = 0; list; list = l, num_args++) { + args[num_args] = list->value; + types[num_args] = list->value->type; + l = list->next; + cmemfree (context->memsuper, list); + } + if (fsym->type != &cexpr_function) { + cexpr_error (context, "invalid function %s", fsym->name); + result = cexpr_value (&cexpr_int, context); + *(int *) result->value = 0; + return result; + } + for (exprfunc_t *f = fsym->value; f->result; f++) { + if (f->num_params == num_args + && memcmp (f->param_types, types, + num_args * sizeof (exprtype_t *)) == 0) { + func = f; + break; + } + } + if (!func) { + dstring_t *argstr = dstring_newstr(); + for (int i = 0; i < num_args; i++) { + dasprintf (argstr, "%s%s", types[i]->name, + i + 1 < num_args ? ", ": ""); + } + cexpr_error (context, "no overload for %s(%s)", fsym->name, + argstr->str); + dstring_delete (argstr); + result = cexpr_value (&cexpr_int, context); + *(int *) result->value = 0; + return result; + } + result = cexpr_value (func->result, context); + func->func (args, result, context); + return result; +} + +static exprlist_t * +expr_item (exprval_t *val, exprctx_t *context) +{ + __auto_type item = (exprlist_t *) cmemalloc (context->memsuper, + sizeof (exprlist_t)); + item->next = 0; + item->value = val; + return item; +} diff --git a/libs/util/cexpr-type.c b/libs/util/cexpr-type.c index 04eef6d70..1a68728de 100644 --- a/libs/util/cexpr-type.c +++ b/libs/util/cexpr-type.c @@ -483,6 +483,13 @@ exprtype_t cexpr_field = { 0, }; +exprtype_t cexpr_function = { + "function", + 0, // has no size of its own + 0, // can't actually do anything with a function other than call + 0, +}; + VISIBLE binop_t * cexpr_find_cast (exprtype_t *dst_type, exprtype_t *src_type) {