Support Statement: Using gmSL to determine if an optional argument was omitted
Q: How to judge %1d has value or empty? Like if ( %1 != ‘ ‘ or “ “ or Null or ???...
A: The %1d is a format string placeholder that tells the tool's code authoring service where to emit the 1st item on the operation stack when it authors a code pattern into the output buffer.Â
The items on the operation stack may be many different things such as variables, literals, arguments, methods, and operations organized into related groups.
I assume you are trying to determine if an optional argument is specified or not so you can select an appropriate pattern to express a COM API call as .NET.
Consider this COM API MSComctlLib.INodes.Add
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ C:\gmTestBed\FileExplorer\proj_csh\idf\FromIdl\mscomctl.ocx.xml ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ >1067 <method id="Add" type="Node"> 1068 <argument id="Relative" type="Variant" status="ByRef" optional="Default"/> 1069 <argument id="Relationship" type="Variant" status="ByRef" optional="Default"/> 1070 <argument id="Key" type="Variant" status="ByRef" optional="Default"/> 1071 <argument id="Text" type="Variant" status="ByRef" optional="Default"/> 1072 <argument id="Image" type="Variant" status="ByRef" optional="Default"/> 1073 <argument id="SelectedImage" type="Variant" status="ByRef" optional="Default"/> 1074 </method>
Use in the following statement
Set nodRoot = tvTreeView.Nodes.Add(, , drv.RootFolder.Path, drv.DriveLetter & ":\")
Only Key and Text arguments specified, the rest of the arguments are omitted and therefore they contain default values.
Here for example is the operation stack this modestly complex line of code:
386 | | | | NEW | 401 Set nodRoot = tvTreeView.Nodes.Add(, , drv.RootFolder.Path, drv.DriveLetter & ":\") 389 | 1.389 | 1.389 | MSComctlLib.Node | LDA | Variable:nodRoot:263980 394 | 1.389 | 1.389 | MSComctlLib.Node | LEV | Nest0 396 | 2.396 | 2.396 | MSComctlLib.TreeView | LDA | MSComctlLib.TreeView:tvTreeView:262914 401 | 3.401 | 2.396 | MSComctlLib.Nodes | LLP | Component:Nodes:150631 406 | 2.396 | 2.396 | MSComctlLib.Nodes | MEM | Child 408 | 3.408 | 2.396 | MSComctlLib.Node | LLP | Component:Add:155184 413 | 2.396 | 2.396 | MSComctlLib.Node | MEM | Child 415 | 2.396 | 2.396 | MSComctlLib.Node | LEV | Nest1 417 | 3.417 | 3.417 | Void | DEF < | Overload 419 | 3.417 | 2.396 | MSComctlLib.Node | ARG | Object 421 | 3.417 | 2.396 | MSComctlLib.Node | LEV | Nest1 423 | 4.423 | 3.423 | Void | DEF < | Overload 425 | 4.423 | 2.396 | MSComctlLib.Node | ARG | Integer 427 | 4.423 | 2.396 | MSComctlLib.Node | LEV | Nest1 429 | 5.429 | 3.429 | Scripting.Drive | LDA | Variable:drv:263878 434 | 6.434 | 3.429 | Scripting.Folder | LLP | Component:RootFolder:67849 439 | 5.429 | 3.429 | Scripting.Folder | MEM | Child 441 | 6.441 | 3.429 | String | LLP | Component:Path:68307 446 | 5.429 | 3.429 | String | MEM | Child 448 | 5.429 | 2.396 | MSComctlLib.Node | ARG | String 450 | 5.429 | 2.396 | MSComctlLib.Node | LEV | Nest1 452 | 6.452 | 3.452 | Scripting.Drive | LDA | Variable:drv:263878 457 | 7.457 | 3.452 | String | LLP | Component:DriveLetter:67693 462 | 6.452 | 3.452 | String | MEM | Child 464 | 7.464 | 4.464 | String | LSC | 2::\ 469 | 6.452 | 3.452 | String | CAT | String 471 | 6.452 | 2.396 | MSComctlLib.Node | ARG | String 473 | 6.452 | 2.396 | MSComctlLib.Node | LEV | Nest1 475 | 7.475 | 3.475 | Void | DEF < | Overload 477 | 7.475 | 2.396 | MSComctlLib.Node | ARG | Variant 479 | 7.475 | 2.396 | MSComctlLib.Node | LEV | Nest1 481 | 8.481 | 3.481 | Void | DEF < | Overload 483 | 8.481 | 2.396 | MSComctlLib.Node | ARG | Variant 485 | 2.396 | 2.396 | MSComctlLib.Node | CUF | Args6 487 | 2.396 | 2.396 | MSComctlLib.Node | REF | Component:Add:155184 492 | 2.396 | 1.389 | MSComctlLib.Node | ARG | Object 494 | | 2.494 | Void | CMD | Set
In order to determine if arguments to INode.Add are specified or not, the gmSL code must look for LEV,DEF,ARG operations in sequence.  This is done in an INode.Add migration event handler in the gmSL script associated with the MSComctlLib API. This is a rather complex migration because the one COM API has five different ways it may be expressed in C# (and additional variations for VB.NET). The code to determine if an argument is used or not is as follows:
int INodes_Add(int subRoot, int iStart, int iRefer) { int icode; int nCode; tCodeBlock codptr; int oper; int subc; tCodeBlock isOmitted; int nOper; int omitRelative; int iType; int stringRelative; int omitRelation; int lcode; int iRet; int intValue; int tvwChild; int tvwLast; tLibComp libComp; int addChild; int addLast; int pattern; int objRoot; int objType; int propAddr; string strValue; int imageAddr; int selectedAddr; int omitKey; // Position the stack pointer to the beginning of the arguments list codptr = Opcode.GetCode(); nCode = Opcode.GetLength() icode = Opcode.GetNext(codptr,iRefer,nCode); subc = 0; oper = Opcode.GetOperation(codptr,icode,subc); if(oper != OPC.MEM) return 0; icode = Opcode.GetNext(codptr,icode,nCode); oper = Opcode.GetOperation(codptr,icode,subc); if(oper != OPC.LEV) return 0; // INodes.Add.Relative nOper = 0; isOmitted = CodePattern.Read("LEV,DEF,ARG",nOper); omitRelative = CodePattern.Match(icode,isOmitted); ...
Given the logic above the variable omitRelative will be non-zero it argument INodes.Add.Relative was omitted.