// this file is shared by the execution and compiler

/*i'm part way through making this work
I've given up now that I can't work out a way to load pointers.
Setting them should be fine.
*/
#ifndef __PR_COMP_H__
#define __PR_COMP_H__


typedef int dstring_t;
#define QCC_string_t dstring_t

//typedef enum {ev_void, ev_string, ev_float, ev_vector, ev_entity, ev_field, ev_function, ev_pointer, ev_integer, ev_struct, ev_union} etype_t;
//				0			1		2			3			4		5			6				7			8		9			10

#define	OFS_NULL		0
#define	OFS_RETURN		1
#define	OFS_PARM0		4		// leave 3 ofs for each parm to hold vectors
#define	OFS_PARM1		7
#define	OFS_PARM2		10
#define	OFS_PARM3		13
#define	OFS_PARM4		16
#define	OFS_PARM5		19
#define	OFS_PARM6		22
#define	OFS_PARM7		25
#define	RESERVED_OFS	28


enum qcop_e {
	OP_DONE,	//0
	OP_MUL_F,
	OP_MUL_V,
	OP_MUL_FV,
	OP_MUL_VF,
	OP_DIV_F,
	OP_ADD_F,
	OP_ADD_V,
	OP_SUB_F,
	OP_SUB_V,
	
	OP_EQ_F,	//10
	OP_EQ_V,
	OP_EQ_S,
	OP_EQ_E,
	OP_EQ_FNC,
	
	OP_NE_F,
	OP_NE_V,
	OP_NE_S,
	OP_NE_E,
	OP_NE_FNC,
	
	OP_LE_F,	//20
	OP_GE_F,
	OP_LT_F,
	OP_GT_F,

	OP_LOAD_F,
	OP_LOAD_V,
	OP_LOAD_S,
	OP_LOAD_ENT,
	OP_LOAD_FLD,
	OP_LOAD_FNC,

	OP_ADDRESS,	//30

	OP_STORE_F,
	OP_STORE_V,
	OP_STORE_S,
	OP_STORE_ENT,
	OP_STORE_FLD,
	OP_STORE_FNC,

	OP_STOREP_F,
	OP_STOREP_V,
	OP_STOREP_S,
	OP_STOREP_ENT,	//40
	OP_STOREP_FLD,
	OP_STOREP_FNC,

	OP_RETURN,
	OP_NOT_F,
	OP_NOT_V,
	OP_NOT_S,
	OP_NOT_ENT,
	OP_NOT_FNC,
	OP_IF_I,
	OP_IFNOT_I,		//50
	OP_CALL0,		//careful... hexen2 and q1 have different calling conventions
	OP_CALL1,		//remap hexen2 calls to OP_CALL2H
	OP_CALL2,
	OP_CALL3,
	OP_CALL4,
	OP_CALL5,
	OP_CALL6,
	OP_CALL7,
	OP_CALL8,
	OP_STATE,		//60
	OP_GOTO,
	OP_AND_F,
	OP_OR_F,
	
	OP_BITAND_F,
	OP_BITOR_F,

	
	//these following ones are Hexen 2 constants.
	
	OP_MULSTORE_F,
	OP_MULSTORE_VF,
	OP_MULSTOREP_F,
	OP_MULSTOREP_VF,

	OP_DIVSTORE_F,	//70
	OP_DIVSTOREP_F,

	OP_ADDSTORE_F,
	OP_ADDSTORE_V,
	OP_ADDSTOREP_F,
	OP_ADDSTOREP_V,

	OP_SUBSTORE_F,
	OP_SUBSTORE_V,
	OP_SUBSTOREP_F,
	OP_SUBSTOREP_V,

	OP_FETCH_GBL_F,	//80
	OP_FETCH_GBL_V,
	OP_FETCH_GBL_S,
	OP_FETCH_GBL_E,
	OP_FETCH_GBL_FNC,

	OP_CSTATE,
	OP_CWSTATE,

