/* 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: [email protected]\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 */
/***************************************************************************/



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