2 Copyright (C) 1996-1997 Id Software, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
34 #define MAX_STACK_DEPTH 32
35 prstack_t pr_stack
[MAX_STACK_DEPTH
];
38 #define LOCALSTACK_SIZE 2048
39 int localstack
[LOCALSTACK_SIZE
];
44 dfunction_t
*pr_xfunction
;
139 char *PR_GlobalString (int ofs
);
140 char *PR_GlobalStringNoContents (int ofs
);
143 //=============================================================================
150 void PR_PrintStatement (dstatement_t
*s
)
154 if ( (unsigned)s
->op
< sizeof(pr_opnames
)/sizeof(pr_opnames
[0]))
156 Con_Printf ("%s ", pr_opnames
[s
->op
]);
157 i
= strlen(pr_opnames
[s
->op
]);
162 if (s
->op
== OP_IF
|| s
->op
== OP_IFNOT
)
163 Con_Printf ("%sbranch %i",PR_GlobalString(s
->a
),s
->b
);
164 else if (s
->op
== OP_GOTO
)
166 Con_Printf ("branch %i",s
->a
);
168 else if ( (unsigned)(s
->op
- OP_STORE_F
) < 6)
170 Con_Printf ("%s",PR_GlobalString(s
->a
));
171 Con_Printf ("%s", PR_GlobalStringNoContents(s
->b
));
176 Con_Printf ("%s",PR_GlobalString(s
->a
));
178 Con_Printf ("%s",PR_GlobalString(s
->b
));
180 Con_Printf ("%s", PR_GlobalStringNoContents(s
->c
));
190 void PR_StackTrace (void)
197 Con_Printf ("<NO STACK>\n");
201 pr_stack
[pr_depth
].f
= pr_xfunction
;
202 for (i
=pr_depth
; i
>=0 ; i
--)
208 Con_Printf ("<NO FUNCTION>\n");
211 Con_Printf ("%12s : %s\n", pr_strings
+ f
->s_file
, pr_strings
+ f
->s_name
);
222 void PR_Profile_f (void)
224 dfunction_t
*f
, *best
;
234 for (i
=0 ; i
<progs
->numfunctions
; i
++)
236 f
= &pr_functions
[i
];
237 if (f
->profile
> max
)
246 Con_Printf ("%7i %s\n", best
->profile
, pr_strings
+best
->s_name
);
258 Aborts the currently executing function
261 void PR_RunError (char *error
, ...)
266 va_start (argptr
,error
);
267 vsprintf (string
,error
,argptr
);
270 PR_PrintStatement (pr_statements
+ pr_xstatement
);
272 Con_Printf ("%s\n", string
);
274 pr_depth
= 0; // dump the stack so host_error can shutdown functions
276 Host_Error ("Program error");
280 ============================================================================
283 The interpretation main loop
284 ============================================================================
291 Returns the new program statement counter
294 int PR_EnterFunction (dfunction_t
*f
)
298 pr_stack
[pr_depth
].s
= pr_xstatement
;
299 pr_stack
[pr_depth
].f
= pr_xfunction
;
301 if (pr_depth
>= MAX_STACK_DEPTH
)
302 PR_RunError ("stack overflow");
304 // save off any locals that the new function steps on
306 if (localstack_used
+ c
> LOCALSTACK_SIZE
)
307 PR_RunError ("PR_ExecuteProgram: locals stack overflow\n");
309 for (i
=0 ; i
< c
; i
++)
310 localstack
[localstack_used
+i
] = ((int *)pr_globals
)[f
->parm_start
+ i
];
311 localstack_used
+= c
;
315 for (i
=0 ; i
<f
->numparms
; i
++)
317 for (j
=0 ; j
<f
->parm_size
[i
] ; j
++)
319 ((int *)pr_globals
)[o
] = ((int *)pr_globals
)[OFS_PARM0
+i
*3+j
];
325 return f
->first_statement
- 1; // offset the s++
333 int PR_LeaveFunction (void)
338 Sys_Error ("prog stack underflow");
340 // restore locals from the stack
341 c
= pr_xfunction
->locals
;
342 localstack_used
-= c
;
343 if (localstack_used
< 0)
344 PR_RunError ("PR_ExecuteProgram: locals stack underflow\n");
346 for (i
=0 ; i
< c
; i
++)
347 ((int *)pr_globals
)[pr_xfunction
->parm_start
+ i
] = localstack
[localstack_used
+i
];
351 pr_xfunction
= pr_stack
[pr_depth
].f
;
352 return pr_stack
[pr_depth
].s
;
361 void PR_ExecuteProgram (func_t fnum
)
366 dfunction_t
*f
, *newf
;
373 if (!fnum
|| fnum
>= progs
->numfunctions
)
375 if (pr_global_struct
->self
)
376 ED_Print (PROG_TO_EDICT(pr_global_struct
->self
));
377 Host_Error ("PR_ExecuteProgram: NULL function");
380 f
= &pr_functions
[fnum
];
385 // make a stack frame
386 exitdepth
= pr_depth
;
388 s
= PR_EnterFunction (f
);
392 s
++; // next statement
394 st
= &pr_statements
[s
];
395 a
= (eval_t
*)&pr_globals
[st
->a
];
396 b
= (eval_t
*)&pr_globals
[st
->b
];
397 c
= (eval_t
*)&pr_globals
[st
->c
];
400 PR_RunError ("runaway loop error");
402 pr_xfunction
->profile
++;
406 PR_PrintStatement (st
);
411 c
->_float
= a
->_float
+ b
->_float
;
414 c
->vector
[0] = a
->vector
[0] + b
->vector
[0];
415 c
->vector
[1] = a
->vector
[1] + b
->vector
[1];
416 c
->vector
[2] = a
->vector
[2] + b
->vector
[2];
420 c
->_float
= a
->_float
- b
->_float
;
423 c
->vector
[0] = a
->vector
[0] - b
->vector
[0];
424 c
->vector
[1] = a
->vector
[1] - b
->vector
[1];
425 c
->vector
[2] = a
->vector
[2] - b
->vector
[2];
429 c
->_float
= a
->_float
* b
->_float
;
432 c
->_float
= a
->vector
[0]*b
->vector
[0]
433 + a
->vector
[1]*b
->vector
[1]
434 + a
->vector
[2]*b
->vector
[2];
437 c
->vector
[0] = a
->_float
* b
->vector
[0];
438 c
->vector
[1] = a
->_float
* b
->vector
[1];
439 c
->vector
[2] = a
->_float
* b
->vector
[2];
442 c
->vector
[0] = b
->_float
* a
->vector
[0];
443 c
->vector
[1] = b
->_float
* a
->vector
[1];
444 c
->vector
[2] = b
->_float
* a
->vector
[2];
448 c
->_float
= a
->_float
/ b
->_float
;
452 c
->_float
= (int)a
->_float
& (int)b
->_float
;
456 c
->_float
= (int)a
->_float
| (int)b
->_float
;
461 c
->_float
= a
->_float
>= b
->_float
;
464 c
->_float
= a
->_float
<= b
->_float
;
467 c
->_float
= a
->_float
> b
->_float
;
470 c
->_float
= a
->_float
< b
->_float
;
473 c
->_float
= a
->_float
&& b
->_float
;
476 c
->_float
= a
->_float
|| b
->_float
;
480 c
->_float
= !a
->_float
;
483 c
->_float
= !a
->vector
[0] && !a
->vector
[1] && !a
->vector
[2];
486 c
->_float
= !a
->string
|| !pr_strings
[a
->string
];
489 c
->_float
= !a
->function
;
492 c
->_float
= (PROG_TO_EDICT(a
->edict
) == sv
.edicts
);
496 c
->_float
= a
->_float
== b
->_float
;
499 c
->_float
= (a
->vector
[0] == b
->vector
[0]) &&
500 (a
->vector
[1] == b
->vector
[1]) &&
501 (a
->vector
[2] == b
->vector
[2]);
504 c
->_float
= !strcmp(pr_strings
+a
->string
,pr_strings
+b
->string
);
507 c
->_float
= a
->_int
== b
->_int
;
510 c
->_float
= a
->function
== b
->function
;
515 c
->_float
= a
->_float
!= b
->_float
;
518 c
->_float
= (a
->vector
[0] != b
->vector
[0]) ||
519 (a
->vector
[1] != b
->vector
[1]) ||
520 (a
->vector
[2] != b
->vector
[2]);
523 c
->_float
= strcmp(pr_strings
+a
->string
,pr_strings
+b
->string
);
526 c
->_float
= a
->_int
!= b
->_int
;
529 c
->_float
= a
->function
!= b
->function
;
535 case OP_STORE_FLD
: // integers
537 case OP_STORE_FNC
: // pointers
541 b
->vector
[0] = a
->vector
[0];
542 b
->vector
[1] = a
->vector
[1];
543 b
->vector
[2] = a
->vector
[2];
548 case OP_STOREP_FLD
: // integers
550 case OP_STOREP_FNC
: // pointers
551 ptr
= (eval_t
*)((byte
*)sv
.edicts
+ b
->_int
);
555 ptr
= (eval_t
*)((byte
*)sv
.edicts
+ b
->_int
);
556 ptr
->vector
[0] = a
->vector
[0];
557 ptr
->vector
[1] = a
->vector
[1];
558 ptr
->vector
[2] = a
->vector
[2];
562 ed
= PROG_TO_EDICT(a
->edict
);
564 NUM_FOR_EDICT(ed
); // make sure it's in range
566 if (ed
== (edict_t
*)sv
.edicts
&& sv
.state
== ss_active
)
567 PR_RunError ("assignment to world entity");
568 c
->_int
= (byte
*)((int *)&ed
->v
+ b
->_int
) - (byte
*)sv
.edicts
;
576 ed
= PROG_TO_EDICT(a
->edict
);
578 NUM_FOR_EDICT(ed
); // make sure it's in range
580 a
= (eval_t
*)((int *)&ed
->v
+ b
->_int
);
585 ed
= PROG_TO_EDICT(a
->edict
);
587 NUM_FOR_EDICT(ed
); // make sure it's in range
589 a
= (eval_t
*)((int *)&ed
->v
+ b
->_int
);
590 c
->vector
[0] = a
->vector
[0];
591 c
->vector
[1] = a
->vector
[1];
592 c
->vector
[2] = a
->vector
[2];
599 s
+= st
->b
- 1; // offset the s++
604 s
+= st
->b
- 1; // offset the s++
608 s
+= st
->a
- 1; // offset the s++
620 pr_argc
= st
->op
- OP_CALL0
;
622 PR_RunError ("NULL function");
624 newf
= &pr_functions
[a
->function
];
626 if (newf
->first_statement
< 0)
627 { // negative statements are built in functions
628 i
= -newf
->first_statement
;
629 if (i
>= pr_numbuiltins
)
630 PR_RunError ("Bad builtin call number");
635 s
= PR_EnterFunction (newf
);
640 pr_globals
[OFS_RETURN
] = pr_globals
[st
->a
];
641 pr_globals
[OFS_RETURN
+1] = pr_globals
[st
->a
+1];
642 pr_globals
[OFS_RETURN
+2] = pr_globals
[st
->a
+2];
644 s
= PR_LeaveFunction ();
645 if (pr_depth
== exitdepth
)
650 ed
= PROG_TO_EDICT(pr_global_struct
->self
);
652 ed
->v
.nextthink
= pr_global_struct
->time
+ 0.05;
654 ed
->v
.nextthink
= pr_global_struct
->time
+ 0.1;
656 if (a
->_float
!= ed
->v
.frame
)
658 ed
->v
.frame
= a
->_float
;
660 ed
->v
.think
= b
->function
;
664 PR_RunError ("Bad opcode %i", st
->op
);