Skip to content

gmslCodePatternClass

The service class CodePattern contains methods to provide a notation for doing tests for operation code sequences with a code block. To use this class knowledge of the actual operation codes in the intermediate language is required, but knowledge of the layout of those codes is not. Here are some sample code patterns.

LSC,LLP,STR.AssignProperty
MEM.Get,Argument,CUF,REF
MEM.Set,Argument,CUF,REF,STR
MEM,STR",nOper);
Argument,LDA,LLP.[MSComctlLib.IListView.Sortkey],MEM
FOR.Controls,MEM.Child,LIC,TYP,IFS.ForEachTemp

Each code pattern consists of a list of comma delimited specifications. Each specification is either one of the opcode identifiers, or an opcode identifier followed by a period and a subcode value, or one of the special keywords Argumement or lValue. Subcode values are either a subcode identifier of the opcode or a value specification of the type expected for the opcode, like the value associated with the LLP opcode above. The keyword Argument finds the end of the code associated with a given argument within a larger code block. Note that argument code always begins with a LEV operation which specifies the nesting level of the argument code, and ends with an ARG which specifies the type of the parameter that is to receive the argument. The end of the argument code is the offset of the first code following the ARG operation. The keyword lValue finds the end of the code associated with a given lValue — variable expression capable of receiving a value — argument within a code block.

Methods in this class perform matches using these code pattern specifications and methods that read them using a simplified notation.

Interface: int Match(int icode,tCodeBlock codeBlock);
: int Match(int icode,string codeBlock);

<Method id="Match" type="Integer" opcode="SCM.CodePattern_Match" >
<Argument id="icode" type="Integer" status="ByVal" />
<Argument id="codeBlock" type="tCodeBlock" status="ByVal" />
</Method>

The method Match checks if a sequence of operation codes stored in the global code block match a code pattern. The parameter icode is the starting offset in the global code where the match is to begin. The parameter codeBlock contains the code pattern to be matched. It can either be a tCodeBlock initialize earlier using the Read method, of it can be a string containing the code pattern itself. If a match is made, then the method returns the offset of the first byte in the code block beyond the end of the match. If no match is made, the method returns zero.

The method below scans a code block for references to comboBox item data indexed by the list index of the combobox. Note that the code pattern is read first into an operation code block so that it can be used efficiently in a loop though target code block.

void TestMatch()
{
int subRoot;
tVbSub subInfo;
tCodeBlock codptr;
int nCode;
tCodeBlock operation;
int nOper;
int icode;
int lcode;
Write.Line "Unit test for CodePattern.Match() Method"
Store.Open("\fkgtest\vb6test\csh\vb242.vbi",StorageUnit.USER,0);
subRoot = Symbol.FindIdentifier("VisData.frmAddField.cboFieldType_Click");
subInfo = Store.GetVector(subRoot);
codptr = Opcode.GetCode();
nCode = Store.ReadInfo(codptr,subInfo.cmpCodeStart);
Opcode.SetLength(nCode);
operation = CodePattern.Read("LDA,CBO.ItemData,MEM,LEV,LDA,CBO.ListIndex,MEM,ARG,INX",nOper);
for(icode = 0; icode >= 0; icode = Opcode.GetNext(codptr,icode,ncode))
{
lcode = CodePattern.Match(icode,operation);
if(lcode)
{
Write.Line("Found match for operation at " + icode + " Length = " + (lcode-icode));
Opcode.DumpCode(icode,lcode);
}
}
Store.Close();
}

The output shows that there were two matches found.

Unit test for CodePattern.Match() Method
Found match for operation at 30 Length = 24
Offset | Sl.Start | Ql.Start | Quantity type | Opcode | Operation support information
------ | -------- | -------- | ------------- | ------ | -----------------------------
30 | 1.30 | 1.30 | ComboBox | LDA | ComboBox:cboFieldType:1086366
35 | 2.35 | 1.30 | Variant | CBO | ItemData
37 | 1.30 | 1.30 | Variant | MEM | Child
39 | 1.30 | 1.30 | Variant | LEV | Nest2
41 | 2.41 | 2.41 | ComboBox | LDA | ComboBox:cboFieldType:1086366
46 | 3.46 | 2.41 | Integer | CBO | ListIndex
48 | 2.41 | 2.41 | Integer | MEM | Child
50 | 2.41 | 1.30 | Variant | ARG | Integer
52 | 1.30 | 1.30 | Variant | INX | Subs1
Found match for operation at 111 Length = 24
Offset | Sl.Start | Ql.Start | Quantity type | Opcode | Operation support information
------ | -------- | -------- | ------------- | ------ | -----------------------------
111 | 1.111 | 1.111 | ComboBox | LDA | ComboBox:cboFieldType:1086366
116 | 2.116 | 1.111 | Variant | CBO | ItemData
118 | 1.111 | 1.111 | Variant | MEM | Child
120 | 1.111 | 1.111 | Variant | LEV | Nest1
122 | 2.122 | 2.122 | ComboBox | LDA | ComboBox:cboFieldType:1086366
127 | 3.127 | 2.122 | Integer | CBO | ListIndex
129 | 2.122 | 2.122 | Integer | MEM | Child
131 | 2.122 | 1.111 | Variant | ARG | Integer
133 | 1.111 | 1.111 | Variant | INX | Subs1

Interface: int Read(char* source,UBYTE* operation);

<Method id="Read" type="tCodeBlock" opcode="SCM.CodePattern_Read" >
<Argument id="source" type="String" status="ByVal" />
<Argument id="nCode" type="Integer" status="ByRef" />
</Method>

The method Read reads a code pattern string into a tCodeBlock for later use by a Match method. The parameter source is a null-terminated string containing the source representation of the code pattern, and the parameter nCode returns the length of the compiled code pattern, else it returns a negative error code. The method itself returns the handle to the code block that contains the actual opcode pattern. As can be seen from the following method the code pattern returned is a valid code stream that can be audited using the methods of the Opcode service class.

void TestRead()
{
tCodeBlock codptr;
tCodeBlock operation;
int nCode;
Write.Line "Unit test for CodePattern.Read() Method"
codptr = Opcode.GetCode();
operation = CodePattern.Read("LDA,LSB.List,MEM,LEV,LDA,LSB.ListIndex,MEM,ARG,INX",nCode);
Opcode.SetCode(operation);
Opcode.SetLength(nCode);
Opcode.DumpCode(0,nCode);
Opcode.SetCode(codptr);
}

The output shows the resultant code pattern that can be executed using the Match method.

Unit test for CodePattern.Read() Method
Offset | Sl.Start | Ql.Start | Quantity type | Opcode | Operation support information
------ | -------- | -------- | ------------- | ------ | -----------------------------
0 | | | | OPC | LDA
2 | 1.2 | 1.2 | Variant | LSB | List
4 | 1.2 | | | OPC | MEM
6 | 1.2 | | | OPC | LEV
8 | 1.2 | | | OPC | LDA
10 | 2.10 | 1.10 | Integer | LSB | ListIndex
12 | 2.10 | | | OPC | MEM
14 | 2.10 | | | OPC | ARG
16 | 2.10 | | | OPC | INX
18 | 2.10 | | | OPO | EndList