LPeter1997 / CppCmb

A generic C++17 parser-combinator library with a natural grammar notation.
MIT License
122 stars 8 forks source link

pc::product<> with no template arguments? #5

Closed tomoyanonymous closed 5 years ago

tomoyanonymous commented 5 years ago

If I have a code like below

cppcmb_decl(expr, pc::product<>);

cppcmb_def(expr) = pc::pass
    | (num & match<'+'> & num)// [pc::select<1,0,2>]
    ;

std::string to_num(std::vector<char> const& chs) {//just for conversion from vector<char>->string
    const std::string str(chs.begin(), chs.end());
    return str;
}
cppcmb_def(num) = (+digit)[to_string];
cppcmb_def(digit) = pc::one[pc::filter(isdigit)];

I get an error like

error: no viable conversion from returned value of type 'result<product<std::__1::vector<char, std::__1::allocator<char> >, char, std::__1::vector<char, std::__1::allocator<char> >>>' to function return type 'result<product<(no argument), (no argument), (no argument)>>'

if I specify a return type to template arguments of pc::product

cppcmb_decl(expr, pc::product<std::string,char,std::string>);

The compiltion succeeds. When can we use pc::product<> without template arguments?

LPeter1997 commented 5 years ago

pc::product<> is roughly equivalent to std::tuple<>. When you write the declaration:

cppcmb_decl(expr, pc::product<>);

You basically say "expr is a rule that returns nothing." The definition of expr however returns a pc::product<std::string, char, std::string>.

So when is it useful to have pc::product<>? Probably when you don't need anything as a result, just syntax validation. When you have pc::select</* nothing */>, you probably return pc::product<>.

tomoyanonymous commented 5 years ago

I see,, that's why anbn example does not output any actual strings, but just a result. Then I would like to switch my question, how should I keep AST that has a recursive structure(for example, like S-expression) from parse result? Left recursion may contain nested types, so a template parameter also becomes nested. Maybe it's not a good functional way that creates AST as a struct, what is the best way to solve?

LPeter1997 commented 5 years ago

Right, the ANBN example is exactly for that.

Creating an AST is certainly possible, you just need to have a base-type that erases the recursion. Something like:

struct S_Expr {};

struct ListExpr : public S_Expr {
    std::vector<S_Expr*> exprs;
};

struct LiteralExpr : public S_Expr {
    std::string value;
};

Then every parser can just return an S_Expr*. This is the usual way for every parser in C++ AFAIK.

Thanks for the issue by the way, it has shown me that the project is still lacking documentation and examples, which I'm working on right now.

tomoyanonymous commented 5 years ago

Yeah, I know this question is like a that of computer science, I'm just wandering the labyrinth...anyway, thanks! will try upcasting.

tomoyanonymous commented 5 years ago

it worked nicely! thanks for your help. Screen Shot 2019-05-19 at 23 08 28 your help.)