/**********************************************************************/
/*                                                                    */
/*	CRISP - Programmable editor                                   */
/*	===========================                                   */
/*                                                                    */
/*  File:          crunch.h                                           */
/*  Author:        P. D. Fox                                          */
/*  Created:       2 Apr 1991                      		      */
/*                                                                    */
/*  Copyright (c) 1990, 1991 Paul Fox                                 */
/*                All Rights Reserved.                                */
/*                                                                    */
/*                                                                    */
/*--------------------------------------------------------------------*/
/*  Description:  Include file for the crunch language.               */
/*                                                                    */
/**********************************************************************/

/* SCCS ID: %Z% %M% %R%.%L% */
# include	"../machine.h"

# include	<stdio.h>
/* Xenix and OS/2 bugger up NULL in large model. */
# undef	NULL
# define	NULL	0
# include	<llist.h>
# include	<chkalloc.h>
# include	<string.h>
# if	defined(GOT_STDLIB)
# 	include	<stdlib.h>
# endif
# include	<assert.h>
# include	"../ansic.h"

# include	"gen.h"

# if	!defined(TRUE)
# 	define	TRUE	1
#	define	FALSE	0
# endif


# if !defined(PROTO)
#	if defined(__STDC__)
#		define	PROTO(x)	x
#	else
#		define	PROTO(x)	()
#	endif
# endif

enum node_type {
	node_keywd,
	node_integer,
	node_float,
	node_string,
	node_symbol
	};

typedef struct block_t	{
	Head_p	b_stmt;
	Head_p	b_init;
	} block_t;

/**********************************************************************/
/*   A  basic  type is : class, qualifiers, type1, type2 stored in a  */
/*   32 bit field.						      */
/**********************************************************************/
# define	SC_MASK		0xf0000
# define	TQ_MASK		0x0f000
# define	TY_MASK		0x00fff

# define	TY_HI_MASK	0x00fc0
# define	TY_LO_MASK	0x0003f

# define	SC_SHIFT	16
# define	TQ_SHIFT	12
# define	TY_SHIFT	6	/* 6 bits for each type. 	*/
					/* Then we can have 		*/
					/* (TY_LONG << TY_SHIFT) | TY_LONG */
					/* for a 'long long' type.	*/
/**********************************************************************/
/*   Base types.						      */
/**********************************************************************/
# define	TY_IMPLICIT	0
# define	TY_INT		1
# define	TY_CHAR		2
# define	TY_SHORT	3
# define	TY_VOID		4
# define	TY_LONG		5
# define	TY_FLOAT	6
# define	TY_DOUBLE	7
# define	TY_SIGNED	8
# define	TY_UNSIGNED	9
# define	TY_STRUCT	10
# define	TY_UNION	11
# define	TY_ENUM		12
# define	TY_STRING	13
# define	TY_DECLARE	14
# define	TY_LIST		15
# define	TY_STRUCTI	16
# define	TY_UNIONI	17
/**********************************************************************/
/*   Storage class specifiers.					      */
/**********************************************************************/
# define	SC_AUTO		0x0
# define	SC_REGISTER	0x1
# define	SC_STATIC	0x2
# define	SC_EXTERN	0x3
# define	SC_TYPEDEF	0x4
# define	SC_GLOBAL	0x5

/**********************************************************************/
/*   Type qualifiers.						      */
/**********************************************************************/
# define	TQ_CONST	0x30
# define	TQ_VOLATILE	0x31

