CSegDebugSearch.mesa
Last Edited by: Sweet, July 31, 1984 3:04:21 pm PDT
DIRECTORY
Ascii,
Convert,
CSegDebugDefs,
ListerUtils,
RefText,
RESOut,
Rope,
ViewerTools;
CSegDebugSearch: CEDAR PROGRAM
IMPORTS
Convert, CSegDebugDefs, ListerUtils, RefText, RESOut, Rope, ViewerTools
EXPORTS CSegDebugDefs =
BEGIN OPEN RESOut;
BYTE: TYPE = CSegDebugDefs.BYTE;
Handle: TYPE = CSegDebugDefs.Handle;
ROPE: TYPE = Rope.ROPE;
searchRange: PUBLIC CARDINAL ← 100;
KeySeq: TYPE = RECORD[ seq: SEQUENCE l: CARDINAL OF CSegDebugDefs.Operation];
IntSeq: TYPE = RECORD[ seq: SEQUENCE l: CARDINAL OF INTEGER];
Search: PUBLIC PROC [handle: Handle] RETURNS [found: BOOLEAN] =
BEGIN
keyString: ROPE = ViewerTools.GetContents[handle.cmd.keyString];
keyLength: CARDINAL = Rope.Length[keyString];
searchRange: CARDINAL = CSegDebugDefs.CellCard[handle, handle.cmd.rangeVal];
keyOps: REF KeySeq;
kptr: CARDINAL ← 0;
k, p: CARDINAL;
operand: REF TEXT = NEW[TEXT[20]];
op: CSegDebugDefs.Operation;
SkipWhite: PROC =
BEGIN
WHILE kptr < keyLength AND Rope.Fetch[keyString, kptr] <= Ascii.SP DO
kptr ← kptr + 1;
ENDLOOP;
END;
Scan: PROC [op: REF TEXT] =
BEGIN
c: CHAR;
op.length ← 0;
SkipWhite[];
WHILE kptr < keyLength AND (c ← Rope.Fetch[keyString, kptr]) > Ascii.SP
AND c # '; DO
IF op.length = op.maxLength THEN
BadForm[handle, "Token too long: ", TR[op], "..."]
ELSE {op[op.length] ← c; op.length ← op.length + 1};
kptr ← kptr + 1;
ENDLOOP;
END;
IF keyString = NIL OR Rope.Length[keyString] = 0 THEN
{Complain[handle, "Enter search key"]; RETURN};
k ← 1;
FOR i: CARDINAL IN [0..keyLength) DO
IF Rope.Fetch[keyString, i] = '; THEN k ← k+1;
ENDLOOP;
keyOps ← NEW[KeySeq[k]];
k ← 0;
DO
ENABLE InvalidNumber => BadForm[handle, "Invalid number: ", TR[operand]];
b: BYTE;
il: CARDINAL;
Scan[operand];
IF operand.length = 0 THEN EXIT;
IF operand[0] IN ['0..'9] THEN b ← TextToNumber[operand]
ELSE b ← MopForRope[handle, TR[operand]];
il ← MAX[CARDINAL[handle.opData[b].length], 1];
TRUSTED {op ← [inst: b, params: il-1]};
p ← 1;
DO
SkipWhite[];
IF kptr = keyLength THEN EXIT;
IF Rope.Fetch[keyString, kptr] = '; THEN {kptr ← kptr + 1; EXIT};
IF p = 3 THEN BadForm[handle, "Too many", " operand bytes"];
Scan[operand];
SELECT operand[0] FROM
'* => {
IF operand.length # 1 THEN
BadForm[handle, "Missing space or '; after '*"];
op.wild[p] ← TRUE};
IN ['0..'9] => op.param[p] ← TextToNumber[operand];
ENDCASE => BadForm[handle, "Missing '; before ", TR[operand]];
p ← p+1;
ENDLOOP;
IF p # il THEN
BadForm[handle,
IF p > il THEN "Too many" ELSE "Too few",
" operand bytes"];
TRUSTED {keyOps[k] ← op};
k ← k+1;
ENDLOOP;
found ← FindOpString[handle, keyOps];
IF ~found THEN RESOut.Complain[handle, "not found"];
END;
TR: PROC [t: REF TEXT] RETURNS [ROPE] = {RETURN[RefText.TrustTextAsRope[t]]};
InvalidNumber: SIGNAL = CODE;
TextToNumber: PROC [t: REF TEXT] RETURNS [n: INT] = {
n ← Convert.CardFromWholeNumberLiteral[TR[t] !
Convert.Error => SIGNAL InvalidNumber]};
BadForm: PROC [handle: Handle, s1, s2, s3, s4: ROPENIL] =
BEGIN
RESOut.Complain[handle, s1, FALSE];
IF s2 # NIL THEN RESOut.Complain[handle, s2, FALSE, FALSE];
IF s3 # NIL THEN RESOut.Complain[handle, s3, FALSE, FALSE];
IF s4 # NIL THEN RESOut.Complain[handle, s4, FALSE, FALSE];
ERROR RESOut.cancelAction;
END;
MopForRope: PUBLIC PROC [handle: Handle, s: ROPE] RETURNS [b: BYTE] =
BEGIN
IF handle.opData = NIL THEN TRUSTED {handle.opData ← ListerUtils.GetOpCodeArray[]};
FOR b IN BYTE DO
IF Rope.Equal[s1: s, s2: handle.opData[b].name, case: FALSE] THEN RETURN[b];
REPEAT
FINISHED => BadForm[handle, "Unrecognized Mopcode: ", s]; --BadForm doesn't return
ENDLOOP;
END;
RopeForMop: PUBLIC PROC [handle: Handle, b: BYTE] RETURNS [s: ROPE] =
BEGIN
IF handle.opData = NIL THEN TRUSTED {handle.opData ← ListerUtils.GetOpCodeArray[]};
s ← handle.opData[b].name;
IF s = NIL THEN s ← Convert.RopeFromCard[b];
END;
FailureFn: PROCEDURE [key: REF KeySeq]
RETURNS[ff: REF IntSeq] =
BEGIN
i,j: INTEGER;
l: INTEGER = key.l;
ff ← NEW[IntSeq[l]];
set up failure function
j ← 0; i ← ff[0] ← -1;
WHILE j < l-1 DO
WHILE i >= 0 AND key[j].inst # key[i].inst DO i ← ff[i] ENDLOOP;
i ← i+1; j ← j+1;
ff[j] ← IF key[j].inst = key[i].inst THEN ff[i] ELSE i;
ENDLOOP;
END;
FindOpString: PROCEDURE [handle: Handle, key: REF KeySeq]
RETURNS[BOOLEAN] =
BEGIN
l: INTEGER = key.l;
k: INTEGER;
bytePC: CARDINAL = CSegDebugDefs.CellCard[handle, handle.cmd.bpcVal];
ff: REF IntSeq;
lastPC: CARDINAL;
extra: CARDINAL;
first: BOOLEANTRUE;
EqualOps: PROC [kop, op: CSegDebugDefs.Operation] RETURNS [BOOLEAN] =
BEGIN
IF key[k].inst # op.inst THEN GO TO different;
SELECT key[k].params FROM
0 => NULL;
1 => IF ~key[k].wild[1] AND key[k].param[1] # op.param[1] THEN
GO TO different;
2 =>IF (~key[k].wild[1] AND key[k].param[1] # op.param[1]) OR
(~key[k].wild[2] AND key[k].param[2] # op.param[2]) THEN
GO TO different;
ENDCASE => ERROR;
RETURN[TRUE];
EXITS
different => RETURN [FALSE];
END;
testOp: PROCEDURE [handle: Handle, pc: CARDINAL, op: CSegDebugDefs.Operation] RETURNS [BOOLEAN] =
BEGIN
IF first THEN {first ← FALSE; RETURN [FALSE]}; -- start from .+1
WHILE k >= 0 DO
IF EqualOps[key[k], op] THEN EXIT;
k ← ff[k];
ENDLOOP;
IF k = 0 THEN lastPC ← pc;
k ← k+1;
RETURN[k=l];
END;
ff ← FailureFn[key];
k𡤀
extra ← CSegDebugDefs.GenOperations[handle, bytePC, testOp, searchRange];
IF k=l THEN {
ViewerTools.SetContents [
handle.cmd.bpcVal,
Convert.RopeFromInt[from: lastPC, base: 8, showRadix: TRUE]];
handle.bytesSeen ← 0}
ELSE handle.bytesSeen ← searchRange - extra;
RETURN [k=l];
END;
END.