/*
 * Copyright (c) 1990-2004 by Wayne C. Gramlich.
 * All rights reserved.
 */

#ifndef CALL_DEFS_H
#include "call_defs.h"
#endif

#ifndef ERROR_EXPORTS_H
#include "error_exports.h"
#endif

#ifndef FLAGS_DEFS_H
#include "flags_defs.h"
#endif

#ifndef GEN_DEFS_H
#include "gen_defs.h"
#endif

#ifndef HEAP_EXPORTS_H
#include "heap_exports.h"
#endif

#ifndef LIBC_EXPORTS_H
#include "libc_exports.h"
#endif

#ifndef LINT_H
#include "lint.h"
#endif

#ifndef MODULE_DEFS_H
#include "module_defs.h"
#endif

#ifndef MSG_EXPORTS_H
#include "msg_exports.h"
#endif

#ifndef OBJECT_EXPORTS_H
#include "object_exports.h"
#endif

#ifndef OUT_EXPORTS_H
#include "out_exports.h"
#endif

#ifndef PARSER_DEFS_H
#include "parser_defs.h"
#endif

#ifndef ROUTINE_EXPORTS_H
#include "routine_exports.h"
#endif

#ifndef STRVEC_EXPORTS_H
#include "strvec_exports.h"
#endif

#ifndef STR_EXPORTS_H
#include "str_exports.h"
#endif

#ifndef TABLE_EXPORTS_H
#include "table_exports.h"
#endif

#ifndef TYPE_DEFS_H
#include "type_defs.h"
#endif

#ifndef UNIX_STDLIB_H
#include "unix_stdlib.h"
#endif

#ifndef VECTOR_EXPORTS_H
#include "vector_exports.h"
#endif

LOCAL void	gen_tables_dump(Gen, Stdio);

/*
 * This program will compile a *.st file and generate a *.o file.
 */