	OP_THINKTIME,

	OP_BITSET,
	OP_BITSETP,
	OP_BITCLR,		//90
	OP_BITCLRP,

	OP_RAND0,
	OP_RAND1,
	OP_RAND2,
	OP_RANDV0,
	OP_RANDV1,
	OP_RANDV2,

	OP_SWITCH_F,
	OP_SWITCH_V,
	OP_SWITCH_S,	//100
	OP_SWITCH_E,
	OP_SWITCH_FNC,

	OP_CASE,
	OP_CASERANGE,





	//the rest are added
	//mostly they are various different ways of adding two vars with conversions.

	OP_CALL1H,
	OP_CALL2H,
	OP_CALL3H,
	OP_CALL4H,
	OP_CALL5H,
	OP_CALL6H,		//110
	OP_CALL7H,
	OP_CALL8H,


	OP_STORE_I,
	OP_STORE_IF,
	OP_STORE_FI,
	
	OP_ADD_I,
	OP_ADD_FI,
	OP_ADD_IF,
  
	OP_SUB_I,
	OP_SUB_FI,		//120
	OP_SUB_IF,

	OP_CONV_ITOF,
	OP_CONV_FTOI,
	OP_CP_ITOF,
	OP_CP_FTOI,
	OP_LOAD_I,
	OP_STOREP_I,
	OP_STOREP_IF,
	OP_STOREP_FI,

	OP_BITAND_I,	//130
	OP_BITOR_I,

	OP_MUL_I,
	OP_DIV_I,
	OP_EQ_I,
	OP_NE_I,

	OP_IFNOT_S,
	OP_IF_S,

	OP_NOT_I,

	OP_DIV_VF,

	OP_XOR_I,		//140
	OP_RSHIFT_I,
	OP_LSHIFT_I,

	OP_GLOBALADDRESS,
	OP_POINTER_ADD,	//32 bit pointers

	OP_LOADA_F,
	OP_LOADA_V,	
	OP_LOADA_S,
	OP_LOADA_ENT,
	OP_LOADA_FLD,
	OP_LOADA_FNC,	//150
	OP_LOADA_I,

	OP_STORE_P,	//152... erm.. wait...
	OP_LOAD_P,

	OP_LOADP_F,
	OP_LOADP_V,	
	OP_LOADP_S,
	OP_LOADP_ENT,
	OP_LOADP_FLD,
	OP_LOADP_FNC,
	OP_LOADP_I,		//160

	OP_LE_I,
	OP_GE_I,
	OP_LT_I,
	OP_GT_I,

	OP_LE_IF,
	OP_GE_IF,
	OP_LT_IF,
	OP_GT_IF,

	OP_LE_FI,
	OP_GE_FI,		//170
	OP_LT_FI,
	OP_GT_FI,

	OP_EQ_IF,
	OP_EQ_FI,

	//-------------------------------------
	//string manipulation.
	OP_ADD_SF,	//(char*)c = (char*)a + (float)b    add_fi->i
	OP_SUB_S,	//(float)c = (char*)a - (char*)b    sub_ii->f
	OP_STOREP_C,//(float)c = *(char*)b = (float)a
	OP_LOADP_C,	//(float)c = *(char*)
	//-------------------------------------


