/* l2xistup  LTX2X interpreter initialisation and start up code */

#include <stdio.h>
#include "getopt.h"
#include "l2xicmon.h"
#include "l2xisymt.h"
#include "l2xiexec.h"
#include "l2xierr.h"        /* need this for MISSING_ENDCODE */
#include "l2xiscan.h"       /* need this for SEMICOLON, etc */
#include "l2xiprse.h"       /* need this for if_token_get_else_error */

#include "l2xiidbg.h"

#ifndef l2xicpr_h
#include "l2xicpr.h"        /* the before/after token lists */
#endif


/* EXTERNALS */

/* extern int exec_line_number; */
/* extern char word_string[]; */
/* extern SYMTAB_NODE_PTR symtab_display[]; */
/* extern int level; */

extern TYPE_STRUCT_PTR integer_typep, real_typep,
                       boolean_typep;
extern int exec_stmt_count;
extern STACK_ITEM *stack;
/* extern SYMTAB_NODE_PTR program(); */
extern SYMTAB_NODE_PTR create_dummy_prog();

extern int DEBUG;           /* defined in l2xlib.c */
extern int cl_debug;        /* defined in l2xlib.c */
extern int cdebug;      /* defined in l2xlib.c */
extern int edebug;      /* defined in l2xlib.c */

extern BOOLEAN executed_return;         /* TRUE iff return statement executed */

/* GLOBALS */

char THE_TITLE[] = "THE INTERPRETER";
char INT_FILE_VERSION[] = "Version 0.1";
char INT_FILE_DATE[] = "January 1997";

/* int DEBUG = 0;    debugging level */
int Dbasic = 1;   /* DEBUG >= Dbasic  -> basic debugging */
int Danalyze = 2; /* DEBUG >= Danalyze -> declaration analysis debugging */
int Dtrace = 3;   /* DEBUG >= Dtrace  -> trace routine call tree */
int Dscan = 4;    /* DEBUG >= Dscan -> source buffer debugging */
int Dtraceall = 5; /* DEBUG >= Dtraceall ->  */
int Dott = 100;   /* Hopefully, too high for all debugging */
extern int SLD_OFF; /* FALSE to enable source level debugger */

ICT *code_buffer;           /*  code buffer */
ICT *code_bufferp;          /*  code buffer ptr */

FILE *ferr;                 /* error o/p */
FILE *fcodeseg;             /* code segment o/p */
FILE *filout;               /* output file */

     /* EXTERNALS */
extern ICT *create_code_segment();
extern TYPE_STRUCT dummy_type;
extern TOKEN_CODE statement_start_list[];
extern TOKEN_CODE token;
extern TOKEN_CODE ctoken;
extern ICT *code_segmentp;
extern FILE *source_file;           /* file the scanner reads */
extern FILE *yyout;                 /* output file for LTX2X */
extern int get_ct_linenum();        /* gets current ct line number */
extern void set_ct_linenum();       /* sets current ct line number */
extern int line_number;             /* interp scanners line number */
extern FILE *filerr;                /* LTX2X's error file */


     /* FORWARDS */
/* SYMTAB_NODE_PTR create_dummy_prog(); */
void start_code();


/***************************************************************************/
/* code_setup(filtabin)  Initialise the scanner, etc then                  */
/*                    call the start_code routine to do the work.          */

