Merge branch 'master' into vulkan

This commit is contained in:
Bill Currie 2020-02-16 18:17:50 +09:00
commit 9ff4eefe65
78 changed files with 2810 additions and 508 deletions

View file

@ -3,38 +3,39 @@
/**
\page connection_sequence QW Connection Sequence
\msc
Client,Server;
Client=>Server [label = "getchallenge\n"];
Server=>Client [label = "c[challenge][ext]"];
Client=>Server [label = "connect [protover] [qport] [challenge] [userinfo]"];
Server=>Client [label = "j"];
Client->Server [label = "[clc_stringcmd]new"];
Server->Client [label = "[svc_serverdata][data]"];
|||;
Client->Server [label = "[clc_stringcmd]soundlist [svcount] 0"];
--- [label = "soundlist loop start"];
Server->Client [label = "[svc_soundlist][data][next]"];
Client->Server [label = "[clc_stringcmd]soundlist [svcount] [next]"];
--- [label = "soundlist loop end"];
Server->Client [label = "[svc_soundlist][data]0"];
|||;
Client->Server [label = "[clc_stringcmd]modellist [svcount] 0"];
--- [label = "modellist list loop start"];
Server->Client [label = "[svc_modellist][data][next]"];
Client->Server [label = "[clc_stringcmd]modellist [svcount] [next]"];
--- [label = "modellist list loop end"];
Server->Client [label = "[svc_modellist][data]0"];
|||;
Client->Server [label = "[clc_stringcmd]prespawn [svcount] [n=0] [wcsum]"];
--- [label = "prespawn loop start"];
Server->Client [label = "[signon buffer n][stuffcmd]prespawn..."];
Client->Server [label = "[clc_stringcmd]prespawn [svcount] [n]"];
--- [label = "prespawn loop end"];
Server->Client [label = "[signon buffer n][stuffcmd]spawn..."];
|||;
Client->Server [label = "[clc_stringcmd]spawn [svcount] 0"];
Server->Client [label = "[spawn info][stuffcmd]skins"];
Client->Server [label = "[clc_stringcmd]begin [svcount]"];
#... [label = "in game message sequence"];
Client [linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black],
Server [linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black];
Client=>Server [label = "getchallenge\n", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black];
Server=>Client [label = "c[challenge][ext]", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black];
Client=>Server [label = "connect [protover] [qport] [challenge] [userinfo]", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black];
Server=>Client [label = "j", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black];
Client->Server [label = "[clc_stringcmd]new", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black];
Server->Client [label = "[svc_serverdata][data]", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black];
||| [linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black];
Client->Server [label = "[clc_stringcmd]soundlist [svcount] 0", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black];
--- [label = "soundlist loop start", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black];
Server->Client [label = "[svc_soundlist][data][next]", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black];
Client->Server [label = "[clc_stringcmd]soundlist [svcount] [next]", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black];
--- [label = "soundlist loop end", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black];
Server->Client [label = "[svc_soundlist][data]0", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black];
||| [linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black];
Client->Server [label = "[clc_stringcmd]modellist [svcount] 0", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black];
--- [label = "modellist list loop start", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black];
Server->Client [label = "[svc_modellist][data][next]", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black];
Client->Server [label = "[clc_stringcmd]modellist [svcount] [next]", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black];
--- [label = "modellist list loop end", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black];
Server->Client [label = "[svc_modellist][data]0", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black];
||| [linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black];
Client->Server [label = "[clc_stringcmd]prespawn [svcount] [n=0] [wcsum]", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black];
--- [label = "prespawn loop start", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black];
Server->Client [label = "[signon buffer n][stuffcmd]prespawn...", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black];
Client->Server [label = "[clc_stringcmd]prespawn [svcount] [n]", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black];
--- [label = "prespawn loop end", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black];
Server->Client [label = "[signon buffer n][stuffcmd]spawn...", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black];
||| [linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black];
Client->Server [label = "[clc_stringcmd]spawn [svcount] 0", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black];
Server->Client [label = "[spawn info][stuffcmd]skins", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black];
Client->Server [label = "[clc_stringcmd]begin [svcount]", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black];
... [label = "in game message sequence", linecolor=white, textcolor=white, arclinecolor=white, arctextcolor=white, textbgcolor=black, arctextbgcolor=black];
\endmsc
*/

View file

@ -30,16 +30,28 @@
#include "QF/qtypes.h"
/** \defgroup llist Linked lists
\ingroup utils
*/
//@{
typedef struct llist_node_s {
struct llist_s *parent;
struct llist_node_s *prev, *next;
void *data;
struct llist_s *parent; ///< The list owning this node.
struct llist_node_s *prev; ///< The previous node in the list, or null.
struct llist_node_s *next; ///< The flowing node in the list, or null.
void *data; ///< The actual list item.
} llist_node_t;
typedef struct llist_s {
struct llist_node_s *start, *end, *iter;
struct llist_node_s *start; ///< The first node in the list, or null.
struct llist_node_s *end; ///< The last node in the list, or null.
struct llist_node_s *iter;
/// Function called when deleting a list item.
/// \param element The item being deleted.
/// \param userdata Pointer to user data supplied to llist_new().
void (*freedata)(void *element, void *userdata);
qboolean (*cmpdata)(const void *element, const void *comparison, void *userdata);
qboolean (*cmpdata)(const void *element, const void *comparison,
void *userdata);
void *userdata;
} llist_t;
@ -48,8 +60,43 @@ typedef qboolean (*llist_iterator_t)(void *element, llist_node_t *node);
#define LLIST_ICAST(x) (llist_iterator_t)(x)
#define LLIST_DATA(node, type) ((type *)((node)->data))
llist_t *llist_new (void (*freedata)(void *element, void *userdata), qboolean (*cmpdata)(const void *element, const void *comparison, void *userdata), void *userdata);
/** Create a new, empty, linked list.
\param freedata Function to call when deleting a list item.
\param cmpdata Function to call to compare two list items. It must
return true when the items are the same and false when
they differ.
\param userdata User data pointer. Set to whatever you want, it will be
passed to the \a freedata and \a cmpdata functions as
their final parameter.
\return Pointer to the list's control structure, which is to be
passed to the other functions accessing the list.
*/
llist_t *llist_new (void (*freedata)(void *element, void *userdata),
qboolean (*cmpdata)(const void *element,
const void *comparison,
void *userdata),
void *userdata);
/** Empty a linked list.
All of the items in the list will be deleted via the list's \a freedata
function and the list will become empty.
\param list Pointer to the list's control structure created by
llist_new(). May be null, in which case no operation is
performed.
*/
void llist_flush (llist_t *list);
/** Delete a linked list.
All of the items in the list will be deleted via the list's \a freedata
function and the list will be destroyed. Do not attempt to use the list
pointer after destroying the list.
\param list Pointer to the list's control structure created by
llist_new(). May be null, in which case no operation is
performed.
*/
void llist_delete (llist_t *list);
llist_node_t *llist_append (llist_t *list, void *element);
llist_node_t *llist_prefix (llist_t *list, void *element);
@ -62,4 +109,7 @@ void llist_iterate (llist_t *list, llist_iterator_t iterate);
void *llist_find (llist_t *list, void *comparison);
llist_node_t *llist_findnode (llist_t *list, void *comparison);
void *llist_createarray (llist_t *list, size_t esize);
//@}
#endif

View file

