static char rcsid[] = "$Id: C-main.c,v 1.18 2001/11/16 07:44:57 m-hirano Exp $";
/* 
 * $RWC_Release: Omni-1.6 $
 * $RWC_Copyright:
 *  Omni Compiler Software Version 1.5-1.6
 *  Copyright (C) 2002 PC Cluster Consortium
 *  
 *  This software is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License version
 *  2.1 published by the Free Software Foundation.
 *  
 *  Omni Compiler Software Version 1.0-1.4
 *  Copyright (C) 1999, 2000, 2001.
 *   Tsukuba Research Center, Real World Computing Partnership, Japan.
 *  
 *  Please check the Copyright and License information in the files named
 *  COPYRIGHT and LICENSE under the top  directory of the Omni Compiler
 *  Software release kit.
 *  
 *  
 *  $
 */
/* C-main.c: C language front-end: for now, K&R */

#include "C-front.h"

extern int	yyparse _ANSI_ARGS_((void));

static void 	usage _ANSI_ARGS_((char *com, int level));
static void 	where _ANSI_ARGS_((lineno_info *ln));
static void 	check_nerrors _ANSI_ARGS_((void));

/* for debug */
FILE   *debug_fp;
	/* these are used func in C-compile-decl.c(and C-lex.c) */
int     debug_flag = FALSE;	/* check point output */
int     debug_flag2 = FALSE;	/* check point output */
int     debug_expr_flag = FALSE;	/* func/ext.def input arg out */
int     debug_X_flag = FALSE;	/* func/ext.def result IR out */
int     debug_X_flag2 = FALSE;	/* local debug for IR */

/* process mode flag: default is only 'C source -> internal-structure' */
int     output_X_flag = FALSE;	/* int-structure -> file */
int     input_X_flag = FALSE;	/* file -> structure */
int     decompile_flag = FALSE;	/* int-structure -> (new) C source */
int     no_omp_flag = FALSE;   /* disable openmp, enable default. */
#ifdef USE_OPENGR_PRAGMA
int	no_ogr_flag = FALSE;	/* disable OpenGR, enable default. */
#endif /* USE_OPENGR_PRAGMA */
int     array_arg_flag = FALSE; /* don't convert array arg to pointer */

expv    global_decl_list;	/* root of global decl and procedure */
TYPE_DESC type_list, type_list_tail;	/* used in X-io.c */

/* the number of errors */
int     nerrors;

/* input file table */
int  	n_files = 0;
char 	*file_names[MAX_N_FILES];

/* input-X/output C/output-X file name and FILE pointer */
char   *source_file_name, *output_file_name, *outX_file_name;
FILE   *source_file, *output_file, *out_X_file;

/* command line options */
struct option_name{
    int  lev;	/* option level(public(0) or internal(1)) */
    int  * flagp;	/* pointer to the flag */
    char * lname;	/* long or full option name */
    char * sname;	/* short name */
    char * detail;	/* for help */
};

static struct option_name  option_strings[] = {
    {0, NULL, "help", "h", "show help message"},
    {1, NULL, "-help", "-h", "show extra help message"},
    {2, NULL, "-help2", "-h2", "show extra help message 2"},
    {0, &input_X_flag, "input-X", "inx", "read X-code"},
    {0, &output_X_flag, "output-X", "outx", "output X-code"},
    {0, &decompile_flag, "decompile", "outc", "output decompiled C source"},
    {0, &output_X_flag, "out-Xfile", "xf", "file name for X-code"},
    {0, &decompile_flag, "decomp-file", "o", "file name for C source"},
    {1, &debug_flag, "debug", "d", "debug ouput mode"},
    {1, &debug_expr_flag, "debug-expr", "de", "function input output"},
    {1, &debug_X_flag, "debug-X", "dx", "transformed IR output"},
    {2, &debug_flag2, "dbg-xtr", "d2", "debug output mode 2"},
    {2, &debug_X_flag2, "dbgX-xtr", "dx2", "transformed IR output 2"},
    {0, &alignment_double, "malign-double", "ad", "set double aligment to 8 byte align"},
    {0, &no_omp_flag, "no_omp", "omp", "disable OpenMP pragma"},
    {0, &array_arg_flag, "array-arg", "array-arg", "don't convert arrray arg to pointer"},
#ifdef USE_OPENGR_PRAGMA
    {0, &no_ogr_flag, "no_ogr", "ogr", "disable OpenGR pragma"},
#endif /* USE_OPENGR_PRAGMA */
    {INT_MAX, NULL, NULL, NULL, NULL}
};

