Hi,

Thanks for looking into this.  It would be nice to have a way to 
automatically generate the help text for STAF service requests.

The STAFCommandParser lets you specify the following:
1) The valid command options
2) The number of times an option may be specified (0 is unlimited)
3) If there is a value associated with the option (can be required, not 
allowed, or optional)
4) Groupings for options and if there is a minimum or maximum number of 
options that can be specified in a grouping
5) Dependency relationships (needee and needer options)

So far it appears you've implemented something for 1 and 5, but nothing 
yet for 2, 3, and 4.  I would be interested to see how you plan to 
represent all of these attributes in your output.

Could you provide an example of the output you envision for an existing 
STAF service, like the RESPOOL service?

C:\>STAF local RESPOOL HELP
Response
--------
*** RESPOOL Service Help ***

CREATE  POOL <PoolName> DESCRIPTION <Pool Description>
DELETE  POOL <PoolName> CONFIRM [FORCE]
LIST    [POOLS | SETTINGS]
ADD     POOL <PoolName> ENTRY <Value> [ENTRY <Value>]...
REMOVE  POOL <PoolName> ENTRY <Value> [ENTRY <Value>]... CONFIRM [FORCE]
QUERY   POOL <PoolName>
REQUEST POOL <PoolName>
        [FIRST | RANDOM | ENTRY <Value>] [PRIORITY <Number>]
        [TIMEOUT <Number>[s|m|h|d|w]] [GARBAGECOLLECT <Yes | No>]
RELEASE POOL <PoolName> ENTRY <Value> [FORCE]
CANCEL  POOL <PoolName>
        [FORCE [MACHINE <Machine>] [HANDLE <Handle #> | NAME <Handle 
Name>]]
        [ENTRY <Value>] [PRIORITY <Priority>] [FIRST | LAST]
VERSION
HELP

--------------------------------------------------------------
Sharon Lucas
IBM Austin,   luc...@us.ibm.com
(512) 286-7313 or Tieline 363-7313




"jander...@talentex.co.uk" <jander...@talentex.co.uk> 
06/22/2010 06:19 AM

To
staf <staf-users@lists.sourceforge.net>
cc

Subject
[staf-users] A first shot at a self-documenting parser interface






I have been messing about with the code in STAFCommandParser, and I 
thought it might be of use to others; also, it would be quite nice if 
somebody felt inspired to give the code a shove or two, now that I 
have begun. One may ask why I waste my time doing this, since most 
parsers presumably are static and this code therefore doesn't save 
large amounts of work. Personally I do it because I work on dynamic 
parsers - potentially large numbers of them, so I need something like. 
But I think it may be of more general interest too, since it can be 
used to identify structural problems in a parser - I identified a 
couple in the example I provided; one of those things that creep in 
when you change a parser. And of course, you won't have to remember to 
change your HELP text if you can generate it directly from the parser.

The philosophy is simple - when you build a parser in STAF, you are 
(potentially) constructing a hierarchy by defining the relations 
between "needers" and "needees"; I have created two functions, one 
that translates needer/needee into a hierarchical structure, and one 
that prints out a representation of the same.

I have provided an example in the included file (UNIX text file) along 
with the code I added to STAFCommandParser.*

Among the things that still need doing are:

1. printtree() only outputs to stdout - ideally one should get a 
something in a format that can be returned to the client.

