/* cMain - Print out our main module, which is in C even if
 * we are generating the bulk of the code in assembler. */

#include "common.h"
#include "hash.h"
#include "dystring.h"
#include "pfCompile.h"
#include "pfParse.h"
#include "codedType.h"
#include "recodedType.h"
#include "cMain.h"

char *cStackName = "_pf_stack";
char *cStackType = "_pf_Stack";

void cPrintPreamble(struct pfCompile *pfc, FILE *f, char *fileName, 
	boolean doExtern)
/* Print out C code for preamble. */
{
fprintf(f, "/* This file is a translation of %s by paraFlow. */\n", 
	fileName);
fprintf(f, "\n");
fprintf(f, "#include \"pfPreamble.h\"\n");
fprintf(f, "\n");
if (doExtern)
   fprintf(f, "extern ");
fprintf(f, "_pf_Var _pf_var_zero;   /* Helps initialize vars to zero. */\n");
if (doExtern)
   fprintf(f, "extern ");
fprintf(f, "_pf_Array %sargs;	    /* Command line arguments go here. */\n",
	pfcGlobalPrefix);
fprintf(f, "static _pf_Bit %strue=1, %sfalse=0;\n", pfcGlobalPrefix, pfcGlobalPrefix);
if (doExtern)
   fprintf(f, "extern ");
fprintf(f, "_pf_String %sprogramName; /* Name of program (argv[0]) */\n",
	pfcGlobalPrefix);
fprintf(f, "\n");
}

static void printSysVarsAndPrototypes(FILE *f)
/* Print stuff needed for main() */
{
fprintf(f, "struct _pf_activation *_pf_activation_stack;\n");
fprintf(f, "struct %s *%s;\n", cModuleRuntimeType, cModuleRuntimeList);
fprintf(f, "void _pf_init_args(int argc, char **argv, _pf_String *retProg, _pf_Array *retArgs, char *environ[]);\n");
fprintf(f, "\n");
}

static void printModuleTable(struct pfCompile *pfc, FILE *f, 
	struct pfParse *program)
/* Print out table with basic info on each module */
{
struct pfParse *module;
int moduleCount = 0;
for (module = program->children; module != NULL; module = module->next)
    {
    if (module->name[0] != '<')
        {
	char *mangledName = mangledModuleName(module->name);
	fprintf(f, "extern struct %s %s_%s[];\n", 
	    recodedStructType, recodedTypeTableName, mangledName);
        fprintf(f, "extern struct _pf_poly_info _pf_poly_info_%s[];\n",
		mangledName);
	fprintf(f, "void _pf_entry_%s(%s *%s);\n", 
		mangledName, cStackType, cStackName);
	}
    }
fprintf(f, "\n");
fprintf(f, "struct _pf_module_info _pf_module_info[] = {\n");
for (module = program->children; module != NULL; module = module->next)
    {
    if (module->name[0] != '<')
        {
	char *mangledName = mangledModuleName(module->name);
	fprintf(f, "  {\"%s\", %s_%s, _pf_poly_info_%s, _pf_entry_%s,},\n",
	    mangledName, recodedTypeTableName, mangledName, mangledName,
	    mangledName);
	++moduleCount;
	}
    }
fprintf(f, "};\n");
fprintf(f, "int _pf_module_info_count = %d;\n\n", moduleCount);
}

static void printConclusion(struct pfCompile *pfc, FILE *f, 
	struct pfParse *mainModule)
/* Print out C code for end of program. */
{
fprintf(f, 
"\n"
"int main(int argc, char *argv[], char *environ[])\n"
"{\n"
"static _pf_Stack stack[16*1024];\n"
"_pf_init_mem();\n"
"_pf_init_types(_pf_base_info, _pf_base_info_count,\n"
"               _pf_type_info, _pf_type_info_count,\n"
"               _pf_field_info, _pf_field_info_count,\n"
"               _pf_module_info, _pf_module_info_count);\n"
"_pf_init_args(argc, argv, &%sprogramName, &%sargs, environ);\n"
"_pf_punt_init();\n"
"_pf_paraRunInit();\n"
"_pf_entry_%s(stack);\n"
"while (%s != 0)\n"
"    {\n"
"    %s->cleanup(%s, stack);\n"
"    %s = %s->next;\n"
"    }\n"
"return 0;\n"
"}\n", 
pfcGlobalPrefix, pfcGlobalPrefix, mangledModuleName(mainModule->name),
cModuleRuntimeList, cModuleRuntimeList, cModuleRuntimeList,
cModuleRuntimeList, cModuleRuntimeList);
}

void cMain(struct pfCompile *pfc, struct pfParse *program, char *fileName)
/* cMain - Print out our main module, which is in C even if
 * we are generating the bulk of the code in assembler.  This
 * includes type info, a module table, and the main entry point. */
{
FILE *f = mustOpen(fileName, "w");
struct pfParse *mainModule = program->children;
assert(mainModule->type == pptMainModule);
cPrintPreamble(pfc, f, fileName, FALSE);
printSysVarsAndPrototypes(f);
printModuleTable(pfc, f, program);
codedTypesToC(pfc, program, f);
printConclusion(pfc, f, mainModule);
carefulClose(&f);
}
