Start implementing vec = [x,y,z].

This is a nice feature found in fteqcc (also a bit of a challenge from
Spike). Getting bison to accept the new expression required rewriting the
state expression grammar, so this is mostly for the state expression. A
test to ensure the state expression doesn't break is included.
This commit is contained in:
Bill Currie 2013-06-24 11:36:52 +09:00
parent 35de42aeac
commit a6cdc8735a
8 changed files with 131 additions and 23 deletions

View file

@ -571,6 +571,7 @@ void convert_name (expr_t *e);
expr_t *append_expr (expr_t *block, expr_t *e);
expr_t *reverse_expr_list (expr_t *e);
void print_expr (expr_t *e);
void dump_dot_expr (void *e, const char *filename);
@ -607,7 +608,7 @@ expr_t *build_do_while_statement (expr_t *statement, int not, expr_t *test,
expr_t *build_for_statement (expr_t *init, expr_t *test, expr_t *next,
expr_t *statement,
expr_t *break_label, expr_t *continue_label);
expr_t *build_state_expr (expr_t *frame, expr_t *think, expr_t *step);
expr_t *build_state_expr (expr_t *e);
expr_t *think_expr (struct symbol_s *think_sym);
expr_t *assign_expr (expr_t *e1, expr_t *e2);
expr_t *cast_expr (struct type_s *t, expr_t *e);

View file

@ -2472,8 +2472,18 @@ build_for_statement (expr_t *init, expr_t *test, expr_t *next,
}
expr_t *
build_state_expr (expr_t *frame, expr_t *think, expr_t *step)
build_state_expr (expr_t *e)
{
expr_t *frame = 0;
expr_t *think = 0;
expr_t *step = 0;
e = reverse_expr_list (e);
frame = e;
think = frame->next;
step = think->next;
if (think->type == ex_symbol)
think = think_expr (think->e.symbol);
if (is_integer_val (frame))
convert_int (frame);
if (!type_assignable (&type_float, get_type (frame)))
@ -2481,10 +2491,12 @@ build_state_expr (expr_t *frame, expr_t *think, expr_t *step)
if (extract_type (think) != ev_func)
return error (think, "invalid type for think");
if (step) {
if (step->next)
return error (step->next, "too many state arguments");
if (is_integer_val (step))
convert_int (step);
if (!type_assignable (&type_float, get_type (step)))
return error (step, "invalid type for frame number");
return error (step, "invalid type for step");
}
return new_state_expr (frame, think, step);
}
@ -2951,3 +2963,17 @@ sizeof_expr (expr_t *expr, struct type_s *type)
expr = new_integer_expr (type_size (type));
return expr;
}
expr_t *
reverse_expr_list (expr_t *e)
{
expr_t *r = 0;
while (e) {
expr_t *t = e->next;
e->next = r;
r = e;
e = t;
}
return r;
}

View file

