DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - download
Index: ┃ T u

⟦fe663cf12⟧ TextFile

    Length: 18118 (0x46c6)
    Types: TextFile
    Names: »utils.c«

Derivation

└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki
    └─ ⟦this⟧ »EUUGD11/gnu-31mar87/scheme/microcode/utils.c« 

TextFile

/*          Hey EMACS, this is -*- C -*- code!                 */

/****************************************************************
*                                                               *
*                         Copyright (c) 1984                    *
*               Massachusetts Institute of Technology           *
*                                                               *
* This material was developed by the Scheme project at the      *
* Massachusetts Institute of Technology, Department of          *
* Electrical Engineering and Computer Science.  Permission to   *
* copy this software, to redistribute it, and to use it for any *
* purpose is granted, subject to the following restrictions and *
* understandings.                                               *
*                                                               *
* 1. Any copy made of this software must include this copyright *
* notice in full.                                               *
*                                                               *
* 2. Users of this software agree to make their best efforts (a)*
* to return to the MIT Scheme project any improvements or       *
* extensions that they make, so that these may be included in   *
* future releases; and (b) to inform MIT of noteworthy uses of  *
* this software.                                                *
*                                                               *
* 3.  All materials developed as a consequence of the use of    *
* this software shall duly acknowledge such use, in accordance  *
* with the usual standards of acknowledging credit in academic  *
* research.                                                     *
*                                                               *
* 4. MIT has made no warrantee or representation that the       *
* operation of this software will be error-free, and MIT is     *
* under no obligation to provide any services, by way of        *
* maintenance, update, or otherwise.                            *
*                                                               *
* 5.  In conjunction with products arising from the use of this *
* material, there shall be no use of the name of the            *
* Massachusetts Institute of Technology nor of any adaptation   *
* thereof in any advertising, promotional, or sales literature  *
* without prior written consent from MIT in each case.          *
*                                                               *
****************************************************************/
\f


/* File: Utils.C
 *
 * This file contains a number of utility routines for use
 * in the Scheme SCode interpreter.
 */

#include "scheme.h"
#include "primitive.h"

/* Set_Up_Interrupt is called from the Interrupt
 * macro to do all of the setup for calling the user's
 * interrupt routines.
 */

void Setup_Interrupt(Masked_Interrupts)
long Masked_Interrupts;
{ Pointer Int_Vector, Handler;
  long i, Int_Number, The_Int_Code = IntCode, New_Int_Enb;

  Int_Vector = Get_Fixed_Obj_Slot(System_Interrupt_Vector);
  for (Int_Number=0, i=1; Int_Number < MAX_INTERRUPT_NUMBER;
       i = i<<1, Int_Number++) if ((Masked_Interrupts & i) != 0) goto OK;
  printf("Int_Vector %x\n", Int_Vector);
  printf("\nInterrupts = 0x%x, Mask= 0x%x, Masked = 0x%x\n",
         IntCode, IntEnb, Masked_Interrupts);
  Microcode_Termination(TERM_NO_INTERRUPT_HANDLER);
OK:
  New_Int_Enb = (1<<Int_Number)-1;
  Global_Interrupt_Hook();
  if (Int_Number > Vector_Length(Int_Vector))
  { printf("\nInterrupt out of range: 0x%x (vector length = 0x%x)\n",
           Int_Number, Vector_Length(Int_Vector));
    printf("Interrupts = 0x%x, Mask= 0x%x, Masked = 0x%x\n",
           IntCode, IntEnb, Masked_Interrupts);
    Microcode_Termination(TERM_NO_INTERRUPT_HANDLER);
  }
  else Handler = User_Vector_Ref(Int_Vector, Int_Number);

/* Setup_Interrupts continues on the next page */
\f


/* Setup_Interrupts, continued */

Passed_Checks:
  Stop_History();
 Will_Push(CONTINUATION_SIZE + STACK_ENV_EXTRA_SLOTS+3);
  /* Return from interrupt handler will re-enable interrupts */
  Store_Return(RC_RESTORE_INT_MASK);
  Store_Expression(FIXNUM_0 + IntEnb);
  Save_Cont();

/* Now make an environment frame for use in calling the
 * user supplied interrupt routine.  It will be given
 * two arguments: the UNmasked interrupt requests, and
 * the currently enabled interrupts.
 */

  Push(FIXNUM_0+IntEnb);
  Push(FIXNUM_0+The_Int_Code);
  Push(Handler);
  Push(STACK_FRAME_HEADER+2);
 Pushed();
  IntEnb = New_Int_Enb;	/* Turn off interrupts */
  New_Compiler_MemTop();
}
\f


                      /******************/
                      /* ERROR HANDLING */
                      /******************/

