/****************************************************************
 *								*
 *	Copyright 2001, 2011 Fidelity Information Services, Inc	*
 *								*
 *	This source code contains the intellectual property	*
 *	of its copyright holder(s), and is made available	*
 *	under a license.  If you do not know the terms of	*
 *	the license, please stop and do not read further.	*
 *								*
 ****************************************************************/

#include "mdef.h"

#include "gtm_string.h"

#include "compiler.h"
#include "opcode.h"
#include "cmd_qlf.h"
#include "mdq.h"
#include "cgp.h"
#include "error.h"
#include "mmemory.h"
#include "stringpool.h"
#include "list_file.h"
#include "source_file.h"
#include "lb_init.h"
#include "reinit_externs.h"
#include "comp_esc.h"
#include "resolve_blocks.h"
#include "hashtab_str.h"

#define HOPELESS_COMPILE 128

GBLREF short int source_column, source_line;

/* ensure source_buffer is aligned on a int4 word boundary so that
 * we can calculate the checksum a longword at a time.
 */
GBLREF int4 			aligned_source_buffer[MAX_SRCLINE / SIZEOF(int4) + 1];
GBLREF unsigned char 		*source_buffer;
GBLREF src_line_struct 		src_head;
GBLREF triple			t_orig, *curr_fetch_trip, *curr_fetch_opr;
GBLREF int4			curr_fetch_count;
GBLREF command_qualifier	cmd_qlf;
GBLREF int			mlmax;
GBLREF mline			mline_root;
GBLREF char			cg_phase;	/* code generation phase */
GBLREF boolean_t		mstr_native_align, save_mstr_native_align;
GBLREF hash_table_str		*complits_hashtab;

LITDEF char compile_terminated[] = "COMPILATION TERMINATED DUE TO EXCESS ERRORS";

