mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-10 07:11:41 +00:00
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:
parent
35de42aeac
commit
a6cdc8735a
8 changed files with 131 additions and 23 deletions
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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
53
tools/qfcc/test/state.r
Normal 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;
|
||||
}
|
|
@ -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}
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
6
tools/qfcc/test/test-harness.h
Normal file
6
tools/qfcc/test/test-harness.h
Normal 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;
|
Loading…
Reference in a new issue