# define	TO_NOOP		0x40	/* No-op for tree joining. */
# define	TO_INIT		0x41	/* Declarator + initialiser. */
# define	TO_PTR		0x42	/* Pointer to declarator.	*/
# define	TO_LIST		0x43	/* Links declarations together. */
# define	TO_SYMBOL	0x44	/* left link points to symbol table. */
# define	TO_ARRAY	0x45	/* Array indexing.		     */
# define	TO_FUNC		0x46	/* Function 			     */
/**********************************************************************/
/*   Following enum helps in debugging.				      */
/**********************************************************************/
enum ntypes {
	e_TY_VOID = TY_VOID,
	e_TY_CHAR = TY_CHAR,
	e_TY_SHORT = TY_SHORT,
	e_TY_INT = TY_INT,
	e_TY_LONG = TY_LONG,
	e_TY_FLOAT = TY_FLOAT,
	e_TY_DOUBLE = TY_DOUBLE,
	e_TY_SIGNED = TY_SIGNED,
	e_TY_UNSIGNED = TY_UNSIGNED,
	e_TY_STRUCT = TY_STRUCT,
	e_TY_UNION = TY_UNION,
	e_TY_ENUM = TY_ENUM,
	e_TY_STRING = TY_STRING,
	e_TY_DECLARE = TY_DECLARE,
	e_TY_LIST = TY_LIST,
	e_TY_STRUCTI = TY_STRUCTI,
	e_TY_UNIONI = TY_UNIONI,
	e_SC_AUTO = SC_AUTO,
	e_SC_REGISTER = SC_REGISTER,
	e_SC_STATIC = SC_STATIC,
	e_SC_EXTERN = SC_EXTERN,
	e_SC_TYPEDEF = SC_TYPEDEF,
	e_TQ_CONST = TQ_CONST,
	e_TQ_VOLATILE = TQ_VOLATILE,
	e_TO_NOOP = TO_NOOP,
	e_TO_INIT = TO_INIT,
	e_TO_PTR = TO_PTR,
	e_TO_LIST = TO_LIST,
	e_TO_SYMBOL = TO_SYMBOL,
	e_TO_ARRAY = TO_ARRAY,
	e_TO_FUNC = TO_FUNC,
	/***********************************************/
	/*   Following  are  derived  from  the  yacc  */
	/*   grammar.				       */
	/***********************************************/
	e_K_BLOCK = K_BLOCK,
	e_K_INIT = K_INIT,
	e_K_SWITCH = K_SWITCH,
	e_K_CASE = K_CASE,
	e_K_DEFAULT = K_DEFAULT,
	e_K_LIST = K_LIST,
	e_K_INT = K_INT,
	e_K_STRING = K_STRING,
	e_K_DECLARE = K_DECLARE,
	e_K_FLOAT = K_FLOAT,
	e_K_DOUBLE = K_DOUBLE,
	e_K_NOOP = K_NOOP,
	e_K_FUNCALL = K_FUNCALL,
	e_K_DOTS = K_DOTS,
	e_K_STRUCT = K_STRUCT,
	e_K_UNION = K_UNION,
	e_K_CONST = K_CONST,
	e_K_VOLATILE = K_VOLATILE,
	e_K_CHAR = K_CHAR,
	e_K_LONG = K_LONG,
	e_K_SHORT = K_SHORT,
	e_K_UNSIGNED = K_UNSIGNED,
	e_K_VOID = K_VOID,
	e_K_SIGNED = K_SIGNED,
	e_K_IF = K_IF,
	e_K_ELSE = K_ELSE,
	e_K_FOR = K_FOR,
	e_K_BREAK = K_BREAK,
	e_K_CONTINUE = K_CONTINUE,
	e_K_WHILE = K_WHILE,
	e_K_DO = K_DO,
	e_K_RETURN = K_RETURN,
	e_K_INITLIST = K_INITLIST,
	e_K_ENUM = K_ENUM,
	e_K_AUTO = K_AUTO,
	e_K_REGISTER = K_REGISTER,
	e_K_STATIC = K_STATIC,
	e_K_EXTERN = K_EXTERN,
	e_K_TYPEDEF = K_TYPEDEF,
	e_OCURLY = OCURLY,
	e_CCURLY = CCURLY,
	e_OROUND = OROUND,
	e_CROUND = CROUND,
	e_COMMA = COMMA,
	e_SEMICOLON = SEMICOLON,
	e_COLON = COLON,
	e_LSHIFT = LSHIFT,
	e_RSHIFT = RSHIFT,
	e_QUESTION = QUESTION,
	e_OSQUARE = OSQUARE,
	e_CSQUARE = CSQUARE,
	e_DOT = DOT,
	e_ARROW = ARROW,
	e_INTEGER = INTEGER,
	e_EQ = EQ,
	e_PLUS_EQ = PLUS_EQ,
	e_MINUS_EQ = MINUS_EQ,
	e_MUL_EQ = MUL_EQ,
	e_DIV_EQ = DIV_EQ,
	e_MOD_EQ = MOD_EQ,
	e_AND_EQ = AND_EQ,
	e_OR_EQ = OR_EQ,
	e_XOR_EQ = XOR_EQ,
	e_LSHIFT_EQ = LSHIFT_EQ,
	e_RSHIFT_EQ = RSHIFT_EQ,
	e_EQ_OP = EQ_OP,
	e_NE_OP = NE_OP,
	e_GT_OP = GT_OP,
	e_GE_OP = GE_OP,
	e_LT_OP = LT_OP,
	e_LE_OP = LE_OP,
	e_PLUS = PLUS,
	e_MINUS = MINUS,
	e_MUL = MUL,
	e_DIV = DIV,
	e_MOD = MOD,
	e_OR = OR,
	e_AND = AND,
	e_XOR = XOR,
	e_NOT = NOT,
	e_COMPLEMENT = COMPLEMENT,
	e_PLUS_PLUS = PLUS_PLUS,
	e_MINUS_MINUS = MINUS_MINUS,
	e_CAND = CAND,
	e_COR = COR,
	e_SYMBOL = SYMBOL,
	e_STRING = STRING,
	e_UMINUS = UMINUS,
	e_UPLUS = UPLUS
	};


