gmslCodePatternClass
The CodePattern Service Class
Section titled “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.AssignPropertyMEM.Get,Argument,CUF,REFMEM.Set,Argument,CUF,REF,STRMEM,STR",nOper);Argument,LDA,LLP.[MSComctlLib.IListView.Sortkey],MEMFOR.Controls,MEM.Child,LIC,TYP,IFS.ForEachTempEach 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
Section titled “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() MethodFound match for operation at 30 Length = 24Offset | 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 | Subs1Found match for operation at 111 Length = 24Offset | 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 | Subs1The method Read
Section titled “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() MethodOffset | 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