SYMTAB_NODE_PTR code_setup(filtabin)
FILE *filtabin;                          /* input file */
{
  char optchar;
  int n, k;
  SYMTAB_NODE_PTR program_idp;
/*  BOOLEAN cdebug = TRUE;              if TRUE enable source Code debug */
/*  BOOLEAN edebug = TRUE;              if TRUE enable Execution debug */

              /* print the banner */
/*
*  fprintf(stdout, "\n    %s", THE_TITLE);
*  fprintf(stdout, "\n    (%s, %s)\n", INT_FILE_VERSION, INT_FILE_DATE);
*/

             /* open output log files */
/*  ferr = fopen("interp.err", "w"); */
  ferr = filerr;    /* set error file to be ltx2x's */
  fcodeseg = fopen("interp.csg", "w");

/*  fprintf(stdout, "\nLog file is interp.err\n"); */
  fprintf(stdout, "Code segment log file is interp.csg\n");

  fprintf(ferr, "Error log file for %s (%s, %s)\n", 
                                    THE_TITLE, INT_FILE_VERSION, INT_FILE_DATE);
  fprintf(ferr, "Author: Peter Wilson (Catholic University and NIST)\n");
  fprintf(ferr, "Email any comments or suggestions to: pwilson@cme.nist.gov\n\n");
  fprintf(ferr, "Code segment log file is interp.csg\n\n");

            /* set the output file */
  filout = yyout;

  
  /* set debug level for source Code */
  if (cdebug) {
    DEBUG = cl_debug;
  }
  else {
    DEBUG = 0;
  }



  /* initialise the scanner */
/*  init_scanner(argv[k]); */
  line_number = get_ct_linenum();     /* set scanner's line number counter */
  init_scanner(filtabin);

  /* initialise code buffer */
  code_buffer = alloc_array(ICT, MAX_CODE_BUFFER_SIZE);
  code_bufferp = code_buffer;
  if (DEBUG >= Dbasic) {
    sprintf(dbuffer, "Initialised: code_buffer = %d, code_bufferp = %d\n",
                      code_buffer, code_bufferp);
    debug_print(dbuffer);
  }

  /* initialise the symbol table */
  init_symtab();
  if (DEBUG >= Dbasic) {
    sprintf(dbuffer, "Initialised the symbol table\n");
    debug_print(dbuffer);
  }

  /* create an artificial program node */
  program_idp = create_dummy_prog();

  /* parse the remainder of the code */
  /* zero or more declarations, followed by zero or more statements */
  start_code(program_idp);

    /* Don't think we want this as everyting from now on is in prog scope */
/*  program_idp->defn.info.routine.local_symtab = exit_scope(); */
  program_idp->defn.info.routine.code_segment = create_code_segment();
  analyze_block(program_idp->defn.info.routine.code_segment);

  /* reset CT line number to the scanner's value */
  set_ct_linenum(line_number);
  return(program_idp);



  /* free the stack */
/*
  free(stack);
  fprintf(filout, "\n\nCompleted. %ld statements executed. \n\n",
                  exec_stmt_count);

  if (DEBUG >= Dbasic) {
    sprintf(dbuffer, "\n\n***That's all for run4\n\n");
    debug_print(dbuffer);
  }
  return(program_idp);
*/
}                                                      /* end CODE_SETUP */
/***************************************************************************/



/***************************************************************************/
/* SYMTAB_NODE_PTR create_dummy_prog()  create an artifical program node   */
/*                 much of this code comes from `program_header'           */

SYMTAB_NODE_PTR old_create_dummy_prog()
{

  SYMTAB_NODE_PTR prog_idp;

  prog_idp = alloc_struct(SYMTAB_NODE);
  /* use dummy program name */
/*  strcpy(word_string, "_PrOgRaM"); */
/*  search_and_enter_local_symtab(prog_idp); */
  prog_idp->defn.key = PROG_DEFN;
  prog_idp->defn.info.routine.key = DECLARED;
  prog_idp->defn.info.routine.parm_count = 0;
  prog_idp->defn.info.routine.total_parm_size = 0;
  prog_idp->defn.info.routine.total_local_size = 0;
  prog_idp->typep = &dummy_type;
  prog_idp->label_index = 0;

  enter_scope(NULL);
  
  prog_idp->defn.info.routine.locals = NULL;
  prog_idp->defn.info.routine.parms = NULL;

  return(prog_idp);
}                                                 /* end CREATE_DUMMY_PROG */
/***************************************************************************/


TOKEN_CODE ltx2x_start_declarations_list[] = {XCONSTANT, XLOCAL, PROCEDURE,
                                             FUNCTION, 0};

/***************************************************************************/
/* start_code(rtn_idp)  Parse the starting code, which consists of         */
/*                      declarations, followed by zero or more statements  */
/*                      ends at token ENDCODE                              */
/*                      ( similar to block in interp )                     */

void start_code(rtn_idp)
SYMTAB_NODE_PTR rtn_idp;        /* id of `program' or routine */
{

  extern BOOLEAN block_flag;

  get_token();
  if (token == ENDCODE) {
    crunch_token();
    crunch_statement_marker();
    return;
  }

  if (token_in(declaration_start_list)) {
    declarations(rtn_idp);
    /* error synchronization: Should be ; */
    synchronize(ltx2x_follow_decls_list, NULL, NULL);
  }
  else {
    skip_declarations(rtn_idp);
  }

  if (token == ENDCODE) {
    crunch_token();
    crunch_statement_marker();
    return;
  }

/*  if (token == BEGIN) {
*    crunch_token(); 
*  }
*/

  block_flag = TRUE;
  
  /* now for possibly empty list of statements */
  statement_block();
/*  if (token_in(statement_start_list)) {
*    crunch_token();
*    statements();
*  }
*/
  block_flag = FALSE;

  return;

}                                                        /* end START_CODE */
/***************************************************************************/