/* It is assumed that any caller of the error code has already
 * restored its state to a situation which will make it
 * restartable if the error handler returns normally.  As a
 * result, the only work to be done on an error is to verify
 * that there is an error handler, save the current continuation and
 * create a new one if entered from Pop_Return rather than Eval,
 * turn off interrupts, and call it with two arguments: Error-Code
 * and Interrupt-Enables.
 */

/* Back_Out_Of_Primitive pushes the primitive number and prepares an
 * appropriate return code so that the primitive can be restarted.
 */

void Back_Out_Of_Primitive()
{ 
  /* When you come back to the primitive, the environment is
   * irrelevant .... primitives run with no real environment.
   * Similarly, the value register is meaningless. 
   */
  Store_Return(RC_REPEAT_PRIMITIVE);
  Store_Env(Make_Non_Pointer(GLOBAL_ENV, END_OF_CHAIN));
  Val = NIL;
}

void Do_Micro_Error(Err, From_Pop_Return)
long Err;
Boolean From_Pop_Return;
{ Pointer Error_Vector, Handler;

  if (Consistency_Check)
  { printf( "Error 0x%x happened.\n", Err);
    Print_Expression(Fetch_Expression(), "Expression was");
    printf("\nEnvironment 0x%x (#%o).\n", Fetch_Env(), Fetch_Env());
    Print_Return("Return code");
    printf( "\n");
  }
  Error_Exit_Hook();
  if (Trace_On_Error)
  { printf( "\n\nStack trace:\n\n");
    Back_Trace();
  }

/* Do_Micro_Error continues on the next page. */
\f


/* Do_Micro_Error, continued */

#ifdef ENABLE_DEBUGGING_TOOLS
  Copy_Trace_Circle();
#endif  
  if ((!Valid_Fixed_Obj_Vector()) ||
      (Consistency_Check &&
       (Vector_Length(Fixed_Objects) <= System_Error_Vector))  || 
      (Type_Code((Error_Vector = 
		  User_Vector_Ref(Fixed_Objects, System_Error_Vector))) !=
       TC_VECTOR))
  { printf("\nBogus Error Vector! I'm terribly confused!\n");
    Microcode_Termination(TERM_NO_ERROR_HANDLER, Err);
  }
  if (Err >= Vector_Length(Error_Vector))
  { if (Vector_Length(Error_Vector) == 0)
    { printf("\nEmpty Error Vector! I'm terribly confused!\n");
      Microcode_Termination(TERM_NO_ERROR_HANDLER, Err);
    }
    Handler = User_Vector_Ref(Error_Vector, ERR_BAD_ERROR_CODE);
  }
  else Handler = User_Vector_Ref(Error_Vector, Err);
  if (From_Pop_Return) Save_Cont();
  Stop_History();
 Will_Push(STACK_ENV_EXTRA_SLOTS+3+2*CONTINUATION_SIZE+
           (From_Pop_Return ? 0 : 1));
  if (From_Pop_Return) Store_Expression(Val);
  else Push(Fetch_Env());
  Store_Return(From_Pop_Return? RC_POP_RETURN_ERROR : RC_EVAL_ERROR);
  Save_Cont();
  /* Return from interrupt handler will re-enable interrupts */
  Store_Return(RC_RESTORE_INT_MASK);
  Store_Expression(FIXNUM_0 + IntEnb);
  Save_Cont();
  Push(FIXNUM_0+IntEnb);		    /* Arg 2:    Int. mask */
  Push(FIXNUM_0+Err);			    /* Arg 1:    Err. No   */
  Push(Handler);			    /* Function: Handler   */
  Push(STACK_FRAME_HEADER+2);
 Pushed();
  IntEnb = 0;		/* Turn off interrupts */
  New_Compiler_MemTop();
}
\f


                      /******************/
                      /* CONTROL POINTS */
                      /******************/

/* Pointer Make_Control_Point() -- this function logically
   belongs here, and is documented here, but has been coded
   in-line in the one place it is used: Prim_Catch
*/