@ -44,6 +44,7 @@ typedef enum {
ev_integer,
ev_uinteger,
ev_short, // value is embedded in the opcode
ev_double,
ev_invalid, // invalid type. used for instruction checking
ev_type_count // not a type, gives number of types
@ -180,8 +181,8 @@ typedef enum {
OP_SHL_I,
OP_SHR_I,
OP_MOD_F,
OP_MOD_I,
OP_REM_F,
OP_REM_I,
OP_LOADB_F,
OP_LOADB_V,
@ -305,6 +306,7 @@ typedef enum {
OP_PUSH_P,
OP_PUSH_Q,
OP_PUSH_I,
OP_PUSH_D,
OP_PUSHB_S,
OP_PUSHB_F,
@ -315,6 +317,7 @@ typedef enum {
OP_PUSHB_P,
OP_PUSHB_Q,
OP_PUSHB_I,
OP_PUSHB_D,
OP_PUSHBI_S,
OP_PUSHBI_F,
@ -325,6 +328,7 @@ typedef enum {
OP_PUSHBI_P,
OP_PUSHBI_Q,
OP_PUSHBI_I,
OP_PUSHBI_D,
OP_POP_S,
OP_POP_F,
@ -335,6 +339,7 @@ typedef enum {
OP_POP_P,
OP_POP_Q,
OP_POP_I,
OP_POP_D,
OP_POPB_S,
OP_POPB_F,
@ -345,6 +350,7 @@ typedef enum {
OP_POPB_P,
OP_POPB_Q,
OP_POPB_I,
OP_POPB_D,
OP_POPBI_S,
OP_POPBI_F,
@ -355,6 +361,40 @@ typedef enum {
OP_POPBI_P,
OP_POPBI_Q,
OP_POPBI_I,
OP_POPBI_D,
OP_ADD_D,
OP_SUB_D,
OP_MUL_D,
OP_MUL_QD,
OP_MUL_DQ,
OP_MUL_VD,
OP_MUL_DV,
OP_DIV_D,
OP_REM_D,
OP_GE_D,
OP_LE_D,
OP_GT_D,
OP_LT_D,
OP_NOT_D,
OP_EQ_D,
OP_NE_D,
OP_CONV_FD,
OP_CONV_DF,
OP_CONV_ID,
OP_CONV_DI,
OP_STORE_D,
OP_STOREB_D,
OP_STOREBI_D,
OP_STOREP_D,
OP_LOAD_D,
OP_LOADB_D,
OP_LOADBI_D,
OP_ADDRESS_D,
OP_MOD_I,
OP_MOD_F,
OP_MOD_D,
} pr_opcode_e;
typedef struct opcode_s {
@ -383,6 +423,11 @@ typedef struct ddef_s {
pr_int_t s_name;
} ddef_t;
typedef struct dparmsize_s {
uint8_t size:5;
uint8_t alignment:3;
} dparmsize_t;
#define DEF_SAVEGLOBAL (1<<15)
#define MAX_PARMS 8
@ -398,7 +443,7 @@ typedef struct dfunction_s {
pr_int_t s_file; // source file defined in
pr_int_t numparms;
uint8_t parm_size[MAX_PARMS];
dparmsize_t parm_size[MAX_PARMS];
} dfunction_t;
typedef union pr_type_u {
@ -423,7 +468,7 @@ typedef struct pr_va_list_s {
|(((0x##b) & 0xfff) << 12) \
|(((0x##c) & 0xfff) << 0) )
#define PROG_ID_VERSION 6
#define PROG_VERSION PROG_VERSION_ENCODE(0,fff,009)
#define PROG_VERSION PROG_VERSION_ENCODE(0,fff,00a)
typedef struct dprograms_s {
pr_uint_t version;

View file

@ -320,6 +320,18 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_
*/
#define G_FLOAT(p,o) G_var (p, o, float)
/** Access a double global. Can be assigned to.
\par QC type:
\c double
\param p pointer to ::progs_t VM struct
\param o offset into global data space
\return double lvalue
\hideinitializer
*/
#define G_DOUBLE(p,o) (*(double *) ((p)->pr_globals + o))
/** Access an integer global. Can be assigned to.
\par QC type:
@ -510,6 +522,18 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_
*/
#define P_FLOAT(p,n) P_var (p, n, float)
/** Access a double parameter. Can be assigned to.
\par QC type:
\c double
\param p pointer to ::progs_t VM struct
\param n parameter number (0-7)
\return double lvalue
\hideinitializer
*/
#define P_DOUBLE(p,n) (*(double *) ((p)->pr_params[n]))
/** Access an integer parameter. Can be assigned to.
\par QC type:
@ -702,6 +726,17 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_
*/
#define R_FLOAT(p) R_var (p, float)
/** Access the VM function return value as a \c double
\par QC type:
\c double
\param p pointer to ::progs_t VM struct
\return double lvalue
\hideinitializer
*/
#define R_DOUBLE(p) (*(double *) ((p)->pr_return))
/** Access the VM function return value as a \c ::pr_int_t (AKA int32_t)
\par QC type:
@ -868,6 +903,18 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_
*/
#define E_FLOAT(e,o) E_var (e, o, float)
/** Access a double entity field. Can be assigned to.
\par QC type:
\c double
\param e pointer to the entity
\param o field offset into entity data space
\return double lvalue
\hideinitializer
*/
#define E_DOUBLE(e,o) (*(double *) ((e)->v + o))
/** Access an integer entity field. Can be assigned to.
\par QC type:
@ -1032,7 +1079,7 @@ typedef struct {
pr_int_t locals;
pr_int_t profile;
pr_int_t numparms;
uint8_t parm_size[MAX_PARMS];
dparmsize_t parm_size[MAX_PARMS];
dfunction_t *descriptor;
builtin_proc func;
} bfunction_t;
@ -1520,36 +1567,36 @@ struct progs_s {
int zone_size; ///< set by user
/// \name builtin functions
//@{
///@{
struct hashtab_s *builtin_hash;
struct hashtab_s *builtin_num_hash;
unsigned bi_next;
unsigned (*bi_map) (progs_t *pr, unsigned binum);
//@}
///@}
/// \name symbol management
//@{
///@{
struct hashtab_s *function_hash;
struct hashtab_s *global_hash;
struct hashtab_s *field_hash;
//@}
///@}
/// \name load hooks
//@{
///@{
int num_load_funcs;
int max_load_funcs;
pr_load_func_t **load_funcs;
/// cleared each load
//@{
///@{
int num_load_finish_funcs;
int max_load_finish_funcs;
pr_load_func_t **load_finish_funcs;
//@}
//@}
///@}
///@}
/// \name string management
//@{
///@{
struct dstring_mem_s *ds_mem;
strref_t *free_string_refs;
strref_t *static_strings;
@ -1560,10 +1607,11 @@ struct progs_s {
struct hashtab_s *strref_hash;
int num_strings;
strref_t *pr_xtstr;
//@}
int float_promoted; ///< for PR_Sprintf
///@}
/// \name memory map
//@{
///@{
dfunction_t *pr_functions;
bfunction_t *function_table;
char *pr_strings;
@ -1573,10 +1621,10 @@ struct progs_s {
dstatement_t *pr_statements;
pr_type_t *pr_globals;
unsigned globals_size;
//@}
///@}
/// \name parameter block
//@{
///@{
pr_type_t *pr_return;
pr_type_t *pr_params[MAX_PARMS];
pr_type_t *pr_real_params[MAX_PARMS];
@ -1584,10 +1632,11 @@ struct progs_s {
pr_type_t *pr_saved_params;
int pr_saved_argc;
int pr_param_size; ///< covers both params and return
//@}
int pr_param_alignment; ///< covers both params and return
///@}
/// \name edicts
//@{
///@{
edict_t **edicts;
int max_edicts; ///< set by user
int *num_edicts;
@ -1599,10 +1648,10 @@ struct progs_s {
int pr_edict_size; ///< in bytes
int pr_edictareasize; ///< for bounds checking, starts at 0
func_t edict_parse;
//@}
///@}
/// \name execution state
//@{
///@{
int pr_argc;
qboolean pr_trace;
@ -1620,24 +1669,24 @@ struct progs_s {
/// be considered valid if there is no .stack global.
/// \note The return address and saved locals will not ever be on this
/// stack.
//@{
///@{
pr_type_t *stack;
pointer_t stack_bottom;
int stack_size; ///< set by user
//@}
///@}
int localstack[LOCALSTACK_SIZE];
int localstack_used;
//@}
///@}
/// \name resources
//@{
///@{
pr_resource_t *resources;
struct hashtab_s *resource_hash;
//@}
///@}
/// \name obj info
//@{
///@{
unsigned selector_index;
unsigned selector_index_max;
struct obj_list_s **selector_sels;
@ -1650,10 +1699,10 @@ struct progs_s {
struct obj_list_s *unclaimed_proto_list;
struct obj_list_s *module_list;
struct obj_list_s *class_tree_list;
//@}
///@}
/// \name debug info
//@{
///@{
const char *debugfile;
struct pr_debug_header_s *debug;
struct pr_auxfunction_s *auxfunctions;
@ -1663,10 +1712,10 @@ struct progs_s {
pr_type_t *watch;
int wp_conditional;
pr_type_t wp_val;
//@}
///@}
/// \name globals and fields needed by the VM
//@{
///@{
struct {
float *time; ///< required for OP_STATE
pr_int_t *self; ///< required for OP_STATE
@ -1678,7 +1727,7 @@ struct progs_s {
pr_int_t think; ///< required for OP_STATE
pr_int_t this; ///< optional for entity<->object linking
} fields;
//@}
///@}
};
/** \addtogroup progs_data_access

View file

@ -31,28 +31,110 @@
#ifndef __QF_segtext_h
#define __QF_segtext_h
/** \defgroup segtext Segmented text files.
/** \defgroup segtext Segmented text files
\ingroup utils
Based on The OpenGL Shader Wrangler: http://prideout.net/blog/?p=11
Based on The OpenGL Shader Wrangler:
https://prideout.net/blog/old/blog/index.html@p=11.html
However, nothing is assumed about any of the segments: they are all nothing
more than chunks of mostly random (lines cannot start with --) text with
identifying tags. Also, the identifying tag represents only the shader_key
of OpenGL Shader Wrangler's Effect.shader_key identifier.
*/
///@{
/** Represent a single text segment
Segments are separated by lines beginning with "--" (without the quotes).
The first word ([A-Za-z0-9_.]+) following the double-hyphen is used as an
identifying tag for the segment. Whitespace and any additional characters
are ignored.
The segment itself starts on the following line.
*/
typedef struct segchunk_s {
struct segchunk_s *next;
const char *tag;
const char *text;
int start_line;
const char *tag; ///< identifying tag or null if no tag
const char *text; ///< nul-terminated string holding the segment
int start_line; ///< line number for first line of the segment
} segchunk_t;
/** Container for all the segments extracted from the provided text
The first segment has no tag and may or may not be empty.
Segments are stored sequentially in \a chunk_list are indexed by
identifying tag (if present) in \a tab.
Segments that have no identifying tag are not in \a tab, but can
be accessed by walking \a chunk_list its \a next field.
*/
typedef struct segtext_s {
struct segtext_s *next;
segchunk_t *chunk_list;
struct hashtab_s *tab;
} segtext_t;
/** Parse a nul-terminated string into (optionally) tagged segments
The segments are separated by lines beginning with a double-hyphen ("--"),
with an optional tag following the double-hyphen on the same line. Valid
tag characters are ASCII alpha-numerics, "." and "_". Whitespace is ignored
and invalid characters are treated as whitespace. Only the first tag on the
line is significant.
\param src nul-terminated string to be parsed into segments
\return Pointer to container of parsed segments. Can be freed using
Segtext_delete().
*/
segtext_t *Segtext_new (const char *src);
/** Free a segmented text container created by Segtext_new()
\param st Pointer to segmented text container to be freed. Must have been
created by Segtext_new().
*/
void Segtext_delete (segtext_t *st);
/** Find a text segment via its identifying tag
Like OpenGL Shader Wrangler, the segment tag does not have to be a perfect
match with the specified tag: the segment with the longest string of
sub-tags matching the leading subtags of the specified tag is selected.
Tags are logically broken into sub-tag by the "." character. Thus in a
collection of segments with tags "foo" and "foo.b", "foo.bar" will find the
segment tagged "foo". However, if a segment tagged "foo.bar" is present, it
will be returned. A segment tagged "foo.bar.baz" will not.
\param st Pointer to segmented text container
\param tag String specifying the tag identifying the segment to be
returned. Valid tag characters are alphanumerics, "_" and "."
(ie, [A-Za-z0-9._]). "." is used as a sub-tag separator for
partial matches.
\return Pointer to segment data block with the best matching tag,
providing access to the segment's tag and starting line number,
as well as the segment contents. Null if no matching tag was
found.
*/
const segchunk_t *Segtext_FindChunk (const segtext_t *st, const char *tag);
/** Find a text segment via its identifying tag
Like OpenGL Shader Wrangler, the segment tag does not have to be a perfect
match with the specified tag: the segment with the longest string of
sub-tags matching the leading subtags of the specified tag is selected.
Tags are logically broken into sub-tag by the "." character. Thus in a
collection of segments with tags "foo" and "foo.b", "foo.bar" will find the
segment tagged "foo". However, if a segment tagged "foo.bar" is present, it
will be returned. A segment tagged "foo.bar.baz" will not.
\param st Pointer to segmented text container
\param tag String specifying the tag identifying the segment to be
returned. Valid tag characters are alphanumerics, "_" and "."
(ie, [A-Za-z0-9._]). "." is used as a sub-tag separator for
partial matches.
\return Contents of the segment with the best matching tag, or null if
no matching tag was found.
*/
const char *Segtext_Find (const segtext_t *st, const char *tag);
///@}
#endif//__QF_segtext_h

View file

@ -81,6 +81,10 @@ void S_Init (int *viewentity, double *host_frametime);
*/
void S_Init_Cvars (void);
/** Shutdown the sound engine. Allows audio output modules to shutdown
gracefully.
*/
void S_Shutdown (void);
///@}
/** \defgroup sound_stuff Unclassified

View file

@ -692,7 +692,12 @@ value_string (progs_t *pr, etype_t type, pr_type_t *val)
case ev_uinteger:
dsprintf (line, "$%08x", val->uinteger_var);
break;
default:
case ev_double:
dsprintf (line, "%g", *(double *)val);
break;
case ev_short:
case ev_invalid:
case ev_type_count:
//dsprintf (line, "bad type %i", type);
dsprintf (line, "<%x %x %x %x>",
val[0].integer_var, val[1].integer_var,

View file

@ -142,6 +142,21 @@ PR_PopFrame (progs_t *pr)
pr->pr_xtstr = frame->tstr;
}
static __attribute__((pure)) long
align_offset (long offset, dparmsize_t parmsize)
{
int mask = (1 << parmsize.alignment) - 1;
return (offset + mask) & ~mask;
}
static void
copy_param (pr_type_t *dst, pr_type_t *src, size_t size)
{
while (size--) {
memcpy (dst++, src++, sizeof (pr_type_t));
}
}
/** Setup the stackframe prior to calling a progs function. Saves all local
data the called function will trample on and copies the parameters used
by the function into the function's local data space.
@ -153,39 +168,44 @@ PR_PopFrame (progs_t *pr)
static void
PR_EnterFunction (progs_t *pr, bfunction_t *f)
{
pr_int_t i, j, c, o;
pr_int_t k;
pr_int_t count = 0;
int size[2] = {0, 0};
long paramofs = 0;
long offs;
pr_int_t i;
pr_type_t *dstParams[MAX_PARMS];
pointer_t paramofs = 0;
PR_PushFrame (pr);
if (f->numparms > 0) {
for (i = 0; i < 2 && i < f->numparms; i++) {
paramofs += f->parm_size[i];
size[i] = f->parm_size[i];
paramofs = f->parm_start;
for (i = 0; i < f->numparms; i++) {
paramofs = align_offset (paramofs, f->parm_size[i]);
dstParams[i] = pr->pr_globals + paramofs;
paramofs += f->parm_size[i].size;
if (pr->pr_params[i] != pr->pr_real_params[i]) {
copy_param (pr->pr_real_params[i], pr->pr_params[i],
f->parm_size[i].size);
}
}
count = i;
} else if (f->numparms < 0) {
for (i = 0; i < 2 && i < -f->numparms - 1; i++) {
paramofs += f->parm_size[i];
size[i] = f->parm_size[i];
paramofs = f->parm_start + 2; // argc and argv
for (i = 0; i < -f->numparms - 1; i++) {
paramofs = align_offset (paramofs, f->parm_size[i]);
dstParams[i] = pr->pr_globals + paramofs;
paramofs += f->parm_size[i].size;
if (pr->pr_params[i] != pr->pr_real_params[i]) {
copy_param (pr->pr_real_params[i], pr->pr_params[i],
f->parm_size[i].size);
}
}
for (; i < 2; i++) {
paramofs += pr->pr_param_size;
size[i] = pr->pr_param_size;
dparmsize_t parmsize = { pr->pr_param_size, pr->pr_param_alignment };
paramofs = align_offset (paramofs, parmsize );
if (i < MAX_PARMS) {
dstParams[i] = pr->pr_globals + paramofs;
}
count = i;
}
for (i = 0; i < count && i < pr->pr_argc; i++) {
offs = (pr->pr_params[i] - pr->pr_globals) - f->parm_start;
if (offs >= 0 && offs < paramofs) {
memcpy (pr->pr_real_params[i], pr->pr_params[i],
size[i] * sizeof (pr_type_t));
pr->pr_params[i] = pr->pr_real_params[i];
for (; i < pr->pr_argc; i++) {
if (pr->pr_params[i] != pr->pr_real_params[i]) {
copy_param (pr->pr_real_params[i], pr->pr_params[i],
parmsize.size);
}
}
}
@ -194,44 +214,36 @@ PR_EnterFunction (progs_t *pr, bfunction_t *f)
pr->pr_xstatement = f->first_statement - 1; // offset the st++
// save off any locals that the new function steps on
c = f->locals;
if (pr->localstack_used + c > LOCALSTACK_SIZE)
if (pr->localstack_used + f->locals > LOCALSTACK_SIZE)
PR_RunError (pr, "PR_EnterFunction: locals stack overflow");
memcpy (&pr->localstack[pr->localstack_used],
&pr->pr_globals[f->parm_start],
sizeof (pr_type_t) * c);
pr->localstack_used += c;
sizeof (pr_type_t) * f->locals);
pr->localstack_used += f->locals;
if (pr_deadbeef_locals->int_val)
for (k = f->parm_start; k < f->parm_start + c; k++)
pr->pr_globals[k].integer_var = 0xdeadbeef;
for (i = f->parm_start; i < f->parm_start + f->locals; i++)
pr->pr_globals[i].integer_var = 0xdeadbeef;
// copy parameters
o = f->parm_start;
if (f->numparms >= 0) {
for (i = 0; i < f->numparms; i++) {
for (j = 0; j < f->parm_size[i]; j++) {
memcpy (&pr->pr_globals[o], &P_INT (pr, i) + j,
sizeof (pr_type_t));
o++;
}
copy_param (dstParams[i], pr->pr_params[i], f->parm_size[i].size);
}
} else {
pr_type_t *argc = &pr->pr_globals[o++];
pr_type_t *argv = &pr->pr_globals[o++];
int copy_args;
pr_type_t *argc = &pr->pr_globals[f->parm_start + 0];
pr_type_t *argv = &pr->pr_globals[f->parm_start + 1];
for (i = 0; i < -f->numparms - 1; i++) {
for (j = 0; j < f->parm_size[i]; j++) {
memcpy (&pr->pr_globals[o], &P_INT (pr, i) + j,
sizeof (pr_type_t));
o++;
}
copy_param (dstParams[i], pr->pr_params[i], f->parm_size[i].size);
}
argc->integer_var = pr->pr_argc - i;
argv->integer_var = o;
copy_args = pr->pr_argc - i;
argc->integer_var = copy_args;
argv->integer_var = dstParams[i] - pr->pr_globals;
if (i < MAX_PARMS) {
memcpy (&pr->pr_globals[o], &P_INT (pr, i),
(MAX_PARMS - i) * pr->pr_param_size * sizeof (pr_type_t));
memcpy (dstParams[i], pr->pr_params[i],
(copy_args * pr->pr_param_size) * sizeof (pr_type_t));
}
}
}
@ -239,19 +251,18 @@ PR_EnterFunction (progs_t *pr, bfunction_t *f)
static void
PR_LeaveFunction (progs_t *pr)
{
int c;
bfunction_t *f = pr->pr_xfunction;
PR_PopFrame (pr);
// restore locals from the stack
c = f->locals;
pr->localstack_used -= c;
pr->localstack_used -= f->locals;
if (pr->localstack_used < 0)
PR_RunError (pr, "PR_LeaveFunction: locals stack underflow");
memcpy (&pr->pr_globals[f->parm_start],
&pr->localstack[pr->localstack_used], sizeof (pr_type_t) * c);
&pr->localstack[pr->localstack_used],
sizeof (pr_type_t) * f->locals);
}
VISIBLE void
@ -280,12 +291,15 @@ PR_BoundsCheck (progs_t *pr, int addr, etype_t type)
#define OPB (*op_b)
#define OPC (*op_c)
#define OPA_double_var (*((double *) (op_a)))
#define OPB_double_var (*((double *) (op_b)))
#define OPC_double_var (*((double *) (op_c)))
/*
This gets around the problem of needing to test for -0.0 but denormals
causing exceptions (or wrong results for what we need) on the alpha.
*/
#define FNZ(x) ((x).uinteger_var && (x).uinteger_var != 0x80000000u)
#define FNZ(x) ((x).uinteger_var & ~0x80000000u)
static int
signal_hook (int sig, void *data)
@ -317,6 +331,8 @@ signal_hook (int sig, void *data)
return 1;
case OP_MOD_I:
case OP_MOD_F:
case OP_REM_I:
case OP_REM_F:
OPC.integer_var = 0x00000000;
return 1;
default:
@ -421,6 +437,9 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum)
PR_PrintStatement (pr, st, 1);
switch (st->op) {
case OP_ADD_D:
OPC_double_var = OPA_double_var + OPB_double_var;
break;
case OP_ADD_F:
OPC.float_var = OPA.float_var + OPB.float_var;
break;
@ -437,6 +456,9 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum)
PR_GetString (pr,
OPB.string_var));
break;
case OP_SUB_D:
OPC_double_var = OPA_double_var - OPB_double_var;
break;
case OP_SUB_F:
OPC.float_var = OPA.float_var - OPB.float_var;
break;
@ -446,12 +468,31 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum)
case OP_SUB_Q:
QuatSubtract (OPA.quat_var, OPB.quat_var, OPC.quat_var);
break;
case OP_MUL_D:
OPC_double_var = OPA_double_var * OPB_double_var;
break;
case OP_MUL_F:
OPC.float_var = OPA.float_var * OPB.float_var;
break;
case OP_MUL_V:
OPC.float_var = DotProduct (OPA.vector_var, OPB.vector_var);
break;
case OP_MUL_DV:
{
// avoid issues with the likes of x = x.x * x;
// makes for faster code, too
double scale = OPA_double_var;
VectorScale (OPB.vector_var, scale, OPC.vector_var);
}
break;
case OP_MUL_VD:
{
// avoid issues with the likes of x = x * x.x;
// makes for faster code, too
double scale = OPB_double_var;
VectorScale (OPA.vector_var, scale, OPC.vector_var);
}
break;
case OP_MUL_FV:
{
// avoid issues with the likes of x = x.x * x;
@ -474,6 +515,22 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum)
case OP_MUL_QV:
QuatMultVec (OPA.quat_var, OPB.vector_var, OPC.vector_var);
break;
case OP_MUL_DQ:
{
// avoid issues with the likes of x = x.s * x;
// makes for faster code, too
double scale = OPA_double_var;
QuatScale (OPB.quat_var, scale, OPC.quat_var);
}
break;
case OP_MUL_QD:
{
// avoid issues with the likes of x = x * x.s;
// makes for faster code, too
double scale = OPB_double_var;
QuatScale (OPA.quat_var, scale, OPC.quat_var);
}
break;
case OP_MUL_FQ:
{
// avoid issues with the likes of x = x.s * x;
@ -493,6 +550,9 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum)
case OP_CONJ_Q:
QuatConj (OPA.quat_var, OPC.quat_var);
break;
case OP_DIV_D:
OPC_double_var = OPA_double_var / OPB_double_var;
break;
case OP_DIV_F:
OPC.float_var = OPA.float_var / OPB.float_var;
break;
@ -630,6 +690,9 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum)
case OP_STORE_Q:
QuatCopy (OPA.quat_var, OPB.quat_var);
break;
case OP_STORE_D:
OPB_double_var = OPA_double_var;
break;
case OP_STOREP_F:
case OP_STOREP_ENT:
@ -661,6 +724,14 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum)
ptr = pr->pr_globals + pointer;
QuatCopy (OPA.quat_var, ptr->quat_var);
break;
case OP_STOREP_D:
pointer = OPB.integer_var;
if (pr_boundscheck->int_val) {
PR_BoundsCheck (pr, pointer, ev_double);
}
ptr = pr->pr_globals + pointer;
*(double *) ptr = OPA_double_var;
break;
case OP_ADDRESS:
if (pr_boundscheck->int_val) {
@ -687,6 +758,7 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum)
case OP_ADDRESS_FN:
case OP_ADDRESS_I:
case OP_ADDRESS_P:
case OP_ADDRESS_D:
OPC.integer_var = st->a;
break;
@ -735,6 +807,19 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum)
ed = PROG_TO_EDICT (pr, OPA.entity_var);
memcpy (&OPC, &ed->v[OPB.integer_var], 4 * sizeof (OPC));
break;
case OP_LOAD_D:
if (pr_boundscheck->int_val) {
if (OPA.entity_var < 0
|| OPA.entity_var >= pr->pr_edictareasize)
PR_RunError (pr, "Progs attempted to read an out of "
"bounds edict number");
if (OPB.uinteger_var + 1 >= pr->progs->entityfields)
PR_RunError (pr, "Progs attempted to read an invalid "
"field in an edict");
}
ed = PROG_TO_EDICT (pr, OPA.entity_var);
OPC_double_var = *(double *) (ed->v + OPB.integer_var);
break;
case OP_LOADB_F:
case OP_LOADB_S:
@ -766,6 +851,14 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum)
ptr = pr->pr_globals + pointer;
QuatCopy (ptr->quat_var, OPC.quat_var);
break;
case OP_LOADB_D:
pointer = OPA.integer_var + OPB.integer_var;
if (pr_boundscheck->int_val) {
PR_BoundsCheck (pr, pointer, ev_double);
}
ptr = pr->pr_globals + pointer;
OPC_double_var = *(double *) ptr;
break;
case OP_LOADBI_F:
case OP_LOADBI_S:
@ -797,6 +890,14 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum)
ptr = pr->pr_globals + pointer;
QuatCopy (ptr->quat_var, OPC.quat_var);
break;
case OP_LOADBI_D:
pointer = OPA.integer_var + (short) st->b;
if (pr_boundscheck->int_val) {
PR_BoundsCheck (pr, pointer, ev_quat);
}
ptr = pr->pr_globals + pointer;
OPC_double_var = *(double *) ptr;
break;
case OP_LEA:
pointer = OPA.integer_var + OPB.integer_var;
@ -838,6 +939,14 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum)
ptr = pr->pr_globals + pointer;
QuatCopy (OPA.quat_var, ptr->quat_var);
break;
case OP_STOREB_D:
pointer = OPB.integer_var + OPC.integer_var;
if (pr_boundscheck->int_val) {
PR_BoundsCheck (pr, pointer, ev_quat);
}
ptr = pr->pr_globals + pointer;
*(double *) ptr = OPA_double_var;
break;
case OP_STOREBI_F:
case OP_STOREBI_S:
@ -869,6 +978,14 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum)
ptr = pr->pr_globals + pointer;
QuatCopy (OPA.quat_var, ptr->quat_var);
break;
case OP_STOREBI_D:
pointer = OPB.integer_var + (short) st->c;
if (pr_boundscheck->int_val) {
PR_BoundsCheck (pr, pointer, ev_quat);
}
ptr = pr->pr_globals + pointer;
*(double *) ptr = OPA_double_var;
break;
case OP_PUSH_F:
case OP_PUSH_FLD:
@ -1322,22 +1439,58 @@ op_call:
case OP_MUL_I:
OPC.integer_var = OPA.integer_var * OPB.integer_var;
break;
/*
case OP_DIV_VF:
{
float temp = 1.0f / OPB.float_var;
VectorScale (OPA.vector_var, temp, OPC.vector_var);
}
break;
*/
case OP_DIV_I:
OPC.integer_var = OPA.integer_var / OPB.integer_var;
break;
case OP_MOD_I:
{
// implement true modulo for integers:
// 5 mod 3 = 2
// -5 mod 3 = 1
// 5 mod -3 = -1
// -5 mod -3 = -2
int a = OPA.integer_var;
int b = OPB.integer_var;
int c = a % b;
// % is really remainder and so has the same sign rules
// as division: -5 % 3 = -2, so need to add b (3 here)
// if c's sign is incorrect, but only if c is non-zero
int mask = (a ^ b) >> 31;
mask &= ~(!!c + 0) + 1; // +0 to convert bool to int (gcc)
OPC.integer_var = c + (mask & b);
}
break;
case OP_REM_I:
OPC.integer_var = OPA.integer_var % OPB.integer_var;
break;
case OP_MOD_D:
{
double a = OPA_double_var;
double b = OPB_double_var;
// floating point modulo is so much easier :P
OPC_double_var = a - b * floor (a / b);
}
break;
case OP_REM_D:
{
double a = OPA_double_var;
double b = OPB_double_var;
OPC_double_var = a - b * trunc (a / b);
}
break;
case OP_MOD_F:
OPC.float_var = (int) OPA.float_var % (int) OPB.float_var;
{
float a = OPA.float_var;
float b = OPB.float_var;
OPC.float_var = a - b * floorf (a / b);
}
break;
case OP_REM_F:
{
float a = OPA.float_var;
float b = OPB.float_var;
OPC.float_var = a - b * truncf (a / b);
}
break;
case OP_CONV_IF:
OPC.float_var = OPA.integer_var;
@ -1428,6 +1581,41 @@ op_call:
st->b * 4);
break;
case OP_GE_D:
OPC.float_var = OPA_double_var >= OPB_double_var;
break;
case OP_LE_D:
OPC.float_var = OPA_double_var <= OPB_double_var;
break;
case OP_GT_D:
OPC.float_var = OPA_double_var > OPB_double_var;
break;
case OP_LT_D:
OPC.float_var = OPA_double_var < OPB_double_var;
break;
case OP_NOT_D:
OPC.integer_var = (op_a[0].integer_var
|| (op_a[1].integer_var & ~0x80000000u));
break;
case OP_EQ_D:
OPC.integer_var = OPA_double_var == OPB_double_var;
break;
case OP_NE_D:
OPC.integer_var = OPA_double_var != OPB_double_var;
break;
case OP_CONV_ID:
OPC_double_var = OPA.integer_var;
break;
case OP_CONV_DI:
OPC.integer_var = OPA_double_var;
break;
case OP_CONV_FD:
OPC_double_var = OPA.float_var;
break;
case OP_CONV_DF:
OPC.float_var = OPA_double_var;
break;
// LordHavoc: to be enabled when Progs version 7 (or whatever it will be numbered) is finalized
/*
case OP_BOUNDCHECK:

View file

@ -202,6 +202,8 @@ PR_LoadProgsFile (progs_t *pr, QFile *file, int size)
base -= sizeof (progs); // offsets are from file start
heap = ((byte *) pr->progs + pr->progs_size + pr->pr_edictareasize);
pr->float_promoted = progs.version == PROG_VERSION;
if (pr->edicts) {
*pr->edicts = (edict_t *)((byte *) pr->progs + pr->progs_size);
}

View file

@ -61,6 +61,7 @@ VISIBLE int pr_type_size[ev_type_count] = {
1, // ev_integer
1, // ev_uinteger
0, // ev_short value in opcode
2, // ev_double
};
VISIBLE const char *pr_type_name[ev_type_count] = {
@ -76,6 +77,7 @@ VISIBLE const char *pr_type_name[ev_type_count] = {
"integer",
"uinteger",
"short",
"double",
"invalid",
};
@ -102,6 +104,10 @@ VISIBLE opcode_t pr_opcodes[] = {
"%Va",
},
{"*", "mul.d", OP_MUL_D, false,
ev_double, ev_double, ev_double,
PROG_VERSION,
},
{"*", "mul.f", OP_MUL_F, false,
ev_float, ev_float, ev_float,
PROG_ID_VERSION,
@ -118,6 +124,14 @@ VISIBLE opcode_t pr_opcodes[] = {
ev_vector, ev_float, ev_vector,
PROG_ID_VERSION,
},
{"*", "mul.dv", OP_MUL_DV, false,
ev_double, ev_vector, ev_vector,
PROG_ID_VERSION,
},
{"*", "mul.vd", OP_MUL_VD, false,
ev_vector, ev_double, ev_vector,
PROG_ID_VERSION,
},
{"*", "mul.q", OP_MUL_Q, false,
ev_quat, ev_quat, ev_quat,
PROG_VERSION,
@ -130,6 +144,14 @@ VISIBLE opcode_t pr_opcodes[] = {
ev_quat, ev_float, ev_quat,
PROG_VERSION,
},
{"*", "mul.dq", OP_MUL_DQ, false,
ev_double, ev_quat, ev_quat,
PROG_VERSION,
},
{"*", "mul.qd", OP_MUL_QD, false,
ev_quat, ev_double, ev_quat,
PROG_VERSION,
},
{"*", "mul.qv", OP_MUL_QV, false,
ev_quat, ev_vector, ev_vector,
PROG_VERSION,
@ -145,7 +167,23 @@ VISIBLE opcode_t pr_opcodes[] = {
ev_float, ev_float, ev_float,
PROG_ID_VERSION,
},
{"/", "div.d", OP_DIV_D, false,
ev_double, ev_double, ev_double,
PROG_VERSION,
},
{"%", "rem.d", OP_REM_D, false,
ev_double, ev_double, ev_double,
PROG_VERSION,
},
{"%%", "mod.d", OP_MOD_D, false,
ev_double, ev_double, ev_double,
PROG_VERSION,
},
{"+", "add.d", OP_ADD_D, false,
ev_double, ev_double, ev_double,
PROG_VERSION,
},
{"+", "add.f", OP_ADD_F, false,
ev_float, ev_float, ev_float,
PROG_ID_VERSION,
@ -163,6 +201,10 @@ VISIBLE opcode_t pr_opcodes[] = {
PROG_VERSION,
},
{"-", "sub.d", OP_SUB_D, false,
ev_double, ev_double, ev_double,
PROG_VERSION,
},
{"-", "sub.f", OP_SUB_F, false,
ev_float, ev_float, ev_float,
PROG_ID_VERSION,
@ -176,6 +218,10 @@ VISIBLE opcode_t pr_opcodes[] = {
PROG_VERSION,
},
{"==", "eq.d", OP_EQ_D, false,
ev_double, ev_double, ev_integer,
PROG_VERSION,
},
{"==", "eq.f", OP_EQ_F, false,
ev_float, ev_float, ev_integer,
PROG_ID_VERSION,
@ -201,6 +247,10 @@ VISIBLE opcode_t pr_opcodes[] = {
PROG_ID_VERSION,
},
{"!=", "ne.d", OP_NE_D, false,
ev_double, ev_double, ev_integer,
PROG_VERSION,
},
{"!=", "ne.f", OP_NE_F, false,
ev_float, ev_float, ev_integer,
PROG_ID_VERSION,
@ -226,10 +276,18 @@ VISIBLE opcode_t pr_opcodes[] = {
PROG_ID_VERSION,
},
{"<=", "le.d", OP_LE_D, false,
ev_double, ev_double, ev_integer,
PROG_VERSION,
},
{"<=", "le.f", OP_LE_F, false,
ev_float, ev_float, ev_integer,
PROG_ID_VERSION,
},
{">=", "ge.d", OP_GE_D, false,
ev_double, ev_double, ev_integer,
PROG_VERSION,
},
{">=", "ge.f", OP_GE_F, false,
ev_float, ev_float, ev_integer,
PROG_ID_VERSION,
@ -242,10 +300,18 @@ VISIBLE opcode_t pr_opcodes[] = {
ev_string, ev_string, ev_integer,
PROG_VERSION,
},
{"<", "lt.d", OP_LT_D, false,
ev_double, ev_double, ev_integer,
PROG_VERSION,
},
{"<", "lt.f", OP_LT_F, false,
ev_float, ev_float, ev_integer,
PROG_ID_VERSION,
},
{">", "gt.d", OP_GT_D, false,
ev_double, ev_double, ev_integer,
PROG_VERSION,
},
{">", "gt.f", OP_GT_F, false,
ev_float, ev_float, ev_integer,
PROG_ID_VERSION,
@ -264,6 +330,11 @@ VISIBLE opcode_t pr_opcodes[] = {
PROG_ID_VERSION,
"%Ga.%Gb(%Ec), %gc",//FIXME %E more flexible?
},
{".", "load.d", OP_LOAD_D, false,
ev_entity, ev_field, ev_double,
PROG_VERSION,
"%Ga.%Gb(%Ec), %gc",
},
{".", "load.v", OP_LOAD_V, false,
ev_entity, ev_field, ev_vector,
PROG_ID_VERSION,
@ -305,6 +376,11 @@ VISIBLE opcode_t pr_opcodes[] = {
"%Ga.%Gb(%Ec), %gc",
},
{".", "loadb.d", OP_LOADB_D, false,
ev_pointer, ev_integer, ev_double,
PROG_VERSION,
"*(%Ga + %Gb), %gc",
},
{".", "loadb.f", OP_LOADB_F, false,
ev_pointer, ev_integer, ev_float,
PROG_VERSION,
@ -351,6 +427,11 @@ VISIBLE opcode_t pr_opcodes[] = {
"*(%Ga + %Gb), %gc",
},
{".", "loadbi.d", OP_LOADBI_D, false,
ev_pointer, ev_short, ev_double,
PROG_VERSION,
"*(%Ga + %sb), %gc",
},
{".", "loadbi.f", OP_LOADBI_F, false,
ev_pointer, ev_short, ev_float,
PROG_VERSION,
@ -408,6 +489,11 @@ VISIBLE opcode_t pr_opcodes[] = {
PROG_VERSION,
"%Ga, %gc",
},
{"&", "address.d", OP_ADDRESS_D, false,
ev_double, ev_invalid, ev_pointer,
PROG_VERSION,
"%Ga, %gc",
},
{"&", "address.f", OP_ADDRESS_F, false,
ev_float, ev_invalid, ev_pointer,
PROG_VERSION,
@ -475,7 +561,32 @@ VISIBLE opcode_t pr_opcodes[] = {
PROG_VERSION,
"%Ga, %gc",
},
{"<CONV>", "conv.id", OP_CONV_ID, false,
ev_integer, ev_invalid, ev_double,
PROG_VERSION,
"%Ga, %gc",
},
{"<CONV>", "conv.di", OP_CONV_DI, false,
ev_double, ev_invalid, ev_integer,
PROG_VERSION,
"%Ga, %gc",
},
{"<CONV>", "conv.fd", OP_CONV_FD, false,
ev_float, ev_invalid, ev_double,
PROG_VERSION,
"%Ga, %gc",
},
{"<CONV>", "conv.df", OP_CONV_DF, false,
ev_double, ev_invalid, ev_float,
PROG_VERSION,
"%Ga, %gc",
},
{"=", "store.d", OP_STORE_D, true,
ev_double, ev_double, ev_invalid,
PROG_VERSION,
"%Ga, %gb",
},
{"=", "store.f", OP_STORE_F, true,
ev_float, ev_float, ev_invalid,
PROG_ID_VERSION,
@ -522,6 +633,11 @@ VISIBLE opcode_t pr_opcodes[] = {
"%Ga, %gb",
},
{".=", "storep.d", OP_STOREP_D, true,
ev_double, ev_pointer, ev_invalid,
PROG_ID_VERSION,
"%Ga, *%Gb",
},
{".=", "storep.f", OP_STOREP_F, true,
ev_float, ev_pointer, ev_invalid,
PROG_ID_VERSION,
@ -568,6 +684,11 @@ VISIBLE opcode_t pr_opcodes[] = {
"%Ga, *%Gb",
},
{".=", "storeb.d", OP_STOREB_D, true,
ev_double, ev_pointer, ev_integer,
PROG_VERSION,
"%Ga, *(%Gb + %Gc)",
},
{".=", "storeb.f", OP_STOREB_F, true,
ev_float, ev_pointer, ev_integer,
PROG_VERSION,
@ -614,6 +735,11 @@ VISIBLE opcode_t pr_opcodes[] = {
"%Ga, *(%Gb + %Gc)",
},
{".=", "storebi.d", OP_STOREBI_D, true,
ev_double, ev_pointer, ev_short,
PROG_VERSION,
"%Ga, *(%Gb + %sc)",
},
{".=", "storebi.f", OP_STOREBI_F, true,
ev_float, ev_pointer, ev_short,
PROG_VERSION,
@ -672,6 +798,11 @@ VISIBLE opcode_t pr_opcodes[] = {
"",
},
{"!", "not.d", OP_NOT_D, false,
ev_double, ev_invalid, ev_integer,
PROG_VERSION,
"%Ga, %gc",
},
{"!", "not.f", OP_NOT_F, false,
ev_float, ev_invalid, ev_integer,
PROG_ID_VERSION,
@ -909,7 +1040,11 @@ VISIBLE opcode_t pr_opcodes[] = {
ev_integer, ev_integer, ev_integer,
PROG_VERSION,
},
{"%", "mod.i", OP_MOD_I, false,
{"%", "rem.i", OP_REM_I, false,
ev_integer, ev_integer, ev_integer,
PROG_VERSION,
},
{"%%", "mod.i", OP_MOD_I, false,
ev_integer, ev_integer, ev_integer,
PROG_VERSION,
},
@ -922,7 +1057,12 @@ VISIBLE opcode_t pr_opcodes[] = {
PROG_VERSION,
},
{"%", "mod.f", OP_MOD_F, false,
{"%", "rem.f", OP_REM_F, false,
ev_float, ev_float, ev_float,
PROG_VERSION,
},
{"%%", "mod.f", OP_MOD_F, false,
ev_float, ev_float, ev_float,
PROG_VERSION,
},

View file

@ -122,6 +122,7 @@ PR_ResolveGlobals (progs_t *pr)
pr->pr_params[6] = &pr->pr_globals[OFS_PARM6];
pr->pr_params[7] = &pr->pr_globals[OFS_PARM7];
pr->pr_param_size = OFS_PARM1 - OFS_PARM0;
pr->pr_param_alignment = 0; // log2
} else {
if (!(def = PR_FindGlobal (pr, sym = ".return")))
goto error;
@ -134,6 +135,9 @@ PR_ResolveGlobals (progs_t *pr)
if (!(def = PR_FindGlobal (pr, sym = ".param_size")))
goto error;
pr->pr_param_size = G_INT (pr, def->ofs);
if (!(def = PR_FindGlobal (pr, sym = ".param_alignment")))
goto error;
pr->pr_param_alignment = G_INT (pr, def->ofs);
}
if (pr->pr_saved_params)
free (pr->pr_saved_params);

View file

@ -70,6 +70,7 @@ struct strref_s {
#define FMT_ADDSIGN (1<<3)
#define FMT_ADDBLANK (1<<4)
#define FMT_HEX (1<<5)
#define FMT_LONG (1<<6)
typedef struct fmt_item_s {
byte type;
@ -81,6 +82,7 @@ typedef struct fmt_item_s {
int integer_var;
unsigned uinteger_var;
float float_var;
double double_var;
} data;
struct fmt_item_s *next;
} fmt_item_t;
@ -596,11 +598,19 @@ I_DoPrint (dstring_t *result, fmt_item_t *formatting)
break;
case 'f':
dstring_appendstr (tmp, "f");
PRINT (float);
if (current->flags & FMT_LONG) {
PRINT (double);
} else {
PRINT (float);
}
break;
case 'g':
dstring_appendstr (tmp, "g");
PRINT (float);
if (current->flags & FMT_LONG) {
PRINT (double);
} else {
PRINT (float);
}
break;
default:
break;
@ -639,6 +649,8 @@ free_fmt_item (fmt_item_t *fi)
#undef P_var
#define P_var(p,n,t) (args[n]->t##_var)
#undef P_DOUBLE
#define P_DOUBLE(p,n) (*(double *) (args[n]))
VISIBLE void
PR_Sprintf (progs_t *pr, dstring_t *result, const char *name,
const char *format, int count, pr_type_t **args)
@ -650,7 +662,7 @@ PR_Sprintf (progs_t *pr, dstring_t *result, const char *name,
int fmt_count = 0;
if (!name)
name = "PF_InternalSprintf";
name = "PR_Sprintf";
*fi = new_fmt_item ();
c = l = format;
@ -742,12 +754,19 @@ PR_Sprintf (progs_t *pr, dstring_t *result, const char *name,
fi = &(*fi)->next;
break;
case 'f':
// float
// float or double
case 'g':
// float, no trailing zeroes, trim "." if nothing
// after
// float or double, no trailing zeroes, trim "."
// if nothing after
(*fi)->type = *c;
(*fi)->data.float_var = P_FLOAT (pr, fmt_count);
if (pr->float_promoted) {
(*fi)->flags |= FMT_LONG;
(*fi)->data.double_var
= P_DOUBLE (pr, fmt_count);
} else {
(*fi)->data.float_var
= P_FLOAT (pr, fmt_count);
}
fmt_count++;
(*fi)->next = new_fmt_item ();

View file

@ -42,55 +42,55 @@
#include "rua_internal.h"
static void
bi_sin (progs_t *pr)
bi_sinf (progs_t *pr)
{
R_FLOAT (pr) = sinf (P_FLOAT (pr, 0));
}
static void
bi_cos (progs_t *pr)
bi_cosf (progs_t *pr)
{
R_FLOAT (pr) = cosf (P_FLOAT (pr, 0));
}
static void
bi_tan (progs_t *pr)
bi_tanf (progs_t *pr)
{
R_FLOAT (pr) = tanf (P_FLOAT (pr, 0));
}
static void
bi_asin (progs_t *pr)
bi_asinf (progs_t *pr)
{
R_FLOAT (pr) = asinf (P_FLOAT (pr, 0));
}
static void
bi_acos (progs_t *pr)
bi_acosf (progs_t *pr)
{
R_FLOAT (pr) = acosf (P_FLOAT (pr, 0));
}
static void
bi_atan (progs_t *pr)
bi_atanf (progs_t *pr)
{
R_FLOAT (pr) = atanf (P_FLOAT (pr, 0));
}
static void
bi_atan2 (progs_t *pr)
bi_atan2f (progs_t *pr)
{
R_FLOAT (pr) = atan2f (P_FLOAT (pr, 0), P_FLOAT (pr, 1));
}
static void
bi_log (progs_t *pr)
bi_logf (progs_t *pr)
{
R_FLOAT (pr) = logf (P_FLOAT (pr, 0));
}
static void
bi_log2 (progs_t *pr)
bi_log2f (progs_t *pr)
{
#ifdef HAVE_LOG2F
R_FLOAT (pr) = log2f (P_FLOAT (pr, 0));
@ -100,95 +100,259 @@ bi_log2 (progs_t *pr)
}
static void
bi_log10 (progs_t *pr)
bi_log10f (progs_t *pr)
{
R_FLOAT (pr) = log10f (P_FLOAT (pr, 0));
}
static void
bi_pow (progs_t *pr)
bi_powf (progs_t *pr)
{
R_FLOAT (pr) = powf (P_FLOAT (pr, 0), P_FLOAT (pr, 1));
}
static void
bi_sqrt (progs_t *pr)
bi_sqrtf (progs_t *pr)
{
R_FLOAT (pr) = sqrtf (P_FLOAT (pr, 0));
}
static void
bi_cbrt (progs_t *pr)
bi_cbrtf (progs_t *pr)
{
R_FLOAT (pr) = cbrtf (P_FLOAT (pr, 0));
}
static void
bi_hypot (progs_t *pr)
bi_hypotf (progs_t *pr)
{
R_FLOAT (pr) = hypotf (P_FLOAT (pr, 0), P_FLOAT (pr, 1));
}
static void
bi_sinh (progs_t *pr)
bi_sinhf (progs_t *pr)
{
R_FLOAT (pr) = sinhf (P_FLOAT (pr, 0));
}
static void
bi_cosh (progs_t *pr)
bi_coshf (progs_t *pr)
{
R_FLOAT (pr) = coshf (P_FLOAT (pr, 0));
}
static void
bi_tanh (progs_t *pr)
bi_tanhf (progs_t *pr)
{
R_FLOAT (pr) = tanhf (P_FLOAT (pr, 0));
}
static void
bi_asinh (progs_t *pr)
bi_asinhf (progs_t *pr)
{
double y = P_FLOAT (pr, 0);
R_FLOAT (pr) = logf (y + sqrtf (y * y + 1));
}
static void
bi_acosh (progs_t *pr)
bi_acoshf (progs_t *pr)
{
double y = P_FLOAT (pr, 0);
R_FLOAT (pr) = logf (y + sqrtf (y * y - 1));
}
static void
bi_atanh (progs_t *pr)
bi_atanhf (progs_t *pr)
{
double y = P_FLOAT (pr, 0);
R_FLOAT (pr) = logf ((1 + y) / (1 - y)) / 2;
}
static void
bi_floor (progs_t *pr)
{
R_DOUBLE (pr) = floor (P_DOUBLE (pr, 0));
}
static void
bi_ceil (progs_t *pr)
{
R_DOUBLE (pr) = ceil (P_DOUBLE (pr, 0));
}
static void
bi_fabs (progs_t *pr)
{
R_DOUBLE (pr) = fabs (P_DOUBLE (pr, 0));
}
static void
bi_sin (progs_t *pr)
{
R_DOUBLE (pr) = sin (P_DOUBLE (pr, 0));
}
static void
bi_cos (progs_t *pr)
{
R_DOUBLE (pr) = cos (P_DOUBLE (pr, 0));
}
static void
bi_tan (progs_t *pr)
{
R_DOUBLE (pr) = tan (P_DOUBLE (pr, 0));
}
static void
bi_asin (progs_t *pr)
{
R_DOUBLE (pr) = asin (P_DOUBLE (pr, 0));
}
static void
bi_acos (progs_t *pr)
{
R_DOUBLE (pr) = acos (P_DOUBLE (pr, 0));
}
static void
bi_atan (progs_t *pr)
{
R_DOUBLE (pr) = atan (P_DOUBLE (pr, 0));
}
static void
bi_atan2 (progs_t *pr)
{
R_DOUBLE (pr) = atan2 (P_DOUBLE (pr, 0), P_DOUBLE (pr, 1));
}
static void
bi_log (progs_t *pr)
{
R_DOUBLE (pr) = log (P_DOUBLE (pr, 0));
}
static void
bi_log2 (progs_t *pr)
{
R_DOUBLE (pr) = log (P_DOUBLE (pr, 0)) / M_LOG2E;
}
static void
bi_log10 (progs_t *pr)
{
R_DOUBLE (pr) = log10 (P_DOUBLE (pr, 0));
}
static void
bi_pow (progs_t *pr)
{
R_DOUBLE (pr) = pow (P_DOUBLE (pr, 0), P_DOUBLE (pr, 1));
}
static void
bi_sqrt (progs_t *pr)
{
R_DOUBLE (pr) = sqrt (P_DOUBLE (pr, 0));
}
static void
bi_cbrt (progs_t *pr)
{
R_DOUBLE (pr) = cbrt (P_DOUBLE (pr, 0));
}
static void
bi_hypot (progs_t *pr)
{
R_DOUBLE (pr) = hypot (P_DOUBLE (pr, 0), P_DOUBLE (pr, 1));
}
static void
bi_sinh (progs_t *pr)
{
R_DOUBLE (pr) = sinh (P_DOUBLE (pr, 0));
}
static void
bi_cosh (progs_t *pr)
{
R_DOUBLE (pr) = cosh (P_DOUBLE (pr, 0));
}
static void
bi_tanh (progs_t *pr)
{
R_DOUBLE (pr) = tanh (P_DOUBLE (pr, 0));
}
static void
bi_asinh (progs_t *pr)
{
double y = P_DOUBLE (pr, 0);
R_DOUBLE (pr) = log (y + sqrt (y * y + 1));
}
static void
bi_acosh (progs_t *pr)
{
double y = P_DOUBLE (pr, 0);
R_DOUBLE (pr) = log (y + sqrt (y * y - 1));
}
static void
bi_atanh (progs_t *pr)
{
double y = P_DOUBLE (pr, 0);
R_DOUBLE (pr) = log ((1 + y) / (1 - y)) / 2;
}
static builtin_t builtins[] = {
{"sin", bi_sin, -1},
{"cos", bi_cos, -1},
{"tan", bi_tan, -1},
{"asin", bi_asin, -1},
{"acos", bi_acos, -1},
{"atan", bi_atan, -1},
{"atan2", bi_atan2, -1},
{"log", bi_log, -1},
{"log2", bi_log2, -1},
{"log10", bi_log10, -1},
{"pow", bi_pow, -1},
{"sqrt", bi_sqrt, -1},
{"cbrt", bi_cbrt, -1},
{"hypot", bi_hypot, -1},
{"sinh", bi_sinh, -1},
{"cosh", bi_cosh, -1},
{"tanh", bi_tanh, -1},
{"asinh", bi_asinh, -1},
{"acosh", bi_acosh, -1},
{"atanh", bi_atanh, -1},
{"sin|f", bi_sinf, -1},
{"cos|f", bi_cosf, -1},
{"tan|f", bi_tanf, -1},
{"asin|f", bi_asinf, -1},
{"acos|f", bi_acosf, -1},
{"atan|f", bi_atanf, -1},
{"atan2|ff",bi_atan2f, -1},
{"log|f", bi_logf, -1},
{"log2|f", bi_log2f, -1},
{"log10|f", bi_log10f, -1},
{"pow|ff", bi_powf, -1},
{"sqrt|f", bi_sqrtf, -1},
{"cbrt|f", bi_cbrtf, -1},
{"hypot|ff",bi_hypotf, -1},
{"sinh|f", bi_sinhf, -1},
{"cosh|f", bi_coshf, -1},
{"tanh|f", bi_tanhf, -1},
{"asinh|f", bi_asinhf, -1},
{"acosh|f", bi_acoshf, -1},
{"atanh|f", bi_atanhf, -1},
{"floor|d", bi_floor, -1}, // float version in pr_cmds
{"ceil|d", bi_ceil, -1}, // float version in pr_cmds
{"fabs|d", bi_fabs, -1}, // float version in pr_cmds
{"sin|d", bi_sin, -1},
{"cos|d", bi_cos, -1},
{"tan|d", bi_tan, -1},
{"asin|d", bi_asin, -1},
{"acos|d", bi_acos, -1},
{"atan|d", bi_atan, -1},
{"atan2|dd",bi_atan2, -1},
{"log|d", bi_log, -1},
{"log2|d", bi_log2, -1},
{"log10|d", bi_log10, -1},
{"pow|dd", bi_pow, -1},
{"sqrt|d", bi_sqrt, -1},
{"cbrt|d", bi_cbrt, -1},
{"hypot|dd",bi_hypot, -1},
{"sinh|d", bi_sinh, -1},
{"cosh|d", bi_cosh, -1},
{"tanh|d", bi_tanh, -1},
{"asinh|d", bi_asinh, -1},
{"acosh|d", bi_acosh, -1},
{"atanh|d", bi_atanh, -1},
{0}
};

View file

@ -439,19 +439,23 @@ X11_SetVidMode (int width, int height)
&vidmodes);
XF86VidModeGetModeLine (x_disp, x_screen, &dotclock, &orig_data);
if (developer->int_val & SYS_VID) {
Sys_Printf ("VID: %d modes\n", nummodes);
for (i = 0; i < nummodes; i++) {
Sys_Printf ("VID: %xx%d\n", vidmodes[i]->hdisplay,
vidmodes[i]->vdisplay);
}
}
Sys_MaskPrintf (SYS_VID, "VID: %d modes\n", nummodes);
original_mode = -1;
for (i = 0; i < nummodes; i++) {
if ((vidmodes[i]->hdisplay == orig_data.hdisplay) &&
(vidmodes[i]->vdisplay == orig_data.vdisplay)) {
if (original_mode == -1
&& (vidmodes[i]->hdisplay == orig_data.hdisplay) &&
(vidmodes[i]->vdisplay == orig_data.vdisplay)) {
original_mode = i;
break;
}
if (developer->int_val & SYS_VID) {
Sys_Printf ("VID:%c%dx%d\n",
original_mode == i ? '*' : ' ',
vidmodes[i]->hdisplay, vidmodes[i]->vdisplay);
Sys_Printf ("\t%d %d %d %d:%d %d %d:%d\n",
vidmodes[i]->hsyncstart, vidmodes[i]->hsyncend,
vidmodes[i]->htotal, vidmodes[i]->hskew,
vidmodes[i]->vsyncstart, vidmodes[i]->vsyncend,
vidmodes[i]->vtotal, vidmodes[i]->flags);
}
}
@ -468,8 +472,10 @@ X11_SetVidMode (int width, int height)
Sys_MaskPrintf (SYS_VID, "VID: Chose video mode: %dx%d\n",
viddef.width, viddef.height);
if (0) {
XF86VidModeSwitchToMode (x_disp, x_screen,
vidmodes[best_mode]);
}
vidmode_active = true;
X11_SetScreenSaver ();
} else {
@ -594,7 +600,7 @@ X11_RestoreVidMode (void)
#ifdef HAVE_VIDMODE
if (vidmode_active) {
X11_RestoreScreenSaver ();
XF86VidModeSwitchToMode (x_disp, x_screen, vidmodes[original_mode]);
//XF86VidModeSwitchToMode (x_disp, x_screen, vidmodes[original_mode]);
XFree (vidmodes);
vidmode_active = false;
}

View file

@ -210,6 +210,11 @@ extern progs_t sv_pr_state;
#define SVentity(e,f) SVFIELD (e, f, entity)
#define SVvector(e,f) SVFIELD (e, f, vector)
#define SVinteger(e,f) SVFIELD (e, f, integer)
#if TYPECHECK_PROGS
#define SVdouble(e,f) E_DOUBLE (e, PR_AccessField (&sv_pr_state, #f, ev_##t, __FILE__, __LINE__))
#else
#define SVdouble(e,f) E_DOUBLE (e, sv_fields.f)
#endif
typedef struct edict_leaf_s {
struct edict_leaf_s *next;

View file

@ -361,6 +361,9 @@ set_address (sv_def_t *def, void *address)
case ev_quat:
*(float **)def->field = (float *) address;
break;
case ev_double:
*(double **)def->field = (double *) address;
break;
case ev_string:
case ev_entity:
case ev_field:

View file

@ -195,6 +195,11 @@ extern progs_t sv_pr_state;
#define SVentity(e,f) SVFIELD (e, f, entity)
#define SVvector(e,f) SVFIELD (e, f, vector)
#define SVinteger(e,f) SVFIELD (e, f, integer)
#if TYPECHECK_PROGS
#define SVdouble(e,f) E_DOUBLE (e, PR_AccessField (&sv_pr_state, #f, ev_##t, __FILE__, __LINE__))
#else
#define SVdouble(e,f) E_DOUBLE (e, sv_fields.f)
#endif
typedef struct edict_leaf_s {
struct edict_leaf_s *next;

View file

@ -371,6 +371,9 @@ set_address (sv_def_t *def, void *address)
case ev_quat:
*(float **)def->field = (float *) address;
break;
case ev_double:
*(double **)def->field = (double *) address;
break;
case ev_string:
case ev_entity:
case ev_field:

View file

@ -166,7 +166,7 @@ int HUDHandleClass;
if (looping)
currentFrame = 0;
else {
nextFrameTime = 0.0;
nextFrameTime = 0.0f;
currentFrame = 0;
return;
}
@ -201,7 +201,7 @@ int HUDHandleClass;
- (void) stop
{
nextFrameTime = 0.0;
nextFrameTime = 0.0f;
currentFrame = 0;
}

View file

@ -14,7 +14,7 @@
- (id) init
{
[super init];
damage = (deathmatch > 3) ? 75.0 : 20.0;
damage = (deathmatch > 3) ? 75.0f : 20.0f;
return self;
}
@ -32,7 +32,7 @@
source = s.origin + '0 0 16';
traceline (source, source + v_forward * 64, NO, s);
if (trace_fraction == 1.0)
if (trace_fraction == 1.0f)
return;
org = trace_endpos - v_forward * 4;

View file

@ -60,17 +60,20 @@
/**
Returns \a f, rounded down to the next lower integer
*/
@extern float floor (float f);
@extern @overload float floor (float f);
@extern @overload double floor (double f);
/**
Returns \a f, rounded up to the next highest integer
*/
@extern float ceil (float f);
@extern @overload float ceil (float f);
@extern @overload double ceil (double f);
/**
Returns the absolute value of \a f
*/
@extern float fabs (float f);
@extern @overload float fabs (float f);
@extern @overload double fabs (double f);
//\}
///\name Exponentials and Logarithms
@ -78,32 +81,38 @@
/**
Returns the natural log of \a x.
*/
@extern float log (float x);
@extern @overload float log (float x);
@extern @overload double log (double x);
/**
Returns the base-2 log of \a x.
*/
@extern float log2 (float x);
@extern @overload float log2 (float x);
@extern @overload double log2 (double x);
/**
Returns the base-10 log of \a x.
*/
@extern float log10 (float x);
@extern @overload float log10 (float x);
@extern @overload double log10 (double x);
/**
Returns \a x to the \a y power
*/
@extern float pow (float x, float y);
@extern @overload float pow (float x, float y);
@extern @overload double pow (double x, double y);
/**
Returns the square root of \a x
*/
@extern float sqrt (float x);
@extern @overload float sqrt (float x);
@extern @overload double sqrt (double x);
/**
Returns the cube root of \a x
*/
@extern float cbrt (float x);
@extern @overload float cbrt (float x);
@extern @overload double cbrt (double x);
//\}
///\name Trigonometric functions
@ -112,40 +121,52 @@
/**
Returns the sine of \a x.
*/
@extern float sin (float x);
@extern @overload float sin (float x);
@extern @overload double sin (double x);
/**
Returns the cosine of \a x.
*/
@extern float cos (float x);
@extern @overload float cos (float x);
@extern @overload double cos (double x);
/**
Returns the tangent of \a x.
*/
@extern float tan (float x);
@extern @overload float tan (float x);
@extern @overload double tan (double x);
/**
Returns the arcsine of \a x.
*/
@extern float asin (float x);
@extern @overload float asin (float x);
@extern @overload double asin (double x);
/**
Returns the arccosine of \a x.
*/
@extern float acos (float x);
@extern @overload float acos (float x);
@extern @overload double acos (double x);
/**
Returns the arctangent of \a x.
*/
@extern float atan (float x);
@extern float atan2 (float y, float x);
@extern @overload float atan (float x);
@extern @overload double atan (double x);
/**
Returns the arctangent of \a y / \a x preserving the quadrant.
*/
@extern @overload float atan2 (float y, float x);
@extern @overload double atan2 (double y, double x);
/**
Returns the length of the hypotenuse of a right triangle with sides \a x
and \a y. That is, this function returns
<code>sqrt (\a x*\a x + \a y*\a y)</code>.
*/
@extern float hypot (float x, float y);
@extern @overload float hypot (float x, float y);
@extern @overload double hypot (double x, double y);
//\}
///\name Hyperbolic functions
@ -153,32 +174,38 @@
/**
Returns the hyperbolic sine of \a x
*/
@extern float sinh (float x);
@extern @overload float sinh (float x);
@extern @overload double sinh (double x);
/**
Returns the hyperbolic cosine of \a x
*/
@extern float cosh (float x);
@extern @overload float cosh (float x);
@extern @overload double cosh (double x);
/**
Returns the hyperbolic tangent of \a x
*/
@extern float tanh (float x);
@extern @overload float tanh (float x);
@extern @overload double tanh (double x);
/**
Returns the area hyperbolic sine of \a x
*/
@extern float asinh (float x);
@extern @overload float asinh (float x);
@extern @overload double asinh (double x);
/**
Returns the area hyperbolic cosine of \a x
*/
@extern float acosh (float x);
@extern @overload float acosh (float x);
@extern @overload double acosh (double x);
/**
Returns the area hyperbolic tangent of \a x
*/
@extern float atanh (float x);
@extern @overload float atanh (float x);
@extern @overload double atanh (double x);
//\}
///\name Vector Functions

View file

@ -34,3 +34,27 @@ float (float x) atanh = #0;
float (float x) sqrt = #0;
float (float x) cbrt = #0;
float (float x, float y) hypot = #0;
double (double v) floor = #0;
double (double v) ceil = #0;
double (double f) fabs = #0;
double (double x) sin = #0;
double (double x) cos = #0;
double (double x) tan = #0;
double (double x) asin = #0;
double (double x) acos = #0;
double (double x) atan = #0;
double (double y, double x) atan2 = #0;
double (double x) log = #0;
double (double x) log2 = #0;
double (double x) log10 = #0;
double (double x, double y) pow = #0;
double (double x) sinh = #0;
double (double x) cosh = #0;
double (double x) tanh = #0;
double (double x) asinh = #0;
double (double x) acosh = #0;
double (double x) atanh = #0;
double (double x) sqrt = #0;
double (double x) cbrt = #0;
double (double x, double y) hypot = #0;

View file

@ -24,14 +24,14 @@
bl_info = {
"name": "Quake MDL format",
"author": "Bill Currie",
"blender": (2, 6, 3),
"blender": (2, 80, 0),
"api": 35622,
"location": "File > Import-Export",
"description": "Import-Export Quake MDL (version 6) files. (.mdl)",
"warning": "not even alpha",
"warning": "still work in progress",
"wiki_url": "",
"tracker_url": "",
# "support": 'OFFICIAL',
# "support": 'OFFICIAL',
"category": "Import-Export"}
# To support reload properly, try to access a package var, if it's there,
@ -66,28 +66,33 @@ EFFECTS=(
)
class QFMDLSettings(bpy.types.PropertyGroup):
eyeposition = FloatVectorProperty(
eyeposition : FloatVectorProperty(
name="Eye Position",
description="View possion relative to object origin")
synctype = EnumProperty(
synctype : EnumProperty(
items=SYNCTYPE,
name="Sync Type",
description="Add random time offset for automatic animations")
rotate = BoolProperty(
rotate : BoolProperty(
name="Rotate",
description="Rotate automatically (for pickup items)")
effects = EnumProperty(
effects : EnumProperty(
items=EFFECTS,
name="Effects",
description="Particle trail effects")
#doesn't work :(
#script = PointerProperty(
# type=bpy.types.Object,
# name="Script",
# description="Script for animating frames and skins")
script = StringProperty(
script : PointerProperty(
type=bpy.types.Text,
name="Script",
description="Script for animating frames and skins")
xform : BoolProperty(
name="Auto transform",
description="Auto-apply location/rotation/scale when exporting",
default=True)
md16 : BoolProperty(
name="16-bit",
description="16 bit vertex coordinates: QuakeForge only")
xform = BoolProperty(
name="Auto transform",
description="Auto-apply location/rotation/scale when exporting",
@ -102,7 +107,7 @@ class ImportMDL6(bpy.types.Operator, ImportHelper):
bl_label = "Import MDL"
filename_ext = ".mdl"
filter_glob = StringProperty(default="*.mdl", options={'HIDDEN'})
filter_glob : StringProperty(default="*.mdl", options={'HIDDEN'})
def execute(self, context):
from . import import_mdl
@ -116,7 +121,7 @@ class ExportMDL6(bpy.types.Operator, ExportHelper):
bl_label = "Export MDL"
filename_ext = ".mdl"
filter_glob = StringProperty(default="*.mdl", options={'HIDDEN'})
filter_glob : StringProperty(default="*.mdl", options={'HIDDEN'})
@classmethod
def poll(cls, context):
@ -129,10 +134,11 @@ class ExportMDL6(bpy.types.Operator, ExportHelper):
return export_mdl.export_mdl(self, context, **keywords)
class OBJECT_PT_MDLPanel(bpy.types.Panel):
bl_label = "MDL Properties"
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = 'object'
bl_label = 'QF MDL'
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
@ -157,21 +163,28 @@ def menu_func_import(self, context):
def menu_func_export(self, context):
self.layout.operator(ExportMDL6.bl_idname, text="Quake MDL (.mdl)")
classes = (
QFMDLSettings,
OBJECT_PT_MDLPanel,
ImportMDL6,
ExportMDL6
)
def register():
bpy.utils.register_module(__name__)
for cls in classes:
bpy.utils.register_class(cls)
bpy.types.Object.qfmdl = PointerProperty(type=QFMDLSettings)
bpy.types.INFO_MT_file_import.append(menu_func_import)
bpy.types.INFO_MT_file_export.append(menu_func_export)
bpy.types.TOPBAR_MT_file_import.append(menu_func_import)
bpy.types.TOPBAR_MT_file_export.append(menu_func_export)
def unregister():
bpy.utils.unregister_module(__name__)
for cls in classes:
bpy.utils.unregister_class(cls)
bpy.types.INFO_MT_file_import.remove(menu_func_import)
bpy.types.INFO_MT_file_export.remove(menu_func_export)
bpy.types.TOPBAR_MT_file_import.remove(menu_func_import)
bpy.types.TOPBAR_MT_file_export.remove(menu_func_export)
if __name__ == "__main__":
register()

View file

@ -27,6 +27,7 @@ from .qfplist import pldata, PListError
from .quakepal import palette
from .quakenorm import map_normal
from .mdl import MDL
from .__init__ import SYNCTYPE, EFFECTS
def check_faces(mesh):
#Check that all faces are tris because mdl does not support anything else.
@ -35,17 +36,17 @@ def check_faces(mesh):
faces_ok = True
save_select = []
for f in mesh.polygons:
save_select.append(f.select)
f.select = False
save_select.append(f.select_get())
f.select_set('DESELECT')
if len(f.vertices) > 3:
f.select = True
f.select_set('SELECT')
faces_ok = False
if not faces_ok:
mesh.update()
return False
#reset selection to what it was before the check.
for f, s in map(lambda x, y: (x, y), mesh.polygons, save_select):
f.select = s
f.select_set('SELECT' if s else 'DESELECT')
mesh.update()
return True
@ -85,7 +86,7 @@ def null_skin(size):
return skin
def active_uv(mesh):
for uvt in mesh.uv_textures:
for uvt in mesh.uv_layers:
if uvt.active:
return uvt
return None
@ -94,6 +95,40 @@ def make_skin(operator, mdl, mesh):
uvt = active_uv(mesh)
mdl.skinwidth, mdl.skinheight = (4, 4)
skin = null_skin((mdl.skinwidth, mdl.skinheight))
materials = mesh.materials
if len(materials) > 0:
for mat in materials:
allTextureNodes = list(filter(lambda node: node.type == "TEX_IMAGE", mat.node_tree.nodes))
if len(allTextureNodes) > 1: #=== skingroup
skingroup = MDL.Skin()
skingroup.type = 1
skingroup.skins = []
skingroup.times = []
sortedNodes = list(allTextureNodes)
sortedNodes.sort(key=lambda x: x.location[1], reverse=True)
for node in sortedNodes:
if node.type == "TEX_IMAGE":
image = node.image
mdl.skinwidth, mdl.skinheight = image.size
skin = convert_image(image)
skingroup.skins.append(skin)
skingroup.times.append(0.1) # hardcoded at the moment
mdl.skins.append(skingroup)
elif len(allTextureNodes) == 1: #=== single skin
for node in allTextureNodes:
if node.type == "TEX_IMAGE":
image = node.image
mdl.skinwidth, mdl.skinheight = image.size
skin = convert_image(image)
mdl.skins.append(skin)
else:
mdl.skins.append(skin) # add empty skin - no texture nodes
else:
mdl.skins.append(skin) # add empty skin - no materials
'''
if (uvt and uvt.data and uvt.data[0].image):
image = uvt.data[0].image
if (uvt.data[0].image.size[0] and uvt.data[0].image.size[1]):
@ -102,7 +137,9 @@ def make_skin(operator, mdl, mesh):
else:
operator.report({'WARNING'},
"Texture '%s' invalid (missing?)." % image.name)
mdl.skins.append(skin)
'''
def build_tris(mesh):
# mdl files have a 1:1 relationship between stverts and 3d verts.
@ -182,7 +219,7 @@ def calc_average_area(mdl):
a = Vector(verts[0].r) - Vector(verts[1].r)
b = Vector(verts[2].r) - Vector(verts[1].r)
c = a.cross(b)
totalarea += (c * c) ** 0.5 / 2.0
totalarea += (c @ c) ** 0.5 / 2.0
return totalarea / len(mdl.tris)
def get_properties(operator, mdl, obj):
@ -192,16 +229,11 @@ def get_properties(operator, mdl, obj):
| MDL.EFFECTS[obj.qfmdl.effects])
if obj.qfmdl.md16:
mdl.ident = "MD16"
script = obj.qfmdl.script
mdl.script = None
if script:
try:
script = bpy.data.texts[script].as_string()
except KeyError:
operator.report({'ERROR'},
"Script '%s' not found." % script)
return False
pl = pldata(script)
pl = pldata(script.as_string())
try:
mdl.script = pl.parse()
except PListError as err:
@ -268,17 +300,29 @@ def process_frame(mdl, scene, frame, vertmap, ingroup = False,
return fr
mdl.frames += fr.frames[:-1]
return fr.frames[-1]
scene.frame_set(int(frameno), frameno - int(frameno))
mesh = mdl.obj.to_mesh(scene, True, 'PREVIEW') #wysiwyg?
scene.frame_set(int(frameno), subframe = frameno - int(frameno))
depsgraph = bpy.context.evaluated_depsgraph_get()
mesh = mdl.obj.evaluated_get(depsgraph).to_mesh() #wysiwyg?
if mdl.obj.qfmdl.xform:
mesh.transform(mdl.obj.matrix_world)
fr = make_frame(mesh, vertmap)
fr.name = name
return fr
def get_frame_name(mesh, idx):
name = "frame" + str(idx)
if mesh.shape_keys:
shape_keys_amount = len(mesh.shape_keys.key_blocks)
if shape_keys_amount > idx:
name = mesh.shape_keys.key_blocks[idx].name
return name
def export_mdl(operator, context, filepath):
obj = context.active_object
mesh = obj.to_mesh(context.scene, True, 'PREVIEW') #wysiwyg?
obj.update_from_editmode()
depsgraph = context.evaluated_depsgraph_get()
ob_eval = obj.evaluated_get(depsgraph)
mesh = ob_eval.to_mesh()
#if not check_faces(mesh):
# operator.report({'ERROR'},
# "Mesh has faces with more than 3 vertices.")
@ -287,6 +331,7 @@ def export_mdl(operator, context, filepath):
mdl.obj = obj
if not get_properties(operator, mdl, obj):
return {'CANCELLED'}
mdl.tris, mdl.stverts, vertmap = build_tris(mesh)
if mdl.script:
if 'skins' in mdl.script:
@ -299,13 +344,19 @@ def export_mdl(operator, context, filepath):
if not mdl.skins:
make_skin(operator, mdl, mesh)
if not mdl.frames:
curframe = context.scene.frame_current
for fno in range(1, curframe + 1):
scene = context.scene
for fno in range(scene.frame_start, scene.frame_end + 1):
context.scene.frame_set(fno)
mesh = obj.to_mesh(context.scene, True, 'PREVIEW') #wysiwyg?
if mdl.obj.qfmdl.xform:
obj.update_from_editmode()
depsgraph = context.evaluated_depsgraph_get()
ob_eval = obj.evaluated_get(depsgraph)
mesh = ob_eval.to_mesh()
if obj.qfmdl.xform:
mesh.transform(mdl.obj.matrix_world)
mdl.frames.append(make_frame(mesh, vertmap))
frame = make_frame(mesh, vertmap)
frame.name = get_frame_name(obj.data, fno)
mdl.frames.append(frame)
convert_stverts(mdl, mdl.stverts)
mdl.size = calc_average_area(mdl)
scale_verts(mdl)

View file

@ -39,7 +39,7 @@ def make_verts(mdl, framenum, subframenum=0):
( 0, 0,s.z,o.z),
( 0, 0, 0, 1)))
for v in frame.verts:
verts.append(m * Vector(v.r))
verts.append(m @ Vector(v.r))
return verts
def make_faces(mdl):
@ -87,7 +87,7 @@ def load_skins(mdl):
p[l + 2] = c[2] / 255.0
p[l + 3] = 1.0
img.pixels[:] = p[:]
img.pack(True)
img.pack()
img.use_fake_user = True
mdl.images=[]
@ -98,30 +98,80 @@ def load_skins(mdl):
else:
load_skin(skin, "%s_%d" % (mdl.name, i))
def setup_main_material(mdl):
mat = bpy.data.materials.new(mdl.name)
mat.blend_method = 'OPAQUE'
mat.diffuse_color = (1, 1, 1, 1)
mat.metallic = 1
mat.roughness = 1
mat.specular_intensity = 0
mat.use_nodes = True
return mat
def setup_skins(mdl, uvs):
load_skins(mdl)
img = mdl.images[0] # use the first skin for now
uvlay = mdl.mesh.uv_textures.new(mdl.name)
uvloop = mdl.mesh.uv_layers[0]
for i, texpoly in enumerate(uvlay.data):
# img = mdl.images[0] # use the first skin for now
# uvlay = mdl.mesh.uv_textures.new(mdl.name)
# uvloop = mdl.mesh.uv_layers[0]
# for i, texpoly in enumerate(uvlay.data):
uvloop = mdl.mesh.uv_layers.new(name = mdl.name)
for i in range(len(mdl.mesh.polygons)):
poly = mdl.mesh.polygons[i]
mdl_uv = uvs[i]
texpoly.image = img
# texpoly.image = img # TODO: commented out by jazz
for j,k in enumerate(poly.loop_indices):
uvloop.data[k].uv = mdl_uv[j]
mat = bpy.data.materials.new(mdl.name)
mat.diffuse_color = (1,1,1)
mat.use_raytrace = False
tex = bpy.data.textures.new(mdl.name, 'IMAGE')
tex.extension = 'CLIP'
tex.use_preview_alpha = True
tex.image = img
mat.texture_slots.add()
ts = mat.texture_slots[0]
ts.texture = tex
ts.use_map_alpha = True
ts.texture_coords = 'UV'
mdl.mesh.materials.append(mat)
#Load all skins
img_counter = 0
for i, skin in enumerate(mdl.skins):
if skin.type:
mat = setup_main_material(mdl)
emissionNode = mat.node_tree.nodes.new("ShaderNodeEmission")
shaderOut = mat.node_tree.nodes["Material Output"]
mat.node_tree.nodes.remove(mat.node_tree.nodes["Principled BSDF"])
emissionNode.location = (0, 0)
shaderOut.location = (200, 0)
yPos = 0
for j, subskin in enumerate(skin.skins):
tex_node = mat.node_tree.nodes.new("ShaderNodeTexImage")
tex_node.image = mdl.images[img_counter]
img_counter += 1
tex_node.interpolation = "Closest"
tex_node.location = (-300, yPos)
yPos -= 280
if j == 0:
# connect only first texture (we'll need something smarter in the future)
mat.node_tree.links.new(tex_node.outputs[0], emissionNode.inputs[0])
mat.node_tree.links.new(emissionNode.outputs[0], shaderOut.inputs[0])
mdl.mesh.materials.append(mat)
else:
mat = setup_main_material(mdl)
# TODO: turn transform to True and position it properly in editor
emissionNode = mat.node_tree.nodes.new("ShaderNodeEmission")
shaderOut = mat.node_tree.nodes["Material Output"]
mat.node_tree.nodes.remove(mat.node_tree.nodes["Principled BSDF"])
tex_node = mat.node_tree.nodes.new("ShaderNodeTexImage")
tex_node.image = mdl.images[img_counter]
img_counter += 1
tex_node.interpolation = "Closest"
emissionNode.location = (0, 0)
shaderOut.location = (200, 0)
tex_node.location = (-300, 0)
mat.node_tree.links.new(tex_node.outputs[0], emissionNode.inputs[0])
mat.node_tree.links.new(emissionNode.outputs[0], shaderOut.inputs[0])
mdl.mesh.materials.append(mat)
def make_shape_key(mdl, framenum, subframenum=0):
frame = mdl.frames[framenum]
@ -133,7 +183,7 @@ def make_shape_key(mdl, framenum, subframenum=0):
name = frame.name
else:
frame.name = name
frame.key = mdl.obj.shape_key_add(name)
frame.key = mdl.obj.shape_key_add(name=name)
frame.key.value = 0.0
mdl.keys.append(frame.key)
s = Vector(mdl.scale)
@ -143,20 +193,25 @@ def make_shape_key(mdl, framenum, subframenum=0):
( 0, 0,s.z,o.z),
( 0, 0, 0, 1)))
for i, v in enumerate(frame.verts):
frame.key.data[i].co = m * Vector(v.r)
frame.key.data[i].co = m @ Vector(v.r)
def build_shape_keys(mdl):
mdl.keys = []
mdl.obj.shape_key_add("Basis")
mdl.obj.shape_key_add(name="Basis",from_mix=False)
mdl.mesh.shape_keys.name = mdl.name
mdl.obj.active_shape_key_index = 0
bpy.context.scene.frame_end = 0
for i, frame in enumerate(mdl.frames):
frame = mdl.frames[i]
if frame.type:
for j in range(len(frame.frames)):
make_shape_key(mdl, i, j)
bpy.context.scene.frame_end += 1
else:
make_shape_key(mdl, i)
bpy.context.scene.frame_end += 1
bpy.context.scene.frame_start = 1
def set_keys(act, data):
for d in data:
@ -241,8 +296,8 @@ def write_text(mdl):
/* This script represents the animation data within the model file. It
is generated automatically on import, and is optional when exporting.
If no script is used when exporting, frames will be exported one per
blender frame from frame 1 to the current frame (inclusive), and only
one skin will be exported.
blender frame from the scene start frame to the scene end frame
(inclusive), and one skin per teximage node will be exported.
The fundamental format of the script is documented at
http://quakeforge.net/doxygen/property-list.html
@ -335,14 +390,14 @@ def set_properties(mdl):
mdl.obj.qfmdl.synctype = 'ST_SYNC'
mdl.obj.qfmdl.rotate = (mdl.flags & MDL.EF_ROTATE) and True or False
mdl.obj.qfmdl.effects = parse_flags(mdl.flags)
mdl.obj.qfmdl.script = mdl.text.name #FIXME really want the text object
mdl.obj.qfmdl.script = mdl.text
mdl.obj.qfmdl.md16 = (mdl.ident == "MD16")
def import_mdl(operator, context, filepath):
bpy.context.user_preferences.edit.use_global_undo = False
def import_mdl(operator, context, filepath, **opts):
bpy.context.preferences.edit.use_global_undo = False
for obj in bpy.context.scene.objects:
obj.select = False
for obj in bpy.context.scene.collection.objects:
obj.select_set(False)
mdl = MDL()
if not mdl.read(filepath):
@ -354,10 +409,14 @@ def import_mdl(operator, context, filepath):
mdl.mesh = bpy.data.meshes.new(mdl.name)
mdl.mesh.from_pydata(verts, [], faces)
mdl.obj = bpy.data.objects.new(mdl.name, mdl.mesh)
bpy.context.scene.objects.link(mdl.obj)
bpy.context.scene.objects.active = mdl.obj
mdl.obj.select = True
bpy.context.scene.collection.objects.link(mdl.obj)
mdl.obj.select_set(True)
bpy.context.view_layer.objects.active = mdl.obj
setup_skins(mdl, uvs)
bpy.context.scene.frame_start = 1
bpy.context.scene.frame_end = 1
if len(mdl.frames) > 1 or mdl.frames[0].type:
build_shape_keys(mdl)
merge_frames(mdl)
@ -367,5 +426,5 @@ def import_mdl(operator, context, filepath):
mdl.mesh.update()
bpy.context.user_preferences.edit.use_global_undo = True
bpy.context.preferences.edit.use_global_undo = True
return {'FINISHED'}

View file

@ -109,6 +109,27 @@ defspace_t *defspace_new (ds_type_t type);
*/
int defspace_alloc_loc (defspace_t *space, int size);
/** Allocate space from the defspace's backing memory.
If the memory is fragmented, then the first available location at least
as large as \a size plus padding for alignment is returned. This means
that freeing a location then allocating the same amount of space may
return a different location.
If memory cannot be allocated (there is no free space in the currently
available memory and defspace_t::grow is null), then an internal error
will be generated.
\param space The space from which to allocate data.
\param size The amount of pr_type_t words to allocated. int and float
need 1 word, vector 3 words, and quaternion 4.
\param alignment The alignment of the allocated space.
\return The offset of the first word of the freshly allocated
space. May be 0 if the allocated space is at the beginning
of the defspace.
*/
int defspace_alloc_aligned_loc (defspace_t *space, int size, int alignment);
/** Free a block of contiguous words, returning them to the defspace.
The block to be freed is specified by \a ofs indicating the offset of the

View file

@ -174,6 +174,7 @@ typedef struct ex_value_s {
etype_t lltype;
union {
const char *string_val; ///< string constant
double double_val; ///< double constant
float float_val; ///< float constant
float vector_val[3]; ///< vector constant
int entity_val; ///< entity constant
@ -397,6 +398,15 @@ expr_t *new_name_expr (const char *name);
expr_t *new_string_expr (const char *string_val);
const char *expr_string (expr_t *e) __attribute__((pure));
/** Create a new double constant expression node.
\param double_val The double constant being represented.
\return The new double constant expression node
(expr_t::e::double_val).
*/
expr_t *new_double_expr (double double_val);
double expr_double (expr_t *e) __attribute__((pure));
/** Create a new float constant expression node.
\param float_val The float constant being represented.

View file

@ -305,6 +305,19 @@ enum {
*/
#define QFO_var(q, s, t, o) ((q)->spaces[s].d.data[o].t##_var)
/** Access a double variable in the object file. Can be assigned to.
\par QC type:
\c double
\param q pointer to ::qfo_t struct
\param s space index
\param o offset into object file data space
\return double lvalue
\hideinitializer
*/
#define QFO_DOUBLE(q, s, o) (*(double *) ((q)->spaces[s].d.data + o))
/** Access a float variable in the object file. Can be assigned to.
\par QC type:
@ -484,6 +497,8 @@ qfo_t *qfo_new (void);
*/
void qfo_delete (qfo_t *qfo);
__attribute__((const)) int qfo_log2 (unsigned x);
///@}
#endif//__obj_file_h

View file

@ -70,6 +70,11 @@ typedef struct {
qboolean silent; // don't even bother (overrides promote)
} notice_options_t;
typedef struct {
qboolean promote; // Promote bugs to internal errors
qboolean silent; // don't even bother (overrides promote)
} bug_options_t;
typedef struct {
qboolean initial;
qboolean thread;
@ -88,6 +93,7 @@ typedef struct {
code_options_t code; // Code generation options
warn_options_t warnings; // Warning options
notice_options_t notices; // Notice options
bug_options_t bug; // Bug options
blockdot_options_t block_dot; // Statement block flow diagrams
int verbosity; // 0=silent, goes up to 2 currently

View file

@ -35,7 +35,8 @@
*/
///@{
void pragma (const char *id);
void pragma_process (void);
void pragma_add_arg (const char *id);
///@}

View file

@ -92,6 +92,7 @@ extern pr_info_t pr;
#define GETSTR(s) (pr.strings->strings + (s))
#define D_var(t, d) ((d)->space->data[(d)->offset].t##_var)
#define D_DOUBLE(d) (*(double *) ((d)->space->data + (d)->offset))
#define D_FLOAT(d) D_var (float, d)
#define D_INT(d) D_var (integer, d)
#define D_VECTOR(d) D_var (vector, d)

View file

@ -116,6 +116,7 @@ struct dstring_s;
const char *optype_str (op_type_e type) __attribute__((const));
operand_t *def_operand (struct def_s *def, struct type_s *type);
operand_t *return_operand (struct type_s *type);
operand_t *value_operand (struct ex_value_s *value);
int tempop_overlap (tempop_t *t1, tempop_t *t2) __attribute__((pure));
operand_t *temp_operand (struct type_s *type);

View file

@ -63,6 +63,7 @@ typedef enum {
typedef struct type_s {
etype_t type; ///< ev_invalid means structure/array etc
const char *name;
int alignment; ///< required alignment for instances
/// function/pointer/array/struct types are more complex
ty_meta_e meta;
union {
@ -98,6 +99,7 @@ typedef struct {
extern type_t type_invalid;
extern type_t type_void;
extern type_t type_string;
extern type_t type_double;
extern type_t type_float;
extern type_t type_vector;
extern type_t type_entity;
@ -153,6 +155,7 @@ const char *type_get_encoding (const type_t *type);
int is_void (const type_t *type) __attribute__((pure));
int is_enum (const type_t *type) __attribute__((pure));
int is_integral (const type_t *type) __attribute__((pure));
int is_double (const type_t *type) __attribute__((pure));
int is_float (const type_t *type) __attribute__((pure));
int is_scalar (const type_t *type) __attribute__((pure));
int is_vector (const type_t *type) __attribute__((pure));

View file

@ -40,6 +40,7 @@ struct ex_value_s;
struct type_s;
struct ex_value_s *new_string_val (const char *string_val);
struct ex_value_s *new_double_val (double double_val);
struct ex_value_s *new_float_val (float float_val);
struct ex_value_s *new_vector_val (const float *vector_val);
struct ex_value_s *new_entity_val (int entity_val);

View file

@ -53,7 +53,7 @@ qfcc_DEPENDENCIES= $(QFCC_DEPS)
qfprogs_SOURCES= \
disassemble.c dump_globals.c dump_lines.c dump_modules.c dump_strings.c \
obj_file.c qfprogs.c strpool.c stub.c
obj_file.c qfprogs.c strpool.c stub.c type.c
qfprogs_LDADD= $(QFCC_LIBS)
qfprogs_DEPENDENCIES= $(QFCC_DEPS)

View file

@ -68,28 +68,29 @@ static hashtab_t *category_hash;
static hashtab_t *protocol_hash;
// these will be built up further
type_t type_obj_selector = { ev_invalid, 0, ty_struct};
type_t type_SEL = { ev_pointer, "SEL", ty_none, {{&type_obj_selector}}};
type_t type_IMP = { ev_func, "IMP", ty_none,
type_t type_obj_selector = { ev_invalid, 0, 0, ty_struct};
type_t type_SEL = { ev_pointer, "SEL", 1, ty_none, {{&type_obj_selector}}};
type_t type_IMP = { ev_func, "IMP", 1, ty_none,
{{&type_id, -3, {&type_id, &type_SEL}}}};
type_t type_obj_super = { ev_invalid, 0 };
type_t type_SuperPtr = { ev_pointer, 0, ty_none, {{&type_obj_super}}};
type_t type_supermsg = { ev_func, ".supermsg", ty_none,
type_t type_obj_super = { ev_invalid, 0, 0 };
type_t type_SuperPtr = { ev_pointer, 0, 1, ty_none, {{&type_obj_super}}};
type_t type_supermsg = { ev_func, ".supermsg", 1, ty_none,
{{&type_id, -3, {&type_SuperPtr, &type_SEL}}}};
type_t type_obj_method = { ev_invalid, 0, ty_struct };
type_t type_obj_method_description = { ev_invalid, 0, ty_struct };
type_t type_obj_category = { ev_invalid, 0, ty_struct};
type_t type_obj_ivar = { ev_invalid, 0, ty_struct};
type_t type_obj_module = { ev_invalid, 0, ty_struct};
type_t type_moduleptr = { ev_pointer, 0, ty_none, {{&type_obj_module}}};
type_t type_obj_exec_class = { ev_func, 0, ty_none,
type_t type_obj_method = { ev_invalid, 0, 0, ty_struct };
type_t type_obj_method_description = { ev_invalid, 0, 0, ty_struct };
type_t type_obj_category = { ev_invalid, 0, 0, ty_struct};
type_t type_obj_ivar = { ev_invalid, 0, 0, ty_struct};
type_t type_obj_module = { ev_invalid, 0, 0, ty_struct};
type_t type_moduleptr = { ev_pointer, 0, 1, ty_none,
{{&type_obj_module}}};
type_t type_obj_exec_class = { ev_func, 0, 1, ty_none,
{{&type_void, 1, { &type_moduleptr }}}};
type_t type_obj_object = {ev_invalid, 0, ty_struct};
type_t type_id = { ev_pointer, "id", ty_none, {{&type_obj_object}}};
type_t type_obj_class = { ev_invalid, 0, ty_struct};
type_t type_Class = { ev_pointer, 0, ty_none, {{&type_obj_class}}};
type_t type_obj_protocol = { ev_invalid, 0, ty_struct};
type_t type_obj_object = {ev_invalid, 0, 0, ty_struct};
type_t type_id = { ev_pointer, "id", 1, ty_none, {{&type_obj_object}}};
type_t type_obj_class = { ev_invalid, 0, 0, ty_struct};
type_t type_Class = { ev_pointer, 0, 1, ty_none, {{&type_obj_class}}};
type_t type_obj_protocol = { ev_invalid, 0, 0, ty_struct};
int obj_initialized = 0;

View file

@ -48,6 +48,7 @@
#include "qfcc.h"
#include "strpool.h"
#include "type.h"
#include "value.h"
#include "qc-parse.h"
typedef expr_t *(*operation_t) (int op, expr_t *e, expr_t *e1, expr_t *e2);
@ -163,6 +164,40 @@ convert_to_float (expr_t *e)
}
}
static expr_t *
convert_to_double (expr_t *e)
{
if (get_type (e) == &type_double)
return e;
switch (e->type) {
case ex_value:
switch (e->e.value->lltype) {
case ev_integer:
e->e.value = new_double_val (expr_integer (e));
return e;
case ev_short:
e->e.value = new_double_val (expr_short (e));
return e;
case ev_float:
e->e.value = new_double_val (expr_float (e));
return e;
default:
internal_error (e, 0);
}
break;
case ex_symbol:
case ex_expr:
case ex_uexpr:
case ex_temp:
case ex_block:
e = cf_cast_expr (&type_float, e);
return e;
default:
internal_error (e, 0);
}
}
static expr_t *
do_op_float (int op, expr_t *e, expr_t *e1, expr_t *e2)
{
@ -292,6 +327,111 @@ do_op_float (int op, expr_t *e, expr_t *e1, expr_t *e2)
return e;
}
static expr_t *
do_op_double (int op, expr_t *e, expr_t *e1, expr_t *e2)
{
double d1, d2;
expr_t *conv;
type_t *type = &type_double;
static int valid[] = {
'=', '+', '-', '*', '/', '%',
LT, GT, LE, GE, EQ, NE, 0
};
if (!valid_op (op, valid))
return error (e1, "invalid operator for double");
if (op == '=' || op == PAS) {
if ((type = get_type (e1)) != &type_double) {
//FIXME optimize casting a constant
e->e.expr.e2 = e2 = cf_cast_expr (type, e2);
} else if ((conv = convert_to_double (e2)) != e2) {
e->e.expr.e2 = e2 = conv;
}
} else {
if ((conv = convert_to_double (e1)) != e1) {
e->e.expr.e1 = e1 = conv;
}
if ((conv = convert_to_double (e2)) != e2) {
e->e.expr.e2 = e2 = conv;
}
}
if (is_compare (op) || is_logic (op)) {
type = &type_integer;
}
e->e.expr.type = type;
if (op == '*' && is_constant (e1) && expr_double (e1) == 1)
return e2;
if (op == '*' && is_constant (e2) && expr_double (e2) == 1)
return e1;
if (op == '*' && is_constant (e1) && expr_double (e1) == 0)
return e1;
if (op == '*' && is_constant (e2) && expr_double (e2) == 0)
return e2;
if (op == '/' && is_constant (e2) && expr_double (e2) == 1)
return e1;
if (op == '/' && is_constant (e2) && expr_double (e2) == 0)
return error (e, "division by zero");
if (op == '/' && is_constant (e1) && expr_double (e1) == 0)
return e1;
if (op == '+' && is_constant (e1) && expr_double (e1) == 0)
return e2;
if (op == '+' && is_constant (e2) && expr_double (e2) == 0)
return e1;
if (op == '-' && is_constant (e2) && expr_double (e2) == 0)
return e1;
if (op == '=' || !is_constant (e1) || !is_constant (e2))
return e;
d1 = expr_double (e1);
d2 = expr_double (e2);
switch (op) {
case '+':
e = new_double_expr (d1 + d2);
break;
case '-':
e = new_double_expr (d1 - d2);
break;
case '*':
e = new_double_expr (d1 * d2);
break;
case '/':
if (!d2)
return error (e1, "divide by zero");
e = new_double_expr (d1 / d2);
break;
case '%':
e = new_double_expr ((int)d1 % (int)d2);
break;
case LT:
e = new_integer_expr (d1 < d2);
break;
case GT:
e = new_integer_expr (d1 > d2);
break;
case LE:
e = new_integer_expr (d1 <= d2);
break;
case GE:
e = new_integer_expr (d1 >= d2);
break;
case EQ:
e = new_integer_expr (d1 == d2);
break;
case NE:
e = new_integer_expr (d1 != d2);
break;
default:
internal_error (e1, 0);
}
e->file = e1->file;
e->line = e1->line;
return e;
}
static expr_t *
do_op_vector (int op, expr_t *e, expr_t *e1, expr_t *e2)
{
@ -884,11 +1024,15 @@ do_op_compound (int op, expr_t *e, expr_t *e1, expr_t *e2)
return do_op_struct (op, e, e1, e2);
if (is_scalar (t1) && is_scalar (t2)) {
if (is_enum (t1)) {
if (t2->type == ev_float)
if (t2->type == ev_double)
return do_op_float (op, e, e1, e2);
if (t2->type == ev_double)
return do_op_float (op, e, e1, e2);
return do_op_integer (op, e, e1, e2);
}
if (is_enum (t2)) {
if (t1->type == ev_double)
return do_op_double (op, e, e1, e2);
if (t1->type == ev_float)
return do_op_float (op, e, e1, e2);
return do_op_integer (op, e, e1, e2);
@ -947,6 +1091,7 @@ static operation_t op_void[ev_type_count] = {
do_op_invalid, // ev_integer
do_op_invalid, // ev_uinteger
do_op_invalid, // ev_short
do_op_invalid, // ev_double
do_op_invalid, // ev_invalid
};
@ -963,6 +1108,7 @@ static operation_t op_string[ev_type_count] = {
do_op_invalid, // ev_integer
do_op_invalid, // ev_uinteger
do_op_invalid, // ev_short
do_op_invalid, // ev_double
do_op_invalid, // ev_invalid
};
@ -979,6 +1125,7 @@ static operation_t op_float[ev_type_count] = {
do_op_float, // ev_integer
do_op_float, // ev_uinteger
do_op_float, // ev_short
do_op_double, // ev_double
do_op_invalid, // ev_invalid
};
@ -995,6 +1142,7 @@ static operation_t op_vector[ev_type_count] = {
do_op_vector, // ev_integer
do_op_vector, // ev_uinteger
do_op_vector, // ev_short
do_op_vector, // ev_double
do_op_invalid, // ev_invalid
};
@ -1011,6 +1159,7 @@ static operation_t op_entity[ev_type_count] = {
do_op_invalid, // ev_integer
do_op_invalid, // ev_uinteger
do_op_invalid, // ev_short
do_op_invalid, // ev_double
do_op_invalid, // ev_invalid
};
@ -1027,6 +1176,7 @@ static operation_t op_field[ev_type_count] = {
do_op_invalid, // ev_integer
do_op_invalid, // ev_uinteger
do_op_invalid, // ev_short
do_op_invalid, // ev_double
do_op_invalid, // ev_invalid
};
@ -1043,6 +1193,7 @@ static operation_t op_func[ev_type_count] = {
do_op_func, // ev_integer
do_op_func, // ev_uinteger
do_op_func, // ev_short
do_op_func, // ev_double
do_op_func, // ev_invalid
};
@ -1059,6 +1210,7 @@ static operation_t op_pointer[ev_type_count] = {
do_op_pointer, // ev_integer
do_op_pointer, // ev_uinteger
do_op_pointer, // ev_short
do_op_pointer, // ev_double
do_op_pointer, // ev_invalid
};
@ -1075,6 +1227,7 @@ static operation_t op_quaternion[ev_type_count] = {
do_op_quaternion, // ev_integer
do_op_quaternion, // ev_uinteger
do_op_quaternion, // ev_short
do_op_quaternion, // ev_double
do_op_invalid, // ev_invalid
};
@ -1091,6 +1244,7 @@ static operation_t op_integer[ev_type_count] = {
do_op_integer, // ev_integer
do_op_uinteger, // ev_uinteger
do_op_integer, // ev_short
do_op_double, // ev_double
do_op_invalid, // ev_invalid
};
@ -1107,6 +1261,7 @@ static operation_t op_uinteger[ev_type_count] = {
do_op_uinteger, // ev_integer
do_op_uinteger, // ev_uinteger
do_op_uinteger, // ev_short
do_op_double, // ev_double
do_op_invalid, // ev_invalid
};
@ -1123,6 +1278,24 @@ static operation_t op_short[ev_type_count] = {
do_op_integer, // ev_integer
do_op_uinteger, // ev_uinteger
do_op_short, // ev_short
do_op_double, // ev_double
do_op_invalid, // ev_invalid
};
static operation_t op_double[ev_type_count] = {
do_op_invalid, // ev_void
do_op_invalid, // ev_string
do_op_float, // ev_float
do_op_vector, // ev_vector
do_op_invalid, // ev_entity
do_op_invalid, // ev_field
do_op_invalid, // ev_func
do_op_invalid, // ev_pointer
do_op_quaternion, // ev_quaternion
do_op_integer, // ev_integer
do_op_uinteger, // ev_uinteger
do_op_short, // ev_short
do_op_double, // ev_double
do_op_invalid, // ev_invalid
};
@ -1139,6 +1312,7 @@ static operation_t op_compound[ev_type_count] = {
do_op_compound, // ev_integer
do_op_compound, // ev_uinteger
do_op_compound, // ev_short
do_op_compound, // ev_double
do_op_compound, // ev_invalid
};
@ -1155,6 +1329,7 @@ static operation_t *do_op[ev_type_count] = {
op_integer, // ev_integer
op_uinteger, // ev_uinteger
op_short, // ev_short
op_double, // ev_double
op_compound, // ev_invalid
};
@ -1203,13 +1378,15 @@ static expr_t *
uop_float (int op, expr_t *e, expr_t *e1)
{
static int valid[] = { '+', '-', '!', '~', 'C', 0 };
type_t *type;
if (!valid_op (op, valid))
return error (e1, "invalid unary operator for float: %s",
get_op_string (op));
if (op == '+')
return e1;
if (op == 'C' && get_type (e) != &type_integer)
type = get_type (e);
if (op == 'C' && type != &type_integer && type != &type_double)
return error (e1, "invalid cast of float");
if (!is_constant (e1))
return e;
@ -1222,7 +1399,11 @@ uop_float (int op, expr_t *e, expr_t *e1)
case '~':
return new_float_expr (~(int) expr_float (e1));
case 'C':
return new_integer_expr (expr_float (e1));
if (type == &type_integer) {
return new_integer_expr (expr_float (e1));
} else {
return new_double_expr (expr_float (e1));
}
}
internal_error (e, "float unary op blew up");
}
@ -1420,6 +1601,38 @@ uop_short (int op, expr_t *e, expr_t *e1)
internal_error (e, "short unary op blew up");
}
static expr_t *
uop_double (int op, expr_t *e, expr_t *e1)
{
static int valid[] = { '+', '-', '!', 'C', 0 };
type_t *type;
if (!valid_op (op, valid))
return error (e1, "invalid unary operator for double: %s",
get_op_string (op));
if (op == '+')
return e1;
type = get_type (e);
if (op == 'C' && type != &type_integer && type != &type_float)
return error (e1, "invalid cast of double");
if (!is_constant (e1))
return e;
switch (op) {
case '-':
return new_double_expr (-expr_double (e1));
case '!':
print_type (get_type (e));
return new_integer_expr (!expr_double (e1));
case 'C':
if (type == &type_integer) {
return new_integer_expr (expr_double (e1));
} else {
return new_float_expr (expr_double (e1));
}
}
internal_error (e, "float unary op blew up");
}
static expr_t *
uop_compound (int op, expr_t *e, expr_t *e1)
{
@ -1446,6 +1659,7 @@ static unaryop_t do_unary_op[ev_type_count] = {
uop_integer, // ev_integer
uop_uinteger, // ev_uinteger
uop_short, // ev_short
uop_double, // ev_double
uop_compound, // ev_invalid
};
@ -1487,7 +1701,7 @@ fold_constants (expr_t *e)
if (t1 >= ev_type_count || t2 >= ev_type_count
|| !do_op[t1] || !do_op[t1][t2])
internal_error (e, "invalid type");
internal_error (e, "invalid type %d %d", t1, t2);
return do_op[t1][t2] (op, e, e1, e2);
}
return e;

View file

@ -148,11 +148,17 @@ new_def (const char *name, type_t *type, defspace_t *space,
if (storage != sc_extern) {
int size = type_size (type);
int alignment = type->alignment;
if (!size) {
error (0, "%s has incomplete type", name);
size = 1;
}
def->offset = defspace_alloc_loc (space, size);
if (alignment < 1) {
print_type (type);
internal_error (0, "temp type has no alignment");
}
def->offset = defspace_alloc_aligned_loc (space, size, alignment);
}
return def;
@ -199,16 +205,20 @@ temp_def (type_t *type)
def_t *temp;
defspace_t *space = current_func->symtab->space;
int size = type_size (type);
int alignment = type->alignment;
if (size < 1 || size > 4) {
internal_error (0, "%d invalid size for temp def", size);
}
if (alignment < 1) {
internal_error (0, "temp type has no alignment");
}
if ((temp = current_func->temp_defs[size - 1])) {
current_func->temp_defs[size - 1] = temp->temp_next;
temp->temp_next = 0;
} else {
ALLOC (16384, def_t, defs, temp);
temp->offset = defspace_alloc_loc (space, size);
temp->offset = defspace_alloc_aligned_loc (space, size, alignment);
*space->def_tail = temp;
space->def_tail = &temp->next;
temp->name = save_string (va (".tmp%d", current_func->temp_num++));
@ -565,7 +575,8 @@ initialize_def (symbol_t *sym, expr_t *init, defspace_t *space,
init_elements (sym->s.def, init);
sym->s.def->initialized = 1;
} else {
if (!type_assignable (sym->type, get_type (init))) {
type_t *init_type = get_type (init);
if (!type_assignable (sym->type, init_type)) {
error (init, "type mismatch in initializer");
return;
}
@ -575,8 +586,20 @@ initialize_def (symbol_t *sym, expr_t *init, defspace_t *space,
// fold_constants takes care of int/float conversions
append_expr (local_expr, fold_constants (init));
} else {
int offset = 0;
if (!is_constant (init)) {
error (init, "non-constant initializier");
return;
}
while ((init->type == ex_uexpr || init->type == ex_expr)
&& init->e.expr.op == 'A') {
if (init->type == ex_expr) {
offset += expr_integer (init->e.expr.e2);
}
init = init->e.expr.e1;
}
if (init->type != ex_value) { //FIXME enum etc
error (0, "non-constant initializier");
internal_error (0, "initializier not a value");
return;
}
if (init->e.value->lltype == ev_pointer
@ -587,6 +610,11 @@ initialize_def (symbol_t *sym, expr_t *init, defspace_t *space,
reloc_def_field (init->e.value->v.pointer.def, sym->s.def);
} else {
ex_value_t *v = init->e.value;
if (is_double (init_type)
&& (is_integral (sym->type) || is_float (sym->type))) {
warning (init, "assigning double to %s in initializer "
"(use a cast)", sym->type->name);
}
if (is_scalar (sym->type))
v = convert_value (v, sym->type);
if (v->lltype == ev_string) {

View file

@ -63,6 +63,33 @@ typedef struct locref_s {
static defspace_t *spaces_freelist;
static locref_t *locrefs_freelist;
static locref_t *
new_locref (int ofs, int size, locref_t *next)
{
locref_t *loc;
ALLOC (1024, locref_t, locrefs, loc);
loc->ofs = ofs;
loc->size = size;
loc->next = next;
return loc;
}
static void
del_locref (locref_t *loc)
{
FREE (locrefs, loc);
}
static defspace_t *
new_defspace (void)
{
defspace_t *space;
ALLOC (1024, defspace_t, spaces, space);
return space;
}
#define GROW 1024
static int
@ -98,9 +125,8 @@ grow_space_virtual (defspace_t *space)
defspace_t *
defspace_new (ds_type_t type)
{
defspace_t *space;
defspace_t *space = new_defspace ();
ALLOC (1024, defspace_t, spaces, space);
space->def_tail = &space->defs;
space->type = type;
if (type == ds_backed) {
@ -116,33 +142,59 @@ defspace_new (ds_type_t type)
int
defspace_alloc_loc (defspace_t *space, int size)
{
int ofs;
return defspace_alloc_aligned_loc (space, size, 1);
}
int
defspace_alloc_aligned_loc (defspace_t *space, int size, int alignment)
{
int ofs, pad;
locref_t *loc;
locref_t **l = &space->free_locs;
if (size <= 0)
internal_error (0, "invalid number of words requested: %d", size);
while (*l && (*l)->size < size)
l = &(*l)->next;
if ((loc = *l)) {
ofs = (*l)->ofs;
if ((*l)->size == size) {
loc = *l;
*l = (*l)->next;
FREE (locrefs, loc);
} else {
(*l)->ofs += size;
(*l)->size -= size;
if (alignment <= 0)
internal_error (0, "invalid alignment requested: %d", alignment);
while ((loc = *l)) {
ofs = loc->ofs;
pad = alignment * ((ofs + alignment - 1) / alignment) - ofs;
// exact fit, so just shrink the block or remove it if there is no
// padding (any padding remains free)
if (size + pad == loc->size) {
if (!pad) {
*l = loc->next;
del_locref (loc);
}
return ofs + pad;
}
return ofs;
// there's excess space in the block. If there's no padding, then
// just shrink it, otherwise split it into two, one on either side
// of the allocated block, such that the padding remains free
if (size + pad < loc->size) {
if (!pad) {
loc->ofs += size;
loc->size -= size;
} else {
loc->next = new_locref (ofs + pad + size,
loc->size - ofs - pad, loc->next);
loc->size = pad;
}
return ofs + pad;
}
l = &(*l)->next;
}
ofs = space->size;
space->size += size;
pad = alignment * ((ofs + alignment - 1) / alignment) - ofs;
space->size += size + pad;
if (space->size > space->max_size) {
if (!space->grow || !space->grow (space))
internal_error (0, "unable to allocate %d words", size);
}
return ofs;
if (pad) {
*l = new_locref (ofs, pad, 0);
}
return ofs + pad;
}
void
@ -184,17 +236,13 @@ defspace_free_loc (defspace_t *space, int ofs, int size)
loc->size += loc->next->size;
loc = loc->next;
*l = loc->next;
FREE (locrefs, loc);
del_locref (loc);
}
return;
}
}
// insert a new free block for the location to be freed
ALLOC (1024, locref_t, locrefs, loc);
loc->ofs = ofs;
loc->size = size;
loc->next = *l;
*l = loc;
*l = new_locref (ofs, size, *l);
}
int

View file

@ -141,17 +141,39 @@ _debug (expr_t *e, const char *file, int line, const char *fmt, ...)
va_end (args);
}
static __attribute__((noreturn, format(printf, 4, 0))) void
__internal_error (expr_t *e, const char *file, int line,
const char *fmt, va_list args)
{
dstring_t *message = dstring_new ();
report_function (e);
format_message (message, "internal error", e, fmt, args);
dasprintf (message, " (%s:%d)", file, line);
fprintf (stderr, "%s\n", message->str);
dstring_delete (message);
abort ();
}
void
_bug (expr_t *e, const char *file, int line, const char *fmt, ...)
{
va_list args;
report_function (e);
if (options.bug.silent)
return;
va_start (args, fmt);
if (options.bug.promote) {
__internal_error (e, file, line, fmt, args);
}
{
dstring_t *message = dstring_new ();
report_function (e);
format_message (message, "BUG", e, fmt, args);
dasprintf (message, " (%s:%d)", file, line);
if (bug_hook) {
@ -211,19 +233,9 @@ _internal_error (expr_t *e, const char *file, int line, const char *fmt, ...)
{
va_list args;
report_function (e);
va_start (args, fmt);
{
dstring_t *message = dstring_new ();
format_message (message, "internal error", e, fmt, args);
dasprintf (message, " (%s:%d)", file, line);
fprintf (stderr, "%s\n", message->str);
dstring_delete (message);
}
__internal_error (e, file, line, fmt, args);
va_end (args);
abort ();
}
expr_t *

View file

@ -88,6 +88,7 @@ get_op_string (int op)
case '*': return "*";
case '/': return "/";
case '%': return "%";
case MOD: return "%%";
case '&': return "&";
case '|': return "|";
case '^': return "^";
@ -438,6 +439,9 @@ print_value (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next)
case ev_string:
label = va ("\\\"%s\\\"", quote_string (e->e.value->v.string_val));
break;
case ev_double:
label = va ("f %g", e->e.value->v.double_val);
break;
case ev_float:
label = va ("f %g", e->e.value->v.float_val);
break;

View file

@ -97,6 +97,9 @@ dump_def (progs_t *pr, ddef_t *def, int indent)
case ev_float:
comment = va (" %g", G_FLOAT (pr, offset));
break;
case ev_double:
comment = va (" %.17g", G_DOUBLE (pr, offset));
break;
case ev_vector:
comment = va (" '%g %g %g'",
G_VECTOR (pr, offset)[0],
@ -214,7 +217,8 @@ dump_functions (progs_t *pr)
else
count = func->numparms;
for (j = 0; j < count; j++)
printf (" %d", func->parm_size[j]);
printf (" %d:%d", func->parm_size[j].alignment,
func->parm_size[j].size);
printf (") %d @ %x", func->locals, func->parm_start);
puts ("");
if (pr->debug) {

View file

@ -611,6 +611,15 @@ new_string_expr (const char *string_val)
return e;
}
expr_t *
new_double_expr (double double_val)
{
expr_t *e = new_expr ();
e->type = ex_value;
e->e.value = new_double_val (double_val);
return e;
}
expr_t *
new_float_expr (float float_val)
{
@ -768,6 +777,10 @@ new_short_expr (short short_val)
int
is_constant (expr_t *e)
{
while ((e->type == ex_uexpr || e->type == ex_expr)
&& e->e.expr.op == 'A') {
e = e->e.expr.e1;
}
if (e->type == ex_nil || e->type == ex_value || e->type == ex_labelref
|| (e->type == ex_symbol && e->e.symbol->sy_type == sy_const)
|| (e->type == ex_symbol && e->e.symbol->sy_type == sy_var
@ -845,6 +858,23 @@ is_float_val (expr_t *e)
return 0;
}
double
expr_double (expr_t *e)
{
if (e->type == ex_nil)
return 0;
if (e->type == ex_value && e->e.value->lltype == ev_double)
return e->e.value->v.double_val;
if (e->type == ex_symbol && e->e.symbol->sy_type == sy_const
&& e->e.symbol->type->type == ev_double)
return e->e.symbol->s.value->v.double_val;
if (e->type == ex_symbol && e->e.symbol->sy_type == sy_var
&& e->e.symbol->s.def->constant
&& is_double (e->e.symbol->s.def->type))
return D_DOUBLE (e->e.symbol->s.def);
internal_error (e, "not a double constant");
}
float
expr_float (expr_t *e)
{
@ -1024,8 +1054,6 @@ new_alias_expr (type_t *type, expr_t *expr)
{
expr_t *alias;
if (expr->type == ex_value)
return new_value_expr (alias_value (expr->e.value, type));
alias = new_unary_expr ('A', expr);
alias->e.expr.type = type;
//if (expr->type == ex_uexpr && expr->e.expr.op == 'A')
@ -1276,6 +1304,9 @@ test_expr (expr_t *e)
}
new = new_float_expr (0);
break;
case ev_double:
new = new_double_expr (0);
break;
case ev_vector:
new = new_vector_expr (zero);
break;
@ -1610,6 +1641,8 @@ unary_expr (int op, expr_t *e)
case ev_func:
case ev_pointer:
internal_error (e, "type check failed!");
case ev_double:
return new_double_expr (-expr_double (e));
case ev_float:
return new_float_expr (-expr_float (e));
case ev_vector:
@ -1676,6 +1709,8 @@ unary_expr (int op, expr_t *e)
case ev_string:
s = expr_string (e);
return new_integer_expr (!s || !s[0]);
case ev_double:
return new_integer_expr (!expr_double (e));
case ev_float:
return new_integer_expr (!expr_float (e));
case ev_vector:
@ -1735,6 +1770,7 @@ unary_expr (int op, expr_t *e)
case ev_func:
case ev_pointer:
case ev_vector:
case ev_double:
return error (e, "invalid type for unary ~");
case ev_float:
return new_float_expr (~(int) expr_float (e));
@ -1881,6 +1917,10 @@ build_function_call (expr_t *fexpr, type_t *ftype, expr_t *params)
if (is_integer_val (e)
&& options.code.progsversion == PROG_ID_VERSION)
convert_int (e);
if (is_float (get_type (e))
&& options.code.progsversion != PROG_ID_VERSION) {
t = &type_double;
}
if (is_integer_val (e) && options.warnings.vararg_integer)
warning (e, "passing integer constant into ... function");
}
@ -2235,6 +2275,14 @@ address_expr (expr_t *e1, expr_t *e2, type_t *t)
e = e1->e.expr.e2;
break;
}
if (e1->e.expr.op == 'A') {
if (!t)
t = e1->e.expr.type;
if (e2) {
e2 = binary_expr ('+', e1->e.expr.e2, e2);
}
return address_expr (e1->e.expr.e1, e2, t);
}
return error (e1, "invalid type for unary &");
case ex_uexpr:
if (e1->e.expr.op == '.') {
@ -2577,8 +2625,9 @@ cast_expr (type_t *type, expr_t *e)
e->e.value = convert_value (val, type);
e->type = ex_value;
c = e;
} else if ((is_float (type) && is_integral (e_type))
|| (is_integral (type) && is_float (e_type))) {
} else if (is_integral (type) && is_integral (e_type)) {
c = new_alias_expr (type, e);
} else if (is_scalar (type) && is_scalar (e_type)) {
c = new_unary_expr ('C', e);
c->e.expr.type = type;
} else if (e->type == ex_uexpr && e->e.expr.op == '.') {

View file

@ -151,6 +151,10 @@ check_types_compatible (expr_t *dst, expr_t *src)
if (type_assignable (dst_type, src_type)) {
if (is_scalar (dst_type) && is_scalar (src_type)) {
if (is_double (src_type)) {
warning (dst, "assignment of double to %s (use a cast)\n",
dst_type->name);
}
// the types are different but cast-compatible
expr_t *new = cast_expr (dst_type, src);
// the cast was a no-op, so the types are compatible at the

View file

@ -47,6 +47,7 @@ typedef struct {
static expr_t *pointer_arithmetic (int op, expr_t *e1, expr_t *e2);
static expr_t *inverse_multiply (int op, expr_t *e1, expr_t *e2);
static expr_t *double_compare (int op, expr_t *e1, expr_t *e2);
static expr_type_t string_string[] = {
{'+', &type_string},
@ -68,6 +69,7 @@ static expr_type_t float_float[] = {
{'|', &type_float},
{'^', &type_float},
{'%', &type_float},
{MOD, &type_float},
{SHL, &type_float},
{SHR, &type_float},
{EQ, &type_integer},
@ -86,7 +88,6 @@ static expr_type_t float_vector[] = {
static expr_type_t float_quat[] = {
{'*', &type_quaternion},
{'/', 0, 0, 0, inverse_multiply},
{0, 0}
};
@ -99,6 +100,7 @@ static expr_type_t float_integer[] = {
{'|', &type_float, 0, &type_float},
{'^', &type_float, 0, &type_float},
{'%', &type_float, 0, &type_float},
{MOD, &type_float, 0, &type_float},
{SHL, &type_float, 0, &type_float},
{SHR, &type_float, 0, &type_float},
{EQ, &type_integer, 0, &type_float},
@ -112,6 +114,22 @@ static expr_type_t float_integer[] = {
#define float_uinteger float_integer
#define float_short float_integer
static expr_type_t float_double[] = {
{'+', &type_double, &type_double, 0},
{'-', &type_double, &type_double, 0},
{'*', &type_double, &type_double, 0},
{'/', &type_double, &type_double, 0},
{'%', &type_double, &type_double, 0},
{MOD, &type_double, &type_double, 0},
{EQ, 0, 0, 0, double_compare},
{NE, 0, 0, 0, double_compare},
{LE, 0, 0, 0, double_compare},
{GE, 0, 0, 0, double_compare},
{LT, 0, 0, 0, double_compare},
{GT, 0, 0, 0, double_compare},
{0, 0}
};
static expr_type_t vector_float[] = {
{'*', &type_vector},
{'/', 0, 0, 0, inverse_multiply},
@ -131,6 +149,12 @@ static expr_type_t vector_vector[] = {
#define vector_uinteger vector_float
#define vector_short vector_float
static expr_type_t vector_double[] = {
{'*', &type_vector},
{'/', 0, 0, 0, inverse_multiply},
{0, 0}
};
static expr_type_t entity_entity[] = {
{EQ, &type_integer},
{NE, &type_integer},
@ -170,7 +194,7 @@ static expr_type_t pointer_integer[] = {
static expr_type_t quat_float[] = {
{'*', &type_quaternion},
{'/', &type_quaternion},
{'/', 0, 0, 0, inverse_multiply},
{0, 0}
};
@ -190,12 +214,18 @@ static expr_type_t quat_quat[] = {
static expr_type_t quat_integer[] = {
{'*', &type_quaternion, 0, &type_float},
{'/', &type_quaternion, 0, &type_float},
{'/', 0, 0, 0, inverse_multiply},
{0, 0}
};
#define quat_uinteger quat_integer
#define quat_short quat_integer
static expr_type_t quat_double[] = {
{'*', &type_quaternion},
{'/', 0, 0, 0, inverse_multiply},
{0, 0}
};
static expr_type_t integer_float[] = {
{'+', &type_float, &type_float, 0},
{'-', &type_float, &type_float, 0},
@ -205,6 +235,7 @@ static expr_type_t integer_float[] = {
{'|', &type_float, &type_float, 0},
{'^', &type_float, &type_float, 0},
{'%', &type_float, &type_float, 0},
{MOD, &type_float, &type_float, 0},
{SHL, &type_integer, 0, &type_integer}, //FIXME?
{SHR, &type_integer, 0, &type_integer}, //FIXME?
{EQ, &type_integer, &type_float, 0},
@ -228,7 +259,6 @@ static expr_type_t integer_pointer[] = {
static expr_type_t integer_quat[] = {
{'*', &type_quaternion, &type_float, 0},
{'/', &type_quaternion, &type_float, 0},
{0, 0}
};
@ -241,6 +271,7 @@ static expr_type_t integer_integer[] = {
{'|', &type_integer},
{'^', &type_integer},
{'%', &type_integer},
{MOD, &type_integer},
{SHL, &type_integer},
{SHR, &type_integer},
{EQ, &type_integer},
@ -261,6 +292,7 @@ static expr_type_t integer_uinteger[] = {
{'|', &type_integer},
{'^', &type_integer},
{'%', &type_integer},
{MOD, &type_integer},
{SHL, &type_integer},
{SHR, &type_integer},
{EQ, &type_integer},
@ -281,6 +313,7 @@ static expr_type_t integer_short[] = {
{'|', &type_integer, 0, &type_integer},
{'^', &type_integer, 0, &type_integer},
{'%', &type_integer, 0, &type_integer},
{MOD, &type_integer, 0, &type_integer},
{SHL, &type_integer, 0, &type_integer},
{SHR, &type_integer, 0, &type_integer},
{EQ, &type_integer, 0, &type_integer},
@ -292,6 +325,22 @@ static expr_type_t integer_short[] = {
{0, 0}
};
static expr_type_t integer_double[] = {
{'+', &type_double, &type_double, 0},
{'-', &type_double, &type_double, 0},
{'*', &type_double, &type_double, 0},
{'/', &type_double, &type_double, 0},
{'%', &type_double, &type_double, 0},
{MOD, &type_double, &type_double, 0},
{EQ, &type_integer, &type_double, 0},
{NE, &type_integer, &type_double, 0},
{LE, &type_integer, &type_double, 0},
{GE, &type_integer, &type_double, 0},
{LT, &type_integer, &type_double, 0},
{GT, &type_integer, &type_double, 0},
{0, 0}
};
#define uinteger_float integer_float
#define uinteger_vector integer_vector
#define uinteger_pointer integer_pointer
@ -306,6 +355,7 @@ static expr_type_t uinteger_integer[] = {
{'|', &type_integer},
{'^', &type_integer},
{'%', &type_integer},
{MOD, &type_integer},
{SHL, &type_uinteger},
{SHR, &type_uinteger},
{EQ, &type_integer},
@ -326,6 +376,7 @@ static expr_type_t uinteger_uinteger[] = {
{'|', &type_uinteger},
{'^', &type_uinteger},
{'%', &type_uinteger},
{MOD, &type_uinteger},
{SHL, &type_uinteger},
{SHR, &type_uinteger},
{EQ, &type_integer},
@ -337,6 +388,7 @@ static expr_type_t uinteger_uinteger[] = {
{0, 0}
};
#define uinteger_short uinteger_integer
#define uinteger_double integer_double
#define short_float integer_float
#define short_vector integer_vector
@ -352,6 +404,7 @@ static expr_type_t short_integer[] = {
{'|', &type_integer, &type_integer, 0},
{'^', &type_integer, &type_integer, 0},
{'%', &type_integer, &type_integer, 0},
{MOD, &type_integer, &type_integer, 0},
{SHL, &type_short},
{SHR, &type_short},
{EQ, &type_integer, &type_integer, 0},
@ -372,6 +425,7 @@ static expr_type_t short_uinteger[] = {
{'|', &type_uinteger, &type_uinteger, 0},
{'^', &type_uinteger, &type_uinteger, 0},
{'%', &type_uinteger, &type_uinteger, 0},
{MOD, &type_uinteger, &type_uinteger, 0},
{SHL, &type_short},
{SHR, &type_short},
{EQ, &type_integer, &type_uinteger, 0},
@ -392,6 +446,7 @@ static expr_type_t short_short[] = {
{'|', &type_short},
{'^', &type_short},
{'%', &type_short},
{MOD, &type_short},
{SHL, &type_short},
{SHR, &type_short},
{EQ, &type_integer},
@ -402,8 +457,69 @@ static expr_type_t short_short[] = {
{GT, &type_integer},
{0, 0}
};
#define short_double integer_double
static expr_type_t *string_x[] = {
static expr_type_t double_float[] = {
{'+', &type_double, 0, &type_double},
{'-', &type_double, 0, &type_double},
{'*', &type_double, 0, &type_double},
{'/', &type_double, 0, &type_double},
{'%', &type_double, 0, &type_double},
{MOD, &type_double, 0, &type_double},
{EQ, 0, 0, 0, double_compare},
{NE, 0, 0, 0, double_compare},
{LE, 0, 0, 0, double_compare},
{GE, 0, 0, 0, double_compare},
{LT, 0, 0, 0, double_compare},
{GT, 0, 0, 0, double_compare},
{0, 0}
};
static expr_type_t double_vector[] = {
{'*', &type_vector},
{0, 0}
};
static expr_type_t double_quat[] = {
{'*', &type_quaternion},
{0, 0}
};
static expr_type_t double_integer[] = {
{'+', &type_double, 0, &type_double},
{'-', &type_double, 0, &type_double},
{'*', &type_double, 0, &type_double},
{'/', &type_double, 0, &type_double},
{'%', &type_double, 0, &type_double},
{MOD, &type_double, 0, &type_double},
{EQ, 0, 0, 0, double_compare},
{NE, 0, 0, 0, double_compare},
{LE, 0, 0, 0, double_compare},
{GE, 0, 0, 0, double_compare},
{LT, 0, 0, 0, double_compare},
{GT, 0, 0, 0, double_compare},
{0, 0}
};
#define double_uinteger double_integer
#define double_short double_integer
static expr_type_t double_double[] = {
{'+', &type_double},
{'-', &type_double},
{'*', &type_double},
{'/', &type_double},
{'%', &type_double},
{MOD, &type_double},
{EQ, &type_integer},
{NE, &type_integer},
{LE, &type_integer},
{GE, &type_integer},
{LT, &type_integer},
{GT, &type_integer},
{0, 0}
};
static expr_type_t *string_x[ev_type_count] = {
0, // ev_void
string_string,
0, // ev_float
@ -416,9 +532,10 @@ static expr_type_t *string_x[] = {
0, // ev_integer
0, // ev_uinteger
0, // ev_short
0, // ev_double
};
static expr_type_t *float_x[] = {
static expr_type_t *float_x[ev_type_count] = {
0, // ev_void
0, // ev_string
float_float,
@ -431,9 +548,10 @@ static expr_type_t *float_x[] = {
float_integer,
float_uinteger,
float_short,
float_double,
};
static expr_type_t *vector_x[] = {
static expr_type_t *vector_x[ev_type_count] = {
0, // ev_void
0, // ev_string
vector_float,
@ -446,9 +564,10 @@ static expr_type_t *vector_x[] = {
vector_integer,
vector_uinteger,
vector_short,
vector_double,
};
static expr_type_t *entity_x[] = {
static expr_type_t *entity_x[ev_type_count] = {
0, // ev_void
0, // ev_string
0, // ev_float
@ -461,9 +580,10 @@ static expr_type_t *entity_x[] = {
0, // ev_integer
0, // ev_uinteger
0, // ev_short
0, // ev_double
};
static expr_type_t *field_x[] = {
static expr_type_t *field_x[ev_type_count] = {
0, // ev_void
0, // ev_string
0, // ev_float
@ -476,9 +596,10 @@ static expr_type_t *field_x[] = {
0, // ev_integer
0, // ev_uinteger
0, // ev_short
0, // ev_double
};
static expr_type_t *funcx[] = {
static expr_type_t *func_x[ev_type_count] = {
0, // ev_void
0, // ev_string
0, // ev_float
@ -491,9 +612,10 @@ static expr_type_t *funcx[] = {
0, // ev_integer
0, // ev_uinteger
0, // ev_short
0, // ev_double
};
static expr_type_t *pointer_x[] = {
static expr_type_t *pointer_x[ev_type_count] = {
0, // ev_void
0, // ev_string
0, // ev_float
@ -506,9 +628,10 @@ static expr_type_t *pointer_x[] = {
pointer_integer,
pointer_uinteger,
pointer_short,
0, // ev_double
};
static expr_type_t *quat_x[] = {
static expr_type_t *quat_x[ev_type_count] = {
0, // ev_void
0, // ev_string
quat_float,
@ -521,9 +644,10 @@ static expr_type_t *quat_x[] = {
quat_integer,
quat_uinteger,
quat_short,
quat_double,
};
static expr_type_t *integer_x[] = {
static expr_type_t *integer_x[ev_type_count] = {
0, // ev_void
0, // ev_string
integer_float,
@ -536,9 +660,10 @@ static expr_type_t *integer_x[] = {
integer_integer,
integer_uinteger,
integer_short,
integer_double,
};
static expr_type_t *uinteger_x[] = {
static expr_type_t *uinteger_x[ev_type_count] = {
0, // ev_void
0, // ev_string
uinteger_float,
@ -551,9 +676,10 @@ static expr_type_t *uinteger_x[] = {
uinteger_integer,
uinteger_uinteger,
uinteger_short,
uinteger_double,
};
static expr_type_t *short_x[] = {
static expr_type_t *short_x[ev_type_count] = {
0, // ev_void
0, // ev_string
short_float,
@ -566,21 +692,39 @@ static expr_type_t *short_x[] = {
short_integer,
short_uinteger,
short_short,
short_double,
};
static expr_type_t **binary_expr_types[] = {
static expr_type_t *double_x[ev_type_count] = {
0, // ev_void
0, // ev_string
double_float,
double_vector,
0, // ev_entity
0, // ev_field
0, // ev_func
0, // ev_pointer
double_quat,
double_integer,
double_uinteger,
double_short,
double_double,
};
static expr_type_t **binary_expr_types[ev_type_count] = {
0, // ev_void
string_x,
float_x,
vector_x,
entity_x,
field_x,
funcx,
func_x,
pointer_x,
quat_x,
integer_x,
uinteger_x,
short_x,
double_x
};
static expr_t *
@ -611,6 +755,36 @@ inverse_multiply (int op, expr_t *e1, expr_t *e2)
return binary_expr ('*', e1, binary_expr ('/', one, e2));
}
static expr_t *
double_compare (int op, expr_t *e1, expr_t *e2)
{
type_t *t1 = get_type (e1);
type_t *t2 = get_type (e2);
expr_t *e;
if ((is_double (t1) && is_float (t2))
|| (is_float (t1) && is_double (t2))) {
}
if (is_double (t1)) {
if (is_float (t2)) {
warning (e2, "comparison between double and float");
} else if (!is_constant (e2)) {
warning (e2, "comparison between double and integer");
}
e2 = cast_expr (&type_double, e2);
} else {
if (is_float (t1)) {
warning (e1, "comparison between float and double");
} else if (!is_constant (e1)) {
warning (e1, "comparison between integer and double");
}
e1 = cast_expr (&type_double, e1);
}
e = new_binary_expr (op, e1, e2);
e->e.expr.type = &type_double;
return e;
}
static expr_t *
invalid_binary_expr (int op, expr_t *e1, expr_t *e2)
{
@ -630,32 +804,14 @@ reimplement_binary_expr (int op, expr_t *e1, expr_t *e2)
switch (op) {
case '%':
{
expr_t *tmp1, *tmp2, *tmp3, *tmp4, *t1, *t2;
expr_t *tmp1, *tmp2;
e = new_block_expr ();
t1 = new_temp_def_expr (&type_float);
t2 = new_temp_def_expr (&type_float);
tmp1 = new_temp_def_expr (&type_float);
tmp2 = new_temp_def_expr (&type_float);
tmp3 = new_temp_def_expr (&type_float);
tmp4 = new_temp_def_expr (&type_float);
append_expr (e, assign_expr (t1, e1));
e1 = binary_expr ('&', t1, t1);
append_expr (e, assign_expr (tmp1, e1));
append_expr (e, assign_expr (t2, e2));
e2 = binary_expr ('&', t2, t2);
append_expr (e, assign_expr (tmp2, e2));
e1 = binary_expr ('/', tmp1, tmp2);
append_expr (e, assign_expr (tmp3, e1));
e2 = binary_expr ('&', tmp3, tmp3);
append_expr (e, assign_expr (tmp4, e2));
e1 = binary_expr ('*', tmp2, tmp4);
e2 = binary_expr ('-', tmp1, e1);
e->e.block.result = e2;
append_expr (e, assign_expr (tmp1, binary_expr ('/', e1, e2)));
append_expr (e, assign_expr (tmp2, binary_expr ('&', tmp1, tmp1)));
e->e.block.result = binary_expr ('-', e1, binary_expr ('*', e2, tmp2));
return e;
}
break;
@ -798,9 +954,9 @@ binary_expr (int op, expr_t *e1, expr_t *e2)
et1 = low_level_type (t1);
et2 = low_level_type (t2);
if (et1 > ev_short || !binary_expr_types[et1])
if (et1 >= ev_type_count || !binary_expr_types[et1])
return invalid_binary_expr(op, e1, e2);
if (et2 > ev_short || !binary_expr_types[et1][et2])
if (et2 >= ev_type_count || !binary_expr_types[et1][et2])
return invalid_binary_expr(op, e1, e2);
expr_type = binary_expr_types[et1][et2];
while (expr_type->op && expr_type->op != op)

View file

@ -158,6 +158,7 @@ parse_params (type_t *type, param_t *parms)
new = new_type ();
new->type = ev_func;
new->alignment = 1;
new->t.func.type = type;
new->t.func.num_params = 0;
@ -339,8 +340,11 @@ find_function (expr_t *fexpr, expr_t *params)
for (func_count = 0; funcs[func_count]; func_count++)
;
if (func_count < 2) {
free (funcs);
return fexpr;
f = (overloaded_function_t *) funcs[0];
if (func_count && !f->overloaded) {
free (funcs);
return fexpr;
}
}
type.t.func.type = ((overloaded_function_t *) funcs[0])->type->t.func.type;
dummy.type = find_type (&type);

View file

@ -665,7 +665,7 @@ get_def_type (qfo_t *qfo, pointer_t type)
return ev_invalid;
}
static __attribute__((pure)) etype_t
static __attribute__((pure)) int
get_type_size (qfo_t *qfo, pointer_t type)
{
qfot_type_t *type_def;
@ -701,6 +701,62 @@ get_type_size (qfo_t *qfo, pointer_t type)
return 0;
}
int
qfo_log2 (unsigned x)
{
int log2 = 0;
while (x > 1) {
x >>= 1;
log2++;
}
return log2;
}
static __attribute__((pure)) int
get_type_alignment_log (qfo_t *qfo, pointer_t type)
{
qfot_type_t *type_def;
int i, alignment;
if (type >= qfo->spaces[qfo_type_space].data_size)
return 0;
type_def = QFO_POINTER (qfo, qfo_type_space, qfot_type_t, type);
switch ((ty_meta_e)type_def->meta) {
case ty_none:
// field, pointer and function types store their basic type in
// the same location.
return qfo_log2 (ev_types[type_def->t.type]->alignment);
case ty_struct:
case ty_union:
for (i = alignment = 0; i < type_def->t.strct.num_fields; i++) {
qfot_var_t *field = type_def->t.strct.fields + i;
int a;
a = get_type_alignment_log (qfo, field->type);
if (a > alignment) {
alignment = a;
}
}
return alignment;
case ty_enum:
return qfo_log2 (ev_types[ev_integer]->alignment);
case ty_array:
return get_type_alignment_log (qfo, type_def->t.array.type);
case ty_class:
return 0; // FIXME
}
return 0;
}
static __attribute__((pure)) dparmsize_t
get_parmsize (qfo_t *qfo, pointer_t type)
{
dparmsize_t parmsize = {
get_type_size (qfo, type),
get_type_alignment_log (qfo, type),
};
return parmsize;
}
static void
function_params (qfo_t *qfo, qfo_func_t *func, dfunction_t *df)
{
@ -716,8 +772,9 @@ function_params (qfo_t *qfo, qfo_func_t *func, dfunction_t *df)
df->numparms = num_params = type->t.func.num_params;
if (num_params < 0)
num_params = ~num_params;
for (i = 0; i < num_params; i++)
df->parm_size[i] = get_type_size (qfo, type->t.func.param_types[i]);
for (i = 0; i < num_params; i++) {
df->parm_size[i] = get_parmsize (qfo, type->t.func.param_types[i]);
}
}
static void
@ -795,6 +852,14 @@ qfo_relocate_refs (qfo_t *qfo)
}
}
static unsigned
align_globals_size (unsigned size)
{
if (options.code.progsversion == PROG_ID_VERSION)
return size;
return RUP (size, 16 / sizeof (pr_type_t));
}
dprograms_t *
qfo_to_progs (qfo_t *qfo, int *size)
{
@ -811,6 +876,7 @@ qfo_to_progs (qfo_t *qfo, int *size)
dprograms_t *progs;
qfo_def_t *types_def = 0;
unsigned i, j;
unsigned near_data_size = 0;
unsigned locals_size = 0;
int locals_start;
unsigned big_locals = 0;
@ -827,9 +893,8 @@ qfo_to_progs (qfo_t *qfo, int *size)
progs->numfunctions = qfo->num_funcs + 1;
progs->numstrings = qfo->spaces[qfo_strings_space].data_size;
progs->numglobals = qfo->spaces[qfo_near_data_space].data_size;
progs->numglobals += qfo->spaces[qfo_far_data_space].data_size;
progs->numglobals += qfo->spaces[qfo_type_space].data_size;
locals_start = qfo->spaces[qfo_near_data_space].data_size;
progs->numglobals = align_globals_size (progs->numglobals);
locals_start = progs->numglobals;
for (i = qfo_num_spaces; i < qfo->num_spaces; i++) {
if (options.code.local_merging) {
if (locals_size < qfo->spaces[i].data_size) {
@ -837,11 +902,14 @@ qfo_to_progs (qfo_t *qfo, int *size)
big_locals = i;
}
} else {
locals_size += qfo->spaces[i].data_size;
locals_size += align_globals_size (qfo->spaces[i].data_size);
}
}
progs->numglobals += locals_size;
near_data_size = progs->numglobals;
progs->numglobals = RUP (progs->numglobals, 16 / sizeof (pr_type_t));
progs->numglobals += qfo->spaces[qfo_far_data_space].data_size;
progs->numglobals += qfo->spaces[qfo_type_space].data_size;
progs->entityfields = qfo->spaces[qfo_entity_space].data_size;
*size += progs->numstatements * sizeof (dstatement_t);
*size += progs->numglobaldefs * sizeof (ddef_t);
@ -878,8 +946,8 @@ qfo_to_progs (qfo_t *qfo, int *size)
progs->ofs_globals = data - (byte *) progs;
globals = (pr_type_t*) data;
locals = globals + qfo->spaces[qfo_near_data_space].data_size;
far_data = locals + locals_size;
locals = globals + locals_start;
far_data = globals + near_data_size;
type_data = far_data + qfo->spaces[qfo_far_data_space].data_size;
memcpy (strings, qfo->spaces[qfo_strings_space].d.strings,
@ -902,7 +970,7 @@ qfo_to_progs (qfo_t *qfo, int *size)
for (j = 0; j < space->num_defs; j++)
space->defs[j].offset += locals_start;
if (!options.code.local_merging)
locals_start += df->locals;
locals_start += align_globals_size (df->locals);
df->profile = 0;
df->s_name = qf->name;
df->s_file = qf->file;
@ -936,7 +1004,7 @@ qfo_to_progs (qfo_t *qfo, int *size)
memcpy (globals, qfo->spaces[qfo_near_data_space].d.data,
qfo->spaces[qfo_near_data_space].data_size * sizeof (pr_type_t));
qfo->spaces[qfo_near_data_space].d.data = globals;
// lcear locals data
// clear locals data
memset (locals, 0, locals_size * sizeof (pr_type_t));
// copy far data
memcpy (far_data, qfo->spaces[qfo_far_data_space].d.data,
@ -978,8 +1046,7 @@ qfo_to_progs (qfo_t *qfo, int *size)
printf ("%6i global defs\n", progs->numglobaldefs);
printf ("%6i fielddefs\n", progs->numfielddefs);
printf ("%6i globals\n", progs->numglobals);
printf (" %6i near globals\n",
qfo->spaces[qfo_near_data_space].data_size + locals_size);
printf (" %6i near globals\n", near_data_size);
printf (" %6i locals size%s\n", locals_size, big_function);
printf (" %6i far globals\n",
qfo->spaces[qfo_far_data_space].data_size);

View file

@ -69,11 +69,13 @@ enum {
OPT_PROGDEFS,
OPT_QCCX_ESCAPES,
OPT_TRADITIONAL,
OPT_BUG,
};
static struct option const long_options[] = {
{"advanced", no_argument, 0, OPT_ADVANCED},
{"block-dot", optional_argument, 0, OPT_BLOCK_DOT},
{"bug", required_argument, 0, OPT_BUG},
{"code", required_argument, 0, 'C'},
{"cpp", required_argument, 0, OPT_CPP},
{"define", required_argument, 0, 'D'},
@ -139,6 +141,7 @@ usage (int status)
"Options:\n"
" --advanced Advanced Ruamoko mode\n"
" default for separate compilation mode\n"
" --bug OPTION,... Set bug options\n"
" -C, --code OPTION,... Set code generation options\n"
" -c Only compile, don't link\n"
" --cpp CPPSPEC cpp execution command line\n"
@ -264,6 +267,21 @@ notice_usage (void)
exit (0);
}
static void
bug_usage (void)
{
printf ("%s - QuakeForge Code Compiler\n", this_program);
printf ("Bug options\n");
printf (
" help Display his text.\n"
" none Turn off all bugs (don't we wish: messages).\n"
" die Change bugs to internal errors.\n"
"\n"
"This is a developer feature and thus not in the manual page\n"
);
exit (0);
}
static void
add_file (const char *file)
{
@ -590,6 +608,23 @@ DecodeArgs (int argc, char **argv)
free (opts);
}
break;
case OPT_BUG:{
char *opts = strdup (optarg);
char *temp = strtok (opts, ",");
while (temp) {
if (!strcasecmp (temp, "help")) {
bug_usage ();
} else if (!(strcasecmp (temp, "none"))) {
options.bug.silent = true;
} else if (!(strcasecmp (temp, "die"))) {
options.bug.promote = true;
}
temp = strtok (NULL, ",");
}
free (opts);
}
break;
case OPT_CPP: // --cpp=
cpp_name = save_string (optarg);
break;

View file

@ -39,14 +39,25 @@
#endif
#include <stdlib.h>
#include "QF/alloc.h"
#include "QF/pr_comp.h"
#include "diagnostic.h"
#include "opcodes.h"
#include "options.h"
#include "pragma.h"
#include "strpool.h"
#include "type.h"
typedef struct pragma_arg_s {
struct pragma_arg_s *next;
const char *arg;
} pragma_arg_t;
static pragma_arg_t *pragma_args_freelist;
static pragma_arg_t *pragma_args;
static pragma_arg_t **pragma_args_tail = &pragma_args;
static void
set_traditional (int traditional)
{
@ -73,20 +84,58 @@ set_traditional (int traditional)
opcode_init (); // reset the opcode table
}
void
pragma (const char *id)
static void
set_bug (pragma_arg_t *args)
{
if (!args) {
warning (0, "missing bug flag");
return;
}
const char *flag = args->arg;
if (!strcmp (flag, "none")) {
options.bug.silent = true;
} else if (!strcmp (flag, "!none")) {
options.bug.silent = false;
} else if (!strcmp (flag, "die")) {
options.bug.promote = true;
} else if (!strcmp (flag, "!die")) {
options.bug.promote = false;
}
if (args->next) {
warning (0, "pragma bug: ignoring extra arguments");
}
}
void
pragma_process ()
{
if (!pragma_args) {
warning (0, "empty pragma");
return;
}
const char *id = pragma_args->arg;
if (!strcmp (id, "traditional")) {
set_traditional (2);
return;
}
if (!strcmp (id, "extended")) {
} else if (!strcmp (id, "extended")) {
set_traditional (1);
return;
}
if (!strcmp (id, "advanced")) {
} else if (!strcmp (id, "advanced")) {
set_traditional (0);
return;
} else if (!strcmp (id, "bug")) {
set_bug (pragma_args->next);
} else {
warning (0, "unknown pragma: '%s'", id);
}
warning (0, "unknown pragma: %s", id);
*pragma_args_tail = pragma_args_freelist;
pragma_args_tail = &pragma_args;
pragma_args = 0;
}
void
pragma_add_arg (const char *id)
{
pragma_arg_t *arg;
ALLOC (16, pragma_arg_t, pragma_args, arg);
arg->arg = save_string (id);
*pragma_args_tail = arg;
pragma_args_tail = &arg->next;
}

View file

@ -93,6 +93,8 @@ B [01]
X [0-9a-fA-F]
ID [a-zA-Z_][a-zA-Z_0-9]*
FLOAT ({D}+|{D}*\.{D}+|{D}+\.{D}*)([eE]{m}?{D}+)?
FLOATf {FLOAT}[fF]
FLOATd {FLOAT}[dD]
INT ({D}+|0[xX]{X}+|0[bB]{B})
RANGE \.\.
ELLIPSIS \.\.\.
@ -136,10 +138,35 @@ STRING \"(\\.|[^"\\])*\"
}
{FLOAT} {
// advanced code defaults to double, but traditional
// and extended code defaults to float
if (options.traditional < 1) {
double d = strtod (yytext, 0);
qc_yylval.expr = new_double_expr (d);
} else {
float f = strtof (yytext, 0);
qc_yylval.expr = new_float_expr (f);
}
return VALUE;
}
{FLOATf} {
float f = strtof (yytext, 0);
qc_yylval.expr = new_float_expr (f);
return VALUE;
}
{FLOATd} {
// advanced code defaults to double, but traditional
// and extended code defaults to float
if (options.traditional < 1) {
double d = strtod (yytext, 0);
qc_yylval.expr = new_double_expr (d);
} else {
float f = strtof (yytext, 0);
qc_yylval.expr = new_float_expr (f);
warning (0, "truncating double constant to float");
}
return VALUE;
}
{ID} {
int tok = keyword_or_id(yytext);
@ -189,6 +216,11 @@ STRING \"(\\.|[^"\\])*\"
return ASX;
}
"%%=" {
qc_yylval.op = MOD;
return ASX;
}
"<<=" {
qc_yylval.op = SHL;
return ASX;
@ -204,6 +236,11 @@ STRING \"(\\.|[^"\\])*\"
return yytext[0];
}
"%%" {
qc_yylval.pointer = 0; // ensure pointer vals are null
return MOD;
}
{ELLIPSIS} return ELLIPSIS;
"<<" return SHL;
@ -245,9 +282,12 @@ STRING \"(\\.|[^"\\])*\"
write_frame_macros (s);
BEGIN (GRAB_OTHER); // ignore rest of line
}
<PRAGMA>{ID} { pragma (yytext); }
<PRAGMA>{ID} { pragma_add_arg (yytext); }
<*>\r*\n {
if (YY_START == PRAGMA) {
pragma_process ();
}
pr.source_line++;
BEGIN (INITIAL);
}
@ -333,6 +373,7 @@ static keyword_t at_keywords[] = {
// be supported (sanely) by v6 progs.
static keyword_t qf_keywords[] = {
{"quaternion", TYPE, &type_quaternion},
{"double", TYPE, &type_double},
{"int", TYPE, &type_integer },
{"unsigned", TYPE, &type_integer },//FIXME
{"function", TYPE, &type_function },

View file

@ -135,7 +135,7 @@ int yylex (void);
%left SHL SHR
%left '+' '-'
%left '*' '/' '%'
%left '*' '/' '%' MOD
%right <op> SIZEOF UNARY INCOP
%left HYPERUNARY
%left '.' '(' '['
@ -1335,6 +1335,7 @@ expr
| expr '|' expr { $$ = binary_expr ('|', $1, $3); }
| expr '^' expr { $$ = binary_expr ('^', $1, $3); }
| expr '%' expr { $$ = binary_expr ('%', $1, $3); }
| expr MOD expr { $$ = binary_expr (MOD, $1, $3); }
;
texpr

View file

@ -418,8 +418,11 @@ finish_link (void)
flags = (QFOD_GLOBAL | QFOD_CONSTANT | QFOD_INITIALIZED | QFOD_NOSAVE);
if (options.code.progsversion != PROG_ID_VERSION) {
pr_int_t param_size = type_size (&type_param);
pr_int_t param_alignment = qfo_log2 (type_param.alignment);
linker_add_def (".param_size", &type_integer, flags,
&param_size);
linker_add_def (".param_alignment", &type_integer, flags,
&param_alignment);
}
if (options.code.debug) {

View file

@ -87,6 +87,8 @@ operand_string (operand_t *op)
case ev_string:
return va ("\"%s\"",
quote_string (op->o.value->v.string_val));
case ev_double:
return va ("%g", op->o.value->v.double_val);
case ev_float:
return va ("%g", op->o.value->v.float_val);
case ev_vector:
@ -159,6 +161,9 @@ print_operand (operand_t *op)
case ev_string:
printf ("\"%s\"", op->o.value->v.string_val);
break;
case ev_double:
printf ("%g", op->o.value->v.double_val);
break;
case ev_float:
printf ("%g", op->o.value->v.float_val);
break;
@ -313,6 +318,15 @@ def_operand (def_t *def, type_t *type)
return op;
}
operand_t *
return_operand (type_t *type)
{
symbol_t *return_symbol;
return_symbol = make_symbol (".return", &type_param, pr.symtab->space,
sc_extern);
return def_operand (return_symbol->s.def, type);
}
operand_t *
value_operand (ex_value_t *value)
{
@ -389,7 +403,7 @@ alias_operand (type_t *type, operand_t *op)
operand_t *aop;
if (type_size (type) != type_size (op->type)) {
internal_error (0, "\naliasing operand with type of diffent size"
internal_error (0, "\naliasing operand with type of different size"
" (%d, %d)", type_size (type), type_size (op->type));
}
aop = new_operand (op_alias);
@ -425,6 +439,7 @@ convert_op (int op)
case '*': return "*";
case '/': return "/";
case '%': return "%";
case MOD: return "%%";
case '&': return "&";
case '|': return "|";
case '^': return "^";
@ -901,6 +916,8 @@ expr_alias (sblock_t *sblock, expr_t *e, operand_t **op)
while (def->alias)
def = def->alias;
*op = def_operand (alias_def (def, type, offset), 0);
} else if (aop->op_type == op_value) {
*op = value_operand (aop->o.value);
} else {
internal_error (e, "invalid alias target: %s: %s",
optype_str (aop->op_type), operand_string (aop));
@ -953,8 +970,7 @@ expr_cast (sblock_t *sblock, expr_t *e, operand_t **op)
statement_t *s;
src_type = get_type (e->e.expr.e1);
if ((src_type->type == ev_integer && type->type == ev_float)
|| (src_type->type == ev_float && type->type == ev_integer)) {
if (is_scalar (src_type) && is_scalar (type)) {
operand_t *src = 0;
sblock = statement_subexpr (sblock, e->e.expr.e1, &src);
*op = temp_operand (e->e.expr.type);
@ -1381,8 +1397,10 @@ statement_uexpr (sblock_t *sblock, expr_t *e)
}
}
s = new_statement (st_func, opcode, e);
if (e->e.expr.e1)
if (e->e.expr.e1) {
s->opa = return_operand (get_type (e->e.expr.e1));
sblock = statement_subexpr (sblock, e->e.expr.e1, &s->opa);
}
sblock_add_statement (sblock, s);
sblock->next = new_sblock ();
sblock = sblock->next;
@ -1661,10 +1679,6 @@ static void
check_final_block (sblock_t *sblock)
{
statement_t *s = 0;
symbol_t *return_symbol = 0;
def_t *return_def = 0;
operand_t *return_operand = 0;
const char *return_opcode = "<RETURN_V>";
if (!sblock)
return;
@ -1685,16 +1699,11 @@ check_final_block (sblock_t *sblock)
sblock->next = new_sblock ();
sblock = sblock->next;
}
s = new_statement (st_func, "<RETURN_V>", 0);
if (options.traditional || options.code.progsversion == PROG_ID_VERSION) {
return_symbol = make_symbol (".return", &type_param, pr.symtab->space,
sc_extern);
return_def = return_symbol->s.def;
return_opcode = "<RETURN>";
s->opcode = save_string ("<RETURN>");
s->opa = return_operand (&type_void);
}
if (return_symbol)
return_operand = def_operand (return_def, &type_void);
s = new_statement (st_func, return_opcode, 0);
s->opa = return_operand;
sblock_add_statement (sblock, s);
}

View file

@ -112,6 +112,7 @@ build_struct (int su, symbol_t *tag, symtab_t *symtab, type_t *type)
{
symbol_t *sym = find_struct (su, tag, type);
symbol_t *s;
int alignment = 1;
symtab->parent = 0; // disconnect struct's symtab from parent scope
@ -130,10 +131,14 @@ build_struct (int su, symbol_t *tag, symtab_t *symtab, type_t *type)
if (size > symtab->size)
symtab->size = size;
}
if (s->type->alignment > alignment) {
alignment = s->type->alignment;
}
}
if (!type)
sym->type = find_type (sym->type); // checks the tag, not the symtab
sym->type->t.symtab = symtab;
sym->type->alignment = alignment;
if (!type && sym->type->type_def->external) //FIXME should not be necessary
sym->type->type_def = qfo_encode_type (sym->type);
return sym;
@ -166,6 +171,7 @@ finish_enum (symbol_t *sym)
enum_type = sym->type = find_type (sym->type);
enum_tab = enum_type->t.symtab;
enum_type->alignment = 1;
for (name = enum_tab->symbols; name; name = name->next) {
name->type = sym->type;

View file

@ -2,6 +2,8 @@
# include "config.h"
#endif
#include <stdlib.h>
#include "class.h"
#include "codespace.h"
#include "diagnostic.h"
@ -12,9 +14,12 @@
#include "expr.h"
#include "function.h"
#include "obj_file.h"
#include "obj_type.h"
#include "options.h"
#include "qfcc.h"
#include "strpool.h"
#include "struct.h"
#include "symtab.h"
#include "type.h"
#include "value.h"
@ -23,11 +28,22 @@ options_t options;
int num_linenos;
pr_lineno_t *linenos;
pr_info_t pr;
type_t type_Class;
type_t type_SEL;
type_t type_id;
__attribute__((const)) string_t ReuseString (const char *str) {return 0;}
void encode_type (struct dstring_s *str, const type_t *type) {}
__attribute__((const)) codespace_t *codespace_new (void) {return 0;}
void codespace_addcode (codespace_t *codespace, struct dstatement_s *code, int size) {}
__attribute__((const)) int function_parms (function_t *f, byte *parm_size) {return 0;}
void def_to_ddef (def_t *def, ddef_t *ddef, int aux) {}
__attribute__((noreturn)) void _internal_error (expr_t *e, const char *file, int line, const char *fmt, ...) {abort();}
__attribute__((const)) expr_t *_warning (expr_t *e, const char *file, int line, const char *fmt, ...) {return 0;}
__attribute__((const)) expr_t *_error (expr_t *e, const char *file, int line, const char *fmt, ...) {return 0;}
__attribute__((const)) symbol_t *make_structure (const char *name, int su, struct_def_t *defs, type_t *type) {return 0;}
__attribute__((const)) symbol_t *symtab_addsymbol (symtab_t *symtab, symbol_t *symbol) {return 0;}
__attribute__((const)) symbol_t *new_symbol_type (const char *name, type_t *type) {return 0;}
__attribute__((const)) def_t *qfo_encode_type (type_t *type) {return 0;}
__attribute__((const)) int obj_types_assignable (const type_t *dst, const type_t *src) {return 0;}
void print_protocollist (struct dstring_s *dstr, protocollist_t *protocollist) {}
int obj_is_id (const type_t *type){return type->type;}
int compare_protocols (protocollist_t *protos1, protocollist_t *protos2){return protos1->count - protos2->count;}

View file

@ -63,30 +63,33 @@
// simple types. function types are dynamically allocated
type_t type_invalid = { ev_invalid, "invalid" };
type_t type_void = { ev_void, "void" };
type_t type_string = { ev_string, "string" };
type_t type_float = { ev_float, "float" };
type_t type_vector = { ev_vector, "vector" };
type_t type_entity = { ev_entity, "entity" };
type_t type_field = {ev_field, "field", ty_none, {{&type_void}} };
type_t type_string = { ev_string, "string", 1 };
type_t type_float = { ev_float, "float", 1 };
type_t type_vector = { ev_vector, "vector", 1 };
type_t type_entity = { ev_entity, "entity", 1 };
type_t type_field = {ev_field, "field", 1, ty_none, {{&type_void}} };
// type_function is a void() function used for state defs
type_t type_function = { ev_func, "function", ty_none, {{&type_void}} };
type_t type_pointer = { ev_pointer, "pointer", ty_none, {{&type_void}} };
type_t type_quaternion = { ev_quat, "quaternion" };
type_t type_integer = { ev_integer, "int" };
type_t type_uinteger = { ev_uinteger, "uint" };
type_t type_short = { ev_short, "short" };
type_t type_function = { ev_func, "function", 1, ty_none, {{&type_void}} };
type_t type_pointer = { ev_pointer, "pointer", 1, ty_none, {{&type_void}} };
type_t type_quaternion = { ev_quat, "quaternion", 1 };
type_t type_integer = { ev_integer, "int", 1 };
type_t type_uinteger = { ev_uinteger, "uint", 1 };
type_t type_short = { ev_short, "short", 1 };
type_t type_double = { ev_double, "double", 2 };
type_t *type_nil;
type_t *type_default;
// these will be built up further
type_t type_va_list = { ev_invalid, 0, ty_struct };
type_t type_param = { ev_invalid, 0, ty_struct };
type_t type_zero = { ev_invalid, 0, ty_struct };
type_t type_type_encodings = { ev_invalid, "@type_encodings", ty_struct };
type_t type_va_list = { ev_invalid, 0, 0, ty_struct };
type_t type_param = { ev_invalid, 0, 0, ty_struct };
type_t type_zero = { ev_invalid, 0, 0, ty_struct };
type_t type_type_encodings = { ev_invalid, "@type_encodings", 0,
ty_struct };
type_t type_floatfield = { ev_field, ".float", ty_none, {{&type_float}} };
type_t type_floatfield = { ev_field, ".float", 1, ty_none,
{{&type_float}} };
type_t *ev_types[ev_type_count] = {
&type_void,
@ -101,6 +104,7 @@ type_t *ev_types[ev_type_count] = {
&type_integer,
&type_uinteger,
&type_short,
&type_double,
&type_invalid,
};
@ -180,6 +184,7 @@ free_type (type_t *type)
case ev_integer:
case ev_uinteger:
case ev_short:
case ev_double:
break;
case ev_field:
case ev_pointer:
@ -214,19 +219,24 @@ append_type (type_t *type, type_t *new)
case ev_integer:
case ev_uinteger:
case ev_short:
case ev_double:
internal_error (0, "append to basic type");
case ev_field:
case ev_pointer:
t = &(*t)->t.fldptr.type;
type->alignment = 1;
break;
case ev_func:
t = &(*t)->t.func.type;
type->alignment = 1;
break;
case ev_invalid:
if ((*t)->meta == ty_array)
if ((*t)->meta == ty_array) {
t = &(*t)->t.array.type;
else
type->alignment = new->alignment;
} else {
internal_error (0, "append to object type");
}
break;
}
}
@ -360,6 +370,7 @@ field_type (type_t *aux)
else
new = new_type ();
new->type = ev_field;
new->alignment = 1;
new->t.fldptr.type = aux;
if (aux)
new = find_type (new);
@ -377,6 +388,7 @@ pointer_type (type_t *aux)
else
new = new_type ();
new->type = ev_pointer;
new->alignment = 1;
new->t.fldptr.type = aux;
if (aux)
new = find_type (new);
@ -394,6 +406,9 @@ array_type (type_t *aux, int size)
else
new = new_type ();
new->type = ev_invalid;
if (aux) {
new->alignment = aux->alignment;
}
new->meta = ty_array;
new->t.array.type = aux;
new->t.array.size = size;
@ -413,6 +428,9 @@ based_array_type (type_t *aux, int base, int top)
else
new = new_type ();
new->type = ev_invalid;
if (aux) {
new->alignment = aux->alignment;
}
new->meta = ty_array;
new->t.array.type = aux;
new->t.array.base = base;
@ -582,6 +600,9 @@ encode_type (dstring_t *encoding, const type_t *type)
case ev_string:
dasprintf (encoding, "*");
break;
case ev_double:
dasprintf (encoding, "d");
break;
case ev_float:
dasprintf (encoding, "f");
break;
@ -685,6 +706,12 @@ is_integral (const type_t *type)
return is_enum (type);
}
int
is_double (const type_t *type)
{
return type->type == ev_double;
}
int
is_float (const type_t *type)
{
@ -694,7 +721,7 @@ is_float (const type_t *type)
int
is_scalar (const type_t *type)
{
return is_float (type) || is_integral (type);
return is_float (type) || is_integral (type) || is_double (type);
}
int
@ -830,6 +857,7 @@ type_size (const type_t *type)
case ev_integer:
case ev_uinteger:
case ev_short:
case ev_double:
case ev_type_count:
return pr_type_size[type->type];
case ev_invalid:
@ -869,6 +897,7 @@ init_types (void)
{
static struct_def_t zero_struct[] = {
{"string_val", &type_string},
{"double_val", &type_double},
{"float_val", &type_float},
{"entity_val", &type_entity},
{"field_val", &type_field},
@ -895,6 +924,7 @@ init_types (void)
{"integer_val", &type_integer},
{"uinteger_val", &type_uinteger},
{"quaternion_val", &type_quaternion},
{"double_val", &type_double},
{0, 0}
};
static struct_def_t vector_struct[] = {
@ -982,6 +1012,7 @@ chain_initial_types (void)
chain_type (&type_integer);
chain_type (&type_uinteger);
chain_type (&type_short);
chain_type (&type_double);
}
chain_type (&type_param);

View file

@ -69,6 +69,7 @@ typedef struct {
ex_pointer_t pointer;
float quaternion_val[4];
int integer_val;
double double_val;
} i;
} immediate_t;
@ -132,6 +133,16 @@ new_string_val (const char *string_val)
return find_value (&val);
}
ex_value_t *
new_double_val (double double_val)
{
ex_value_t val;
memset (&val, 0, sizeof (val));
set_val_type (&val, &type_double);
val.v.double_val = double_val;
return find_value (&val);
}
ex_value_t *
new_float_val (float float_val)
{
@ -265,6 +276,7 @@ static hashtab_t *func_imm_defs;
static hashtab_t *pointer_imm_defs;
static hashtab_t *quaternion_imm_defs;
static hashtab_t *integer_imm_defs;
static hashtab_t *double_imm_defs;
static void
imm_free (void *_imm, void *unused)
@ -296,6 +308,8 @@ imm_get_hash (const void *_imm, void *_tab)
} else if (tab == &quaternion_imm_defs) {
return Hash_Buffer (&imm->i.quaternion_val,
sizeof (&imm->i.quaternion_val));
} else if (tab == &double_imm_defs) {
return Hash_Buffer (&imm->i.double_val, sizeof (&imm->i.double_val));
} else if (tab == &integer_imm_defs) {
return imm->i.integer_val;
} else {
@ -330,6 +344,8 @@ imm_compare (const void *_imm1, const void *_imm2, void *_tab)
sizeof (imm1->i.pointer));
} else if (tab == &quaternion_imm_defs) {
return QuatCompare (imm1->i.quaternion_val, imm2->i.quaternion_val);
} else if (tab == &double_imm_defs) {
return imm1->i.double_val == imm2->i.double_val;
} else if (tab == &integer_imm_defs) {
return imm1->i.integer_val == imm2->i.integer_val;
} else {
@ -352,6 +368,24 @@ value_as_float (ex_value_t *value)
return value->v.integer_val;
if (value->lltype == ev_short)
return value->v.short_val;
if (value->lltype == ev_double)
return value->v.double_val;
if (value->lltype == ev_float)
return value->v.float_val;
return 0;
}
static double
value_as_double (ex_value_t *value)
{
if (value->lltype == ev_uinteger)
return value->v.uinteger_val;
if (value->lltype == ev_integer)
return value->v.integer_val;
if (value->lltype == ev_short)
return value->v.short_val;
if (value->lltype == ev_double)
return value->v.double_val;
if (value->lltype == ev_float)
return value->v.float_val;
return 0;
@ -366,6 +400,8 @@ value_as_int (ex_value_t *value)
return value->v.integer_val;
if (value->lltype == ev_short)
return value->v.short_val;
if (value->lltype == ev_double)
return value->v.double_val;
if (value->lltype == ev_float)
return value->v.float_val;
return 0;
@ -380,6 +416,8 @@ value_as_uint (ex_value_t *value)
return value->v.integer_val;
if (value->lltype == ev_short)
return value->v.short_val;
if (value->lltype == ev_double)
return value->v.double_val;
if (value->lltype == ev_float)
return value->v.float_val;
return 0;
@ -395,6 +433,9 @@ convert_value (ex_value_t *value, type_t *type)
if (is_float (type)) {
float val = value_as_float (value);
return new_float_val (val);
} else if (is_double (type)) {
double val = value_as_double (value);
return new_double_val (val);
} else if (type->type == ev_short) {
int val = value_as_int (value);
return new_short_val (val);
@ -494,6 +535,10 @@ emit_value (ex_value_t *value, def_t *def)
tab = quaternion_imm_defs;
type = &type_quaternion;
break;
case ev_double:
tab = double_imm_defs;
type = &type_double;
break;
default:
internal_error (0, 0);
}
@ -591,6 +636,7 @@ clear_immediates (void)
Hash_FlushTable (pointer_imm_defs);
Hash_FlushTable (quaternion_imm_defs);
Hash_FlushTable (integer_imm_defs);
Hash_FlushTable (double_imm_defs);
} else {
value_table = Hash_NewTable (16381, 0, 0, 0);
Hash_SetHashCompare (value_table, value_get_hash, value_compare);
@ -624,6 +670,10 @@ clear_immediates (void)
integer_imm_defs =
Hash_NewTable (16381, 0, imm_free, &integer_imm_defs);
Hash_SetHashCompare (integer_imm_defs, imm_get_hash, imm_compare);
double_imm_defs =
Hash_NewTable (16381, 0, imm_free, &double_imm_defs);
Hash_SetHashCompare (double_imm_defs, imm_get_hash, imm_compare);
}
def = make_symbol (".zero", &type_zero, 0, sc_extern)->s.def;

View file

@ -29,15 +29,19 @@ test_bins=\
fail_bins=
test_progs_dat=\
address-cast.dat \
alignment.dat \
chewed-alias.dat \
chewed-return.dat \
comma-expr.dat \
deadbool.dat \
double.dat \
enum.dat \
fordecl.dat \
func-expr.dat \
func-static.dat \
infloop.dat \
ivar-struct-return.dat \
modulo.dat \
paramret.dat \
quaternion.dat \
@ -57,11 +61,31 @@ test_progs_dat=\
fail_progs_dat=
test_build_errors=\
double-demote-float.r \
double-demote-float-ainit.r \
double-demote-float-ginit.r \
double-demote-float-linit.r \
double-demote-int.r \
double-demote-int-ainit.r \
double-demote-int-ginit.r \
double-demote-int-linit.r \
double-int-compare.r \
double-float-compare.r
fail_build_errors=
test_defspace_src=\
tw-defspace.c tw-diagnostic.c tw-strpool.c
TESTS=$(test_bins) $(test_progs_dat:.dat=.run)
XFAIL_TESTS=$(fail_bins) $(fail_progs_dat:.dat=.run)
TESTS=\
$(test_bins) \
$(test_progs_dat:.dat=.run) \
$(test_build_errors:.r=.run)
XFAIL_TESTS=\
$(fail_bins) \
$(fail_progs_dat:.dat=.run) \
$(fail_build_errors:.r=.run)
check_PROGRAMS=test-harness $(test_progs_dat) $(test_bins)
@ -75,6 +99,24 @@ test_harness_DEPENDENCIES= $(QFCC_TEST_DEPS)
r_depfiles_remade=
address_cast_dat_SOURCES=address-cast.r
address_cast_obj=$(address_cast_dat_SOURCES:.r=.qfo)
address-cast.dat$(EXEEXT): $(address_cast_obj) $(QFCC_DEP)
$(QFCC) $(QCFLAGS) -o $@ $(address_cast_obj)
address-cast.run: Makefile build-run
$(srcdir)/build-run $@
include ./$(DEPDIR)/address-cast.Qo # am--include-marker
r_depfiles_remade += ./$(DEPDIR)/address-cast.Qo
alignment_dat_SOURCES=alignment.r
alignment_obj=$(alignment_dat_SOURCES:.r=.qfo)
alignment.dat$(EXEEXT): $(alignment_obj) $(QFCC_DEP)
$(QFCC) $(QCFLAGS) -o $@ $(alignment_obj)
alignment.run: Makefile build-run
$(srcdir)/build-run $@
include ./$(DEPDIR)/alignment.Qo # am--include-marker
r_depfiles_remade += ./$(DEPDIR)/alignment.Qo
chewed_alias_dat_SOURCES=chewed-alias.r
chewed_alias_obj=$(chewed_alias_dat_SOURCES:.r=.qfo)
chewed-alias.dat$(EXEEXT): $(chewed_alias_obj) $(QFCC_DEP)
@ -111,6 +153,45 @@ deadbool.run: Makefile build-run
include ./$(DEPDIR)/deadbool.Qo # am--include-marker
r_depfiles_remade += ./$(DEPDIR)/deadbool.Qo
double_dat_SOURCES=double.r
double_obj=$(double_dat_SOURCES:.r=.qfo)
double.dat$(EXEEXT): $(double_obj) $(QFCC_DEP)
$(QFCC) $(QCFLAGS) -o $@ $(double_obj)
double.run: Makefile build-run
$(srcdir)/build-run $@
include ./$(DEPDIR)/double.Qo # am--include-marker
r_depfiles_remade += ./$(DEPDIR)/double.Qo
double-demote-int.run$(EXEEXT): double-demote-int.r Makefile build-compile-fail-run
$(srcdir)/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $<
double-demote-float.run$(EXEEXT): double-demote-float.r Makefile build-compile-fail-run
$(srcdir)/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $<
double-demote-int-ainit.run$(EXEEXT): double-demote-int-ainit.r Makefile build-compile-fail-run
$(srcdir)/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $<
double-demote-float-ainit.run$(EXEEXT): double-demote-float-ainit.r Makefile build-compile-fail-run
$(srcdir)/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $<
double-demote-int-ginit.run$(EXEEXT): double-demote-int-ginit.r Makefile build-compile-fail-run
$(srcdir)/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $<
double-demote-float-ginit.run$(EXEEXT): double-demote-float-ginit.r Makefile build-compile-fail-run
$(srcdir)/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $<
double-demote-int-linit.run$(EXEEXT): double-demote-int-linit.r Makefile build-compile-fail-run
$(srcdir)/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $<
double-demote-float-linit.run$(EXEEXT): double-demote-float-linit.r Makefile build-compile-fail-run
$(srcdir)/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $<
double-int-compare.run$(EXEEXT): double-int-compare.r Makefile build-compile-fail-run
$(srcdir)/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $<
double-float-compare.run$(EXEEXT): double-float-compare.r Makefile build-compile-fail-run
$(srcdir)/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $<
enum_dat_SOURCES=enum.r
enum_obj=$(enum_dat_SOURCES:.r=.qfo)
enum.dat$(EXEEXT): $(enum_obj) $(QFCC_DEP)
@ -156,6 +237,15 @@ infloop.run: Makefile build-run
include ./$(DEPDIR)/infloop.Qo # am--include-marker
r_depfiles_remade += ./$(DEPDIR)/infloop.Qo
ivar_struct_return_dat_SOURCES=ivar-struct-return.r
ivar_struct_return_obj=$(ivar_struct_return_dat_SOURCES:.r=.qfo)
ivar-struct-return.dat$(EXEEXT): $(ivar_struct_return_obj) $(QFCC_DEP)
$(QFCC) $(QCFLAGS) -o $@ $(ivar_struct_return_obj)
ivar-struct-return.run: Makefile build-run
$(srcdir)/build-run $@
include ./$(DEPDIR)/ivar-struct-return.Qo # am--include-marker
r_depfiles_remade += ./$(DEPDIR)/ivar-struct-return.Qo
modulo_dat_SOURCES=modulo.r
modulo_obj=$(modulo_dat_SOURCES:.r=.qfo)
modulo.dat$(EXEEXT): $(modulo_obj) $(QFCC_DEP)

View file

@ -0,0 +1,21 @@
int a;
double b;
int c = (int) &b;
double d;
void printf (string fmt, ...) = #0;
int main()
{
int di = (int) &d;
int fail = 0;
if (!c) {
printf ("global init address cast fail: %d\n", c);
fail |= 1;
}
if (!di) {
printf ("local init address cast fail: %d\n", di);
fail |= 1;
}
return fail;
}

View file

@ -0,0 +1,36 @@
int a;
double b;
int c;
double d;
void printf (string fmt, ...) = #0;
int main()
{
int fail = 0;
void *ap = &a;
void *bp = &b;
void *cp = &c;
void *dp = &d;
int aa = (int) ap;
int ba = (int) bp;
int ca = (int) cp;
int da = (int) dp;
if (ba & 1) {
printf ("double b is not aligned: %d\n", ba);
fail |= 1;
}
if (da & 1) {
printf ("double d is not aligned: %d\n", da);
fail |= 1;
}
if (ca - aa != 1) {
printf ("int c (%d) is not adjacant to int a (%d)\n", ca, aa);
fail |= 1;
}
if (ba <= ca) {
printf ("double b does not come after int c: %d %d\n", ba, ca);
fail |= 1;
}
return fail;
}

View file

@ -0,0 +1,15 @@
#! /bin/sh
script=$1
shift
cat > $script <<EOF
#! /bin/sh
# compile must fail
$@
if test \$? != 1; then
exit 1
fi
exit 0
EOF
chmod +x $script

View file

@ -9,7 +9,7 @@ void foo (void)
return;
if (!time) {
ent = spawn ();
ent.f = time + 0.1;
ent.f = time + 0.1f;
}
}

View file

@ -0,0 +1,6 @@
double a;
int b[] = {1.0d};
int main ()
{
return 1; // test fails if compile succeeds
}

View file

@ -0,0 +1,6 @@
double a;
float b = 1.0d;
int main ()
{
return 1; // test fails if compile succeeds
}

View file

@ -0,0 +1,6 @@
double a;
int main ()
{
float b = a;
return 1; // test fails if compile succeeds
}

View file

@ -0,0 +1,7 @@
double a;
float b;
int main ()
{
b = a;
return 1; // test fails if compile succeeds
}

View file

@ -0,0 +1,6 @@
double a;
int b[] = {1.0d};
int main ()
{
return 1; // test fails if compile succeeds
}

View file

@ -0,0 +1,6 @@
double a;
int b = 1.0d;
int main ()
{
return 1; // test fails if compile succeeds
}

View file

@ -0,0 +1,6 @@
double a;
int main ()
{
int b = a;
return 1; // test fails if compile succeeds
}

View file

@ -0,0 +1,7 @@
double a;
int b;
int main ()
{
b = a;
return 1; // test fails if compile succeeds
}

View file

@ -0,0 +1,7 @@
double a;
float b;
int main ()
{
int x = a == b;
return 1; // test fails if compile succeeds
}

View file

@ -0,0 +1,7 @@
double a;
int b;
int main ()
{
int x = a == b;
return 1; // test fails if compile succeeds
}

106
tools/qfcc/test/double.r Normal file
View file

@ -0,0 +1,106 @@
void printf (string fmt, ...) = #0;
# define M_PI 3.14159265358979323846
union {
double d;
int i[2];
} type_pun;
int
test_format ()
{
int fail = 0;
type_pun.d = M_PI;
printf ("%g %08x%08x\n", type_pun.d, type_pun.i[1], type_pun.i[0]);
// this will fail on big-endian systems
fail = type_pun.i[0] != 0x54442d18 || type_pun.i[1] != 0x400921fb;
return fail;
}
int
test_constant ()
{
int fail = 0;
double a, b, c, d, e;
a = 1;
b = 2.0;
c = 3.2f;
d = 3.2d;
e = 3.2;
printf ("%.17g %.17g %.17g %.17g %.17g\n", a, b, c, d, e);
// this will fail on big-endian systems
fail |= c == d; // 3.2 is not exactly representable, so must be different
fail |= c == e; // 3.2 is not exactly representable, so must be different
fail |= d != e; // 3.2d and 3.2 are both double, so must be the same
return fail;
}
double less = 3;
double greater_equal = 3;
double less_equal = 5;
double greater = 5;
int
test_copare ()
{
int fail = 0;
fail |= !(less < greater);
fail |= (less > greater);
fail |= !(less != greater);
fail |= (less == greater);
fail |= !(less <= greater);
fail |= (less >= greater);
fail |= (less_equal < greater);
fail |= (less_equal > greater);
fail |= !(less_equal == greater);
fail |= (less_equal != greater);
fail |= !(less_equal <= greater);
fail |= !(less_equal >= greater);
fail |= (greater < less);
fail |= !(greater > less);
fail |= !(greater != less);
fail |= (greater == less);
fail |= (greater <= less);
fail |= !(greater >= less);
fail |= (greater_equal < less);
fail |= (greater_equal > less);
fail |= !(greater_equal == less);
fail |= (greater_equal != less);
fail |= !(greater_equal <= less);
fail |= !(greater_equal >= less);
return fail;
}
int
test_ops ()
{
int fail = 0;
double a = 6.25, b = 2.375;
double c;
c = a + b;
fail |= c != 8.625;
c = a - b;
fail |= c != 3.875;
c = a * b;
fail |= c != 14.84375;
c = a / b;
fail |= c != 50d/19d;
c = a % b;
fail |= c != 1.5;
return fail;
}
int
main ()
{
int fail = 0;
fail |= test_format ();
fail |= test_constant ();
fail |= test_ops ();
return fail;
}

View file

@ -0,0 +1,27 @@
#pragma bug die
struct Point {
int x;
int y;
};
typedef struct Point Point;
@interface Object
{
int foo;
Point origin;
}
-(Point) origin;
@end
@implementation Object
-(Point) origin
{
return origin;
}
@end
void __obj_exec_class (struct obj_module *msg) = #0;
int main()
{
return 0; // to survive and prevail
}

View file

@ -1,11 +1,34 @@
#pragma traditional
void printf (string ftm, ...) = #0;
void (...) printf = #0;
float snafu (float a, float b)
{
float c = a % b;
return c;
}
int imodulo (int a, int b)
{
return a %% b;
}
float fmodulo (float a, float b)
{
return a %% b;
}
double dmodulo (double a, double b)
{
return a %% b;
}
#pragma traditional
float foo (float a, float b)
{
float c = a % b;
return c;
}
#pragma advanced
float bar (float a, float b)
{
float c;
@ -15,14 +38,35 @@ float bar (float a, float b)
return c;
}
#pragma traditional
float baz (float a, float b)
{
float c = (a + b) % (a - b);
return c;
}
#pragma advanced
float test (string name, float (func)(float a, float b),
float a, float b, float c)
@overload int
test (string name, string op, int (func)(int a, int b), int a, int b, int c)
{
int ret;
ret = func (a, b);
if (ret != c) {
if (func == baz)
printf ("%s: (%d + %d) %% (%d - %d): %d != %d\n",
name, a, b, a, b, ret, c);
else
printf ("%s: %d %s %d: %d != %d\n",
name, a, op, b, ret, c);
return 1;
}
return 0;
}
@overload int
test (string name, string op, float (func)(float a, float b),
float a, float b, float c)
{
float ret;
@ -32,8 +76,27 @@ float test (string name, float (func)(float a, float b),
printf ("%s: (%g + %g) %% (%g - %g): %g != %g\n",
name, a, b, a, b, ret, c);
else
printf ("%s: %g %% %g: %g != %g\n",
name, a, b, ret, c);
printf ("%s: %g %s %g: %g != %g\n",
name, a, op, b, ret, c);
return 1;
}
return 0;
}
@overload int
test (string name, string op, double (func)(double a, double b),
double a, double b, double c)
{
double ret;
ret = func (a, b);
if (ret != c) {
if (func == baz)
printf ("%s: (%g + %g) %% (%g - %g): %g != %g\n",
name, a, b, a, b, ret, c);
else
printf ("%s: %g %s %g: %g != %g\n",
name, a, op, b, ret, c);
return 1;
}
return 0;
@ -42,20 +105,56 @@ float test (string name, float (func)(float a, float b),
float main (void)
{
float res = 0;
res |= test ("foo", foo, 5, 3, 2);
res |= test ("bar", bar, 5, 3, 2);
res |= test ("baz", baz, 5, 3, 0);
res |= test ("foo", "%", foo, 5, 3, 2);
res |= test ("bar", "%", bar, 5, 3, 2);
res |= test ("baz", "%", baz, 5, 3, 0);
res |= test ("snafu", "%", snafu, 5, 3, 2);
res |= test ("foo", foo, -5, 3, -2);
res |= test ("bar", bar, -5, 3, -2);
res |= test ("baz", baz, -5, 3, -2);
res |= test ("foo", "%", foo, -5, 3, -2);
res |= test ("bar", "%", bar, -5, 3, -2);
res |= test ("baz", "%", baz, -5, 3, -2);
res |= test ("snafu", "%", snafu, -5, 3, -2);
res |= test ("foo", foo, 5, -3, 2);
res |= test ("bar", bar, 5, -3, 2);
res |= test ("baz", baz, 5, -3, 2);
res |= test ("foo", "%", foo, 5, -3, 2);
res |= test ("bar", "%", bar, 5, -3, 2);
res |= test ("baz", "%", baz, 5, -3, 2);
res |= test ("snafu", "%", snafu, 5, -3, 2);
res |= test ("foo", foo, -5, -3, -2);
res |= test ("bar", bar, -5, -3, -2);
res |= test ("baz", baz, -5, -3, 0);
res |= test ("foo", "%", foo, -5, -3, -2);
res |= test ("bar", "%", bar, -5, -3, -2);
res |= test ("baz", "%", baz, -5, -3, 0);
res |= test ("snafu", "%", snafu, -5, -3, -2);
res |= test ("foo", "%", foo, 5, 3.5, 1.5);
res |= test ("foo", "%", foo, -5, 3.5, -1.5);
res |= test ("snafu", "%", snafu, 5, 3.5, 1.5);
res |= test ("snafu", "%", snafu, -5, 3.5, -1.5);
res |= test ("int modulo", "%%", imodulo, 5, 3, 2);
res |= test ("int modulo", "%%", imodulo, -5, 3, 1);
res |= test ("int modulo", "%%", imodulo, 5, -3, -1);
res |= test ("int modulo", "%%", imodulo, -5, -3, -2);
res |= test ("int modulo", "%%", imodulo, 6, 3, 0);
res |= test ("int modulo", "%%", imodulo, -6, 3, 0);
res |= test ("int modulo", "%%", imodulo, 6, -3, 0);
res |= test ("int modulo", "%%", imodulo, -6, -3, 0);
res |= test ("float modulo", "%%", fmodulo, 5, 3, 2);
res |= test ("float modulo", "%%", fmodulo, -5, 3, 1);
res |= test ("float modulo", "%%", fmodulo, 5, -3, -1);
res |= test ("float modulo", "%%", fmodulo, -5, -3, -2);
res |= test ("float modulo", "%%", fmodulo, 6, 3, 0);
res |= test ("float modulo", "%%", fmodulo, -6, 3, 0);
res |= test ("float modulo", "%%", fmodulo, 6, -3, 0);
res |= test ("float modulo", "%%", fmodulo, -6, -3, 0);
res |= test ("double modulo", "%%", dmodulo, 5, 3, 2);
res |= test ("double modulo", "%%", dmodulo, -5, 3, 1);
res |= test ("double modulo", "%%", dmodulo, 5, -3, -1);
res |= test ("double modulo", "%%", dmodulo, -5, -3, -2);
res |= test ("double modulo", "%%", dmodulo, 6, 3, 0);
res |= test ("double modulo", "%%", dmodulo, -6, 3, 0);
res |= test ("double modulo", "%%", dmodulo, 6, -3, 0);
res |= test ("double modulo", "%%", dmodulo, -6, -3, 0);
return res;
}

View file

@ -13,7 +13,7 @@ state0 (void)
[$frame1, state1]
{
if (self.frame != $frame1 || self.think != state1
|| self.nextthink != 0.1) {
|| self.nextthink != 0.1f) {
printf ("state0: %g %x %g\n", self.frame, self.think, self.nextthink);
exit (1);
}
@ -21,10 +21,10 @@ state0 (void)
void
state1 (void)
[$frame2, state2, 0.2]
[$frame2, state2, 0.2f]
{
if (self.frame != $frame2 || self.think != state2
|| self.nextthink != 0.2) {
|| self.nextthink != 0.2f) {
printf ("state0: %g %x %g\n", self.frame, self.think, self.nextthink);
exit (1);
}
@ -32,10 +32,10 @@ state1 (void)
void
state2 (void)
[$frame0, state0, 0.5]
[$frame0, state0, 0.5f]
{
if (self.frame != $frame0 || self.think != state0
|| self.nextthink != 0.5) {
|| self.nextthink != 0.5f) {
printf ("state0: %g %x %g\n", self.frame, self.think, self.nextthink);
exit (1);
}

View file

@ -135,9 +135,13 @@ init_qf (void)
Memory_Init (malloc (1024 * 1024), 1024 * 1024);
Cvar_Get ("pr_debug", "2", 0, 0, 0);
cvar_t *debug = Cvar_Get ("pr_debug", "2", 0, 0, 0);
Cvar_Get ("pr_boundscheck", "2", 0, 0, 0);
if (options.trace > 1) {
Cvar_SetValue (debug, 4);
}
pr.edicts = &edicts;
pr.num_edicts = &num_edicts;
pr.reserved_edicts = &reserved_edicts;
@ -207,7 +211,7 @@ parse_options (int argc, char **argv)
options.flote = 1;
break;
case 't':
options.trace = 1;
options.trace++;
break;
case 'h':
usage (0);

View file

@ -1,6 +1,6 @@
void printf (string fmt, ...) = #0;
float (string s) stof = #0;
float (float x) sqrt = #0;
@overload float (float x) sqrt = #0;
float
heron (float a, float b, float c)