Live data from Hacker News

Ohm: Parsing Made Easy

nextjournal.com

51–60 of 100 posts

Re: Ohm: Parsing Made Easy

#51

In many parser generators (e.g. Yacc and ANTLR), a grammar author can specify the language semantics by including semantic actions inside the grammar. A semantic action is a snippet of code — typically written in a different language —that produces a desired value or effect each time a particular rule is matched. Actually, the need for that went away with ANTLR4. The grammar is now all grammar (and lexer) and the sem…

It did not exactly went away.

It is still possible to embed semantics inside an Antlr4 grammar.

For example see the Antlr4 EcmaScript grammar sample: https://github.com/antlr/grammars-v4/tree/master/ecmascript which uses embedded code to solve the RegExp vs division operator ambiguity.

Another scenario when embedding code could be preferred is optimizing for maximum performance as abstractions normally come at a performance overhead.

I do agree that the default approach should be to separate the semantics unless there is a very good reason why not to...

Re: Ohm: Parsing Made Easy

#52
post #6

Hi HN, I'm a researcher at HARC ( https://harc.ycr.org/ ) and one of the authors of Ohm. We've used it to power several of our programming language investigations, such as Seymour (which was on HN yesterday: https://news.ycombinator.com/item?id=15471954 ) and Chorus ( http://www.chorus-home.org/ ). If you're interested, here's the grammar for the language used in the Seymour demo: https://github.com/harc/seymour/blob…

Many PEG-based parser generators do not support left recursion — requiring grammar authors to use repetition or right recursion instead. But left recursion is the most straightforward way to express left associative operators, which is why left recursion is supported by Ohm.

Does Ohm have any limitation with regard to left recursion? The last time I checked there was a paper by Warth et al. [1] extending PEG Packrat Parsers to handle left recursion but later a paper by Tratt [2] pointed out a flaw in that algorithm and only managed to fix the problem for a limited subset of grammars.

[1] http://www.vpri.org/pdf/tr2007002_packrat.pdf

[2] http://tratt.net/laurie/research/pubs/papers/tratt__direct_l...

Re: Ohm: Parsing Made Easy

#53

Earlier quoted context omitted.

> They try to sell this as a "solution" to ambiguous grammars But it is a solution... the grammar is no longer ambiguous if you define choice as giving priority to one side or the other. There's no need for scare quotes! It is a solution that removes ambiguity. There is no longer any ambiguity, and there's nothing 'vague' at all about a rule as simple and clear as this. > but they're just ... wrong You'll have to giv…

> But it is a solution... the grammar is no longer ambiguous if you define choice as giving priority to one side or the other. Sure it's no longer ambiguous to the computer. But the important question is: is it ambiguous to a human? Take the "dangling else" problem. What does this mean in C? if (a) if (b) f(); else g(); If you defined your grammar with a PEG, the answer is: whichever alternative you put first (if-wit…

Ambiguity of a grammar is rather unrelated to how surprising it can be to a human. Something like TypeScript:

    var a = { label: f() };
    () => { label : f() };
These constructs look similar, but one is an object literal and the other is a block with a useless label. All of this can be implemented as an unambiguous context-free grammar.

Relying on grammar ambiguity detection to find constructs surprising to humans is not very effective, if only because of the difference between how a human understands the grammar (pattern-based) and how EBNF expresses it (prefix-based).

Re: Ohm: Parsing Made Easy

#54
post #51

In many parser generators (e.g. Yacc and ANTLR), a grammar author can specify the language semantics by including semantic actions inside the grammar. A semantic action is a snippet of code — typically written in a different language —that produces a desired value or effect each time a particular rule is matched. Actually, the need for that went away with ANTLR4. The grammar is now all grammar (and lexer) and the sem…

It did not exactly went away. It is still possible to embed semantics inside an Antlr4 grammar. For example see the Antlr4 EcmaScript grammar sample: https://github.com/antlr/grammars-v4/tree/master/ecmascript which uses embedded code to solve the RegExp vs division operator ambiguity. Another scenario when embedding code could be preferred is optimizing for maximum performance as abstractions normally come at a perf…

I stand corrected. I rewrote my grammar with ANTLR4 and gutted all the embedded semantics. That was a good day.

I'm going to hit reply now and then I'm going to take out my personal neuralyzer and forget that I ever found out that you can still embed.

Re: Ohm: Parsing Made Easy

#55

Earlier quoted context omitted.

Dangling else is solved by changing the definition of the language. Newer languages don't have the dangling else problem, because we learned the hard way in the 60s how to avoid it. PEG-based tools invite more mistakes like this, because they can prevent the discovering of ambiguities until it is too late to fix them. Yes, operator precedence is another example of ambiguity: we live with it because infix math is usef…

> prevent the discovering of ambiguities But there are no ambiguities to discover if you use a PEG! A language grammar defined using PEG cannot be ambiguous!

It's very strange that you keep returning to this. "Dangling else" is a problem regardless of how you write down your grammar or implement your parser.

It's like sweeping a mound of dirt under the rug and then saying "by definition, there is no dirt on the rug!"

Re: Ohm: Parsing Made Easy

#56
Sorry to be negative and this comment probably doesn't belong in a discussion about a specific parsing toolkit but I've become unconvinced that parser generators are useful. My experience is limited to Yacc/lex back in the old days (quickly jumped to Bison/flex), more recently Antlr and a couple of functional parser combinator libraries. In nearly all case it was to deal with "real world" (i.e. not toy) programming languages.

The last time I needed a parser (in Java), I started studying the Antlr docs (it's changed quite a bit since I used it last) but became disillusioned quickly with the amount of reading and studying I would have to do to get something working.

So I quickly wrote a "hand crafted" tokenizer and recursive descent parser. I found this so satisfying that it made me wonder why I had bothered learning relatively complex tools in the past particularly since I had been exposed to recursive descent parsing as an undergrad.

Advantages that pop into my head:

- The code was clean, readable and very concise. For debugging, the stacktraces were helpful and I could use my regular debugger/IDE to step through the parsing process. The method names in my Parser class mostly matched the names of corresponding grammar rules.

- You can code around the theoretical limitations of recursive descent parsing in a very intuitive manner (e.g. "if (tokens.peekAhead(1).getType() == Token.LEFT_BRACE) { parseX(); } else { parseY(); }"). In theory it might seem this would lead to a mess but it actually allows very flexible and natural abstractions.

- You have complete control over the building of the AST - the parseX(...) methods can take arguments or the calling parse method can manipulate the returned AST - doing stuff like flattening (normalising) node trees or re-ordering child nodes, etc. The shape of the AST can be independent of the structure of the grammar rules.

- It's easy to provide helpful error messages and even error recovery without fighting with the toolkit. Better still, you can start with a fairly lazy generic error handler and later, in a natural style, add special cases to make the messages more and more helpful for specific common user mistakes. I sneakily logged all parse failures by users to constantly improve error reporting. After a while the parser seemed almost like an AI when reporting errors.

- For parsing expressions, there is a relatively well-known way to deal with operators with different arities and associativity rules (by adding a numeric "context binding strength" parameter to your parseExpr() method) - a quick google provided the template.

- The entire parser was self contained in a small number of reasonably compact classes: a Lexer/Tokenizer class, a Parser class and a SymbolTable class (and of course a TokenType enum and an ASTNode class). Other developers could grok the code because it was compact and self contained without having to learn a parsing toolkit.

- You feel in control; i.e. you can add features to the language and the parser incrementally without fearing that sinking feeling you get when you think you're 99% of the way there only to realize that the tool you're using makes the last 1% impossible forcing you to rethink/rewrite already "banked" functionality.

- Zero dependencies and trivial to integrate into the build and test process.

edit: paragraphs

Re: Ohm: Parsing Made Easy

#57
post #52
post #6

Hi HN, I'm a researcher at HARC ( https://harc.ycr.org/ ) and one of the authors of Ohm. We've used it to power several of our programming language investigations, such as Seymour (which was on HN yesterday: https://news.ycombinator.com/item?id=15471954 ) and Chorus ( http://www.chorus-home.org/ ). If you're interested, here's the grammar for the language used in the Seymour demo: https://github.com/harc/seymour/blob…

Many PEG-based parser generators do not support left recursion — requiring grammar authors to use repetition or right recursion instead. But left recursion is the most straightforward way to express left associative operators, which is why left recursion is supported by Ohm. Does Ohm have any limitation with regard to left recursion? The last time I checked there was a paper by Warth et al. [1] extending PEG Packrat…

Ohm implements the same algorithm described in [1] -- Alex Warth (the author of that paper) created Ohm.

We're understand the complaint in [2], but we strongly disagree with Laurie's claim that these are "incorrect" parses. He proposes a different way of handling left recursion, which is just that -- different.

You can find a more thorough discussion here: https://github.com/harc/ohm/issues/55

Re: Ohm: Parsing Made Easy

#58

Earlier quoted context omitted.

> But it is a solution... the grammar is no longer ambiguous if you define choice as giving priority to one side or the other. Sure it's no longer ambiguous to the computer. But the important question is: is it ambiguous to a human? Take the "dangling else" problem. What does this mean in C? if (a) if (b) f(); else g(); If you defined your grammar with a PEG, the answer is: whichever alternative you put first (if-wit…

Ambiguity of a grammar is rather unrelated to how surprising it can be to a human. Something like TypeScript: var a = { label: f() }; () => { label : f() }; These constructs look similar, but one is an object literal and the other is a block with a useless label. All of this can be implemented as an unambiguous context-free grammar. Relying on grammar ambiguity detection to find constructs surprising to humans is not…

This is a red herring. Context-free grammar tools don't solve the problem of keeping a language from ever being confusing. However they do solve the problem of allowing literal ambiguity into your language.

Ambiguity is strictly worse than confusion. Ambiguity means you have to communicate more information to your users: when two parses are both syntactically valid, which one does the language actually choose?

Re: Ohm: Parsing Made Easy

#59
Hey, I’m one of the founders of Nextjournal, the coding, writing and publishing platform this article was written in.

This probably isn’t obvious: you can get a copy of the article and play with it if you click remix and sign in/up.

There’s some more context about what we’re trying to build and why in our launch post https://medium.com/nextjournal/launch-nextjournal-public-bet...

Re: Ohm: Parsing Made Easy

#60

Earlier quoted context omitted.

> prevent the discovering of ambiguities But there are no ambiguities to discover if you use a PEG! A language grammar defined using PEG cannot be ambiguous!

It's very strange that you keep returning to this. "Dangling else" is a problem regardless of how you write down your grammar or implement your parser. It's like sweeping a mound of dirt under the rug and then saying "by definition, there is no dirt on the rug!"

I guess I just can't understand where you are coming from then.

Someone said that PEGs don't solve ambiguous grammars. I said that's wrong - they do - they are no longer ambiguous. Now people are arguing about having to understand the grammar and how languages should be designed and things like that? Seems irrelevant to me.

I thought there was one precise technical question - do PEGs make solve the problem of ambiguous grammars. Yes they do - they are no longer ambiguous. If you define your language using a PEG you will never have any ambiguity in your grammar. Seems solved to me!

Post reply on HN