/************************************************************************/
/*                                                                      */
/* Copyright (c) 1988 -                                                 */
/*     The Rector and Visitors of the University of Virginia            */
/*                                                                      */
/* This code may not be distributed further without permission          */
/*      from the University of Virginia.                                */
/* This code is distributed WITHOUT ANY WARRANTY.  No claims are        */
/*      made as to whether it serves any particular purpose or even     */
/*      works at all.                                                   */
/*                                                                      */
/************************************************************************/

#include <stdio.h>
#include "types.h"
#include "error.h"
#include "nextline.h"
#include "object.h"

int  err_fatal=0;
char err_text[128];
extern void exit();

char *err_sev_text[] = {
	"Warning",
	"Fatal",
	"Exiting",
	"Internal Error"
};

/* commonly used error messages.  Many others appear _in_situ_ */

char
	err_undef[] = "%s \"%s\" is undeclared",
	err_notdef[] = "%s \"%s\" was never defined",
	err_open[] = "cannot open file \"%s\"",
	err_nomem[] = "memory allocation failure in \"%s\"",
	err_nonstd[] = "non-standard language feature used",
	err_boole[] = "\"%s\" expression is not boolean",
	err_nest[] = "program block nesting too deep",
	err_setmemb[] = "set members are not of same type",
	err_recurse[] = "recursive reference to %s \"%s\"",
	err_tag[] = "tag field \"%s\" passed as a variable parameter",
	err_forindex[] =
		"\"%s\" and %s for index expression are incompatible",
	err_fwidth[] =
		"illegal/inappropriate output field width (:) specifier",
	err_ordq[] = "\"%s\" is not an ordinal type",
	err_ord[] = "%s is not an ordinal type",
	err_unop[] = "illegal operand for %s",
	err_stdsubp[] =
		"illegal/missing parameter(s) passed to standard %s \"%s\"",
	err_eof[] = "syntax error:  end of file inside %s"
;

/*
 * array err_symbol maps a symbol to a string explaining what the
 * symbol is
 */

char *err_symbol[] = {
	/* Filler */     "",
	/* SY_AND */     "\"and\"",		
	/* SY_ARRAY */   "\"array\"",	
	/* SY_ASSIGN */  "\":=\"",		
	/* SY_BEGIN */   "\"begin\"",	
	/* SY_CASE */    "\"case\"",		
	/* SY_COLON */   "\":\"",		
	/* SY_COMMA */   "\",\"",		
	/* SY_CONST */   "\"const\"",	
	/* SY_DIGSEQ */  "digit sequence",	
	/* SY_DIV */     "\"div\"",		
	/* SY_DO */      "\"do\"",		
	/* SY_DOT */     "\".\"",		
	/* SY_DOTDOT */  "\"..\"",		
	/* SY_DOWNTO */  "\"downto\"",	
	/* SY_ELSE */    "\"else\"",		
	/* SY_END */     "\"end\"",		
	/* SY_ENDFILE */ "end of file",	
	/* SY_EQUAL */   "\"=\"",		
	/* SY_FILE */    "\"file\"",		
	/* SY_FOR */     "\"for\"",		
	/* SY_FUNC */    "\"function\"",	
	/* SY_GE */      "\">=\"",		
	/* SY_GOTO */    "\"goto\"",		
	/* SY_GT */      "\">\"",		
	/* SY_IDENT */   "identifier",	
	/* SY_IF */      "\"if\"",		
	/* SY_IN */      "\"in\"",		
	/* SY_LABEL */   "\"label\"",	
	/* SY_LBRAC */   "\"[\"",		
	/* SY_LE */      "\"<=\"",		
	/* SY_LPAREN */  "\"(\"",		
	/* SY_LT */      "\"<\"",		
	/* SY_MINUS */   "\"-\"",		
	/* SY_MOD */     "\"mod\"",		
	/* SY_NE */      "\"<>\"",		
	/* SY_NIL */     "\"nil\"",		
	/* SY_NOT */     "\"not\"",		
	/* SY_OF */      "\"of\"",		
	/* SY_OR */      "\"or\"",		
	/* SY_OTHERW */  "\"otherwise\"",
	/* SY_PACKED */  "\"packed\"",	
	/* SY_PLUS */    "\"+\"",		
	/* SY_PROC */    "\"procedure\"",	
	/* SY_PROGRAM */ "\"program\"",	
	/* SY_RBRAC */   "\"]\"",		
	/* SY_REAL */    "real constant",		
	/* SY_RECORD */  "\"record\"",	
	/* SY_REPEAT */  "\"repeat\"",	
	/* SY_RPAREN */  "\")\"",		
	/* SY_SEMI */    "\";\"",		
	/* SY_SET */     "\"set\"",		
	/* SY_SLASH */   "\"/\"",		
	/* SY_STAR */    "\"*\"",		
	/* SY_STRING */  "quoted string",	
	/* SY_THEN */    "\"then\"",		
	/* SY_TO */      "\"to\"",		
	/* SY_TYPE */    "\"type\"",		
	/* SY_UNTIL */   "\"until\"",	
	/* SY_UPARROW */ "\"^\"",		
	/* SY_VAR */     "\"var\"",		
	/* SY_WHILE */   "\"while\"",	
	/* SY_WITH */    "\"with\""		
};

