I wrote a C++ PEG packrat parser generator and would love to get some feedback on the code and/or syntax. I currently use the <<
operator for defining grammar expressions and linking the handler functions that are called when a rule is matched. These functions can then store a value of an arbitrary C++ type in the corresponding node of the parse tree using the value<type>()
function.
For example, a very simple math parser can be generated through the following source code:
#include "IO.h"
#include "parserTools.h"
#include <cmath> //pow
using namespace llib;
std::map<std::string, double> variables;
void op(parser::info &lhs,parser::info &rhs,parser::info &r,const std::string &op){
if(op[0]=='+') r.value() = lhs.value<double>() + rhs.value<double>() ;
else if(op[0]=='-') r.value() = lhs.value<double>() - rhs.value<double>() ;
else if(op[0]=='*') r.value() = lhs.value<double>() * rhs.value<double>() ;
else if(op[0]=='/') r.value() = lhs.value<double>() / rhs.value<double>() ;
else if(op[0]=='^') r.value() = pow(lhs.value<double>() , rhs.value<double>());
}
void variable(parser::info &s){ s.value<double>()=variables[s.string()]; }
void negate(parser::info &s) { s.value()=-s[0].value<double>(); }
void set(parser::info &s) { variables[s[0].string()]=s[1].value<double>(); }
int main(){
peg::grammar math("Math");
math << "Math" << "Set | Expression" << parserTools::show("%v0\n");
math << "Set" << "Variable '=' Sum" << set << parserTools::pass(1);
math << "Expression" << "Sum" << parserTools::pass();
math << "Sum" << "Product ([+-] Product )*" << parserTools::leftbinary(op);
math << "Product" << "Exponent ([*/] Exponent)*" << parserTools::leftbinary(op);
math << "Exponent" << "Atomic ('^' Atomic )*" << parserTools::leftbinary(op);
math << "Atomic" << "Parentheses | Number | Negate | Variable" << parserTools::pass();
math << "Parentheses" << "'(' Expression ')'" << parserTools::pass();
math << "Negate" << "'-' Atomic" << negate;
math << "Variable" << "[a-zA-Z] [a-zA-Z0-9]*" << variable;
math << "Number" << parserTools::doubleGrammar() << parserTools::pass();
math.ignored=" \t";
math.setStart("Math");
parser p(math);
p.error=parserTools::genericError;
p.warning=parserTools::genericWarning;
while (1) {
std::string str;
IO << "> " >> str << str << " -> ";
if(str=="q") break;
else if(str!="") p.parse(str);
else IO << clearline << endl;
}
return 0;
}
The full code and documentation is available on GitHub (though LParser is probably pretty boring name).
So any thoughts on the project? Is it something you would actually use?