@ -180,8 +180,8 @@ int yylex (void);
%type <symbol> methoddef
%type <expr> opt_initializer var_initializer local_def
%type <expr> opt_expr fexpr expr element_list element
%type <expr> optional_state_expr think opt_step texpr
%type <expr> opt_expr fexpr expr element_list element vector_expr
%type <expr> optional_state_expr texpr
%type <expr> statement statements compound_statement
%type <expr> else label break_label continue_label
%type <expr> unary_expr cast_expr opt_arg_list arg_list
@ -1026,23 +1026,7 @@ var_initializer
optional_state_expr
: /* emtpy */ { $$ = 0; }
| '[' fexpr ',' think opt_step ']' { $$ = build_state_expr ($2, $4, $5); }
;
think
: identifier
{
$$ = think_expr ($1);
}
| '(' fexpr ')'
{
$$ = $2;
}
;
opt_step
: ',' fexpr { $$ = $2; }
| /* empty */ { $$ = 0; }
| vector_expr { $$ = build_state_expr ($1); }
;
element_list
@ -1261,9 +1245,21 @@ unary_expr
{
$$ = sizeof_expr (0, $3->type);
}
| vector_expr { $$ = $1; }
| obj_expr { $$ = $1; }
;
vector_expr
: '[' fexpr ',' arg_list ']'
{
expr_t *t = $4;
while (t->next)
t = t->next;
t->next = $2;
$$ = $4;
}
;
cast_expr
: '(' abstract_decl ')' cast_expr
{

View file

@ -28,6 +28,7 @@ test_progs_dat=\
paramret.dat \
return-ivar.dat \
sendv.dat \
state.dat \
structlive.dat \
structptr.dat \
vecinit.dat \
@ -109,6 +110,13 @@ sendv.dat: $(sendv_obj) $(QFCC_DEP)
sendv.run: Makefile build-run
$(srcdir)/build-run $@
state_dat_SOURCES=state.r
state_obj=$(state_dat_SOURCES:.r=.qfo)
state.dat: $(state_obj) $(QFCC_DEP)
$(QFCC) $(QCFLAGS) -o $@ $(state_obj)
state.run: Makefile build-run
$(srcdir)/build-run $@
structlive_dat_SOURCES=structlive.r
structlive_obj=$(structlive_dat_SOURCES:.r=.qfo)
structlive.dat: $(structlive_obj) $(QFCC_DEP)

53
tools/qfcc/test/state.r Normal file
View file

@ -0,0 +1,53 @@
#include "test-harness.h"
.void() think;
.float nextthink;
.float frame;
entity self;
float time;
$frame frame0 frame1 frame2 frame3
void
state0 (void)
[$frame1, state1]
{
if (self.frame != $frame1 || self.think != state1
|| self.nextthink != 0.1) {
printf ("state0: %g %x %g\n", self.frame, self.think, self.nextthink);
exit (1);
}
}
void
state1 (void)
[$frame2, state2, 0.2]
{
if (self.frame != $frame2 || self.think != state2
|| self.nextthink != 0.2) {
printf ("state0: %g %x %g\n", self.frame, self.think, self.nextthink);
exit (1);
}
}
void
state2 (void)
[$frame0, state0, 0.5]
{
if (self.frame != $frame0 || self.think != state0
|| self.nextthink != 0.5) {
printf ("state0: %g %x %g\n", self.frame, self.think, self.nextthink);
exit (1);
}
}
int
main ()
{
self = spawn ();
state0();
while (self.frame != $frame0) {
self.think();
}
return 0;
}

View file

@ -79,11 +79,29 @@ bi_exit (progs_t *pr)
exit (P_INT (pr, 0));
}
static void
bi_spawn (progs_t *pr)
{
edict_t *ed;
ed = ED_Alloc (pr);
RETURN_EDICT (pr, ed);
}
static void
bi_remove (progs_t *pr)
{
edict_t *ed;
ed = P_EDICT (pr, 0);
ED_Free (pr, ed);
}
static builtin_t builtins[] = {
{"printf", bi_printf, -1},
{"errno", bi_errno, -1},
{"strerror", bi_strerror, -1},
{"exit", bi_exit, -1},
{"spawn", bi_spawn, -1},
{"remove", bi_remove, -1},
{0}
};

View file

@ -165,7 +165,7 @@ load_progs (const char *name)
return 0;
}
pr.progs_name = name;
PR_LoadProgsFile (&pr, file, size, 1, 1024 * 1024);
PR_LoadProgsFile (&pr, file, size, 16, 1024 * 1024);
Qclose (file);
if (!PR_RunLoadFuncs (&pr))
PR_Error (&pr, "unable to load %s", pr.progs_name);

View file

@ -0,0 +1,6 @@
void printf (string fmt, ...) = #0;
int errno (void) = #0;
string strerror (int err) = #0;
void exit (int code) = #0;
entity spawn (void) = #0;
void remove (entity e) = #0;