#include "cmdlib.h"
#include <stdio.h>
#include <setjmp.h>

#include "pr_comp.h"

#define DefCmp(s1, s2) \
  ( stricmp(s1, s2) /*|| ( *(short *)s1 != *(short *)s2 )*/ )

#define PncCmp(s1, s2) \
  ( ( *(short *)s1 == *(short *)s2 ) )

/*
TODO:

"stopped at 10 errors"
other pointer types for models and clients?
compact string heap?
allways initialize all variables to something safe
the def->type->type arrangement is really silly.
return type checking
parm count type checking
immediate overflow checking
pass the first two parms in call->b and call->c
*/

//=============================================================================

// offsets are allways multiplied by 4 before using
typedef int	gofs_t;				// offset in global data block
typedef struct function_s function_t;

#define	MAX_PARMS	8

typedef struct type_s
{
	etype_t			type;
	struct def_s	*def;		// a def that points to this type
	struct type_s	*next;
// function types are more complex
	struct type_s	*aux_type;	// return type or field type
	int				num_parms;	// -1 = variable args
	struct type_s	*parm_types[MAX_PARMS];	// only [num_parms] allocated
} type_t;

typedef struct def_s
{
	type_t        *type;
	char          *name;
	struct def_s  *next, *prev;
	gofs_t        ofs;
	struct def_s  *scope;		// function the var was defined in, or NULL
	int           initialized;	// 1 when a declaration included "= immediate"
}
def_t;

//============================================================================

// pr_loc.h -- program local defs

#define	MAX_ERRORS		30               // 10

#define	MAX_NAME		128	  // chars long  (64)

#define	MAX_REGS		80000              // 40000

//=============================================================================

typedef union eval_s
{
	string_t			string;
	float				_float;
	float				vector[3];
	func_t				function;
	int					_int;
	union eval_s		*ptr;
} eval_t;	

extern int walkeddefs;

extern  int   type_size[8];
extern  def_t *def_for_type[8];

extern  type_t  type_void, type_string, type_float, type_vector, type_entity, type_field, type_function, type_pointer, type_floatfield;

extern  def_t def_void, def_string, def_float, def_vector, def_entity, def_field, def_function, def_pointer;

struct function_s
{
	int					builtin;	// if non 0, call an internal function
	int					code;		// first statement
	char				*file;		// source file with definition
	int					file_line;
	struct def_s		*def;
	int					parm_ofs[MAX_PARMS];	// allways contiguous, right?
};


//
// output generated by prog parsing
//
typedef struct
{
	char		*memory;
	int			max_memory;
	int			current_memory;
	type_t		*types;
	
	def_t		*def_head;		// head of linked list
	def_t    *def_tail;     // tail of linked list

	int			size_fields;
} pr_info_t;

extern	pr_info_t	pr;

typedef struct
{
	char		*name;
	char		*opname;
//        float           priority;
        int             priority;
	boolean	right_associative;
	def_t		*type_a, *type_b, *type_c;
} opcode_t;

//============================================================================


extern	opcode_t	pr_opcodes[99];		// sized by initialization

extern	boolean	pr_dumpasm;

extern	def_t		*pr_global_defs[MAX_REGS];	// to find def for a global variable

typedef enum {
tt_eof,			// end of file reached
tt_name, 		// an alphanumeric name token
tt_punct, 		// code punctuation
tt_immediate,	// string, float, vector
} token_type_t;

extern  char    *pr_typename;
extern	char		pr_token[2048];
extern	token_type_t	pr_token_type;
extern	type_t		*pr_immediate_type;
extern	eval_t		pr_immediate;

void PR_PrintStatement (dstatement_t *s);

void PR_Lex (void);
// reads the next token into pr_token and classifies its type

type_t *PR_ParseType (void);
char *PR_ParseName (void);

#ifndef INLINE
boolean PR_Check (char *string);
void PR_Expect (char *string);
#endif
void PR_ParseError (char *error, ...);

extern	jmp_buf		pr_parse_abort;		// longjump with this on parse error
extern	int			pr_source_line;
extern	char		*pr_file_p;

void *PR_Malloc (int size);


#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	RESERVED_OFS	28


extern	def_t	*pr_scope;
extern	int		pr_error_count;

void PR_NewLine (void);
def_t *PR_GetDef (type_t *type, char *name, def_t *scope, boolean allocate);

void PR_PrintDefs (void);

void PR_SkipToSemicolon (void);

extern	char		pr_parm_names[MAX_PARMS][MAX_NAME];
extern	boolean	pr_trace;

#define	G_FLOAT(o) (pr_globals[o])
#define	G_INT(o) (*(int *)&pr_globals[o])
#define	G_VECTOR(o) (&pr_globals[o])
#define	G_STRING(o) (strings + *(string_t *)&pr_globals[o])
#define	G_FUNCTION(o) (*(func_t *)&pr_globals[o])

char *PR_ValueString (etype_t type, void *val);

void PR_ClearGrabMacros (void);

boolean	PR_CompileFile (char *string, char *filename);

extern	boolean	pr_dumpasm;

extern	string_t	s_file;			// filename for function definition

extern	def_t	def_ret, def_parms[MAX_PARMS];

//=============================================================================

#define	MAX_STRINGS		500000
#define	MAX_GLOBALS		40000
#define	MAX_FIELDS		2048
#define	MAX_STATEMENTS	65536
#define	MAX_FUNCTIONS	8192

#define	MAX_SOUNDS		1024
#define	MAX_MODELS		1024
#define	MAX_FILES		1024
#define	MAX_DATA_PATH	64

extern	char	strings[MAX_STRINGS];
extern	int		strofs;

extern	dstatement_t	statements[MAX_STATEMENTS];
extern	int			numstatements;
extern	int			statement_linenums[MAX_STATEMENTS];

extern	dfunction_t	functions[MAX_FUNCTIONS];
extern	int			numfunctions;

extern	float		pr_globals[MAX_REGS];
extern	int			numpr_globals;

extern	char	pr_immediate_string[2048];

extern	char		precache_sounds[MAX_SOUNDS][MAX_DATA_PATH];
extern	int			precache_sounds_block[MAX_SOUNDS];
extern	int			numsounds;

extern	char		precache_models[MAX_MODELS][MAX_DATA_PATH];
extern	int			precache_models_block[MAX_SOUNDS];
extern	int			nummodels;

extern	char		precache_files[MAX_FILES][MAX_DATA_PATH];
extern	int			precache_files_block[MAX_SOUNDS];
extern	int			numfiles;

int	CopyString (char *str);


#if 0 // def INLINE
inline static void PR_Expect (char *string)
{
	if (DefCmp(string, pr_token))
		PR_ParseError ("expected %s, found %s",string, pr_token);
	PR_Lex ();
}

inline static boolean PR_Check (char *string)
{
	if (DefCmp(string, pr_token))
		return false;

	PR_Lex ();
	return true;
}

#endif