/***************************************************************************/
/* statements()       process a set of statements                          */
/*                  originally based on `compound_statement'               */
/*    at entry, token is (crunched) start of a statement                   */
/*    at exit, token is after closing ; of a statement                     */

statements()
{

  entry_debug("statements");
/*  get_token(); */

  while (token_in(statement_start_list)) {
    statement();
    get_token();
  }

  exit_debug("statements");
  return;

}                                                        /* end STATEMENTS */
/***************************************************************************/



/***************************************************************************/
/* statement_block()    Process a list of statements ended by END_CODE     */
/*          at entry, token is start of a statement or ENDCODE             */
/*          at exit, parsing is complete                                   */

statement_block()
{
  entry_debug("statement_block");

  if (token_in(statement_start_list)) {
    crunch_token();
    statements();
  }

  if (token != ENDCODE) {
    error(MISSING_ENDCODE);
  }
  else {
    crunch_statement_marker();
/*    crunch_token(); */
  }

  exit_debug("statement_block");
  return;
}                                                   /* end STATEMENT_BLOCK */
/***************************************************************************/





/***************************************************************************/
/* code_action(filtabin)       Parsing for CODE:                           */
/*                                                                         */

ICT *code_action(filtabin)
FILE *filtabin;                  /* the input file */
{
  extern BOOLEAN block_flag;
  entry_debug("code_action");

  /* set the file and the line number for the scanner */
  source_file = filtabin;
  line_number = get_ct_linenum();

  get_token();

  if (token == ENDCODE) {
    crunch_token();
    crunch_statement_marker();
    exit_debug("code_action at ENDCODE");
    return(create_code_segment());
  }

/*  if (token == BEGIN) {
*    crunch_token(); 
*  }
*/

  block_flag = TRUE;
  
  /* now for possibly empty list of statements */

  statement_block();
/*  if (token_in(statement_start_list)) {
*    crunch_token();
*    statements();
*  }
*/
  block_flag = FALSE;

  /* reset the CT line number to the scanner's value */
  set_ct_linenum(line_number);

  /* store results in a new code segment, and return it */

  exit_debug("code_action");
  return(create_code_segment());

}                                                       /* end CODE_ACTION */
/***************************************************************************/



/***************************************************************************/
/* exec_startup(prog_idp)    Execute the start up code                     */
/*                           based on `program'                            */

exec_startup(prog_idp)
SYMTAB_NODE_PTR prog_idp;           /* program id */
{
  entry_debug("exec_startup");


  /* set debug level for Execution */
  if (edebug) {
    DEBUG = cl_debug;
  }
  else {
    DEBUG = 0;
  }

  /* Execute the program */
  /* allocate runtime stack and initialise program's stack frame */
  init_stack();
  /* initialise the debugger */
  init_debugger();

  /* allocate locals and point to the code */
  routine_entry(prog_idp);

  /* DO IT */
  get_ctoken();
  while (ctoken != ENDCODE) exec_statement();

  exit_debug("exec_startup");
  return;
}                                                      /* end EXEC_STARTUP */
/***************************************************************************/



/***************************************************************************/
/* exec_statements(code_seg)     Execute set of statements                 */
/*                               based on `execute' and `routine_entry'    */

exec_statements(code_seg)
ICT *code_seg;                   /* the code */
{
  entry_debug("exec_statements");
  if (code_seg == NULL) return;

  /* switch to new code segment */
  code_segmentp = code_seg;

  get_ctoken();
  while (ctoken != ENDCODE) exec_statement();

  exit_debug("exec_statements");
  return;
}                                                   /* end EXEC_STATEMENTS */
/***************************************************************************/



/***************************************************************************/
/* exec_algorithm()        Execute the body of an algorithm                */
/*  This is a rewrite of Pascal execute() in l2xixutl.c                    */
/*   call this from exec_declared_routine_call() in l2xixstm.c             */
/*                     (FUNCTION, PROCEDURE     )                          */
/*            last token is END_OF_STATEMENTS                              */

exec_algorithm(rtn_idp)
SYMTAB_NODE_PTR rtn_idp;                 /* ponter to the routine */
{
  entry_debug("exec_algorithm");
  executed_return = FALSE;

  routine_entry(rtn_idp);

  get_ctoken();
  while (ctoken != END_OF_STATEMENTS && !executed_return) exec_statement();

  routine_exit(rtn_idp);

  exit_debug("exec_algorithm");
  return;
}                                                    /* end EXEC_ALGORITHM */
/***************************************************************************/



/***************************************************************************/