# define	NF_LVALUE	0x01	/* Expression is an lvalue.	*/	

/**********************************************************************/
/*   Following MUST agree with type generated by bison/yacc.	      */
/**********************************************************************/
typedef union myYYSTYPE {
		char		 *sval;
		struct node_leaf *nval;
		struct func_t	*fval;	/* Function.		*/
		double		floatval;
		long		 ival;
		enum ntypes	 eval;	/* Same as ival but enumerated so the 	*/
					/* debugger can see them.		*/
		} myYYSTYPE;
# if !defined(Y_TAB_H)
	extern myYYSTYPE	yylval;
# endif
# if 0
# define	NODE_MAGIC	0x12345678
# define	NODE_FREE	0x99887766
# endif
typedef	struct node_leaf {
# if defined(NODE_MAGIC)
	long	magic;
# endif
	struct node_leaf *left;
	struct node_leaf *right;
	struct node_leaf *next;	/* Linked list of allocated nodes so we can */
				/* free items in bulk after end of compilation*/
	enum node_type	type;
	myYYSTYPE	atom;
	int	lineno;		/* Needed if '-g' specified.			*/
	} node_t;

/**********************************************************************/
/*   Structure describing a function.				      */
/**********************************************************************/
typedef struct func_t {
	node_t		*f_type;
	node_t		*f_name;
	node_t		*f_arglist;
	node_t		*f_body;
	} func_t;
	
typedef struct switch_t {
	Head_p	sw_cases;	/* Pending cases.	*/
	Head_p	sw_stmts;	/* Pending stmts in current case. */
	} switch_t;


# define	SF_FORWARD	0x01	/* definition is a forward reference. */
# define	SF_DEFINING	0x02	/* In middle of definition.	*/
# define	SF_REF		0x04	/* Symbol was referenced.	*/
typedef	struct symbol {
	char		*name;	/* Symbol name.			   	*/
	int		level;	/* Block level so we can 	   	*/
				/* remove things as we come out    	*/
				/* of blocks.			   	*/
	long		s_type;	/* Data type of symbol. 	   	*/
	struct symbol	*s_susym;
				/* Pointer to structure symbol, e.g. 	*/
				/* if we are 'struct fred x', then	*/
				/* s_susym pointers to 'fred'.		*/
	struct symbol	*s_owner;/* Pointer to owning structure etc. 	*/
	node_t		*s_tree;/* Tree describing type modifiers. 	*/
	Head_p		s_members;
				/* List (in order) of members.		*/
	short		s_flags;
	short		s_align;/* For a struct/union - the base alignment*/
	int		s_size;	/* Size of variable. (Base type or 	*/
				/* base type * sizeof array).	   	*/
	int		s_line_no;/* Line where original defined.	*/
	char		*s_filename;/* File in which originally defined.*/
	} symbol_t;

