mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-10 15:22:04 +00:00
more expression handling. turns out I'm mis-parsing field types, so that's next
This commit is contained in:
parent
ba17807833
commit
aac91d8cd6
3 changed files with 432 additions and 24 deletions
|
@ -1,6 +1,7 @@
|
|||
typedef enum {
|
||||
ex_statement,
|
||||
ex_expr,
|
||||
ex_expr, // binary expression
|
||||
ex_uexpr, // unary expression
|
||||
ex_def,
|
||||
ex_int,
|
||||
ex_float,
|
||||
|
@ -13,6 +14,7 @@ typedef struct estatement_s {
|
|||
} estatement_t;
|
||||
|
||||
typedef struct expr_s {
|
||||
struct expr_s *next;
|
||||
expr_type type;
|
||||
union {
|
||||
struct {
|
||||
|
@ -34,3 +36,4 @@ typedef struct expr_s {
|
|||
expr_t *new_expr (void);
|
||||
expr_t *binary_expr (int op, expr_t *e1, expr_t *e2);
|
||||
expr_t *unary_expr (int op, expr_t *e);
|
||||
expr_t *function_expr (expr_t *e1, expr_t *e2);
|
||||
|
|
|
@ -1,12 +1,19 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#include <QF/mathlib.h>
|
||||
|
||||
#include "qfcc.h"
|
||||
#include "expr.h"
|
||||
#include "scope.h"
|
||||
#include "qc-parse.h"
|
||||
|
||||
void yyerror (const char*);
|
||||
|
||||
static etype_t qc_types[] = {
|
||||
ev_void,
|
||||
ev_void,
|
||||
ev_void,
|
||||
ev_void,
|
||||
ev_void, // FIXME ex_int
|
||||
ev_float, // ex_float
|
||||
ev_string, // ex_string
|
||||
|
@ -25,18 +32,6 @@ static type_t *types[] = {
|
|||
&type_pointer,
|
||||
};
|
||||
|
||||
expr_t *
|
||||
new_expr ()
|
||||
{
|
||||
return calloc (1, sizeof (expr_t));
|
||||
}
|
||||
|
||||
static expr_t *
|
||||
binary_const (int op, expr_t *e1, expr_t *e2)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static etype_t
|
||||
get_type (expr_t *e)
|
||||
{
|
||||
|
@ -45,6 +40,7 @@ get_type (expr_t *e)
|
|||
case ex_quaternion: //FIXME
|
||||
return ev_void;
|
||||
case ex_expr:
|
||||
case ex_uexpr:
|
||||
return e->e.expr.type->type;
|
||||
case ex_def:
|
||||
return e->e.def->type->type;
|
||||
|
@ -61,34 +57,434 @@ get_type (expr_t *e)
|
|||
return ev_void;
|
||||
}
|
||||
|
||||
expr_t *
|
||||
new_expr ()
|
||||
{
|
||||
return calloc (1, sizeof (expr_t));
|
||||
}
|
||||
|
||||
static expr_t *
|
||||
do_op_string (int op, expr_t *e1, expr_t *e2)
|
||||
{
|
||||
int len;
|
||||
char *buf;
|
||||
char *s1, *s2;
|
||||
|
||||
s1 = G_STRING(e1->e.string_val);
|
||||
s2 = G_STRING(e2->e.string_val);
|
||||
|
||||
switch (op) {
|
||||
case '+':
|
||||
len = strlen (s1) + strlen (s2) + 1;
|
||||
buf = alloca (len);
|
||||
strcpy (buf, s1);
|
||||
strcat (buf, s2);
|
||||
e1->e.string_val = ReuseString (buf);
|
||||
break;
|
||||
case LT:
|
||||
e1->type = ex_int;
|
||||
e1->e.int_val = strcmp (s1, s2) < 0;
|
||||
break;
|
||||
case GT:
|
||||
e1->type = ex_int;
|
||||
e1->e.int_val = strcmp (s1, s2) > 0;
|
||||
break;
|
||||
case LE:
|
||||
e1->type = ex_int;
|
||||
e1->e.int_val = strcmp (s1, s2) <= 0;
|
||||
break;
|
||||
case GE:
|
||||
e1->type = ex_int;
|
||||
e1->e.int_val = strcmp (s1, s2) >= 0;
|
||||
break;
|
||||
case EQ:
|
||||
e1->type = ex_int;
|
||||
e1->e.int_val = strcmp (s1, s2) == 0;
|
||||
break;
|
||||
case NE:
|
||||
e1->type = ex_int;
|
||||
e1->e.int_val = strcmp (s1, s2) != 0;
|
||||
break;
|
||||
default:
|
||||
yyerror ("invalid operand for string");
|
||||
return 0;
|
||||
}
|
||||
return e1;
|
||||
}
|
||||
|
||||
static expr_t *
|
||||
do_op_float (int op, expr_t *e1, expr_t *e2)
|
||||
{
|
||||
float f1, f2;
|
||||
|
||||
f1 = e1->e.float_val;
|
||||
f2 = e2->e.float_val;
|
||||
|
||||
switch (op) {
|
||||
case '+':
|
||||
e1->e.float_val += f2;
|
||||
break;
|
||||
case '-':
|
||||
e1->e.float_val -= f2;
|
||||
break;
|
||||
case '*':
|
||||
e1->e.float_val *= f2;
|
||||
break;
|
||||
case '/':
|
||||
e1->e.float_val /= f2;
|
||||
break;
|
||||
case '&':
|
||||
e1->e.float_val = (int)f1 & (int)f2;
|
||||
break;
|
||||
case '|':
|
||||
e1->e.float_val += (int)f1 | (int)f2;
|
||||
break;
|
||||
case AND:
|
||||
e1->e.float_val = f1 && f2;
|
||||
break;
|
||||
case OR:
|
||||
e1->e.float_val += f1 || f2;
|
||||
break;
|
||||
case LT:
|
||||
e1->type = ex_int;
|
||||
e1->e.int_val = f1 < f2;
|
||||
break;
|
||||
case GT:
|
||||
e1->type = ex_int;
|
||||
e1->e.int_val = f1 > f2;
|
||||
break;
|
||||
case LE:
|
||||
e1->type = ex_int;
|
||||
e1->e.int_val = f1 <= f2;
|
||||
break;
|
||||
case GE:
|
||||
e1->type = ex_int;
|
||||
e1->e.int_val = f1 >= f2;
|
||||
break;
|
||||
case EQ:
|
||||
e1->type = ex_int;
|
||||
e1->e.int_val = f1 == f2;
|
||||
break;
|
||||
case NE:
|
||||
e1->type = ex_int;
|
||||
e1->e.int_val = f1 != f2;
|
||||
break;
|
||||
default:
|
||||
yyerror ("invalid operand for string");
|
||||
return 0;
|
||||
}
|
||||
return e1;
|
||||
}
|
||||
|
||||
static expr_t *
|
||||
do_op_vector (int op, expr_t *e1, expr_t *e2)
|
||||
{
|
||||
float *v1, *v2;
|
||||
|
||||
v1 = e1->e.vector_val;
|
||||
v2 = e2->e.vector_val;
|
||||
|
||||
switch (op) {
|
||||
case '+':
|
||||
VectorAdd (v1, v2, v1);
|
||||
break;
|
||||
case '-':
|
||||
VectorSubtract (v1, v2, v1);
|
||||
break;
|
||||
case '*':
|
||||
e1->type = ex_float;
|
||||
e1->e.float_val = DotProduct (v1, v2);
|
||||
break;
|
||||
case EQ:
|
||||
e1->type = ex_int;
|
||||
e1->e.int_val = (v1[0] == v2[0])
|
||||
&& (v1[1] == v2[1])
|
||||
&& (v1[2] == v2[2]);
|
||||
break;
|
||||
case NE:
|
||||
e1->type = ex_int;
|
||||
e1->e.int_val = (v1[0] == v2[0])
|
||||
|| (v1[1] != v2[1])
|
||||
|| (v1[2] != v2[2]);
|
||||
break;
|
||||
default:
|
||||
yyerror ("invalid operand for string");
|
||||
return 0;
|
||||
}
|
||||
return e1;
|
||||
}
|
||||
|
||||
static expr_t *
|
||||
do_op_huh (int op, expr_t *e1, expr_t *e2)
|
||||
{
|
||||
yyerror ("funny constant");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static expr_t *(*do_op[]) (int op, expr_t *e1, expr_t *e2) = {
|
||||
do_op_huh,
|
||||
do_op_string,
|
||||
do_op_float,
|
||||
do_op_vector,
|
||||
do_op_huh,
|
||||
do_op_huh,
|
||||
do_op_huh,
|
||||
do_op_huh,
|
||||
};
|
||||
|
||||
static expr_t *
|
||||
binary_const (int op, expr_t *e1, expr_t *e2)
|
||||
{
|
||||
etype_t t1, t2;
|
||||
//expr_t *e;
|
||||
|
||||
t1 = get_type (e1);
|
||||
t2 = get_type (e2);
|
||||
|
||||
if (t1 == t2) {
|
||||
return do_op[t1](op, e1, e2);
|
||||
} else {
|
||||
yyerror ("type missmatch for");
|
||||
fprintf (stderr, "%d (%c)\n", op, (op > ' ' && op < 127) ? op : ' ');
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static expr_t *
|
||||
field_expr (expr_t *e1, expr_t *e2)
|
||||
{
|
||||
etype_t t1, t2;
|
||||
expr_t *e;
|
||||
|
||||
t1 = get_type (e1);
|
||||
t2 = get_type (e2);
|
||||
|
||||
if (t1 != ev_entity && t2 != ev_field) {
|
||||
yyerror ("type missmatch for .");
|
||||
return 0;
|
||||
}
|
||||
|
||||
e = new_expr ();
|
||||
e->type = ex_expr;
|
||||
e->e.expr.op = '.';
|
||||
e->e.expr.type = (e2->type == ex_def)
|
||||
? e2->e.def->type->aux_type
|
||||
: e2->e.expr.type;
|
||||
e->e.expr.e1 = e1;
|
||||
e->e.expr.e2 = e2;
|
||||
return e;
|
||||
}
|
||||
|
||||
expr_t *
|
||||
binary_expr (int op, expr_t *e1, expr_t *e2)
|
||||
{
|
||||
etype_t t1, t2;
|
||||
|
||||
if (op == '.')
|
||||
return field_expr (e1, e2);
|
||||
|
||||
if (e1->type >= ex_int && e2->type >= ex_int)
|
||||
return binary_const (op, e1, e2);
|
||||
|
||||
t1 = get_type (e1);
|
||||
t2 = get_type (e2);
|
||||
if (t1 == ev_void || t2 == ev_void)
|
||||
return 0;
|
||||
if (t1 == ev_void || t2 == ev_void) {
|
||||
yyerror ("internal error");
|
||||
abort ();
|
||||
}
|
||||
|
||||
if (t1 == t2) {
|
||||
expr_t *e = new_expr ();
|
||||
e->type = ex_expr;
|
||||
e->e.expr.op = op;
|
||||
if (op >= OR && op <= GT)
|
||||
e->e.expr.type = &type_float;
|
||||
else
|
||||
e->e.expr.type = types[t1];
|
||||
e->e.expr.e1 = e1;
|
||||
e->e.expr.e2 = e2;
|
||||
return e;
|
||||
} else {
|
||||
switch (t1) {
|
||||
case ev_float:
|
||||
if (t2 == ev_vector) {
|
||||
expr_t *e = new_expr ();
|
||||
e->type = ex_expr;
|
||||
e->e.expr.op = op;
|
||||
e->e.expr.type = &type_vector;
|
||||
e->e.expr.e1 = e1;
|
||||
e->e.expr.e2 = e2;
|
||||
return e;
|
||||
} else {
|
||||
goto type_mismatch;
|
||||
}
|
||||
case ev_vector:
|
||||
if (t2 == ev_float) {
|
||||
expr_t *e = new_expr ();
|
||||
e->type = ex_expr;
|
||||
e->e.expr.op = op;
|
||||
e->e.expr.type = &type_vector;
|
||||
e->e.expr.e1 = e1;
|
||||
e->e.expr.e2 = e2;
|
||||
return e;
|
||||
} else {
|
||||
goto type_mismatch;
|
||||
}
|
||||
case ev_field:
|
||||
if (e1->e.expr.type->aux_type->type == t2) {
|
||||
expr_t *e = new_expr ();
|
||||
e->type = ex_expr;
|
||||
e->e.expr.op = op;
|
||||
e->e.expr.type = e->e.expr.type->aux_type;
|
||||
e->e.expr.e1 = e1;
|
||||
e->e.expr.e2 = e2;
|
||||
return e;
|
||||
} else {
|
||||
goto type_mismatch;
|
||||
}
|
||||
default:
|
||||
type_mismatch:
|
||||
yyerror ("type missmatch");
|
||||
fprintf (stderr, "%d %d\n", t1, t2);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
expr_t *
|
||||
unary_expr (int op, expr_t *e)
|
||||
{
|
||||
switch (op) {
|
||||
case '-':
|
||||
switch (e->type) {
|
||||
case ex_statement:
|
||||
return ev_void;
|
||||
case ex_uexpr:
|
||||
if (e->e.expr.op == '-')
|
||||
return e->e.expr.e1;
|
||||
case ex_expr:
|
||||
case ex_def:
|
||||
{
|
||||
expr_t *n = new_expr ();
|
||||
n->type = ex_expr;
|
||||
n->e.expr.op = op;
|
||||
n->e.expr.type = (e->type == ex_def)
|
||||
? e->e.def->type
|
||||
: e->e.expr.type;
|
||||
n->e.expr.e1 = e;
|
||||
return n;
|
||||
}
|
||||
case ex_int:
|
||||
e->e.int_val *= -1;
|
||||
return e;
|
||||
case ex_float:
|
||||
e->e.float_val *= -1;
|
||||
return e;
|
||||
case ex_string:
|
||||
return 0; // FIXME
|
||||
case ex_vector:
|
||||
e->e.vector_val[0] *= -1;
|
||||
e->e.vector_val[1] *= -1;
|
||||
e->e.vector_val[2] *= -1;
|
||||
return e;
|
||||
case ex_quaternion:
|
||||
e->e.quaternion_val[0] *= -1;
|
||||
e->e.quaternion_val[1] *= -1;
|
||||
e->e.quaternion_val[2] *= -1;
|
||||
e->e.quaternion_val[3] *= -1;
|
||||
return e;
|
||||
}
|
||||
break;
|
||||
case '!':
|
||||
switch (e->type) {
|
||||
case ex_statement:
|
||||
return ev_void;
|
||||
case ex_uexpr:
|
||||
case ex_expr:
|
||||
case ex_def:
|
||||
{
|
||||
expr_t *n = new_expr ();
|
||||
n->type = ex_expr;
|
||||
n->e.expr.op = op;
|
||||
n->e.expr.type = &type_float;
|
||||
n->e.expr.e1 = e;
|
||||
return n;
|
||||
}
|
||||
case ex_int:
|
||||
e->e.int_val = !e->e.int_val;
|
||||
return e;
|
||||
case ex_float:
|
||||
e->e.int_val = !e->e.float_val;
|
||||
e->type = ex_int;
|
||||
return e;
|
||||
case ex_string:
|
||||
e->e.int_val = !e->e.string_val
|
||||
|| !G_STRING(e->e.string_val)[0];
|
||||
e->type = ex_int;
|
||||
return e;
|
||||
case ex_vector:
|
||||
e->e.int_val = !e->e.vector_val[0]
|
||||
&& !e->e.vector_val[1]
|
||||
&& !e->e.vector_val[2];
|
||||
e->type = ex_int;
|
||||
return e;
|
||||
case ex_quaternion:
|
||||
e->e.int_val = !e->e.quaternion_val[0]
|
||||
&& !e->e.quaternion_val[1]
|
||||
&& !e->e.quaternion_val[2]
|
||||
&& !e->e.quaternion_val[3];
|
||||
e->type = ex_int;
|
||||
return e;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
abort ();
|
||||
}
|
||||
yyerror ("internal error");
|
||||
abort ();
|
||||
}
|
||||
|
||||
expr_t *
|
||||
function_expr (expr_t *e1, expr_t *e2)
|
||||
{
|
||||
etype_t t1;
|
||||
expr_t *e;
|
||||
int parm_count = 0;
|
||||
type_t *ftype;
|
||||
|
||||
t1 = get_type (e1);
|
||||
|
||||
if (t1 != ev_func) {
|
||||
yyerror ("called object is not a function");
|
||||
fprintf (stderr, "%d\n", t1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ftype = e1->type == ex_def
|
||||
? e1->e.def->type
|
||||
: e1->e.expr.type;
|
||||
|
||||
for (e = e2; e; e = e->next)
|
||||
parm_count++;
|
||||
if (parm_count > 8) {
|
||||
yyerror ("more than 8 paramters");
|
||||
return 0;
|
||||
}
|
||||
if (ftype->num_parms != -1) {
|
||||
if (parm_count > ftype->num_parms) {
|
||||
yyerror ("too many arguments");
|
||||
return 0;
|
||||
} else if (parm_count < ftype->num_parms) {
|
||||
yyerror ("too few arguments");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
e = new_expr ();
|
||||
e->type = ex_expr;
|
||||
e->e.expr.op = 'c';
|
||||
e->e.expr.type = ftype->aux_type;
|
||||
e->e.expr.e1 = e1;
|
||||
e->e.expr.e2 = e2;
|
||||
return e;
|
||||
}
|
||||
|
|
|
@ -44,7 +44,8 @@ typedef struct {
|
|||
%left EQ NE LE GE LT GT
|
||||
%left '+' '-'
|
||||
%left '*' '/' '&' '|'
|
||||
%left '!' '.' '('
|
||||
%left '!' '.'
|
||||
%right '('
|
||||
|
||||
%token <string_val> NAME STRING_VAL
|
||||
%token <int_val> INT_VAL
|
||||
|
@ -287,7 +288,11 @@ statement
|
|||
| RETURN ';' {}
|
||||
| WHILE '(' expr ')' statement {}
|
||||
| DO statement WHILE '(' expr ')' ';' {}
|
||||
| LOCAL type def_list ';' {}
|
||||
| LOCAL type
|
||||
{
|
||||
current_type = $2;
|
||||
}
|
||||
def_list ';' {}
|
||||
| IF '(' expr ')' statement {}
|
||||
| IF '(' expr ')' statement ELSE statement {}
|
||||
| FOR '(' expr ';' expr ';' expr ')' statement {}
|
||||
|
@ -297,7 +302,7 @@ statement
|
|||
expr
|
||||
: expr AND expr { $$ = binary_expr (AND, $1, $3); }
|
||||
| expr OR expr { $$ = binary_expr (OR, $1, $3); }
|
||||
| expr '=' expr { $$ = binary_expr ('.', $1, $3); }
|
||||
| expr '=' expr { $$ = binary_expr ('=', $1, $3); }
|
||||
| expr EQ expr { $$ = binary_expr (EQ, $1, $3); }
|
||||
| expr NE expr { $$ = binary_expr (NE, $1, $3); }
|
||||
| expr LE expr { $$ = binary_expr (LE, $1, $3); }
|
||||
|
@ -309,10 +314,10 @@ expr
|
|||
| expr '*' expr { $$ = binary_expr ('*', $1, $3); }
|
||||
| expr '/' expr { $$ = binary_expr ('/', $1, $3); }
|
||||
| expr '&' expr { $$ = binary_expr ('&', $1, $3); }
|
||||
| expr '|' expr { $$ = binary_expr ('!', $1, $3); }
|
||||
| expr '|' expr { $$ = binary_expr ('|', $1, $3); }
|
||||
| expr '.' expr { $$ = binary_expr ('.', $1, $3); }
|
||||
| expr '(' arg_list ')'
|
||||
| expr '(' ')'
|
||||
| expr '(' arg_list ')' { $$ = function_expr ($1, $3); }
|
||||
| expr '(' ')' { $$ = function_expr ($1, 0); }
|
||||
| '-' expr { $$ = unary_expr ('-', $2); }
|
||||
| '!' expr { $$ = unary_expr ('!', $2); }
|
||||
| NAME
|
||||
|
@ -328,6 +333,10 @@ expr
|
|||
arg_list
|
||||
: expr
|
||||
| arg_list ',' expr
|
||||
{
|
||||
$3->next = $1;
|
||||
$$ = $3;
|
||||
}
|
||||
;
|
||||
|
||||
const
|
||||
|
|
Loading…
Reference in a new issue