/* l2xierr.c  LTX2X interpreter error handler */
/*  Written by: Peter Wilson, CUA  [email protected]                */
/*  This code is partly based on algorithms presented by Ronald Mak in */
/*  "Writing Compilers & Interpreters", John Wiley & Sons, 1991        */

#include <stdio.h>
#include "l2xicmon.h"
#include "l2xierr.h"

/* externals */

extern char *tokenp;
extern BOOLEAN print_flag;
extern char source_buffer[];
extern char *bufferp;

/* error messages: keyed to enum types in error.h from l2xiertc.h */

char *error_messages[] = {
#define petc(a, b) b,
#define pwtc(a, b)
#define rtetc(a, b)
#define rtwtc(a, b)
#include "l2xiertc.h"
#undef petc
#undef pwtc
#undef rtetc
#undef rtwtc
     };


char *warning_messages[] = {
#define petc(a, b)
#define pwtc(a, b) b,
#define rtetc(a, b)
#define rtwtc(a, b)
#include "l2xiertc.h"
#undef petc
#undef pwtc
#undef rtetc
#undef rtwtc
     };

char *runtime_error_messages[] = {
#define petc(a, b)
#define pwtc(a, b)
#define rtetc(a, b) b,
#define rtwtc(a, b)
#include "l2xiertc.h"
#undef petc
#undef pwtc
#undef rtetc
#undef rtwtc
     };

char *runtime_warning_messages[] = {
#define petc(a, b)
#define pwtc(a, b)
#define rtetc(a, b)
#define rtwtc(a, b) b,
#include "l2xiertc.h"
#undef petc
#undef pwtc
#undef rtetc
#undef rtwtc
     };

/* stack types */
typedef enum {
#define fotc(a, b, c, d)
#define sotc(a, b, c, d) a,
#define sftc(a, b, c, d) a,
#include "l2xisftc.h"
#undef fotc
#undef sotc
#undef sftc
} STACK_TYPE;


/* LOCALS */
#define EOS '\0'

/* GLOBALS  */

int isynt_error_count = 0;   /* number of syntax errors */
int isynt_warn_count = 0;    /* number of syntax warnings */
int irun_error_count = 0;    /* number of runtime errors */
int irun_warn_count = 0;     /* number of runtime warnings */
char message_buffer[MAX_PRINT_LINE_LENGTH];

/***************************************************************************/
/* error(code)   Print an arrow under the error, then the error message    */

error(code)
ERROR_CODE code;     /* error code */
{
 extern int buffer_offset;
 char *message = error_messages[code];
 int offset = buffer_offset - 2;

 ++isynt_error_count;

 /* print the arrow pointing to just scanned token */
 if (print_flag) offset += 8;
 sprintf(message_buffer, "%*s^\n", offset, " ");
 if (print_flag) {
   print_line(message_buffer);
 }
 else {
    print_error(message_buffer);
  }

 /* print the error message */
 sprintf(message_buffer, " ***ERROR: %s.\n", message);
 if (print_flag) {
   print_line(message_buffer);
 }
 else {
    print_error(message_buffer);
  }

 *tokenp = EOS;

 if (isynt_error_count > MAX_SYNTAX_ERRORS) {
   sprintf(message_buffer, "Too many syntax errors.\n");
   if (print_flag) {
     print_line(message_buffer);
   }
   else {
     print_error(message_buffer);
   }
   exit(-TOO_MANY_SYNTAX_ERRORS);
 }

}                                                             /* end error */
/***************************************************************************/



/***************************************************************************/
/* compile_warning(code)   Print an arrow under the error, then the        */
/*                         warning message                                 */

compile_warning(code)
WARNING_CODE code;     /* warning code */
{
 extern int buffer_offset;
 char *message = warning_messages[code];
 int offset = buffer_offset - 2;

 ++isynt_warn_count;

 /* print the arrow pointing to just scanned token */
 if (print_flag) offset += 8;
 sprintf(message_buffer, "%*s^\n", offset, " ");
 if (print_flag) {
   print_line(message_buffer);
 }
 else {
    print_error(message_buffer);
  }

 /* print the warning message */
 sprintf(message_buffer, " ***WARNING: %s.\n", message);
 if (print_flag) {
   print_line(message_buffer);
 }
 else {
    print_error(message_buffer);
  }

 *tokenp = EOS;

}                                                           /* end warning */
/***************************************************************************/



/***************************************************************************/
/* runtime_error(code)   Print a runtime error message and then debug      */

runtime_error(code)
RUNTIME_ERROR_CODE code;     /* error code */
{
 extern int exec_line_number;
 extern long exec_stmt_count;
 char *message = runtime_error_messages[code];
 extern BOOLEAN debugger_command_flag;

 ++irun_error_count;

 if (SLD_OFF) {    /* source level debugger disabled -- abort */
   sprintf(message_buffer, "\n*** RUNTIME ERROR in line %d: %s\n",
            exec_line_number, message);
   print_error(message_buffer);
   sprintf(message_buffer, "\nUnsuccessful completion. %ld statements executed.\n\n",
                            exec_stmt_count);
   print_error(message_buffer);
   exit(-code);
 }

 if (debugger_command_flag) {
   print_error(message);
   print_error("\n");
 }
 else {
   sprintf(message_buffer, "\n*** RUNTIME ERROR in line %d: %s\n",
            exec_line_number, message);
   print_error(message_buffer);
   read_debugger_command();
 }

}                                                     /* end runtime_error */
/***************************************************************************/



