gmslCodePatternClass

The CodePattern Service Class

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.

The method Match

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

The method Read

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
Table of Contents