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