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