Live data from Hacker News

Parsing: The Solved Problem That Isn't (2011)

tratt.net

61–70 of 71 posts

Re: Parsing: The Solved Problem That Isn't (2011)

#61
post #9

Jeffrey Kegler's work on Marpa is pretty exciting, but hasn't got much traction (maybe due to the implementation languages: Perl and Knuth's Literate Programming). https://metacpan.org/pod/Marpa::R2#A-simple-calculator

Seems to be written in C:

"Marpa is available as a open-source library. It is written in C, and the C library can be used directly or via a Perl interface."

http://jeffreykegler.github.io/Ocean-of-Awareness-blog/indiv...

Re: Parsing: The Solved Problem That Isn't (2011)

#62
post #37

The XL programming language ( http://xlr.sf.net ) has a rather unique approach to parsing. There is a short article about it here: http://grenouille-bouillie.blogspot.fr/2010/06/xl-axioms-rec... . XL features 8 simple node types, 4 leafs (integer, real, text, name/symbol) and 4 inner nodes (infix, prefix, postfix and block). With that, you can use a rather standard looking syntax, yet have an inner parse tree structu…

Judging from the article, if you parsed "if 3", you'd get back out (prefix if 3) instead of an error, since `if` is just a regular prefix operator. So, presumably there's some sort of well-formedness checking that goes on after parsing? Does anyone know more? The website says very little.

True, 'if 3' will stay there if there is no rewrite for it. You can also use treat a lack of possible rewrite as an error, this is what the Tao 3D document description language does. You'd get an error like "No form matches 'if 3'".

Underneath, there is a rewrite operator, ->, that means to transform the shape on the left into the shape on the right.

The precise semantics are a tiny bit more complicated than that, but it iterates until there is no more transformation that applies. Some specific rewrites will be transformed into "opcodes" of the underlying machine model. So A+B with integers on each side will execute an addition (the inner representation of the transform is something like A+B -> opcode Add).

For more details, you can read http://xlr.sourceforge.net/sites/default/files/XLRef.pdf. I badly need to update it, it's out of date, I have a more recent version, but I need to learn the new way to connect to SourceForge.

Re: Parsing: The Solved Problem That Isn't (2011)

#63

Earlier quoted context omitted.

Yeah that puzzles me a bit too. Multifix operators are not more complicated than prefix/postfix/infix (well, only marginally). For instance, you can give each operator a left priority and a right priority and merge them when they meet with the same priority. Then `if x then y else z` would become (if/then/else x y z) or something like that. I think that's saner and easier to handle than what he does.

Yeah, that's what I was expecting too. And then XL could claim to have only five node types: integer, real, text, name, and multifix :-)

In XL, a multifix is a combination of infix, prefix or postfix. Note that the various nodes exist only for the programmer's convenience, i.e. they represent a user-visible syntax. Internally, I could do with only a node with two children.

Something like [A,B,C,D] writes as:

Block with [] containing Infix , containing Symbol A Infix , containing Symbol B Infix , containing Symbol C Symbol D

So this allows me to represent multifix along with their expected syntax. I could also represent for example:

[A, B; C, D]

if A then B else C unless D

for A in B..C loop D

The last one is actually one of the for loop forms in XL

Re: Parsing: The Solved Problem That Isn't (2011)

#64
post #63

Earlier quoted context omitted.

Yeah, that's what I was expecting too. And then XL could claim to have only five node types: integer, real, text, name, and multifix :-)

In XL, a multifix is a combination of infix, prefix or postfix. Note that the various nodes exist only for the programmer's convenience, i.e. they represent a user-visible syntax. Internally, I could do with only a node with two children. Something like [A,B,C,D] writes as: Block with [] containing Infix , containing Symbol A Infix , containing Symbol B Infix , containing Symbol C Symbol D So this allows me to repres…

Multifix is more general than a combination of infix, prefix and postfix, though. For instance, a [] block is a multifix operator, but you can't implement it as a combination.

The advantage of supporting multifix directly is that you get a more convenient and less confusing representation. For instance, given "if A then B else C" why should I expect (else (then (if A) B) C) and not (if (then A (else B C))? It's not obvious, and both are unwieldy compared to a ternary operator like (if/then/else A B C).

Re: Parsing: The Solved Problem That Isn't (2011)

#65
post #38

It is nice to see someone summarizing this kind of information. However, really this is a continuation of the academic attitude toward parsers making them MUCH harder than they have to be. If you want to study grammars in an abstract sense, then think of them this way, and that's fine. If you want to build a parser for a programming language, don't use any of this stuff. Just write code to parse the language in a str…

Which tools in particular do you feel are acceptable? "Just writing the code to parse the language" is almost definitional of shotgun parsers, so it sounds like you are advocating an ad-hoc parser (probably something recursive descent-ish, or perhaps with even less structure than that), but I wouldn't want to put words in your mouth.

ADDENDUM: In particular, the article mentions PEGs. Not in an unambiguously positive light, but nonetheless: do you count PEGs as being a useless overly academic tool?

The LANGSEC project has done (in my opinion) a pretty good job arguing that this behavior causes many security issues in software. Perhaps only to some extent for programming languages in general, but in particular for data format languages and network protocols. The issue is slightly mitigated for programming languages because they typically don't have many wildly varying parsers; but (programming) languages without clearly specified grammars certainly have had problems with this in the past.

Are you familiar with their work? Do you just disagree with their conclusions?

[LANGSEC]: http://langsec.org

Re: Parsing: The Solved Problem That Isn't (2011)

#66
post #63

Earlier quoted context omitted.

In XL, a multifix is a combination of infix, prefix or postfix. Note that the various nodes exist only for the programmer's convenience, i.e. they represent a user-visible syntax. Internally, I could do with only a node with two children. Something like [A,B,C,D] writes as: Block with [] containing Infix , containing Symbol A Infix , containing Symbol B Infix , containing Symbol C Symbol D So this allows me to repres…

Multifix is more general than a combination of infix, prefix and postfix, though. For instance, a [] block is a multifix operator, but you can't implement it as a combination. The advantage of supporting multifix directly is that you get a more convenient and less confusing representation. For instance, given "if A then B else C" why should I expect (else (then (if A) B) C) and not (if (then A (else B C))? It's not o…

Multifix is not more general than combinations of the 8 node types in XL, only more powerful than a combination of some subset.

It's not simpler. XL started with a multifix representation, see http://mozart-dev.sourceforge.net/notes.html. Switching to the current representation was a MAJOR simplification.

The current representation captures the way humans parse the code. Infix captures "A+B" or "A and B". Prefix captures "+3" or "sin x". Postfix captures "3!" or "3km". Block captures "[A]", "(A)", "{A}" or indentation. Since humans perceive a difference, you need to record that difference somewhere. XL records that structure in the parse tree itself, not on side data structures such as grammar tables.

This approach also enables multiple tree shapes that overlap. Consider the following XL program (I replaced asterisks with slashes because the asterisk means "italics" for HN):

A/B+C -> multiply_and_add A, B, C

A+B/C -> multiply_and_add B, C, A

A+B -> add A, B

A*B -> mul A, B

In that case, I can match a multifix operator like multiply_and_add without needing a representation that would exclude matching A+B or A/B in other scenarios. This is especially important if you have type constraints on the arguments, e.g.:

A:matrix/B:matrix+C:matrix -> ...

A:matrix/B:real+C:real -> ...

Those would be checked against X/Y+Z in the code, but if X, Y and Z are real numbers, they would not match.

If you want to try it by yourself, you can download Tao from http://www.taodyne.com/shop/dev/en/content/10-compare-versio.... Tao uses XL as the basis of its dynamic document description. There's a tutorial here: http://www.taodyne.com/presentation/tutorial-2.0.html. Please note that the XL implementation used in Tao has several limitations, notably with local functions and closures.

Re: Parsing: The Solved Problem That Isn't (2011)

#67
post #21

Earlier quoted context omitted.

Parsing Techniques by Dick Grune is THE bible for parsing.

It is a nice reference but you won't learn anything from that if you're a beginner. It's super heavy on theory and very light on implementation.

I think you get it backwards.

I learned a lot and PTAPG introduction specifically says that it avoids heavy theory. It has all algorithms required in very understandable presentation. It also says what this or that algorithm does to exploit that or this feature from grammar structure.

Re: Parsing: The Solved Problem That Isn't (2011)

#68
post #12

Earlier quoted context omitted.

Both are based in Bryan Ford's packrat (PEG is Ford's too). OMeta is more like PEGTL in that it's a set of facilities/library at a highish level, more than a particular grammar system (they're all packrat parsers). http://bford.info/packrat/ It's all about descent parsing and memoisation (thus the name).

pegtl is not actually a packrat parser. Not all PEGs and absolutely not all recursive descent parsers are packrats. And actually, my experience with packrat parsers (mostly in ruby) in other languages has been that they actually slow things down on moderately or more complex grammars by massively exploding memory use and thus allocation pressures. Turning it off can make it faster , especially on complex grammars. It…

I've been working on a new PEG parsing algorithm, and though my first crack at it was way too slow and I still haven't finished debugging the second version, I was able to show that packrat parsing had about a 40% runtime hit over recursive descent for well-behaved inputs on some common grammars (and linear memory usage vs. constant).

Re: Parsing: The Solved Problem That Isn't (2011)

#69
post #44

Earlier quoted context omitted.

One issue with PEG's (and other parsers) is that it doesn't address (unbounded) count fields (or bounded count fields in an elegant manner) or offsets. This means a pure PEG can't express e.g. PDF or ZIP files. To address this, we built a PEG-based parser generator with a few new features, Nail (paper at OSDI 14, github.com/jbangert/nail)

Another issue is that it uses at least the same memory as the the input. Not that I'm a PEG expert, but it also basically feels like a formalised recursive decent parser. Nothing wrong with that, but changing the grammar afterwards can have a rippling effect and require much more work than with a traditional LALR parser.

I've been working on a derivative parsing algorithm for PEGs; it only uses memory proportional to the amount of backtracking and grammar nesting (i.e. about the same as recursive descent), but still gives a polynomial worst-case bound on time. An early draft of my paper on it is at [1]; this turned out to be about 6x slower than packrat when I actually built and tested it, but I've come up with a substantial simplification to the algorithm that I'm quite optimistic will have better performance results once I finish debugging my code.

[1] http://arxiv.org/abs/1405.4841

Re: Parsing: The Solved Problem That Isn't (2011)

#70
post #66

Earlier quoted context omitted.

Multifix is more general than a combination of infix, prefix and postfix, though. For instance, a [] block is a multifix operator, but you can't implement it as a combination. The advantage of supporting multifix directly is that you get a more convenient and less confusing representation. For instance, given "if A then B else C" why should I expect (else (then (if A) B) C) and not (if (then A (else B C))? It's not o…

Multifix is not more general than combinations of the 8 node types in XL, only more powerful than a combination of some subset. It's not simpler. XL started with a multifix representation, see http://mozart-dev.sourceforge.net/notes.html . Switching to the current representation was a MAJOR simplification. The current representation captures the way humans parse the code. Infix captures "A+B" or "A and B". Prefix cap…

I have gone the other way with the languages I designed, from the system you describe to multifix, and have had the opposite experience. A proper implementation of general operator precedence grammars is much simpler than implementing prefix, postfix, infix and blocks specifically.

Now, I'm not sure how you implemented multifix, but a good general implementation for it is not immediately obvious, so I suspect you simply used an algorithm that's more convoluted than necessary and made you overestimate the scheme's actual complexity. Implemented properly, though, it's ridiculously simple. To demonstrate, I have hacked together a JavaScript version here (sorry, I didn't get around to commenting the code yet):

http://jsfiddle.net/ed37wy5k/2/

The core of the parser is the oparse function, which clocks in at 32 lines of code. Along with a basic tokenizer, order function, evaluator and some fancy display code, the whole thing is barely over 200 LOC. I dug around for XL's source and from what I can tell, what you have is not simpler than this.

I also never suggested making multifix operators like multiply_and_add. Multifix is for operators which are inherently ternary, quaternary and so forth. For instance, when I see "a ? b : c" I don't parse it as prefix, postfix or binary infix, I parse it as ternary.

Post reply on HN