void Throw(P)
/* Clear the stack and replace it with a copy of the contents of the
   control point. Also disables the history collection mechanism,
   since the saved history would be incorrect on the new stack.
*/
Pointer P;
{ long    NCells, Offset;
  fast Pointer *To_Where, *From_Where;
  fast long i;

  if (Consistency_Check)
    if (Type_Code(P) != TC_CONTROL_POINT)
      Microcode_Termination(TERM_BAD_STACK);
  NCells = Vector_Length(P) - (2+REGBLOCK_NDISPLAYS);
  Stack_Check(Stack_Top - NCells);
  From_Where = Nth_Vector_Loc(P, 1);
  IntEnb = Get_Integer(*From_Where++);
  Offset = Get_Integer(*From_Where++);
#ifdef COMPILER
  /* Restore Displays */
  To_Where = &Registers[REGBLOCK_DISPLAYS];
  for (i=0; i < REGBLOCK_NDISPLAYS; i++) *To_Where++ = *From_Where++;
#else
  From_Where = &From_Where[REGBLOCK_NDISPLAYS];
#endif
  To_Where = Stack_Top - NCells;
  Stack_Pointer = To_Where;
  for (i=0; i < NCells; i++) *To_Where++ = *From_Where++;
  if (Offset==0) Previous_Restore_History = NULL;
  else Previous_Restore_History = Stack_Pointer+Offset;
  New_Compiler_MemTop();
  if (Consistency_Check)
    if ((To_Where != Stack_Top) ||
        (From_Where != Nth_Vector_Loc(P, 1+Vector_Length(P))))
      Microcode_Termination(TERM_BAD_STACK);
  if ((!Valid_Fixed_Obj_Vector()) ||
      (Get_Fixed_Obj_Slot(Dummy_History) == NIL))
    History = Make_Dummy_History();
  else History = Get_Pointer(Get_Fixed_Obj_Slot(Dummy_History));
}
\f


/* Make a Scheme string with the characters in C_String. */

Pointer C_String_To_Scheme_String(C_String)
fast char *C_String;
{ fast char *Next;
  fast long Length, Max_Length;
  Pointer Result;

  Result = Make_Pointer(TC_CHARACTER_STRING, Free);
  Next = (char *) Nth_Vector_Loc(Result, STRING_CHARS);
  Max_Length = ((Space_Before_GC() - STRING_CHARS) *
                sizeof(Pointer));
  if (C_String == NULL)
    Length = 0;
  else
    for (Length = 0;
	 (*C_String != '\0') && (Length < Max_Length);
	 Length += 1)
      *Next++ = *C_String++;
  if (Length >= Max_Length) 
    Primitive_GC();
  *Next = '\0';
  Free += STRING_CHARS + (Length+sizeof(Pointer))/sizeof(Pointer);
  Vector_Set(Result, STRING_LENGTH, FIXNUM_0+Length);
  Vector_Set(Result, STRING_HEADER,
    Make_Non_Pointer(TC_MANIFEST_NM_VECTOR, (Free-Get_Pointer(Result))-1));
  return Result;
}
\f


Boolean Open_File(Name, Mode_String, File_Handle)
Pointer Name;
char *Mode_String;
FILE **File_Handle;
{ *File_Handle = fopen(Scheme_String_To_C_String(Name), Mode_String);
  return (Boolean) (*File_Handle != NULL);
}

Close_File(File_Handle)
FILE *File_Handle;
{ fclose(File_Handle);
  return;
}

Pointer *Make_Dummy_History()
{ Pointer *History_Rib = Free;
  Pointer *Result;

  Free[RIB_EXP] = NIL;
  Free[RIB_ENV] = NIL;
  Free[RIB_NEXT_REDUCTION] =
    Make_Pointer(TC_HUNK3, History_Rib);
  Free += 3;
  Result = Free;
  Free[HIST_RIB] = Make_Pointer(TC_HUNK3, History_Rib);
  Free[HIST_NEXT_SUBPROBLEM] =
    Make_Pointer(TC_HUNK3, Result);
  Free[HIST_PREV_SUBPROBLEM] =
    Make_Pointer(TC_HUNK3, Result);
  Free += 3;
  return Result;
}
\f


/* The entire trick to history is right here: it is either copied or
   reused when restored.  Initially, Stop_History marks the stack so
   that the history will merely be popped and reused.  On a catch,
   however, the return code is changed to force the history to be
   copied instead.  Thus, histories saved as part of a control point
   are not side-effected in the history collection process.
*/

