pc::product<> with no template arguments?
tomoyanonymous opened this issue · 5 comments
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?
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<>
.
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?
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.
Yeah, I know this question is like a that of computer science, I'm just wandering the labyrinth...anyway, thanks! will try upcasting.