int main(int     argc, char   *argv[])
{
    char *cp;
    char   * command;	/* command name (except dir) */
    int  i, flag;
    TYPE_DESC tp;

	/* default file */
    source_file_name = NULL;
    output_file_name = NULL;
    outX_file_name = NULL;
    source_file = stdin;
    output_file = stdout;
    out_X_file = stdout;
    debug_fp = stderr;	/* DEBUG output file */

    command = strip_dir(argv[0]);
    argc--, argv++;
    while ( argc > 0 ){
	if ( argv[0][0] != '-' ){	/* last wins */
	    source_file_name = argv[0];
	    argc--, argv++;
	    continue;
	}
	flag = 0;
	cp = &argv[0][1];	/* next to the '-' */
	for (i = 0;
	     (option_strings[i].lname != NULL &&
	      option_strings[i].sname != NULL);
	     i++) {
	    if ( strcmp(option_strings[i].lname, cp) == 0 ||
		 strcmp(option_strings[i].sname, cp) == 0 ){
		if ( option_strings[i].flagp != NULL ){
		    (*option_strings[i].flagp)++;
		    flag++;
		    if ( strcmp(option_strings[i].sname, "xf") == 0 ){
			if ( argv[1][0] != '-' ){
			    outX_file_name = argv[1];
			    argc--, argv++;
			}
			else{
			    fprintf(stderr, "file name must be specified for -%s\n", cp);
			    usage(command, 0);
			    exit(1);
			}
		    }
		    else if ( strcmp(option_strings[i].sname, "o") == 0 ){
			if ( argv[1][0] != '-' ){
			    output_file_name = argv[1];
			    argc--, argv++;
			}
			else{
			    fprintf(stderr, "file name must be specified for -%s\n", cp);
			    usage(command, 0);
			    exit(1);
			}
		    }
		    break;
		}
		else{	/* -h/--h */
		    usage(command, option_strings[i].lev);
		    exit(1);
		}
	    }
	}
	if ( flag == 0 ){
	    fprintf(stderr, "unknown flag: -%s\n", cp);
	    usage(command, 0);
	    exit(1);
	}
	argc--, argv++;
    }

#ifdef USE_OPENGR_PRAGMA
    if (no_ogr_flag == FALSE) {
	init_OGR_pragma();
    }
#endif /* USE_OPENGR_PRAGMA */

    if ( source_file_name != NULL ){
	source_file = fopen(source_file_name, "r");
	if ( source_file == NULL ){
	    fprintf(stderr, "cannot open %s\n", source_file_name);
	    exit(1);
	}
    } else {
	source_file_name = "<stdin>";
    }
    /* set title as input source file name */
    current_line = new_line_info(get_file_id(source_file_name),1);

    if ( outX_file_name != NULL ){
	out_X_file = fopen(outX_file_name, "w");
	if ( out_X_file == NULL ){
	    fprintf(stderr, "cannot open %s\n", outX_file_name);
	    exit(1);
	}
    }

    if ( output_file_name != NULL ){
	output_file = fopen(output_file_name, "w");
	if ( output_file == NULL ){
	    fprintf(stderr, "cannot open %s\n", output_file_name);
	    exit(1);
	}
    }

    initialize_compile();

    if (input_X_flag) {	/* input is IR(X-code) file */
	input_X_file();
    } else {	/* input is C source */
	initialize_lex();
	yyparse();
	if(nerrors == 0){
	    collect_types();	/* list-up used type */
	    if(debug_flag2) debug_output_X_type();
	}
    }

    if (debug_X_flag2){
	fprintf(debug_fp, "\n\n****global ID list dump****************\n");
	dump_id_list(0);
	fprintf(debug_fp, "****global ID list dump end************\n\n\n");
    }

    if (debug_flag){
	int i;
	fprintf(debug_fp, "##type list start=============================\n");
	for( tp = type_list, i = 0 ; tp != NULL ; tp = TYPE_LINK(tp), i++){
	    fprintf(debug_fp, "---------type list[%d]----------\n", i);
	    print_type(tp, debug_fp);
	    fprintf(debug_fp, "\n");
	}
	fprintf(debug_fp, "##type list end===============================\n");

	fprintf(debug_fp, "======global decl list dump===================\n");
	X_output(global_decl_list, debug_fp);
	fprintf(debug_fp, "======global list end=========================\n");
    }

    if(nerrors != 0)
	return (1);

    if(output_X_flag)	/* output IR(X-code) to file */
	output_X_file();

    if(decompile_flag)	/* output C source to file */
	decompile_file();

    return (nerrors ? 1 : 0);
}