	OP_MUL_IF,
	OP_MUL_FI,		//180
	OP_MUL_VI,
	OP_MUL_IV,
	OP_DIV_IF,
	OP_DIV_FI,
	OP_BITAND_IF,
	OP_BITOR_IF,
	OP_BITAND_FI,
	OP_BITOR_FI,
	OP_AND_I,
	OP_OR_I,		//190
	OP_AND_IF,
	OP_OR_IF,
	OP_AND_FI,
	OP_OR_FI,
	OP_NE_IF,
	OP_NE_FI,

//erm... FTEQCC doesn't make use of these... These are for DP.
	OP_GSTOREP_I,
	OP_GSTOREP_F,
	OP_GSTOREP_ENT,
	OP_GSTOREP_FLD,		// integers   //200
	OP_GSTOREP_S,
	OP_GSTOREP_FNC,		// pointers
	OP_GSTOREP_V,
	OP_GADDRESS,
	OP_GLOAD_I,
	OP_GLOAD_F,
	OP_GLOAD_FLD,
	OP_GLOAD_ENT,
	OP_GLOAD_S,
	OP_GLOAD_FNC,		//210
	OP_BOUNDCHECK,

//back to ones that we do use.
	OP_UNUSED,	//used to be OP_STOREP_P, which is now emulated with OP_STOREP_I, fteqcc nor fte generated it
	OP_PUSH,	//push 4octets onto the local-stack (which is ALWAYS poped on function return). Returns a pointer.
	OP_POP,		//pop those ones that were pushed (don't over do it). Needs assembler.

	OP_SWITCH_I,//hmm.
	OP_GLOAD_V,

	OP_IF_F,
	OP_IFNOT_F,

	OP_NUMREALOPS,

	/*
	These ops are emulated out, always, and are only present in the compiler.
	*/

	OP_BITSET_I,	//220
	OP_BITSETP_I,

	OP_MULSTORE_I,
	OP_DIVSTORE_I,
	OP_ADDSTORE_I,
	OP_SUBSTORE_I,
	OP_MULSTOREP_I,
	OP_DIVSTOREP_I,
	OP_ADDSTOREP_I,
	OP_SUBSTOREP_I,

	OP_MULSTORE_IF,	//230
	OP_MULSTOREP_IF,
	OP_DIVSTORE_IF,
	OP_DIVSTOREP_IF,
	OP_ADDSTORE_IF,
	OP_ADDSTOREP_IF,
	OP_SUBSTORE_IF,
	OP_SUBSTOREP_IF,

	OP_MULSTORE_FI,
	OP_MULSTOREP_FI,
	OP_DIVSTORE_FI,		//240
	OP_DIVSTOREP_FI,
	OP_ADDSTORE_FI,
	OP_ADDSTOREP_FI,
	OP_SUBSTORE_FI,
	OP_SUBSTOREP_FI,

	OP_MULSTORE_VI,
	OP_MULSTOREP_VI,

	OP_LOADA_STRUCT,
	OP_STOREP_P,

	OP_BINARYNOT_F,
	OP_BINARYNOT_I,

	OP_NUMOPS
};

#define	MAX_PARMS	8

// qtest structs (used for reordering and not execution)
typedef struct qtest_statement_s
{
	unsigned int	line; // line number in source code file
	unsigned short	op;
	unsigned short	a,b,c;
} qtest_statement_t;

typedef struct qtest_def_s
{
	unsigned int	type; // no DEFGLOBAL found in qtest progs
	unsigned int	s_name; // different order!
	unsigned int	ofs;
} qtest_def_t;

typedef struct qtest_function_s
{
	int		first_statement;
	int		unused1;
	int		locals;	// assumed! (always 0 in real qtest progs)
	int		profile; // assumed! (always 0 in real qtest progs)
	
	int		s_name;
	int		s_file;
	
	int		numparms;
	int		parm_start; // different order
	int		parm_size[MAX_PARMS]; // ints instead of bytes...
} qtest_function_t;

typedef struct statement16_s
{
	unsigned short	op;
	unsigned short	a,b,c;
} dstatement16_t;
typedef struct statement32_s
{
	unsigned int	op;
	unsigned int	a,b,c;
} dstatement32_t;
#define QCC_dstatement16_t dstatement16_t
#define QCC_dstatement_t dstatement32_t
#define QCC_dstatement32_t dstatement32_t

//these should be the same except the string type
typedef struct ddef16_s
{
	unsigned short	type;		// if DEF_SAVEGLOBAL bit is set
								// the variable needs to be saved in savegames
	unsigned short	ofs;
	string_t		s_name;
} ddef16_t;

