Comment by almostgotcaught

Comment by almostgotcaught 2 days ago

13 replies

> you are just consuming tokens from a stream.

My guy... Do you think that parsers just like... concat tokens into tuples or something....??? Do you not understand that after lexing you have tokens (which are a "type") and AST node construction (an "operation") and that the grammar of a language is naturally a graph.... Like where else would you get the "recursion" from....

If that doesn't make sense I invite you to read some literature:

> makeAST():

> asks the tokenizer for the next token t, and then asks t to call the appropriate factory method the int token and the id token call makeLeaf(), the left parenthesis token calls makeBinOp() all other tokens should flag an error! does the above "smell" like the visitor pattern to you or not? Who are the hosts and who are the visitors?

https://www.clear.rice.edu/comp212/02-fall/labs/11/

markus_zhang 2 days ago

OK I might be wrong about the visitor pattern, but what I really did not like is to use the accept() and visitBlah() way to execute AST nodes: https://craftinginterpreters.com/representing-code.html#the-...

I did continue reading the book (not the original author of that reply) but I do think it is distracting for newbies. I had to come back to this page over and over again to recollect memory about the pattern, because I usually read it one chapter or a few sections every week, so every time I had to remind myself how this visitBlah() and accept() pair works. I really think a big switch() (or anything that works but is simpler) would be a lot easier to understand.

The other reason I dislike this kind of stuffs is that I have someone in the team who really likes to use patterns for every piece of code. It's kinda difficult to tell whether it is over-engineering or not, but my principle is that intuition always beats less lines of code (or DRY), unless it is absurdly more lines of code or repetition. And to test that principle you just grab a newbie and see which one makes more sense to him.

  • jpc0 a day ago

    > so every time I had to remind myself how this visitBlah() and accept() pair works. I really think a big switch()…

    This is just and alternative implementation of the visitor pattern. Whether you implement it using dynamic dispatch or a switch or an if stack its all the same pattern…

  • mrkeen 2 days ago

    Nope, you had it right.

    Visitor thoroughly confuses me in the context of parsing (maybe in all contexts.)

    visit and accept are not the verbs I want to be seeing in the code. I want to see then, or, and try.

    • almostgotcaught 2 days ago

      Parsers "accept" or "reject" programs. It's completely standard language.

      • mrkeen a day ago

        Alright, so where can I read more about the visitor pattern's "reject" method?

  • almostgotcaught 2 days ago

    > I really think a big switch() (or anything that works but is simpler) would be a lot easier to understand.

    It's much easier conceptually to implement this using recursion instead of a while loop and a token stack (it's basically DFS). So I disagree with you there.

    > The other reason I dislike this kind of stuffs is that I have someone in the team who really likes to use patterns for every piece of code. It's kinda difficult to tell whether it is over-engineering or not, but my principle is that intuition always beats less lines of code (or DRY), unless it is absurdly more lines of code or repetition. And to test that principle you just grab a newbie and see which one makes more sense to him

    I'm with you - I really don't give a shit about patterns (which was my whole original point - who cares). But that last part I don't agree with - systems code (like a parser) doesn't need to be legible to a noob. Of course we're talking about a textbook so your probably right but like I said most production parsers and AST traversals are written exactly this same way. So anyone learning this stuff hoping to get a job doing it should just get used to it.

ossopite 2 days ago

I see that you've found an example of how recursive descent parsing actually can be implemented with the visitor pattern, which I've never come across before, and I didn't read it carefully enough to understand the motivation - but that doesn't mean they are the same thing - the recursive descent parsers I've seen before just inspect which tokens are seen and directly construct AST nodes

as an adendum, the reason I don't understand the motivation is that the visitor pattern in the way I described it is useful when you have many different operations to perform on your AST. If you have only one operation on tokens - parsing into an AST - I'm not sure why you need dynamic dispatch on a second thing, the first thing being the token type. Maybe the construction is that different operations correspond to different 'grammar rules'?

  • almostgotcaught 2 days ago

    > why you need dynamic dispatch on a second thing

    You're overindexing on maximally generic visitor pattern. If you have one type of visitor but nonetheless dispatch based on type that's still visitor pattern.

    EDIT: to be honest who even cares. My initial point was why in the hell would you stop reading a book because a particular "pattern" offends you. And I'll reassert it here: who cares whether a recursive descent parser fits the exact definition of visitor pattern or not - you have members of a class that do stuff (construct AST nodes) and possibly track other data and then call other members. I usually call that a visitor class even if it's the only one that ever exists <shrug>

    • ossopite 2 days ago

      Ok, that's true, but my claim is that recursive descent parsing does not have to use the visitor pattern and indeed using recursive descent parsing is not the same as using the visitor pattern (you can do the former without the latter and I claim that you usually do)

  • almostgotcaught 2 days ago

    > just inspect which tokens are seen and directly construct AST nodes

    I'll repeat myself: this is not possible because you need to recursively construct the nodes (how else would you get a tree...).

    • ossopite 2 days ago

      I think I'm missing something here. if you have a grammar rule R with children A and B, and a function in your recursive descent parser that corresponds to R, why can R not call the parser functions for A and B, which return AST nodes themselves, and then construct another AST node using the result of those? Where was the visitor pattern required here?

      • mrkeen 2 days ago

        Me too. No-one's denying that recursion is happening. We're just not sure about it being synonymous with the Visitor Pattern.