/* command line argument information */
static void usage(char   *com,
	   int  level /* output control(0: normal, 1-..: extra) */)
{
    int  i;
    fprintf(stderr, "Usage: %s [-options] [input-file]\n", com);
    fprintf(stderr, "\noptions are:\n");

    for (i = 0;
	 (option_strings[i].lname != NULL &&
	  option_strings[i].sname != NULL);
	 i++) {
	if ( option_strings[i].lev > level )
	    continue;
	fprintf(stderr, "    -%s/-%s", option_strings[i].lname, 
		option_strings[i].sname);
	if ( strcmp(option_strings[i].sname, "xf") == 0 ||
	     strcmp(option_strings[i].sname, "o") == 0 )
	    fprintf(stderr, " file-name");
	if ( strcmp(option_strings[i].sname, "h") == 0 ||
	     strcmp(option_strings[i].sname, "-h") == 0 ||
	     strcmp(option_strings[i].sname, "d") == 0 )
	    fprintf(stderr, "\t");
	fprintf(stderr, "\t: %s\n", option_strings[i].detail);
    }
    fprintf(stderr, "\n");
}

/* get command name */
char * strip_dir(char  * name)
{
    char  *str;
    str = strrchr(name, '/');
    if ( str == NULL )
	return name;
    else
	return ++str;
}

/*
 * file name table
 */
int get_file_id( char *file)
{
    int i;
    for(i = 0; i < n_files; i++){
	if(strcmp(file_names[i],file) == 0) return i;
    }
    if(n_files >= MAX_N_FILES) 
      fatal("too many files (max No. of files = %d)",MAX_N_FILES);
    file_names[i = n_files++] = strdup(file);
    return i;
}

/*
 * error messages
 */
static void where(lineno_info *ln)
{
    /* print location of error  */
    if(ln != NULL)
      fprintf(stderr, "\"%s\", line %d: ", FILE_NAME(ln->file_id), ln->ln_no);
    else 
      fprintf(stderr, "\"%s\", line ?: ",FILE_NAME(current_line->file_id));
}

static lineno_info *get_line_no(expr x)
{
    lineno_info *ln;
    struct list_node *lp;

    if(x == NULL) return NULL;
    if((ln = EXPR_LINE(x)) != NULL) return ln;
    if (EXPR_CODE_IS_TERMINAL(EXPR_CODE(x))) return NULL;
    FOR_ITEMS_IN_LIST(lp,x){
	if((ln = get_line_no(LIST_ITEM(lp))) != NULL) 
	    return ln;
    }
    return NULL;
}

/* nonfatal error message */
/* VARARGS0 */
void
error EXC_VARARGS_DEF(char *, fmt)
{ 
    va_list args;

    ++nerrors;
    where(current_line);
    EXC_VARARGS_START(char *, fmt, args);
    vfprintf(stderr, fmt, args);
    va_end(args);
    fprintf(stderr, "\n" );
    fflush(stderr);
    check_nerrors();
}

/* VARARGS0 */
void
warning EXC_VARARGS_DEF(char *, fmt)
{ 
    va_list args;

    where(current_line);
    fprintf(stderr,"warning: ");
    EXC_VARARGS_START(char *, fmt, args);
    vfprintf(stderr, fmt, args);
    va_end(args);
    fprintf(stderr, "\n" );
    fflush(stderr);
    check_nerrors();
}

/* VARARGS0 */
void
error_at_node EXC_VARARGS_DEF(expr, x)
{
    va_list args;
    char *fmt;

    ++nerrors;
    EXC_VARARGS_START(expr, x, args);
    where(get_line_no(x));
    fmt = va_arg(args, char *);
    vfprintf(stderr, fmt, args);
    va_end(args);
    fprintf(stderr, "\n" );
    fflush(stderr);
    check_nerrors();
}

/* VARARGS0 */
void
warning_at_node EXC_VARARGS_DEF(expr, x)
{ 
    va_list args;
    char *fmt;

    where(get_line_no(x)); /*, "WarnAtNode"); */
    fprintf(stderr,"warning: ");
    EXC_VARARGS_START(expr, x, args);
    fmt = va_arg(args, char *);
    vfprintf(stderr, fmt, args);
    va_end(args);
    fprintf(stderr, "\n" );
    fflush(stderr);
}

/* compiler error: die */
/* VARARGS1 */
void
fatal EXC_VARARGS_DEF(char *, fmt)
{ 
    va_list args;
    
    where(current_line); /*, "Fatal");*/
    fprintf(stderr, "compiler error: " );
    EXC_VARARGS_START(char *, fmt, args);
    vfprintf(stderr, fmt, args);
    va_end(args);
    fprintf(stderr, "\n" );
    fflush(stderr);
    abort();
}

static void check_nerrors()
{
    if (nerrors > 30) {	/* give the compiler the benefit of the doubt */
	fprintf(stderr,
	  "too many error, cannot recover from earlier errors: goodbye!\n");
	exit(1);
    }
}