typedef struct ddef32_s
{
	unsigned int	type;		// if DEF_SAVEGLOBAL bit is set
								// the variable needs to be saved in savegames
	unsigned int	ofs;
	string_t		s_name;
} ddef32_t;

typedef void *ddefXX_t;

typedef struct QCC_ddef16_s
{
	unsigned short	type;		// if DEF_SAVEGLOBAL bit is set
								// the variable needs to be saved in savegames
	unsigned short	ofs;
	QCC_string_t		s_name;
} QCC_ddef16_t;

typedef struct QCC_ddef32_s
{
	unsigned int	type;		// if DEF_SAVEGLOBAL bit is set
								// the variable needs to be saved in savegames
	unsigned int	ofs;
	QCC_string_t		s_name;
} QCC_ddef32_t;
#define QCC_ddef_t QCC_ddef32_t

#define	DEF_SAVEGLOBAL 		(1<<15)
#define	DEF_SHARED 		(1<<14)

typedef struct
{
	int		first_statement;	// negative numbers are builtins
	int		parm_start;
	int		locals;				// total ints of parms + locals
	
	int		profile;		// runtime
	
	string_t	s_name;
	string_t	s_file;			// source file defined in
	
	int		numparms;
	qbyte	parm_size[MAX_PARMS];
} dfunction_t;
typedef struct
{
	unsigned int		first_statement;	// negative numbers are builtins
	unsigned int		parm_start;
	int		locals;				// total ints of parms + locals
	
	int		profile;		// runtime
	
	QCC_string_t	s_name;
	QCC_string_t	s_file;			// source file defined in
	
	int		numparms;
	qbyte	parm_size[MAX_PARMS];
} QCC_dfunction_t;

#define PROG_QTESTVERSION	3
#define	PROG_VERSION	6
#define PROG_KKQWSVVERSION 7
#define	PROG_EXTENDEDVERSION	7
#define PROG_SECONDARYVERSION16 (*(int*)"1FTE" ^ *(int*)"PROG")	//something unlikly and still meaningful (to me)
#define PROG_SECONDARYVERSION32 (*(int*)"1FTE" ^ *(int*)"32B ")	//something unlikly and still meaningful (to me)
typedef struct
{
	int		version;
	int		crc;			// check of header file
	
	unsigned int		ofs_statements;	//comp 1
	unsigned int		numstatements;	// statement 0 is an error

	unsigned int		ofs_globaldefs;	//comp 2
	unsigned int		numglobaldefs;
	
	unsigned int		ofs_fielddefs;	//comp 4
	unsigned int		numfielddefs;
	
	unsigned int		ofs_functions;	//comp 8
	unsigned int		numfunctions;	// function 0 is an empty
	
	unsigned int		ofs_strings;	//comp 16
	unsigned int		numstrings;		// first string is a null string

	unsigned int		ofs_globals;	//comp 32
	unsigned int		numglobals;
	
	unsigned int		entityfields;

	//debug / version 7 extensions
	unsigned int		ofsfiles;	//non list format. no comp
	unsigned int		ofslinenums;	//numstatements big	//comp 64
	unsigned int		ofsbodylessfuncs;	//no comp
	unsigned int		numbodylessfuncs;

	unsigned int	ofs_types;	//comp 128
	unsigned int	numtypes;
	unsigned int	blockscompressed;

	int	secondaryversion;	//Constant - to say that any version 7 progs are actually ours, not someone else's alterations.
} dprograms_t;
#define standard_dprograms_t_size ((size_t)&((dprograms_t*)NULL)->ofsfiles)

#endif





typedef struct {
	char filename[128];
	int size;
	int compsize;
	int compmethod;
	int ofs;
} includeddatafile_t;




typedef struct typeinfo_s
{
	etype_t	type;

	int		next;
	int		aux_type;
	int		num_parms;

	int		ofs;	//inside a structure.
	int		size;
	string_t	name;
} typeinfo_t;