/*
 * err_kind() maps the object kind to a string explaining what
 * the object is.
 */

char *
err_kind(kind)
	int kind;
{
	switch(kind) {
	case OB_ARRAY:
		return("array type");
	case OB_BOUNDID:
		return("bound identifier");
	case OB_CONFARRAY:
		return("conformant array type");
	case OB_CONST:
		return("constant");
	case OB_DIRECTIVE:
		return("directive");
	case OB_ENUMER:
		return ("enumerated type");
	case OB_FIELD:
		return ("record field");
	case OB_FILE:
		return ("file type");
	case OB_FUNC:
		return ("function");
	case OB_LABEL:
		return ("statement label");
	case OB_POINTER:
		return ("pointer type");
	case OB_PROC:
		return ("procedure");
	case OB_RECORD:
		return ("record type");
	case OB_SET:
		return ("set type");
	case OB_STDTYPE:
		return ("standard type");
	case OB_SUBRANGE:
		return ("subrange type");
	case OB_TYPE:
		return ("type");
	case OB_VALPARM:
		return ("value parameter");
	case OB_VARIABLE:
		return ("variable");
	case OB_VARPARM:
		return ("variable parameter");
	}
	return("unknown object");
}

/*
 * err_msg() prints all error messages from the compiler.
 * It prints out the source line and puts a ^ under the
 * offending input symbol.  Assumes additional error text
 * has been put in global variable err_text.
 */

err_msg(severity, where)
	int severity, where;
{
	int col;
	char *cp;
	struct src_line *line;
	static int fatalline = -1;
	static char *fatalfile = (char*)0;
	extern int opt_w;

	if (opt_w && severity == E_WARNING)		/* warnings suppressed */
		return;

	switch(where) {
	case E_CURSYMBOL:
		line = src_cursy->s_line;
		col  = src_cursy->s_column;
		break;
	case E_PREVSYMBOL:
		line = src_prevsy->s_line;
		col  = src_prevsy->s_column;
		break;
	case E_CURCHAR:	
		line = src_curline;
		col  = column();
		break;
	case E_CURLINE:
		line = src_curline;
		break;
	}

	if (severity == E_FATAL) {
		err_fatal=1;
		if (line->s_linenum == fatalline && line->s_name == fatalfile)
			return;
		fatalline = line->s_linenum;
		fatalfile = line->s_name;
	}

	fprintf (stderr, "\n%s: file \"%s\": line %d:\n\t%s\n",
		err_sev_text[severity], line->s_name, line->s_linenum,
		err_text);
	putc('\t', stderr);
	fputs(line->s_line, stderr);
	if (where != E_CURLINE) {
		putc('\t', stderr);
		for (cp = line->s_line; col--; cp++)
			putc (*cp == '\t' ? '\t' : ' ', stderr);
		putc('^', stderr);
		putc('\n', stderr);
	}
	if (severity >= E_TERMINATE)
		exit(1);
}
