C++ Compile Time Parser Generator
github.com
github.com
Not sure if the OP is the author, but here are a few comments from someone with no experience in parsing:
- For the documentation, it would be better if it didn't use using namespace, as it make it easier to see which symbols are part of the library and which ones are part of the example.
- There's need to be a note about the lifetime of the buffer under referenced by the string_view parameters. I assume this is just the original buffer passed to parse, but it would be better to be explicit. Also, string_views are probably better passed around by value (the examples are inconsistent).
- The documentation probably need more details about handling parsing errors. Also is there any way to recover from a failed parse?
- It would be nice that a parser with no action could be used to validate a string against a grammar, but it seems that the implicit actions would prevent that.
- (Very minor) val should probably be called always, and create should just be always with an explicit template parameter and a defaulted argument.
- (Again, very minor) making create, push_back and emplace_back inline variables (available in C++17) instead of types would lead to a slightly more pleasant syntax.
I am assuming template metaprogramming is so bad because even elementary data structures have to employ ton of helper types that have to be matched/deduced against gigantic list of all other types and kept all in memory, while straightforward interpretation should not need any of that. I would expect constexpr to perform similarly to interpreted languages, which should be no different than invoking an external code generator written in Python, for example.
That is what killed my own attempt at doing this - the code was large enough that I had to move some polymorphism from compile time to run time in order to - counterintuitively - speed it up!
(Entirely possible they executed better than I did, of course)
Also nice how you can integrate the semantics within the rule by the use of lambda expressions.
(I have experience with writing parser and developed an interpreting parser myself. https://github.com/FransFaase )
Use a real tool instead of hacks like this. For fun? Do whatever you want. If I ever come across something like this in production it's going to be removed immediately.
Seriously, what's so wrong with lex + yacc, or antlr or parsec or ragel or any of the others?
Not sure ANTLR is as fast (doesn't it use recursive descent? which is slower algorithmically) but even ignoring performance, it's basically the cost of adding a new tool to your toolchain. If you already have 20 other tools, maybe the 21st isn't a big deal, but if you have 2, the 3rd adds some complexity. And in general it's kinda nice to have fewer things to glue together.
(I'm not claiming "therefore this approach trumps what you listed", I'm just explaining some of its advantages. Obviously it has disadvantages too.)
Necessary hacks, when the language is inadequate to the job. But C++ is no longer inadequate.
Lex and yacc depend on global variables, so you get one (1) parser per program, unless you further massage their output.
I'm sure you could only have one lexer back at some point in the distant past, but that particular issue has been solvable for a long time by now.
But in general, for anybody deploying software widely, any time you can avoid a necessary build dependency on another tool, you come out ahead.
https://www.gnu.org/software/bison/manual/bison.html#Version...
Even if you have standard-conforming lex and yacc source code that, theoretically, work with any yacc or lex implementation, it's still wise to pick a good implementation and generate code with it, and ship that code. You don't want some random tool from the user's installation writing C code into your project.
And POSIX does not guarantee the presence of a yacc command in an installation; it just describes what it does if it is present. There are Unix-like systems with no dev tools on them; requiring lex plus yacc plus a compiler is a bigger dependency than just requiring a compiler.
People writing C++ code no longer have any need for a thing like yacc, and that is a net good.
Those who maintain some relationship with the cpgg upstream repo have some sort of dependency.
(C++ itself is a heavy dependency. People who don't use C++ demonstrate that C++ is not necessary.) Dependencies are not all the same; they have different weights. Three light dependencies could be equal to one heavy one.)
cpgg is currently not comparable to something like Bison. Bison has documentation, and an active mailing list where you can get quality help from knowledgeable people. It has multiple contributors.
It supports multiple languages, so your parser-writing skill transfers to different stacks: e.g. from C to Java, for instance. In many cases you should be able to port the grammar directly; just the semantic actions need a rewrite.
It has some novel diagnostic features, like the recently added feature of being able to generate counterexamples to explain conflicts.
It has the old diagnostic features, like the y.output file so you can pore over the LALR(1) state graph, and a debug mode.
It supports something called "push parsing": inverting the control flow, so that the parser becomes a state machine to which you can feed tokens one at a time. That makes it possible to do things like, oh, multiplex multiple parse jobs in parallel into a single event loop.
What bug database are you using: I don't know of any ISO-standard bug database.
Git is not an ISO-standard; do you pass around pax archives for version control? Not using SSH, I hope; that's not ISO standard.
Not even XWindow is an ISO standard, so nothing but ANSI terminals for you.
I guess all those logos on ISO C++ meetings would state similar assertions.
Some of them might be playing with Rust, but when it comes down to shipping SDKs, it is all about C++.
But generally the time to analyze a constexpr initializer expression, even of even a pretty substantial grammar, will generally be pretty negligible, particularly given that it need not appear in a header file.
I use this in TXR Lisp. There are situations in which a Lisp macro may be expanded in the context of the parser. The macro can use the parser (e.g. call (read "(1 2 3)"). This works.
It also does not require to link anything, just -I/path/to/boost no matter the platform and tada, you get a fairly performant parser.
Multiple grammars are fine, you just instruct Flex and Bison to use static or add prefixes. No worries about ODR or LTO.
If your build system can't handle generated code, that's an indictment of your build system. I know that's a bit harsh, but there are plenty of build systems which can handle generated code and cross-compile just fine. Flex and Bison work fine on Windows.
Also http://gnuwin32.sourceforge.net/packages/bison.htm is not what "work fine on Windows" mean (hell, it does not even have the prefix thing you mentioned in the other comment). If there's anything ressembling a ./configure / some step that requires bash in its build pipeline then it's a complete no-go and given the GNU history of bison I doubt it'd use CMake.
Though even if all of this was solved, it'd still not be as convenient as Spirit.
I've done this enough times that using Bison on Windows was no problem at all. In my case, I wasn't really interested in Bison itself, but I was using a different third-party dependency which itself depended on Bison.
> or run on windows
If you're using Flex and Bison, you should arrange your project so that it can build without running the tools. Only someone who needs to make changes to the grammar files should require the tools to be installed at all.
That's your first line of defense.
If you want people to be able to develop the grammar files on Windows, you can do it. There are ports of these things to Windows. Cygwin, MinGW-W32 and others.
They're abysmal to use, have poor interfaces and poor error handling facilities.
> antlr
At least when I tried it years ago, it was an unapproachable mess of java tooling and editors.
> parsec
Is a parser combinator. This is different than a generator.
> ragel
Not heard about this.