belrdemo.cc 5.04 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
#include "belr/grammarbuilder.hh"
#include "belr/abnf.hh"
#include <iostream>
#include <fstream>
#include <sstream>
#include <chrono>
#include <ctime>
#include <cstring>

#include "belr/parser-impl.cc" //this file is to be included only in the file where the parser is instanciated, for template instanciation.

using namespace::belr;
using namespace::std;

/*
 * This demo program instanciates a SIP parser from the SIP grammar in a text file.
 * Then it attempts to parse a SIP URI and fill URI components in our custom C++ object.
**/

/*This is our base class for all our parsed elements. It does nothing but is required for run time type identification*/
class SipElement{
public:
	SipElement(){
	}
	//put a virtual destructor to enable polymorphism and dynamic casting.
	virtual ~SipElement(){
	}
};

/*this the class representing uri "other" params, per the grammar. They will be added to the SIP-URI when found.*/
class OtherParam : public SipElement{
private:
	string mName;
	string mValue;
public:
	OtherParam(){
	}
	static shared_ptr<OtherParam> create(){
		return make_shared<OtherParam>();
	}
	void setName(const string & name){
		mName = name;
	}
	const string & getName()const{
		return mName;
	}
	void setValue(const string &value){
		mValue = value;
	}
	const string &getValue()const{
		return mValue;
	}
};

/*This is our SipUri class, representing sip uris. It has accessors for most common field, including accessing parameters*/
class SipUri : public SipElement{
private:
	string mUsername;
	string mHost;
	string mPasswd;
	int mPort;
	list<shared_ptr<OtherParam>> mOtherParams;
public:
	static shared_ptr<SipUri> create(){
		return make_shared<SipUri>();
	}
	SipUri(){
		mPort = 0;
	}
	/*follows all the setter/getters of SIP-URI fields*/
	void setUsername(const string &username){
		mUsername = username;
	}
	const string & getUsername()const{
		return mUsername;
	}
	void setHost(const string &host){
		mHost = host;
	}
	const string & getHost()const{
		return mHost;
	}
	void setPasswd(const string & passwd){
		mPasswd = passwd;
	}
	const string &getPasswd()const{
		return mPasswd;
	}
	void setPort(int port){
		mPort = port;
	}
	int getPort()const{
		return mPort;
	}
	void addOtherParam(const shared_ptr<OtherParam> &params){
		mOtherParams.push_back(params);
	}
	const list<shared_ptr<OtherParam>> & getOtherParams()const{
		return mOtherParams;
	}
};

int main(int argc, char *argv[]){
	string uriToParse;
	
	if (argc<2){
		cerr<<argv[0]<<" <uri to parse>"<<endl;
		return -1;
	}
	uriToParse = argv[1];
	//Create a GrammarBuilder:
	ABNFGrammarBuilder builder;
	//construct the grammar from the grammar file, the core rules are included since required by most RFCs.
Sylvain Berfini's avatar
Sylvain Berfini committed
114
	shared_ptr<Grammar> grammar=builder.createFromAbnfFile("sipgrammar.txt", make_shared<CoreRules>());
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
	
	if (!grammar){
		cerr<<"Could not build grammar from sipgrammar.txt"<<endl;
		return -1;
	}
	
	//now instanciate a parser and assign it collectors and handlers
	//This parser expects to build objects which are all inherited from SipElement, and that are stored as shared_ptr.
	Parser<shared_ptr<SipElement>> parser(grammar);
	
	//Now, tell our parser where to assign elements when they are found during parsing.
	parser.setHandler("SIP-URI", make_fn(&SipUri::create)) //tells that whenever a SIP-URI is found, a SipUri object must be created.
		->setCollector("user", make_sfn(&SipUri::setUsername)) //tells that when a "user" field is found, SipUri::setUsername() is to be called for assigning the "user"
		->setCollector("host", make_sfn(&SipUri::setHost)) //tells that when host is encountered, use SipUri::setHost() to assign it to our SipUri object.
		->setCollector("port", make_sfn(&SipUri::setPort)) // understood ?
		->setCollector("password", make_sfn(&SipUri::setPasswd))
		->setCollector("other-param", make_sfn(&SipUri::addOtherParam));
	parser.setHandler("other-param", make_fn(&OtherParam::create)) //when other-param is matched, construct an OtherParam object to hold the name and value of the other-params.
		->setCollector("pname", make_sfn(&OtherParam::setName))
		->setCollector("pvalue", make_sfn(&OtherParam::setValue));
	
	//now, parse the input. We have to tell the parser the root object, which is the SIP-URI in this example.
	size_t parsedSize = 0;
	shared_ptr<SipElement> ret = parser.parseInput("SIP-URI", uriToParse, &parsedSize);
	//if a sip uri is found, the return value is non null and should cast into a SipUri object.
	if (ret){
		shared_ptr<SipUri> sipUri = dynamic_pointer_cast<SipUri>(ret);
		//now let's print the content of uri object to make sure that its content is consistent with the input passed.
		cout<<"user: "<<sipUri->getUsername()<<endl;
		cout<<"passord: "<<sipUri->getPasswd()<<endl;
		cout<<"host: "<<sipUri->getHost()<<endl;
		cout<<"port: "<<sipUri->getPort()<<endl;
		cout<<"Listing of other-params:"<<endl;
		for(auto it = sipUri->getOtherParams().begin(); it != sipUri->getOtherParams().end(); ++it){
			cout<<"name: "<<(*it)->getName()<<" value: "<<(*it)->getValue()<<endl;
		}
	}else{
		cerr<<"Could not parse ["<<uriToParse<<"]"<<endl;
	}
	//so nice, so easy to use belr, isn't it ?
	return 0;
};