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.