|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - downloadIndex: ┃ T u ┃
Length: 18118 (0x46c6) Types: TextFile Names: »utils.c«
└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki └─ ⟦this⟧ »EUUGD11/gnu-31mar87/scheme/microcode/utils.c«
/* 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); }