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