2. I haven't shown any information about parameter values etc
Construction of an example parser:

                pData->fRequestParser=STAFCommandParserPtr(
                        new STAFCommandParser,
                        STAFCommandParserPtr::INIT
                );
                pData->fRequestParser->addOption(
                        "REQUEST",
                        1,
                        STAFCommandParser::kValueNotAllowed
                );
                pData->fRequestParser->addOption(
                        "LIST",
                        1,
                        STAFCommandParser::kValueNotAllowed
                );
                pData->fRequestParser->addOption(
                        "RESCLASS",
                        1,
                        STAFCommandParser::kValueRequired
                );
                pData->fRequestParser->addOption(
                        "RESNAME",
                        1,
                        STAFCommandParser::kValueRequired
                );
                pData->fRequestParser->addOption(
                        "RESTYPE",
                        1,
                        STAFCommandParser::kValueRequired
                );
                pData->fRequestParser->addOption(
                        "RESVERSION",
                        1,
                        STAFCommandParser::kValueRequired
                );
                pData->fRequestParser->addOption(
                        "TIMEOUT",
                        1,
                        STAFCommandParser::kValueRequired
                );
                pData->fRequestParser->addOption(
                        "LOC",
                        1,
                        STAFCommandParser::kValueRequired
                );
                pData->fRequestParser->addOption(
                        "LOCATION",
                        1,
                        STAFCommandParser::kValueRequired
                );
                pData->fRequestParser->addOption(
                        "OS",
                        10,
                        STAFCommandParser::kValueRequired
                );
                pData->fRequestParser->addOption(
                        "OSVERSION",
                        1,
                        STAFCommandParser::kValueRequired
                );
                pData->fRequestParser->addOption(
                        "OSBITS",
                        1,
                        STAFCommandParser::kValueRequired
                );
                pData->fRequestParser->addOption(
                        "DISK",
                        1,
                        STAFCommandParser::kValueRequired
                );
                pData->fRequestParser->addOption(
                        "ROLE",
                        1,
                        STAFCommandParser::kValueRequired
                );
                pData->fRequestParser->addOption(
                        "SCHEMA",
                        1,
                        STAFCommandParser::kValueRequired
                );
                pData->fRequestParser->addOption(
                        "INSTANCE",
                        1,
                        STAFCommandParser::kValueRequired
                );
                pData->fRequestParser->addOption(
                        "DURATION",
                        1,
                        STAFCommandParser::kValueRequired
                );
                pData->fRequestParser->addOption(
                        "LOCKNAME",
                        1,
                        STAFCommandParser::kValueRequired
                );
                pData->fRequestParser->addOption(
                        "ACCESS",
                        1,
                        STAFCommandParser::kValueRequired
                );
                pData->fRequestParser->addOption(
                        "FORMAT",
                        1,
                        STAFCommandParser::kValueRequired
                );
                pData->fRequestParser->addOption(
                        "INTERFACE",
                        1,
                        STAFCommandParser::kValueRequired
                );
                pData->fRequestParser->addOption(
                        "MARSHALL",
                        1,
                        STAFCommandParser::kValueNotAllowed
                );
                pData->fRequestParser->addOptionNeed(
                        "LIST RESCLASS RESNAME RESTYPE RESVERSION TIMEOUT 
"
                        "LOC LOCATION OS OSVERSION OSBITS DISK ROLE SCHEMA 
"
                        "INSTANCE DURATION LOCKNAME ACCESS FORMAT 
INTERFACE "
                        "MARSHALL",
                        "REQUEST"
                );
                pData->fRequestParser->addOptionNeed(
                        "FORMAT",
                        "LIST"
                );
                pData->fRequestParser->addOptionNeed("RDBMS 
FILE","RESCLASS");
                pData->fRequestParser->addOptionGroup("RESCLASS",1,1);
                pData->fRequestParser->addOptionGroup("REQUEST",1,1);
                pData->fRequestParser->addOptionGroup("LOC LOCATION",0,1);



                parsertree p=getParsertree(*pData->fRequestParser);
                printtree(p);

---------------------------------------------------

Output from printtree():

First on each line, the option, indented, and in brackets, the group it 
belongs to, if any. If an option-name is found amongst the needers, which 
hasn't been defined as an option, the text "is missing!" is appended to 
it. Although it can't be seen in the printout, all the information 
included in STAF's internal representation of a parser is extracted and 
returned in the tree-structure.

REQUEST (REQUEST)
    LIST ()
        FORMAT ()
    RESCLASS (RESCLASS)
        RDBMS is missing! ()
        FILE is missing! ()
    RESNAME ()
    RESTYPE ()
    RESVERSION ()
    TIMEOUT ()
    LOC (LOC LOCATION)
    LOCATION (LOC LOCATION)
    OS ()
    OSVERSION ()
    OSBITS ()
    DISK ()
    ROLE ()
    SCHEMA ()
    INSTANCE ()
    DURATION ()
    LOCKNAME ()
    ACCESS ()
    FORMAT ()
    INTERFACE ()
    MARSHALL ()

---------------------------------------------------

>From STAFCommandParser.cpp:

//Parsertree functions

opt::opt()
{
                 name="";
                 numAllowed=0;
                 valueRequirement=STAFCommandParser::kValueNotAllowed;
}

int toplevel(STAFCommandParserImpl &parser,STAFString &name)
{
                 for (
                                 STAFCommandParserImpl::NeedList::iterator 
n=parser.fNeedList.begin();
                                 n!=parser.fNeedList.end();
                                 ++n
                 ){
                                 if (n->needer.find(name)!=0xffffffff){
                                                 return 0;
                                 }
                 }
                 return 1;
}

STAFString getneeders(STAFCommandParserImpl &parser,STAFString &parent)
{
                 STAFString needers;

                 if (parent==""){
                                 for (
 STAFCommandParserImpl::OptionList::iterator o=parser.fOptionList.begin();
 o!=parser.fOptionList.end();
                                                 ++o
                                 ){
                                                 if 
(toplevel(parser,o->second.name)){
 needers+=o->second.name+" ";
}
                                 }
                 }
                 else{
                                 for (
 STAFCommandParserImpl::NeedList::iterator n=parser.fNeedList.begin();
 n!=parser.fNeedList.end();
                                                 ++n
                                 ){
                                                 if (n->needee==parent)
 needers+=n->needer+" ";
                                 }
                 }
                 return needers;
}

int findgrpix(parsertree &pt,STAFString curnm)
{
                 int i=0;
                 for (
                                 glist::iterator o=pt.groups.begin();
                                 o!=pt.groups.end();
                                 o++,i++
                 ){
 if(o->second.group.find(curnm)!=0xffffffff)             //i.e. if found 
curnm in this group
                                                 return i;
                 }
}

void addsub(STAFCommandParserImpl &parser,parsertree &pt,tree &subtree,opt 
&option, int lvl=0)
{
                 STAFString needers=getneeders(parser,option.name);
                 STAFString curnm,CURNM;
                 opt curopt;
                 int w=needers.numWords();

                 for (int i=0;i<w;i++){
                                 CURNM=needers.subWord(i,1);
                                 curnm=CURNM.toLowerCase();
 curopt.name=parser.fOptionList[curnm].name;
 curopt.numAllowed=parser.fOptionList[curnm].numAllowed;
 curopt.valueRequirement=parser.fOptionList[curnm].valueRequirement;
                                 if (curopt.name=="")
                                                 curopt.name=CURNM+" is 
missing!";
                                 subtree[i].option=curopt;
                                 subtree[i].grpix=findgrpix(pt,CURNM);
 addsub(parser,pt,subtree[i].sub,curopt,lvl+1);
                 }
}

parsertree getParsertree(STAFCommandParser &p)
{
                 parsertree pt;
                 opt option;
                 STAFCommandParserImpl *parser_=p.getImpl();
                 STAFCommandParserImpl &parser=*parser_;

                 int i=0;
                 for (
 STAFCommandParserImpl::GroupList::iterator g=parser.fGroupList.begin();
                                 g!=parser.fGroupList.end();
                                 g++,i++
                 ){
                                 pt.groups[i].group=g->group;
                                 pt.groups[i].minimum=g->minimum;
                                 pt.groups[i].maximum=g->maximum;
                 }
                 addsub(parser,pt,pt.ptree,option);

                 return pt;
}

void prtree(parsertree &pt,tree &t,int level=0)
{
                 STAFString spaces;

                 for (int i=0;i<level;i++)
                                 spaces+="    ";
                 for (tree::iterator o=t.begin();o!=t.end();o++){
                                 std::cout<<spaces
                                                 <<o->second.option.name
                                                 <<" 
("<<pt.groups[o->second.grpix].group<<")"
                                                 <<"\n";
                                 if (!o->second.sub.empty())
 prtree(pt,o->second.sub,level+1);
                 }
}

void printtree(parsertree &t)
{
                 prtree(t,t.ptree);
}

//Parsertree funetions - end

---------------------------------------------------

>From STAFCommandParser.h:

struct twig;
typedef std::map<int,twig> tree;

struct opt{
                 opt();

                 STAFString name;
                 unsigned int numAllowed;
                 STAFCommandParser::ValueRequirement valueRequirement;
};

struct twig{
                 tree sub;
                 opt option;
                 unsigned int grpix;
};

struct ogrp{
                 STAFString group;
                 unsigned int minimum,maximum;
};

typedef std::map<int,ogrp> glist;

struct parsertree{
                 tree ptree;
                 glist groups;
};

parsertree getParsertree(STAFCommandParser &p);
void printtree(parsertree &t);
------------------------------------------------------------------------------
ThinkGeek and WIRED's GeekDad team up for the Ultimate 
GeekDad Father's Day Giveaway. ONE MASSIVE PRIZE to the 
lucky parental unit.  See the prize list and enter to win: 
http://p.sf.net/sfu/thinkgeek-promo
_______________________________________________
staf-users mailing list
staf-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/staf-users

------------------------------------------------------------------------------
ThinkGeek and WIRED's GeekDad team up for the Ultimate 
GeekDad Father's Day Giveaway. ONE MASSIVE PRIZE to the 
lucky parental unit.  See the prize list and enter to win: 
http://p.sf.net/sfu/thinkgeek-promo
_______________________________________________
staf-users mailing list
staf-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/staf-users

Reply via email to