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:
ROPE ←
NIL] =
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: BOOLEAN ← TRUE;
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.