# define	TY_PTR		0 /* Pointer */
# define	TY_ARRAY	1 /* Array (includes size dimensions). */
# define	TY_FUNC		2 /* Function.	*/
typedef struct type_t {
	int	t_type;
	int	t_size;
	} type_t;

typedef struct decl_t {
	long		d_type;		/* type/qualifier/specifier etc. */
	symbol_t	*d_symbol;	/* Owning structure/union/enum. */
	} decl_t;
typedef struct struct_t {
	symbol_t	*s_symbol;	/* Sym tab entry for current structure. */
	symbol_t	*s_struct_sp;	/* Previous version of struct_sp.	*/
	} struct_t;
/**********************************************************************/
/*   Order in which to insert entries into symbol table.	      */
/**********************************************************************/
# define	INSERT_AT_END	0
# define	INSERT_AT_FRONT	1

/**********************************************************************/
/*   Following  used  to keep track of whether we are in a loop or a  */
/*   awitch  so  that  when we see a break we can figure out what it  */
/*   is applying to.						      */
/**********************************************************************/
# define	INSIDE_LOOP	1
# define	INSIDE_SWITCH	2
/**********************************************************************/
/*   Statistics (used for watching for memory leaks, etc).	      */
/**********************************************************************/
typedef struct stat_t {
	long	s_new_nodes;
	long	s_free_nodes;
	} stat_t;
	

extern stat_t	stats;
extern FILE *ofp;
extern FILE *errfp;
extern char *filename;
extern int g_flag;

char	*peek_id PROTO((void));
char	*pop_id PROTO((void));
char	*type_to_str PROTO((long));
int	get_typedef_type PROTO((char *));
long	peek_decl PROTO((void));
int	yylex PROTO((void));
int	yyparse PROTO((void));
node_t	*end_switch PROTO((node_t *));
node_t	*exit_block PROTO((void));
node_t *	alloc_node PROTO((long));
node_t *	new_node PROTO((void));
node_t *	new_number PROTO((long));
node_t *	new_float PROTO((double));
node_t *	node PROTO((long, node_t *, node_t *));
node_t *	node_opt PROTO((long, node_t *, node_t *));
node_t *	node_lvalue PROTO((long, node_t *, node_t *));
node_t *	string_node PROTO((char *));
node_t *	string_node1 PROTO((char *));
symbol_t	*add_symbol PROTO((char *, node_t *, long));
symbol_t	*add_symbol_to_table PROTO((Head_p *, int, char *, node_t *, long, symbol_t *));
symbol_t	*defining_struct PROTO((char *, long));
symbol_t	*ending_struct PROTO((void));
symbol_t	*lookup_struct PROTO((char *));
symbol_t	*lookup_sym PROTO((char *, int));
void	nl PROTO((void));
char	*map PROTO((int));
void	add_decl PROTO((node_t *));
void	add_member PROTO((node_t *));
void	add_stmt PROTO((Head_p *, node_t *));
void	bcopy(/**/);
int	compile_arglist PROTO((Head_p, int));
void	compile_func PROTO((char *, node_t *, node_t *));
int	compile_globals PROTO((int));
void	compile_list PROTO((Head_p, int, int, int));
void	compile_main PROTO((node_t *));
void	compile_node PROTO((node_t *, int));
void	compile_switch PROTO((node_t *, int));
void	end_case PROTO((void));
void	enter_block PROTO((void));
void	enter_loop PROTO((void));
void	exit_loop PROTO((void));
void	init_ascii PROTO((void));
char	*get_filename PROTO((char *));
void	init_symtab PROTO((void));
void	init_lex PROTO((void));
void	init_binary PROTO((void));
void	init_parser PROTO((void));
void	pop_decl PROTO((void));
void	pr_string PROTO((char *));
void	print_node PROTO((node_t *, int));
void	print_space PROTO((void));
void	push_decl PROTO((long));
void	push_id PROTO((char *));
void	start_case PROTO((node_t *));
void	start_switch PROTO((void));
void	yyerror PROTO((char *));
void	yyerror1 PROTO((char *, char *));
void	LPUT16 PROTO((char *, int));
void	LPUT32 PROTO((char *, long));
void	LPUT_FLOAT();
void	yywarn PROTO((char *));
void	yywarn_with_line_no PROTO((char *, int));
void	free_list PROTO((Head_p *));
void	print_function_name PROTO((void));
void	init_codegen PROTO((void));
void	enter_loop_or_switch PROTO((int));
void	exit_loop_or_switch PROTO((void));
int	start_function PROTO((node_t *, node_t *));
void	return_value PROTO((int));

