mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-03-22 02:11:19 +00:00
[util] Implement more of cexpr
This adds unary, vector and function expressions.
This commit is contained in:
parent
81300f89f8
commit
4562e0b876
3 changed files with 194 additions and 20 deletions
|
@ -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[];
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#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 <op> SIZEOF UNARY INCOP
|
||||
%left HYPERUNARY
|
||||
%left '.' '(' '['
|
||||
|
||||
%token <symbol> NAME
|
||||
%token <value> VALUE
|
||||
|
||||
%type <value> expr field
|
||||
%type <value> expr field uexpr
|
||||
%type <list> 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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue