You could have invented Parser Combinators
theorangeduck.com
theorangeduck.com
(I had exactly this experience, in fact[0][1]. My name was way worse, though: "Jars".)
0: http://twistedoakstudios.com/blog/Post4708_optimizing-a-pars...
1: https://github.com/Strilanc/Tinker/blob/master/Warcraft3/Pro...
While targeting Lua, the original is actually written in C. It compiles patterns to bytecode interpreted by a custom VM.
I was wary to write an interpreter in a language that's already interpreted and chose to compile patterns to Lua functions instead. It turns out that the most straightforward way to do that is by using closures higher level functions, in a way that I later learned was known as parser combinators...
————
In particular I exploit the structure of a parser combinator type as a monad transformer.
1: http://blog.sigfpe.com/2006/08/you-could-have-invented-monad... 2: http://blog.ezyang.com/2012/02/anatomy-of-you-could-have-inv...
I had the same problem in java.
Parser combinators are elegant but, at the end of the day, I find DSLs like PEGs, Ragels, and good old regex easier to read.
For example, nowadays gcc use recursive descent to parse C.
Also, not handling arbitrary CFG grammars well is extremely common, it is a feature that LL, LR, LALR, PEG and other all share. Is it obviously worse to have exponential time parsing something if compared to not parsing it at all? No, but if you need to handle ambiguity you probably should use a different algorithm.
One thing I've found that's nice about recursive descent parsers written by hand is that you provide useful and meaningful error messages. 'yacc' was always just saying "error" (and if you helped, the lexer might even supply a line number).
A message like "Expected a number for operator +" is way better than "syntax error line 109 around column 30".
That said, usually recursive descent gives better errors but in my experience it's mostly from better recovery.
Between those points, the parser was working on several alternate possible parsings, none of which could be completed. Give the names of those grammar constructs to the user. So an error message should look like:
struct point { float x, float y };
^^^^^^^^^ Expected one of:
<structure-variable-name>
;
}parse(Output)--> [Input], {member(Input, [ab, cd]), atom_codes(Input, Output)}.
test(In):- phrase(parse(L), [In]), writeln(L).
?- test(ab). [97,98] true .
?- test(cd). [99,100] true.
?- test(xy). false.
As a result I had to write a parser and interpreter. The thing about a lot of these computer science things is that you don't need them until you do. And then when you do it's nice to know about how they work.
It's used to parse arbitrarily complex transformations to apply to an image in the URL.
So imagine I wanted to write a "middleware" piece for that milling machine - maybe it has a slight defect where its width measure isn't exactly the same as its depth measure (I expect modern machines automatically recalibrate themselves, but you can imagine weirder problems that this might not solve). Then I could write a program that would rescale models exported from a CAD application to match the weirdness of my particular machine, by reading the file, making the adjustments, and writing a new file.
For a less industrial example that I've actually done, I worked on a fan translation of a videogame. The scripts were, of course, in a weird format that the original makers came up with, with no publicly available libraries. So I wrote a parser that could separate the actual text lines from the timing information and so forth, allowing the translators to translate.