/**********************************************************************/
/*   Pointer to structure containing code generation routines.	      */
/**********************************************************************/
typedef struct gen_t {
	void	(*g_macro) PROTO((void));
	void	(*g_list) PROTO((void));
	void	(*g_id) PROTO((char *));
	void	(*g_lit) PROTO((char *));
	void	(*g_end_list) PROTO((void));
	void	(*g_int) PROTO((long));
	void	(*g_string) PROTO((char *));
	void	(*g_float) PROTO((double));
	void	(*g_token) PROTO((int));
	void	(*g_finish) PROTO((void));
	void	(*g_null) PROTO((void));
	} gen_t;
# define	gen_macro()	generate_ascii ? \
			(*gen_ascii.g_macro)() : \
			(*gen_binary.g_macro)()
# define	gen_list()	generate_ascii ? \
			(*gen_ascii.g_list)() : \
			(*gen_binary.g_list)()
# define	gen_id(id)	generate_ascii ? \
			(*gen_ascii.g_id)(id) : \
			(*gen_binary.g_id)(id)
# define	gen_lit(l)	generate_ascii ? \
			(*gen_ascii.g_lit)(l) : \
			(*gen_binary.g_lit)(l)
# define	gen_end_list()	generate_ascii ? \
			(*gen_ascii.g_end_list)() : \
			(*gen_binary.g_end_list)()
# define	gen_int(n)	generate_ascii ? \
			(*gen_ascii.g_int)(n) : \
			(*gen_binary.g_int)(n)
# define	gen_string(s)	generate_ascii ? \
			(*gen_ascii.g_string)(s) : \
			(*gen_binary.g_string)(s)
# define	gen_float(f)	generate_ascii ? \
			(*gen_ascii.g_float)(f) : \
			(*gen_binary.g_float)(f)
# define	gen_token(t)	generate_ascii ? \
			(*gen_ascii.g_token)(t) : \
			(*gen_binary.g_token)(t)
# define	gen_finish()	generate_ascii ? \
			(*gen_ascii.g_finish)() : \
			(*gen_binary.g_finish)()
# define	gen_null()	generate_ascii ? \
			(*gen_ascii.g_null)() : \
			(*gen_binary.g_null)()
void	gena_macro PROTO((void));
void	gena_list PROTO((void));
void	gena_id PROTO((char *));
void	gena_lit PROTO((char *));
void	gena_end_list PROTO((void));
void	gena_int PROTO((long));
void	gena_string PROTO((char *));
void	gena_float PROTO((double));
void	gena_token PROTO((int));
void	gena_finish PROTO((void));
void	gena_null PROTO((void));

void	genb_macro PROTO((void));
void	genb_list PROTO((void));
void	genb_id PROTO((char *));
void	genb_lit PROTO((char *));
void	genb_end_list PROTO((void));
void	genb_int PROTO((long));
void	genb_string PROTO((char *));
void	genb_float PROTO((double));
void	genb_token PROTO((int));
void	genb_finish PROTO((void));
void	genb_null PROTO((void));

int	WGET16 PROTO((int));
long	WGET32 PROTO((long));
