InterpreterTool
To Cedar Users Date December 9, 1983
From Paul Rovner Location PARC
Subject Cedar InterpreterTool Organization CSL
XEROX
Release as /Indigo/Cedar/Documentation/InterpreterToolDoc.tioga
Came from /Indigo/PreCedar/Documentation/InterpreterToolDoc.tioga
Last edited by Paul Rovner, December 9, 1983 8:36 am
Abstract This document describes the InterpreterTool for Cedar 5. The InterpreterTool is a typescript-style tool with a read/eval/print control loop at the top level, like the CommandTool. It is used primarily for debugging and testing, but it is also used for determining and occasionally changing status variables in a running system, perhaps one a world-swap or teledebug away. It provides several related facilities: parsing, evaluation and printing of Cedar expressions in the context of the running system; management of breakpoints; and interactive control of uncaught signals, breakpoints and other exceptional conditions.
Top-Level Control
The top-level control loop of an InterpreterTool instance is a sequence of assignment expressions. This behavior is reflected by the prompt rope, which identifies a new "&-variable" followed by "←" on each new line. Each such &-variable is used to hold the result of its right-hand side; the new &variable becomes part of the naming context of the InterpreterTool instance (see below).
If the last character on the line before the CR is "!", then the level of detail of the printout is increased. Multiple !'s can be used at the end of a line to increase the level of detail even more. Special variables (&depth and &width) are available for controlling the default level of detail for printout.
If the last character on the line before the CR is "?" then the assignment is performed, but the type of the expression is printed rather than its value (this is also true if the ? is followed only by !'s).
Creating an instance of the tool
Typing Interpreter<CR> to a CommandTool will create a new instance of the InterpreterTool with the interface records and loaded program modules of the local world as its initial "naming context."
Occurrence of an exceptional condition (uncaught signal, breakpoint, etc.) will also cause creation of a new instance of the InterpreterTool to be an "event handler" for the exceptional condition. The initial naming context will be that at the point of occurrence of the exceptional condition; additional operations associated with handling "events" will be enabled.
SMALL PRINT: Occurrence of an exceptional condition (uncaught signal, breakpoint, etc.) will use an existing instance of the InterpreterTool if possible. An existing instance can be used if it was the last one made "dormant" (see below) or if the exceptional condition was raised as a result of an action initiated from that instance in the same process. In the latter case the new exceptional condition will be identified as a "nested" one and the new prompt rope will get <***> prepended to it. For example, a nested "Event" will occur if a procedure that contains a breakpoint or raises a signal is invoked from an InterpreterTool.
Naming Contexts
The conventions for name-lookup ought to be simple. They should be consistent with the language and with the AMModel. Users should find them easy to determine, understand and utilize. The implementation of name-lookup should be efficient.
At any given time, an InterpreterTool instance has a naming context, i.e. a set of (name, value) pairs with at most one binding to a given name. This is called its "current naming context."
Each naming context identifies ONE of the following:
1. a local frame
Names: the set of ones statically accessible by the code at the specified PC. This includes the names in the global frame of the associated procedure, but does not include names introduced by the module's DIRECTORY or IMPORTS clauses or by any OPEN clause.
2. a global frame
Names: the set of ones defined at the top level of the program module: types, constants, variables, procedures. This does not include names introduced by the module's DIRECTORY or IMPORTS clauses or by any OPEN clause.
3. an interface record
Names: the set of ones defined in the interface.
4. a world: either the local one or the Outload one or one teledebugging.
Names: the current set of program module instances (global frames) and interface records in the world.
AND the set of special (name, value) pairs described below.
For example, when the current naming context identifies a global frame, names from that frame and from the set of special names are normally the only ones accessible. Special procs exist to convert an ir name or module name to its value (&ir, &gf ... see below).
NOTE: The world context of the current context will be used to find any name that is prefixed with %, whether or not the current context is a world context. This is useful for naming interface records or program modules in an event handler, for example.
Summary of changes from Cedar 4.4
No automatic search of local frames in the dynamic procedure-call history is performed.
A global frame as the current context and a local frame as the current context are mutually exclusive options (but if a local frame is the name-lookup context then names in its global frame are accessible.)
Global frames and interface records can be named simply only if the current context is for a world. Of course, &gf and &ir can be used in any context. The world context will be used for any name that is prefixed with %.
Predefined Names
Selected words from the language
Boolean values: TRUE and FALSE
TYPEs: CHARACTER, WORD, PROC ANY, INT, INTEGER, BOOL, ATOM, PROC, CARDINAL, BOOLEAN, PROCESS, CHAR, ROPE, REF, CARD
&-Variables
Each InterpreterTool comes with its own, private, pre-defined set of (name, value) pairs that begin with the letter "&." This set is always included in the current naming context; its bindings can be changed and extended by user actions. I'll call this set "the &-extension."
The interpreter treats assignment to a name that begins with "&" as a new binding between that name and the specified value, just as it does with other assignments. The differences are that type checking is not done for assignment to &-variables and that mention of a new &-variable on the left-hand-side causes the &-extension to be changed to include the new (name, value) pair. If the &-variable is not new then the binding to its old value is replaced with the new one.
This facility is used by the InterpreterTool to remember old results (e.g. &37). It can also be used (by users) to define new temporary variables in InterpreterTool instance, e.g. by interpreting a line like
&temp ← proc[x]
Subsequent reference by the user to &temp will yield the value of the earlier call on "proc."
The pre-defined &-variables are listed below with their names and typical arguments and with the full type of their pre-defined values.
A starving person's help facility
&help["pattern"]
find predefined names that match the pattern and print brief documentation. The pattern need not be quoted if it has no *'s.
Changing the current naming context
&slf[n] set local frame as naming context
SetLocalFrameAsNamingContext:
PROC [n:
INT ← 0];
n: the number of frames to walk downstack--earlier calls-- (upstack--later ones-- if negative) to find the frame
0 => the local frame previously used as the naming context
large positive number => the frame at the root of the stack
large negative number => the frame at the top of the stack
&sgf[progName] set global frame as naming context
SetGlobalFrameAsNamingContext:
PROC [progName:
ROPE ←
NIL];
NIL => the global frame previously used as the naming context; none => error
NOTE the argument typed to &sgf need not be quoted.
&sir[progName] set interface record as naming context
SetInterfaceRecordAsNamingContext:
PROC [interfaceName:
ROPE ←
NIL];
NOTE the argument typed to &sir need not be quoted.
&sw[worldName] set world name as naming context
SetWorldAsNamingContext:
PROC [worldName:
ROPE ←
NIL];
set name-lookup context to be the set of program module instances in a specified world. example worldNames: "Local", "Outload", "Intrepid"
NIL => the world associated with this InterpTool
NOTE the argument typed to &sw need not be quoted.
Debugging aids for mortals
&gf[progName] get global frame
-- new for 5.0
Get
GlobalFrame:
PROC [progName:
ROPE ←
NIL]
RETURNS[
TV];
Gets the given module's context.
NOTE the argument typed to &gf need not be quoted.
use this to select a field of a global frame without changing the name-lookup context, e.g.: &gf[RTRefCountsImpl].collectorRunning
&ir[irName] get interface record
-- new for 5.0
GetInterfaceRecord:
PROC [irName:
ROPE]
RETURNS[
TV];
Gets the given ir's context
NOTE the argument typed to &gf need not be quoted.
use this to select a field of an IR without changing the name-lookup context, e.g.:
&ir[SafeStorage].TrimSystemZone[]
&fm[pattern] print modules with names matching the pattern
FindMatching: PROC [ -- find program modules with matching names
pattern:
ROPE, world: WorldVM.World ←
NIL
--NIL => use local world--];
NOTE the argument typed to &fm need not be quoted.
&type[expr] print the type of the expression
GetType:
PROC [expr:
ROPE];
Print the type of the expression.
& --The last value assigned
Debugging aids for wizards
&or[addr, len] print the addressed contents in octal
OctalRead:
PROC [
-- print the addressed contents in octal
addr: LONG CARDINAL ← 0, len: CARDINAL ← 4,
width: CARDINAL ← 16, base: CARDINAL ← 8,
offset: CARDINAL ← 0];
&ors[addr, len] print the contents addressed in the first bank in octal
OctalReadShort:
PROC [
-- ditto, but address is in the first bank (NOT the MDS)
addr: CARDINAL ← 0, len: CARDINAL ← 4,
width: CARDINAL ← 16, base: CARDINAL ← 8, offset: CARDINAL ← 0];
&ow[addr, word, len] write the contents of the addressed word
OctalWrite:
PROC [
-- write the contents of the addressed word
addr: LONG CARDINAL ← 0, word: CARDINAL ← 0, len: INT ← 1];
&ows[addr, word, len] write the contents of the word addressed in the first bank
OctalWriteShort:
PROC [
-- ditto, but address is in the first bank (NOT the MDS)
addr: CARDINAL ← 0, word: CARDINAL ← 0, len: INT ← 1];
&ar[addr, bytes] print the addressed contents as characters
AsciiRead:
PROC [
-- print the addressed contents as characters
addr: LONG CARDINAL ← 0, bytes: NAT ← 8];
&ars[addr, bytes] print the contents addressed in the first bank as characters
AsciiReadShort:
PROC [
-- ditto, but address is in the first bank (NOT the MDS)
addr: CARDINAL ← 0, bytes: NAT ← 8];
&orc[gf, pc, bytes] print the addressed contents as code bytes
OctalReadCode:
PROC [
-- print the addressed contents as code bytes
gf, pc: CARDINAL, bytes: CARDINAL ← 8];
&ofc[gf, pc, ...] find an instance of the specified code byte sequence
OctalFindCode:
PROC [
-- find an instance of the specified code byte sequence
gf: CARDINAL, pc: CARDINAL ← 0,
b0, b1, b2, b3, b4 , b5, b6, b7, b8, b9: CARDINAL ← 0];
&sob[gf, pc] set octal break
SetOctalBreak: PROC [gf, pc: CARDINAL];
&clob[gf, pc] clear octal break
ClearOctalBreak: PROC [gf, pc: CARDINAL];
&lob[] list octal breaks
ListOctalBreaks: PROC;
&tlf[lf] trust as local frame
NOTE The implementation of tlf is specially wired-in to allow treatment of the result as a local frame.
TrustLocalFrame: PROC [lf: CARDINAL] RETURNS [TV];
&tgf[gf] trust as global frame
NOTE The implementation of tgf is specially wired-in to allow treatment of the result as a global frame.
TrustGlobalFrame: PROC [gf: CARDINAL] RETURNS [TV];
&plf[lf] print local frame
PrintLocalFrame: PROC [lf: CARDINAL];
&pgf[gf] print global frame
PrintGlobalFrame: PROC [gf: CARDINAL];
&H this InterpreterTool's handle
Variables having the default settings for printout detail
&width: printing width for this interpretertool; See PrintTV
&depth: printing depth for this interpretertool; See PrintTV
Procs invoked by the event handler buttons
&SetBreak: set break at selected source loc; any click on SetBreak
Use &H if h = NIL
SetBreak: PROC [h: InterpreterToolPrivate.Handle ← NIL];
&ClearBreak: clear specified break; left click on ClearBreak(s)
Use &H if h = NIL
If breakIndex = 0 then clear the break that caused this event
ClearBreak: PROC[h: InterpreterToolPrivate.Handle ← NIL, breakIndex: BreakIndex ← 0];
&WalkStack: set a local frame context (eventhandler)
left click on WalkStack => nFrames ← 1;
right click on WalkStack => nFrames ← -1;
middle click on WalkStack => nFrames ← 0;
Use &H if h = NIL
Walk the specified number of frames up or down in the stack and change the current naming context to identify it. nFrames positive => walk up to the nFrames'th caller (towards the root). nFrames negative => walk deeper to the nFrames'th callee (towards the deepest frame). nFrames = 0 => walk directly to the deepest frame.
WalkStack: PROC[h: InterpreterToolPrivate.Handle ← NIL, nFrames: INT ← 1];
&Source: show source loc of current lf context (eventhandler); any click on Source
Use &H if h = NIL
Source: PROC [h: InterpreterToolPrivate.Handle ← NIL];
&ListBreaks: list all breaks; any click on ListBreaks
Use &H if h = NIL
ListBreaks: PROC [h: InterpreterToolPrivate.Handle ← NIL];
&ShowFrame: show the current lf context (eventhandler); any click on ShowFrame
Use &H if h = NIL
ShowFrame: PROC [h: InterpreterToolPrivate.Handle ← NIL];
&ClearAllBreaks: clear all breaks; right click on ClearBreak(s)
Use &H if h = NIL
ClearAllBreaks: PROC [h: InterpreterToolPrivate.Handle ← NIL];