/***************************************************************************/
/* runtime_warning(code)   Print a runtime warning message and then debug  */

runtime_warning(code)
RUNTIME_WARNING_CODE code;     /* warning code */
{
 extern int exec_line_number;
 extern long exec_stmt_count;
 char *message = runtime_warning_messages[code];
 extern BOOLEAN debugger_command_flag;

 if (INVALID_STACK_ACCESS == code) return;

 ++irun_warn_count;

 if (SLD_OFF) {    /* source level debugger disabled */
   sprintf(message_buffer, "\n*** RUNTIME WARNING in line %d: %s\n",
            exec_line_number, message);
   print_error(message_buffer);
   return;
 }

 if (debugger_command_flag) {
   print_error(message);
   print_error("\n");
 }
 else {
   sprintf(message_buffer, "\n*** RUNTIME WARNING in line %d: %s\n",
            exec_line_number, message);
   print_error(message_buffer);
   read_debugger_command();
 }
 return;
}                                                   /* end runtime_warning */
/***************************************************************************/



/***************************************************************************/
/* stack_warning(etype, ftype)   Print a runtime warning message about     */
/*               stack access and then debug                               */

stack_warning(etype, ftype)
STACK_TYPE etype;                 /* expected type */
STACK_TYPE ftype;                 /* type actually found */
{
 extern int exec_line_number;
 extern long exec_stmt_count;
 RUNTIME_WARNING_CODE code1, code2;
 extern BOOLEAN debugger_command_flag;

 code1 = RUNTIME_WARN;
 switch (etype) {           /* report the expected type */
   case STKINT:
   case STKREA: {
     code1 = EXPECTED_NUMBER;
     break;
   }
   case STKLOG: {
     code1 = EXPECTED_LOGICAL;
     break;
   }
   case STKADD: {
     code1 = EXPECTED_ADDRESS;
     break;
   }
   case STKARY: {
     code1 = EXPECTED_ARRAY;
     break;
   }
   case STKBAG: {
     code1 = EXPECTED_BAG;
     break;
   }
   case STKLST: {
     code1 = EXPECTED_LIST;
     break;
   }
   case STKSET: {
     code1 = EXPECTED_SET;
     break;
   }
   case STKSTR: {
     code1 = EXPECTED_STRING;
     break;
   }
   case STKENT: {
     code1 = EXPECTED_ENTITY;
     break;
   }
   case STKUDF: {
     code1 = EXPECTED_UDF;
     break;
   }
 }  /* finished expected type */

 code2 = RUNTIME_WARN;
 switch (ftype) {           /* report the found type */
   case STKINT:
   case STKREA: {
     code2 = FOUND_NUMBER;
     break;
   }
   case STKLOG: {
     code2 = FOUND_LOGICAL;
     break;
   }
   case STKADD: {
     code2 = FOUND_ADDRESS;
     break;
   }
   case STKARY: {
     code2 = FOUND_ARRAY;
     break;
   }
   case STKBAG: {
     code2 = FOUND_BAG;
     break;
   }
   case STKLST: {
     code2 = FOUND_LIST;
     break;
   }
   case STKSET: {
     code2 = FOUND_SET;
     break;
   }
   case STKSTR: {
     code2 = FOUND_STRING;
     break;
   }
   case STKENT: {
     code2 = FOUND_ENTITY;
     break;
   }
   case STKUDF: {
     code2 = FOUND_UDF;
     break;
   }
 }  /* finished found type */



 if (SLD_OFF) {    /* source level debugger disabled */
   sprintf(message_buffer, "\n*** RUNTIME WARNING in line %d:\n    %s\n    %s\n",
            exec_line_number,
            runtime_warning_messages[code1],
            runtime_warning_messages[code2]);
   print_error(message_buffer);
   return;
 }

 if (debugger_command_flag) {
   sprintf(message_buffer, "\n    %s\n    %s\n",
            runtime_warning_messages[code1],
            runtime_warning_messages[code2]);
   print_error(message_buffer);
 }
 else {
   sprintf(message_buffer, "\n*** RUNTIME WARNING in line %d:\n    %s\n    %s\n",
            exec_line_number,
            runtime_warning_messages[code1],
            runtime_warning_messages[code2]);
   print_error(message_buffer);
   read_debugger_command();
 }
 return;
}                                                     /* end STACK_WARNING */
/***************************************************************************/



/***************************************************************************/
/* print_error(string) Prints to error file(s)                             */

print_error(string)
char string[];
{

 fprintf(ferr, "%s", string);
 fflush(ferr);
 fprintf(stderr, "%s", string);
 fflush(stderr);
 if (filout != stdout) {
   fprintf(filout, "%s", string);
   fflush(filout);
 }
 return;
}                                                       /* end print_error */
/***************************************************************************/