void Stop_History()
{ long Previous = (Previous_Restore_History==NULL) ?
         0 : (Previous_Restore_History-Stack_Pointer);
  Pointer Save_Exp=Fetch_Expression(), Save_Ret=Fetch_Return();
  Previous_Restore_History = Stack_Pointer;
 Will_Push(3);
  Push(Make_Non_Pointer(TC_FIXNUM, Previous));
  Store_Expression(Make_Pointer(TC_HUNK3, History));
  Store_Return(RC_RESTORE_DONT_COPY_HISTORY);
  Save_Cont();
 Pushed();
  History = Get_Pointer(Get_Fixed_Obj_Slot(Dummy_History));
  Store_Expression(Save_Exp);
  Store_Return(Save_Ret);
}

Pointer *Copy_Rib(Orig_Rib)
Pointer *Orig_Rib;
{ Pointer *Result, *This_Rib;
  for (This_Rib=NULL, Result=Free;
       (This_Rib != Orig_Rib) && (!GC_Check(Free));
       This_Rib = Get_Pointer(This_Rib[RIB_NEXT_REDUCTION]))
  { if (This_Rib==NULL) This_Rib = Orig_Rib;
    Free[RIB_EXP] = This_Rib[RIB_EXP];
    Free[RIB_ENV] = This_Rib[RIB_ENV];
    Free[RIB_NEXT_REDUCTION] = Make_Pointer(TC_HUNK3, Free+3);
    if (Dangerous(This_Rib[RIB_MARK])) Free[RIB_MARK] |= DANGER_BIT;
    Free += 3;
  }
  Store_Address((Free-3)[RIB_NEXT_REDUCTION], C_To_Scheme(Result));
  return Result;
}
\f


/* Restore_History pops a history object off the stack and
   makes a COPY of it the current history collection object.
   This is called only from the RC_RESTORE_HISTORY case in
   Basmod.
*/

Boolean Restore_History(Hist_Obj)
Pointer Hist_Obj;
{ Pointer *New_History, *Next_Vertebra, *Prev_Vertebra,
          *Orig_Vertebra;
  long Offset;
  if (Consistency_Check)
    if (Type_Code(Hist_Obj) != TC_HUNK3)
    { printf("Bad history to restore.\n");
      Microcode_Termination(TERM_EXIT);
    }
  Orig_Vertebra = Get_Pointer(Hist_Obj);
  for (Next_Vertebra=NULL, Prev_Vertebra=NULL;
       Next_Vertebra != Orig_Vertebra;
       Next_Vertebra = 
         Get_Pointer(Next_Vertebra[HIST_NEXT_SUBPROBLEM]))
  { Pointer *New_Rib;
    if (Prev_Vertebra==NULL) Next_Vertebra = Orig_Vertebra;
    New_Rib = Copy_Rib(Get_Pointer(Next_Vertebra[HIST_RIB]));
    if (Prev_Vertebra==NULL) New_History = Free;
    else Prev_Vertebra[HIST_NEXT_SUBPROBLEM] =
           Make_Pointer(TC_HUNK3, Free);
    Free[HIST_RIB] = Make_Pointer(TC_HUNK3, New_Rib);
    Free[HIST_NEXT_SUBPROBLEM] = NIL;
    Free[HIST_PREV_SUBPROBLEM] =
      Make_Pointer(TC_HUNK3, Prev_Vertebra);
    if (Dangerous(Next_Vertebra[HIST_MARK]))
      Free[HIST_MARK] |= DANGER_BIT;
    Prev_Vertebra = Free;
    Free += 3;
    if (GC_Check(Free)) return false;
  }
  Store_Address(New_History[HIST_PREV_SUBPROBLEM], C_To_Scheme(Free-3));
  Prev_Vertebra[HIST_NEXT_SUBPROBLEM] =
    Make_Pointer(TC_HUNK3, New_History); 
  if (Dangerous(Orig_Vertebra[HIST_MARK]))
    Prev_Vertebra[HIST_MARK] |= DANGER_BIT;
  History = New_History;
  return true;
}

CRLF()
{ printf( "\n");
}
\f