boolean_t compiler_startup(void)
{
#ifdef DEBUG
	void		dumpall();
#endif
	boolean_t	compile_w_err;
	unsigned char	err_buf[45];
	unsigned char 	*cp, *cp2;
	int		errknt;
	int4            n;
	uint4		checksum, line_count;
	mlabel		*null_lab;
	src_line_struct	*sl;
	mident		null_mident;
	DCL_THREADGBL_ACCESS;

	SETUP_THREADGBL_ACCESS;
	assert(NULL == complits_hashtab || NULL == complits_hashtab->base);
	memset(&null_mident, 0, SIZEOF(null_mident));
	ESTABLISH_RET(compiler_ch, FALSE);
	/* Since the stringpool alignment is solely based on mstr_native_align, we need to initialize it based
	 * on the ALIGN_STRINGS qualifier so that all strings in the literal text pool are aligned.
	 * However, when a module is compiled at runtime, we need to preserve the existing runtime setting
	 * (that was initialized at GT.M startup) once the compilation is done.  save_mstr_native_align is used for
	 * this purpose. */
	save_mstr_native_align = mstr_native_align;
	/* mstr_native_align = (cmd_qlf.qlf & CQ_ALIGN_STRINGS) ? TRUE : FALSE; */
	mstr_native_align = FALSE; /* TODO: remove this line and  uncomment the above line */
	cg_phase = CGP_NOSTATE;
	TREF(source_error_found) = errknt = 0;
	if(!open_source_file())
	{
		mstr_native_align = save_mstr_native_align;
		REVERT;
		return FALSE;
	}
	cg_phase = CGP_PARSE;
	if (cmd_qlf.qlf & CQ_LIST || cmd_qlf.qlf & CQ_CROSS_REFERENCE)
	{
		if (cmd_qlf.qlf &  CQ_MACHINE_CODE)
			dqinit(&src_head, que);
		open_list_file();
	}
	if (cmd_qlf.qlf & CQ_CE_PREPROCESS)
		open_ceprep_file();
	tripinit();
	null_lab = get_mladdr(&null_mident);
	null_lab->ml = &mline_root;
	mlmax++;
	curr_fetch_trip = curr_fetch_opr = newtriple(OC_LINEFETCH);
	curr_fetch_count = 0;
	TREF(code_generated) = FALSE;
	checksum = 0;
	line_count = 1;
	for (source_line = 1;  errknt <= HOPELESS_COMPILE;  source_line++)
	{
		if (-1 == (n = read_source_file()))
			break;
		if (cmd_qlf.qlf & CQ_LIST || cmd_qlf.qlf & CQ_CROSS_REFERENCE)
		{
			if (cmd_qlf.qlf & CQ_MACHINE_CODE)
			{
				sl = (src_line_struct *)mcalloc(SIZEOF(src_line_struct));
				dqins(&src_head, que, sl);
				sl->addr = mcalloc(n + 1);	/* +1 for zero termination */
				sl->line = source_line;
				memcpy(sl->addr, source_buffer, n + 1);
			} else
			{
				list_line_number();
				list_line((char *)source_buffer);
			}
		}
		/* calculate checksum */
		RTN_SRC_CHKSUM((char *)source_buffer, n, checksum);
		TREF(source_error_found) = 0;
		lb_init();
		if (cmd_qlf.qlf & CQ_CE_PREPROCESS)
			put_ceprep_line();
		if (!line(&line_count))
		{
			assert(TREF(source_error_found));
			errknt++;
		}
	}
	close_source_file();
	if (cmd_qlf.qlf & CQ_CE_PREPROCESS)
		close_ceprep_file();
	cg_phase = CGP_RESOLVE;
	if (t_orig.exorder.fl == &t_orig)	/* if no lines in routine, set up line 0 */
		newtriple(OC_LINESTART);
	newtriple(OC_RET);			/* always provide a default QUIT */
	mline_root.externalentry = t_orig.exorder.fl;
	INVOKE_STP_GCOL(0);
	/* The above invocation of stp_gcol with a parameter of 0 is a critical part of compilation
	 * (both routine compilations and indirect dynamic compilations). This collapses the indirect
	 * (compilation) stringpool so that only the literals are left. This stringpool is then written
	 * out to the compiled object as the literal pool for that compilation. Temporary stringpool
	 * use for conversions or whatever are eliminated. Note the path is different in stp_gcol for
	 * the indirect stringpool which is only used during compilations.
	 */
	start_fetches(OC_NOOP);
	resolve_blocks();
	errknt = resolve_ref(errknt);
	compile_w_err = (errknt <= HOPELESS_COMPILE && (cmd_qlf.qlf & CQ_IGNORE));
	if (cmd_qlf.qlf & CQ_LIST || cmd_qlf.qlf & CQ_CROSS_REFERENCE)
	{
		list_line("");
		if (errknt)
			cp = i2asc(err_buf, errknt);
		else
		{
			cp = err_buf;
			*cp++ = 'n';
			*cp++ = 'o';
		}
		memcpy(cp, " error", SIZEOF(" error"));
		cp += SIZEOF(" error") - 1;
		if (1 != errknt)
			*cp++ = 's';
		*cp = 0;
		list_line((char *)err_buf);
		if (errknt > HOPELESS_COMPILE)
			list_line((char *)compile_terminated);
		if (cmd_qlf.qlf & CQ_MACHINE_CODE && compile_w_err)
			list_head(1);
	}
	if ((!errknt || compile_w_err) && (cmd_qlf.qlf & CQ_OBJECT || cmd_qlf.qlf & CQ_MACHINE_CODE))
	{
		obj_code(line_count, checksum);
		cg_phase = CGP_FINI;
	}
	if (cmd_qlf.qlf & CQ_LIST || cmd_qlf.qlf & CQ_CROSS_REFERENCE)
	{
		list_cmd();
		close_list_file();
	}
	COMPILE_HASHTAB_CLEANUP;
	reinit_externs();
	mstr_native_align = save_mstr_native_align;
	REVERT;
	return errknt ? TRUE : FALSE;
}
