/******************************************************************************
 *      "Copyright (C) 2006, ApS s.r.o Brno, All Rights Reserved"             *
 ******************************************************************************
 *============================================================================*
 *   Version „number“    Header/source file for the project   "file name"     *
 *----------------------------------------------------------------------------*
 * VERSION   DATE    TIME  BY   CHANGE/COMMENTS                               *
 *----------------------------------------------------------------------------*
 *============================================================================*/
 
//  part of assembler generator
//    main assembler source file
//  
//  author:  Adam Husar, xhusar01@stud.fit.vutbr.cz
//  created: 27.03.2005
//  last change: 27.03.2005
//
//  changelist:
//    21.03.2006 Libor Vasicek, xvasic15@stud.fit.vutbr.cz
//    * save output to object file
//
////////////////////////////////////////////////////////////////////

#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <exception>

#include "codegen.h"
#include "objectfile.h"
#include "asmres.h"
#include "opschedull.h"
#include "swtiol.h"

#ifdef _MSC_VER
#define isatty _isatty
#endif

#include "asm_defs.h"
#include "asmparser.cpp"

#ifdef _MSC_VER
#undef isatty
#endif

using namespace std;

FILE *g_fin;
CCodeGen* codegen;

// prototype for the assembler scanner function
int asmscanner();


void PrintFileError(char* sName, const char* sOpeningType)
{
    fprintf(stderr, "Error: file \'%s\' could not be opened for %s.\n", sName, sOpeningType);
}

void ParserInit(/*const string & sFileIn*/ char *fname)
{
    if ((g_fin = fopen(fname, "r")) == NULL)
    {
        PrintFileError(fname, "reading");
        exit(ENOENT);
    }
    
    // initialisation of code generator
    codegen = new CCodeGen(FIRST_NONTERM_ID, LAST_NONTERM_ID, &getresmem);    
    codegen->SetFileName(fname);
}


void ParserClose()
{
    if (g_fin != 0)
    {
        fclose(g_fin);
        g_fin = 0;
    }

    ScannerClose();
    delete codegen;
}

void Parse()
{
    ScannerInit(); // set the default state of some variables
    ScannerSelectInput(g_fin);
    codegen->StartPass(CCodeGen::FIRST_PASS);
    yyparse();

    if (codegen->IsSuccesful())
    {
        rewind(g_fin);
	    ScannerInit();	// set the default state of some variables
        ScannerSelectInput(g_fin);
        codegen->StartPass(CCodeGen::LAST_PASS);
        yyparse();
    }
}

int main(int argc, char *argv[])
{
	char *g_ifilename = NULL;
	char *g_ofilename = NULL;

    try
    {
		// get program arguments
		swtiol_argpars_P2(argc, argv, &g_ifilename, &g_ofilename);

        // initialisation of the operations' scheduler - the argument is the assembler scanner        
        opschedull_init(&asmscanner);
		
		// initialisation of the parser        
        ParserInit(g_ifilename);
        
        // parse the input
        Parse();
		
		// save the created binary output
        if (codegen->PrintFinalResume(true))
        {
            CObjectFile * objFile;
            if ((objFile = codegen->GetAbsObjFile()) != 0)
            {
            	string tmp = g_ofilename; 	
                objFile->SaveFile(tmp + ".abs");
            }
            
            if ((objFile = codegen->GetRelObjFile()) != 0)
            {
            	string tmp = g_ofilename; 	
                objFile->SaveFile(tmp + ".rel");
        	}
        }
		
		// close the parser
        ParserClose();

        // deinitialisation of the operations' scheduler
        opschedull_deinit();
    }
    catch (exception & e)
    {
		// add error prefix before error message alone 
    	string tmp = "Error: ";
    	tmp+=e.what();
        cout << tmp.c_str() << endl;
    }

    return 0;
}