void Err_Print(Micro_Error)
{ switch (Micro_Error)
  { 
/*  case ERR_BAD_ERROR_CODE:
      printf("unknown error code.\n"); break;
*/
    case ERR_UNBOUND_VARIABLE:
      printf("unbound variable.\n"); break;
    case ERR_UNASSIGNED_VARIABLE:
      printf("unassigned variable.\n"); break;
    case ERR_INAPPLICABLE_OBJECT:
      printf("Inapplicable operator.\n"); break;
    case ERR_BAD_FRAME:
      printf("bad environment frame.\n"); break;
    case ERR_BROKEN_COMPILED_VARIABLE:
      printf("compiled variable invalid.\n"); break;
    case ERR_UNDEFINED_USER_TYPE:
      printf("undefined type code.\n"); break;
    case ERR_UNDEFINED_PRIMITIVE:
      printf("undefined primitive.\n"); break;
    case ERR_EXTERNAL_RETURN:
      printf("error during 'external' primitive.\n"); break;
    case ERR_EXECUTE_MANIFEST_VECTOR:
      printf("attempt to EVAL a vector.\n"); break;
    case ERR_WRONG_NUMBER_OF_ARGUMENTS:
      printf("wrong number of arguments.\n"); break;
    case ERR_ARG_1_WRONG_TYPE:
      printf("type error argument 1.\n"); break;
    case ERR_ARG_2_WRONG_TYPE:
      printf("type error argument 2.\n"); break;

/* Err_Print continues on the next page */
\f


/* Err_Print, continued */

    case ERR_ARG_3_WRONG_TYPE:
      printf("type error argument 3.\n"); break;
    case ERR_ARG_1_BAD_RANGE:
      printf("range error argument 1.\n"); break;
    case ERR_ARG_2_BAD_RANGE:
      printf("range error, argument 2.\n"); break;
    case ERR_ARG_3_BAD_RANGE:
      printf("range error, argument 3.\n"); break;
    case ERR_FASL_FILE_TOO_BIG:
      printf("FASL file too large to load.\n"); break;
    case ERR_FASL_FILE_BAD_DATA:
      printf("No such file or not FASL format.\n"); break;
    case ERR_IMPURIFY_OUT_OF_SPACE:
      printf("Not enough room to impurify object.\n"); break;
    case ERR_WRITE_INTO_PURE_SPACE:
      printf("Write into pure area\n"); break;
    case ERR_NO_HASH_TABLE:
      printf("No hash table installed.\n"); break;
    case ERR_BAD_SET:
      printf("Attempt to perform side-effect on 'self'.\n"); break;
    case ERR_ARG_1_FAILED_COERCION:
      printf("First argument couldn't be coerced.\n"); break;
    case ERR_ARG_2_FAILED_COERCION:
      printf("Second argument couldn't be coerced.\n"); break;
    case ERR_OUT_OF_FILE_HANDLES:
      printf("Too many open files.\n"); break;
    default:
      printf("Unknown error 0x%x occurred\n.", Micro_Error);
      break;
  }
  return;
}
\f


/* If a debugging version of the interpreter is made, then this
 * procedure is called to actually invoke a primitive.  When a
 * 'production' version is made, all of the consistency checks are
 * omitted and a macro from DEFAULT.H is used to directly code the
 * call to the primitive function.  This is only used in INTERPRET.C.
 */

#ifdef ENABLE_DEBUGGING_TOOLS
Pointer Apply_Primitive(Primitive_Number)
long Primitive_Number;
{ Pointer Result, *Saved_Stack;
  int NArgs;
  if (Primitive_Number > MAX_PRIMITIVE)
    Primitive_Error(ERR_UNDEFINED_PRIMITIVE);
  NArgs = Arg_Count_Table[Primitive_Number];
  if (Primitive_Debug) Print_Primitive(Primitive_Number);
  Saved_Stack = Stack_Pointer;
  Result = (*(Primitive_Table[Primitive_Number]))();
  if (Saved_Stack != Stack_Pointer)
  { Print_Expression(Make_Non_Pointer(TC_PRIMITIVE, Primitive_Number),
		     "Stack bad after ");
    printf( "\nStack was 0x%x, now 0x%x, #args=%d.\n",
            Saved_Stack, Stack_Pointer, NArgs);
    Microcode_Termination(TERM_EXIT);
  }
  if (Primitive_Debug)
  { Print_Expression(Result, "Primitive Result");
    printf( "\n");
  }
  return Result;
}
#endif

Built_In_Primitive(Prim_Unused, 0, "Unimplemented Primitive Handler")
{ printf("Ignoring missing primitive. Expression = 0x%02x|%06x\n",
         Type_Code(Fetch_Expression()), Address(Fetch_Expression()));
  Primitive_Error(ERR_UNDEFINED_PRIMITIVE);
}