/* MIX simulator, copyright 1994 by Darius Bacon */ 
#include "mix.h"

#include "asm.h"
#include "driver.h"
#include "parse.h"
#include "run.h"
#include "symbol.h"

#include <assert.h>
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

static const char *current_file = NULL;
static unsigned line_number;
static unsigned num_errors = 0;

void fatal_error(const char *message, ...)
{
    va_list args;
    if (current_file)   /*** of course, the error may not have anything to do with the file... */
	fprintf(stderr, "FATAL ERROR (%s, line %u): ", current_file, line_number);
    else
	fprintf(stderr, "FATAL ERROR: ");
    va_start(args, message);
    vfprintf(stderr, message, args);
    va_end(args);
    fprintf(stderr, "\n");
    exit(1);
}

static void (*error_handler)(const char *, va_list) = NULL;

void install_error_handler(void (*handler)(const char *, va_list))
{
    error_handler = handler;
}

void error(const char *message, ...)
{
    va_list args;
    ++num_errors;
    va_start(args, message);
    if (error_handler)
	error_handler(message, args);
    else
        fatal_error("No error handler installed");
    va_end(args);
}

void warn(const char *message, ...)
{
    va_list args;
    if (current_file)
	fprintf(stderr, "WARNING (%s, line %u): ", current_file, line_number);
    else
	fprintf(stderr, "WARNING: ");
    va_start(args, message);
    vfprintf(stderr, message, args);
    va_end(args);
    fprintf(stderr, "\n");
}

/* --- Miscellany --- */

static FILE *open_file(const char *filename, const char *mode)
{
    if (strcmp(filename, "-") == 0) {
	assert(mode[0] == 'r' || mode[0] == 'w');
	return mode[0] == 'w' ? stdout : stdin;
    } else {
	FILE *result = fopen(filename, mode);
	if (!result)
	    fatal_error("%s: %s", filename, strerror(errno));
	return result;
    }
}

/* --- Main program --- */

static void assembler_error(const char *message, va_list args)
{
    if (current_file)
	fprintf(stderr, "ERROR (%s, line %u): ", current_file, line_number);
    else
	fprintf(stderr, "ERROR: ");
    vfprintf(stderr, message, args);
    fprintf(stderr, "\n");
}

static void assemble_file(const char *filename)
{
    FILE *infile = open_file(filename, "r");
    char line[257];
    current_file = filename, line_number = 0;
    while (fgets(line, sizeof line, infile)) {
	++line_number;
	assemble_line(line);
	if (line[strlen(line) - 1] != '\n') {
	    if (!fgets(line, sizeof line, infile))
	        break;		/* the file's last line had no '\n' */
	    else {
	        error("Line length exceeds 256 characters");
		/* Skip the rest of the line */
		while (line[strlen(line) - 1] != '\n')
		    if (!fgets(line, sizeof line, infile))
		        break;
	    }
	}
    }
    if (ferror(infile))
        error("%s: %s", filename, strerror(errno));
    fclose(infile);
    current_file = NULL;
}

int main(int argc, char **argv)
{
    precompute_field_data();

    /* Assemble the input: */
    install_error_handler(assembler_error);
    if (argc == 1)
	assemble_file("-");
    else {
	int i;
	for (i = 1; i < argc; ++i)
	    assemble_file(argv[i]);
    }
    resolve_generated_futures();
    if (num_errors != 0) {
	fprintf(stderr, "%u errors found\n", num_errors);
	exit(1);
    }

    /* Now run it: */
    set_initial_state();
    {
	clock_t finish, start = clock();
	run();
	finish = clock();
	fprintf(stderr, "%g seconds elapsed\n", 
		(float)(finish - start) / CLOCKS_PER_SEC);
    }
    print_CPU_state();
    return 0;
}


syntax highlighted by Code2HTML, v. 0.9.1