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

Reply via email to