/* * parser.h * Copyright (C) 2017 Belledonne Communications SARL * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef _PARSER_H_ #define _PARSER_H_ #include #include #include #include #include "belr.h" // ============================================================================= namespace belr { template class AbstractCollector{ public: virtual void invokeWithChild(_parserElementT obj, _parserElementT child)=0; virtual ~AbstractCollector() = default; }; template class CollectorBase : public AbstractCollector<_parserElementT>{ public: virtual void invoke(_parserElementT obj, _valueT value)=0; }; template class ParserCollector : public CollectorBase<_parserElementT,_valueT>{ public: ParserCollector(const std::function &fn) : mFunc(fn) {} virtual void invoke(_parserElementT obj, _valueT value); void invokeWithChild(_parserElementT obj, _parserElementT child); private: std::function mFunc; }; template class ParserChildCollector : public CollectorBase<_parserElementT,_valueT>{ public: ParserChildCollector(const std::function &fn) : mFunc(fn){} virtual void invoke(_parserElementT obj, _valueT value); virtual void invokeWithChild(_parserElementT obj, _parserElementT child); private: std::function mFunc; }; template class HandlerContext; template class Parser; class HandlerContextBase; template class ParserHandlerBase : public std::enable_shared_from_this>{ friend class HandlerContext<_parserElementT>; public: virtual _parserElementT invoke(const std::string &input, size_t begin, size_t count)=0; std::shared_ptr> createContext(); const std::string &getRulename()const{ return mRulename; } protected: void releaseContext(const std::shared_ptr> &ctx); ParserHandlerBase(const Parser<_parserElementT> &parser, const std::string &name); void installCollector(const std::string &rulename, const std::shared_ptr> &collector); const std::shared_ptr> &getCollector(unsigned int rule_id)const; private: std::map> > mCollectors; const Parser<_parserElementT> &mParser; std::string mRulename; std::shared_ptr> mCachedContext; }; template class ParserHandler : public ParserHandlerBase<_parserElementT>{ public: ParserHandler(const Parser<_parserElementT> &parser, const std::string &rulename, const std::function<_derivedParserElementT ()> &create) : ParserHandlerBase<_parserElementT>(parser, rulename), mHandlerCreateFunc(create){} ParserHandler(const Parser<_parserElementT> &parser, const std::string &rulename, const std::function<_derivedParserElementT (const std::string &, const std::string &)> &create) : ParserHandlerBase<_parserElementT>(parser, rulename), mHandlerCreateDebugFunc(create){} template std::shared_ptr> setCollector(const std::string &child_rule_name, std::function fn){ this->installCollector(child_rule_name, std::make_shared>(fn)); return std::static_pointer_cast>(this->shared_from_this()); } template std::shared_ptr> setCollector(const std::string &child_rule_name, std::function fn){ this->installCollector(child_rule_name, std::make_shared>(fn)); return std::static_pointer_cast>(this->shared_from_this()); } template std::shared_ptr> setCollector(const std::string &child_rule_name, std::function fn){ this->installCollector(child_rule_name, std::make_shared>(fn)); return std::static_pointer_cast>(this->shared_from_this()); } _parserElementT invoke(const std::string &input, size_t begin, size_t count); private: std::function<_derivedParserElementT ()> mHandlerCreateFunc; std::function<_derivedParserElementT (const std::string &, const std::string &)> mHandlerCreateDebugFunc; }; template class Assignment{ public: Assignment(const std::shared_ptr> &c, size_t begin, size_t count, const std::shared_ptr> &child) : mCollector(c.get()), mBegin(begin), mCount(count), mChild(child) {} void invoke(_parserElementT parent, const std::string &input); private: AbstractCollector<_parserElementT> * mCollector;//not a shared_ptr for optimization, the collector cannot disapear size_t mBegin; size_t mCount; std::shared_ptr> mChild; }; class HandlerContextBase : public std::enable_shared_from_this{ public: BELR_PUBLIC virtual ~HandlerContextBase() = default; }; template class HandlerContext : public HandlerContextBase{ public: HandlerContext(const std::shared_ptr> &handler); void setChild(unsigned int subrule_id, size_t begin, size_t count, const std::shared_ptr &child); _parserElementT realize(const std::string &input, size_t begin, size_t count); std::shared_ptr> branch(); void merge(const std::shared_ptr> &other); size_t getLastIterator()const; void undoAssignments(size_t pos); void recycle(); private: ParserHandlerBase<_parserElementT> & mHandler; std::vector> mAssignments; }; struct ParserLocalContext{ void set(const std::shared_ptr& hc, const std::shared_ptr& rec, size_t pos){ mHandlerContext=hc; mRecognizer=rec.get(); mAssignmentPos=pos; } std::shared_ptr mHandlerContext; Recognizer * mRecognizer = nullptr; //not a shared ptr to optimize, the object can't disapear in the context of use of ParserLocalContext. size_t mAssignmentPos = 0; }; class ParserContextBase{ public: virtual void beginParse(ParserLocalContext &ctx, const std::shared_ptr &rec)=0; virtual void endParse(const ParserLocalContext &ctx, const std::string &input, size_t begin, size_t count)=0; virtual std::shared_ptr branch()=0; virtual void merge(const std::shared_ptr &other)=0; virtual void removeBranch(const std::shared_ptr &other)=0; }; template class ParserContext : public ParserContextBase{ public: ParserContext(Parser<_parserElementT> &parser); _parserElementT createRootObject(const std::string &input); protected: virtual void beginParse(ParserLocalContext &ctx, const std::shared_ptr &rec); virtual void endParse(const ParserLocalContext &ctx, const std::string &input, size_t begin, size_t count); virtual std::shared_ptr branch(); virtual void merge(const std::shared_ptr &other); virtual void removeBranch(const std::shared_ptr &other); void _beginParse(ParserLocalContext &ctx, const std::shared_ptr &rec); void _endParse(const ParserLocalContext &ctx, const std::string &input, size_t begin, size_t count); std::shared_ptr> _branch(); void _merge(const std::shared_ptr> &other); void _removeBranch(const std::shared_ptr> &other); private: Parser<_parserElementT> & mParser; std::list>> mHandlerStack; std::shared_ptr> mRoot; }; /** * Parser class. * This template class allows to parse a text input using a Grammar object describing the language of the input to be parsed. * The template argument _parserElementT must be a base class for all elements that will be created to represent the result of the parsing. * This can be 'void*' if the parser is implemented in C, but can also be any C++ class provided that each type representing a parsed entity * inherits from this class. **/ template class Parser{ friend class ParserContext<_parserElementT>; friend class ParserHandlerBase<_parserElementT>; public: Parser(const std::shared_ptr &grammar); template std::shared_ptr> setHandler(const std::string &rulename,const std::function<_derivedParserElementT ()> & handler){ auto ret=std::make_shared>(*this, rulename,handler); installHandler(ret); return ret; } template std::shared_ptr> setHandler(const std::string &rulename, const std::function<_derivedParserElementT (const std::string &, const std::string &)> & handler){ auto ret=std::make_shared>(*this, rulename,handler); installHandler(ret); return ret; } _parserElementT parseInput(const std::string &rulename, const std::string &input, size_t *parsed_size); private: std::shared_ptr> &getHandler(unsigned int); void installHandler(const std::shared_ptr> &handler); std::shared_ptr mGrammar; std::map>> mHandlers; std::shared_ptr> mNullHandler; std::shared_ptr> mNullCollector; }; class DebugElement{ public: DebugElement(const std::string &rulename, const std::string &value); static std::shared_ptr create(const std::string &rulename, const std::string &value); void addChild(const std::shared_ptr &e); BELR_PUBLIC std::ostream &tostream(int level, std::ostream &str)const; private: std::string mRulename; std::string mValue; std::list> mChildren; }; class DebugParser : protected Parser>{ public: BELR_PUBLIC DebugParser(const std::shared_ptr &grammar); BELR_PUBLIC void setObservedRules(const std::list &rules); BELR_PUBLIC std::shared_ptr parseInput(const std::string &rulename, const std::string &input, size_t *parsed_size); }; template std::function< _retT ()> make_fn(_retT (*arg)()){ return std::function<_retT ()>(arg); } template std::function< _retT (_arg1T,_arg2T)> make_fn(_retT (*arg)(_arg1T,_arg2T)){ return std::function< _retT (_arg1T,_arg2T)>(arg); } template std::function< void (_klassT*,_argT)> make_fn(void (_klassT::*arg)(_argT)){ return std::function< void (_klassT*,_argT)>(std::mem_fn(arg)); } template std::function< void (std::shared_ptr<_klassT>,_argT)> make_sfn(void (_klassT::*arg)(_argT)){ return std::function< void (std::shared_ptr<_klassT>,_argT)>(std::mem_fn(arg)); } // ============================================================================= // Parser impl. // ============================================================================= template T universal_pointer_cast(const std::shared_ptr& sp){ return std::static_pointer_cast(sp); } template T universal_pointer_cast(U * p){ return static_cast(p); } template void ParserCollector<_derivedParserElementT,_parserElementT, _valueT>::invoke(_parserElementT obj, _valueT value){ mFunc(universal_pointer_cast<_derivedParserElementT>(obj),value); } template void ParserCollector<_derivedParserElementT,_parserElementT, _valueT>::invokeWithChild(_parserElementT obj, _parserElementT child){ std::cerr<<"We should never be called in ParserCollector<_derivedParserElementT,_parserElementT, _valueT>::invokeWithChild(_parserElementT obj, _parserElementT child)"< void ParserChildCollector<_derivedParserElementT,_parserElementT, _valueT>::invokeWithChild(_parserElementT obj, _parserElementT value){ mFunc(universal_pointer_cast<_derivedParserElementT>(obj),universal_pointer_cast::type>(value)); } template void ParserChildCollector<_derivedParserElementT,_parserElementT, _valueT>::invoke(_parserElementT obj, _valueT value){ std::cerr<<"We should never be called in ParserChildCollector<_derivedParserElementT,_parserElementT, _valueT>::invoke(_parserElementT obj, _valueT value)"< void Assignment<_parserElementT>::invoke(_parserElementT parent, const std::string &input){ if (mChild){ mCollector->invokeWithChild(parent, mChild->realize(input,mBegin,mCount)); }else{ std::string value=input.substr(mBegin, mCount); CollectorBase<_parserElementT,const std::string&>* cc1=dynamic_cast*>(mCollector); if (cc1){ cc1->invoke(parent, value); return; } CollectorBase<_parserElementT,const char*>* cc2=dynamic_cast*>(mCollector); if (cc2){ cc2->invoke(parent, value.c_str()); return; } CollectorBase<_parserElementT,int> *cc3=dynamic_cast*>(mCollector); if (cc3){ cc3->invoke(parent, atoi(value.c_str())); return; } } } // // HandlerContext template class implementation // template HandlerContext<_parserElementT>::HandlerContext(const std::shared_ptr> &handler) : mHandler(*handler.get()){ } template void HandlerContext<_parserElementT>::setChild(unsigned int subrule_id, size_t begin, size_t count, const std::shared_ptr> &child){ auto collector=mHandler.getCollector(subrule_id); if (collector){ mAssignments.push_back(Assignment<_parserElementT>(collector, begin, count, child)); } } template _parserElementT HandlerContext<_parserElementT>::realize(const std::string &input, size_t begin, size_t count){ _parserElementT ret=mHandler.invoke(input, begin, count); for (auto it=mAssignments.begin(); it!=mAssignments.end(); ++it){ (*it).invoke(ret,input); } return ret; } template std::shared_ptr> HandlerContext<_parserElementT>::branch(){ return mHandler.createContext(); } template void HandlerContext<_parserElementT>::merge(const std::shared_ptr> &other){ for (auto it=other->mAssignments.begin();it!=other->mAssignments.end();++it){ mAssignments.emplace_back(*it); } } template size_t HandlerContext<_parserElementT>::getLastIterator()const{ return mAssignments.size(); } template void HandlerContext<_parserElementT>::undoAssignments(size_t pos){ mAssignments.erase(mAssignments.begin()+pos,mAssignments.end()); } template void HandlerContext< _parserElementT >::recycle(){ mAssignments.clear(); mHandler.releaseContext(std::static_pointer_cast>(shared_from_this())); } // // ParserHandlerBase template class implementation // template ParserHandlerBase<_parserElementT>::ParserHandlerBase(const Parser<_parserElementT> &parser, const std::string &name) : mParser(parser), mRulename(tolower(name)), mCachedContext(nullptr) { } template void ParserHandlerBase<_parserElementT>::installCollector(const std::string &rulename, const std::shared_ptr> &collector){ std::shared_ptr rec=mParser.mGrammar->findRule(rulename); if (!rec){ std::cerr<<"There is no rule '"<getId()]=collector; } template const std::shared_ptr> & ParserHandlerBase<_parserElementT>::getCollector(unsigned int rule_id)const{ auto it=mCollectors.find(rule_id); if (it!=mCollectors.end()) return (*it).second; return mParser.mNullCollector; } template void ParserHandlerBase< _parserElementT >::releaseContext(const std::shared_ptr> &ctx){ mCachedContext=ctx; } template std::shared_ptr> ParserHandlerBase<_parserElementT>::createContext(){ if (mCachedContext) { std::shared_ptr> ret=mCachedContext; mCachedContext.reset(); return ret; } return std::make_shared>(this->shared_from_this()); } // // ParserHandler template implementation // template _parserElementT ParserHandler<_derivedParserElementT,_parserElementT>::invoke(const std::string &input, size_t begin, size_t count){ if (mHandlerCreateFunc) return universal_pointer_cast<_parserElementT>(mHandlerCreateFunc()); if (mHandlerCreateDebugFunc) return universal_pointer_cast<_parserElementT>(mHandlerCreateDebugFunc(this->getRulename(), input.substr(begin, count))); return nullptr; } // // ParserContext template class implementation // template ParserContext<_parserElementT>::ParserContext(Parser<_parserElementT> &parser) : mParser(parser) { } template void ParserContext<_parserElementT>::_beginParse(ParserLocalContext & lctx, const std::shared_ptr &rec){ std::shared_ptr ctx; auto h=mParser.getHandler(rec->getId()); if (h){ ctx=h->createContext(); mHandlerStack.push_back(std::static_pointer_cast>(ctx)); } lctx.set(ctx,rec,mHandlerStack.back()->getLastIterator()); } template void ParserContext<_parserElementT>::_endParse(const ParserLocalContext &localctx, const std::string &input, size_t begin, size_t count){ if (localctx.mHandlerContext){ mHandlerStack.pop_back(); if (count!=std::string::npos && count>0){ if (!mHandlerStack.empty()){ /*assign object to parent */ mHandlerStack.back()->setChild(localctx.mRecognizer->getId(), begin, count, std::static_pointer_cast> (localctx.mHandlerContext)); }else{ /*no parent, this is our root object*/ mRoot=std::static_pointer_cast>(localctx.mHandlerContext); } }else{ //no match std::static_pointer_cast>(localctx.mHandlerContext)->recycle(); } }else{ if (count!=std::string::npos && count>0){ /*assign std::string to parent */ if (localctx.mRecognizer->getId()!=0) mHandlerStack.back()->setChild(localctx.mRecognizer->getId(), begin, count, nullptr); }else{ mHandlerStack.back()->undoAssignments(localctx.mAssignmentPos); } } } template _parserElementT ParserContext<_parserElementT>::createRootObject(const std::string &input){ return mRoot ? mRoot->realize(input,0,input.size()) : nullptr; } template std::shared_ptr> ParserContext<_parserElementT>::_branch(){ if (mHandlerStack.empty()){ std::cerr<<"Cannot branch while stack is empty"<> ret=mHandlerStack.back()->branch(); mHandlerStack.push_back(ret); return ret; } template void ParserContext<_parserElementT>::_merge(const std::shared_ptr> &other){ if (mHandlerStack.back()!=other){ std::cerr<<"The branch being merged is not the last one of the stack !"<merge(other); other->recycle(); } template void ParserContext<_parserElementT>::_removeBranch(const std::shared_ptr> &other){ auto it=find(mHandlerStack.rbegin(), mHandlerStack.rend(),other); if (it==mHandlerStack.rend()){ std::cerr<<"A branch could not be found in the stack while removing it !"<recycle(); } template void ParserContext<_parserElementT>::beginParse(ParserLocalContext &ctx, const std::shared_ptr &rec){ _beginParse(ctx, rec); } template void ParserContext<_parserElementT>::endParse(const ParserLocalContext &localctx, const std::string &input, size_t begin, size_t count){ _endParse(localctx, input, begin, count); } template std::shared_ptr ParserContext<_parserElementT>::branch(){ return _branch(); } template void ParserContext<_parserElementT>::merge(const std::shared_ptr &other){ _merge(std::static_pointer_cast>(other)); } template void ParserContext<_parserElementT>::removeBranch(const std::shared_ptr &other){ _removeBranch(std::static_pointer_cast>(other)); } // // Parser template class implementation // template Parser<_parserElementT>::Parser(const std::shared_ptr &grammar) : mGrammar(grammar) { if (!mGrammar->isComplete()){ std::cerr<<"Grammar not complete, aborting."< std::shared_ptr> &Parser<_parserElementT>::getHandler(unsigned int rule_id){ auto it=mHandlers.find(rule_id); if (it==mHandlers.end()) return mNullHandler; return (*it).second; } template void Parser<_parserElementT>::installHandler(const std::shared_ptr> &handler){ std::shared_ptr rec=mGrammar->findRule(handler->getRulename()); if (!rec){ std::cerr<<"There is no rule '"<getRulename()<<"' in the grammar."<getId()]=handler; } template _parserElementT Parser<_parserElementT>::parseInput(const std::string &rulename, const std::string &input, size_t *parsed_size){ size_t parsed; std::shared_ptr rec=mGrammar->getRule(rulename); auto pctx=std::make_shared>(*this); //auto t_start = std::chrono::high_resolution_clock::now(); parsed=rec->feed(pctx, input, 0); //auto t_end = std::chrono::high_resolution_clock::now(); //cout<<"Recognition done in "<(t_end-t_start).count()<<" milliseconds"<createRootObject(input); return ret; } } #endif