int
main(
	int			argc,
	Str			*argv)
{
	Str			base_name;
	Str			cmd;
	Strvec			command;
	Convert			convert;
	Str			compiler;
	Str			depend_line;
	Flags			flags;
	Gen			gen;
	Heap			heap;
	Module			module;
	Msg			msg;
	Object_table		object_table;
	Stdio			out_file;
	Str			out_name;
	Parser			parser;
	Routine_table		routine_table;
	Type_tables		type_tables;
	Type_def_table		type_def_table;

	/* Emit help message if no arguments specified: */
	argc--;
	argv++;
	if (argc == 0) {
		(void)printf(
		    "Usage: stc [-CgiPST][-o <out_file>] <in_file> ...\n");
		return 0;
	}

	/* Scan the flags: */
	heap = heap_standard_create();
	flags = flags_process(argc, argv, heap);

	compiler = flags->compiler;

	/* Open the output file: */
	if (strequal(flags->out_file->full, "/dev/tty")) {
		out_file = stdout;
	} else {
		depend_line = getenv("SUNPRO_DEPENDENCIES");
		if (depend_line != (Str)0) {
			Stdio		depend_file;
			Str		depend_file_name;
			Str		depend_separator;
			Flags_file	in_file;
			Vec(Flags_file)	in_files;
			int		index;
			int		size;

			depend_file_name = strdupl(depend_line, heap);
			depend_separator = strchr(depend_file_name, ' ');
			if (depend_separator != (Str)0) {
				*depend_separator = '\0';
			}
			depend_file = fopen(depend_file_name, "w");
			if (depend_file == (Stdio)0) {
				error_fatal("Could not open %s\n",
					    depend_file_name);
			}
			in_file = flags->in_file;
			(void)fprintf(depend_file, "%s/%s%s:",
				      flags->out_file->path,
				      flags->out_file->base,
				      flags->out_file->suffix);
			in_files = flags->in_files;
			size = vec_size(Flags_file, in_files);
			for (index = 0; index < size; index++) {
				in_file = vec_fetch(Flags_file,
						    in_files, index);
				(void)fprintf(depend_file, " %s/%s%s",
					      in_file->path, in_file->base,
					      in_file->suffix);
			}
			(void)fprintf(depend_file, "\n");
			(void)fclose(depend_file);
		}
		if (!flags->gen_interface) {
			if (flags->gen_object) {
				out_file = fopen(flags->c_file->full, "w");
			} else {
				out_file = fopen(flags->out_file->full, "w");
			}
			if (out_file == (Stdio)0) {
				error_fatal("Could not open %s\n",
					    flags->out_file->full);
			}
		}
	}

	out_initialize(heap);
	msg = msg_create(flags, heap);
	type_tables = type_tables_create(heap);
	object_table = object_table_create(msg, type_tables, heap);
	routine_table = routine_table_create(msg, type_tables, heap);
	type_def_table = type_tables->type_def_table;

	/* Create the gen object: */
	gen = heap_allocate(heap, Gen);
	gen->debug = flags->debug;
	gen->flags = flags;
	gen->frame = flags->debug ? "f." : "";
	gen->heap = heap;
	gen->linkage = flags->linkage;
	gen->loop_stack = vec_create(Str, heap);
	gen->msg = msg;
	gen->need_routine_ref = 0;
	gen->need_type_ref = 0;
	gen->object_table = object_table;
	gen->out_file = out_file;
	gen->package_name = "";
	gen->routine_table = routine_table;
	gen->temps = vec_create(Type_ref, heap);
	gen->type_def_table = type_def_table;
	gen->type_tables = type_tables;

	/* Open .sts file and generate .c file: */
	parser = parser_file_open(flags->in_file->full,
				  msg, 1, type_tables, flags, heap);
	parser->object_table = object_table;
	parser->routine_table = routine_table;
	parser->type_def_table = type_def_table;

	module = module_parse(parser);

	if (flags->gen_parse) {
		module_print(module, gen);
		(void)fclose(out_file);
		return msg_count_get(msg);
	}

	type_defs_insert(module->type_defs, type_tables,
			 object_table, msg, heap);

	if (flags->gen_interface) {
		if (msg_count_get(msg) == 0) {
			out_file = fopen(flags->out_file->full, "w");
			if (out_file == (Stdio)0) {
				error_fatal("Could not open %s\n",
					    flags->out_file->full);
			}
			module_write(module, gen, flags->out_file->full);
		}
		if (flags->dump_tables) {
			gen_tables_dump(gen, stdout);
		}
		return msg_count_get(msg);
	}

	module_imports_read(module, gen);
	type_defs_insert(module->import_type_defs, type_tables,
			 object_table, msg, heap);

	if (flags->import_dump) {
		gen_tables_dump(gen, stdout);
		type_defs_dump(module->import_type_defs, stdout);
	}

	convert = convert_create(gen);
	module_convert(module, convert);

	if (flags->gen_calls) {
		module_print(module, gen);
		(void)fclose(gen->out_file);
		return msg_count_get(msg);
	}

	module_gen(module, gen);
	(void)fclose(out_file);
	if (flags->gen_c) {
		return msg_count_get(msg);
	}

	if (msg_count_get(msg) > 0) {
		return msg_count_get(msg);
	}

	/* Compile the .c file to generate the .s file: */
	base_name = flags->in_file->base;
	out_name = flags->out_file->full;
	command = strvec_create(heap);
	if (flags->gen_patch) {
		strvec_print(command,
			  "%s -o /tmp/%s.o -c /tmp/%s.c; "
			  "ld -o %s /tmp/%s.o; rm /tmp/%s.o",
			  compiler,
			  base_name, base_name, out_name,
			  base_name, base_name);
	} else {
		Vec(Str)	options;
		int		index;
		int		size;

		strvec_print(command, "%s %s -o %s -c",
			      compiler,
			      flags->c_file->full,
			      flags->out_file->full);
		options = flags->options;
		size = vec_size(Str, flags->options);
		for (index = 0; index < size; index++) {
			Str	option;

			option = vec_fetch(Str, options, index);
			strvec_print(command, " %s", option);
		}
#ifdef SOLARIS
		strvec_print(command, " -Xa -vc");
#endif /* SOLARIS */
		if (flags->debug_c) {
			strvec_print(command, " -g");
		}
		if (flags->opt_pic) {
			strvec_print(command, " -pic");
		}
		if (flags->opt_level > 0) {
			strvec_print(command, " -O%d", flags->opt_level);
		}
		if (flags->profile) {
			strvec_print(command, " -xpg");		
		}
	}
	cmd = strvec_str_get(command, heap);
	if (flags->verbose) {
		(void)printf("%s\n", cmd);
	}
	if (flags->dump_tables) {
		gen_tables_dump(gen, stdout);
	}
	if (system(cmd) != 0) {
		return 1;
	}
	return msg_count_get(msg);
}

/*
 * gen_tables_dump(
 */
LOCAL void
gen_tables_dump(
	Gen		gen,
	Stdio		out_file)
{
	routine_table_dump(gen->routine_table, out_file);
	object_table_dump(gen->object_table, out_file);
}

