belr-demo.cc 4.82 KB
Newer Older
1 2 3 4 5 6 7
#include <iostream>
#include <fstream>
#include <sstream>
#include <chrono>
#include <ctime>
#include <cstring>

Ronan's avatar
Ronan committed
8 9
#include "belr/grammarbuilder.h"
#include "belr/abnf.h"
10 11 12 13 14 15 16 17 18 19 20 21

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:
22
	virtual ~SipElement () = default;
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
};

/*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;
100

101 102 103 104 105 106 107 108
	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
109
	shared_ptr<Grammar> grammar=builder.createFromAbnfFile("sipgrammar.txt", make_shared<CoreRules>());
110

111 112 113 114
	if (!grammar){
		cerr<<"Could not build grammar from sipgrammar.txt"<<endl;
		return -1;
	}
115

116 117 118
	//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);
119

120 121 122 123 124 125 126 127 128 129
	//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));
130

131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
	//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;
};