6 ms·
The crafting interpreting asks the reader to use the visitor pattern, and this was quite a turn off for me, I stopped there.
by jokoon 1y ago
The crafting interpreting asks the reader to use the visitor pattern, and this was quite a turn off for me, I stopped there.
- quibono 1y agoCouldn't you write the interpreter without it?
- markus_zhang 1y agoThis part confused me quite a bit so I turned it into the more verbose format by copy-pasting. I don’t like the boilerplate code generation either so I converted that part too. The whole book is still pretty interesting though.
- almostgotcaught 1y agoLolol weirdest reason to reject that book - 90% of production parsers are recursive descent parsers.
- markus_zhang 1y agoIt probably has nothing to do with recursive descent parsing, which is intuitive, but with the visitor pattern as mentioned. I myself find it very distracting too.
- almostgotcaught 1y ago.... They're the same thing....
- ossopite 1y agoWhat? The visitor pattern is a technique for dynamic dispatch on two values (typically one represents 'which variant of data are we working with' and the other 'which operation are we performing'). You would not generally use that in recursive descent parsing, because when parsing you don't have an AST yet, so 'which variant of data' doesn't make sense, you are just consuming tokens from a stream.
- almostgotcaught 1y ago> 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/ https://www.clear.rice.edu/comp212/02-fall/labs/11/
- ossopite 1y agoI 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 1y 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...).
- 1y ago
- jokoon 1y agoI think the book claims to be accessible and easy The visitor pattern is not something I find simple and easy to approach
- UncleEntity 1y ago> The crafting interpreting asks the reader to use the visitor pattern... ...or just a big old, plain jane switch statement. In my current project I modified my ASDL generator to output a C instead of C++ AST and the visitor pattern carried over until realizing a switch statement is just as good (or better) in C so I ripped out that part of the template file. The choice was to write a dispatch function which called the various methods based on the AST node type or have a generated struct full of function pointers with a generated dispatch function which calls the various methods based on the AST node type. Same difference, really, just one has an added level of indirection. The amazing part is I didn't rewrite the ASDL generator for the fifth time and just decided it's 'good enough' for what I need it for. Aside from one small C++ism, which is easily worked around and turns out wasn't even needed in the C++ template, the thing is 100% language and 'access pattern' agnostic in generating the output code. There was probably a point I was trying to make when I started typing, dunno?
- grg0 1y agoMy takeaway from your verbose description is: - You don't need a visitor pattern if you have predetermined the data you are going to work with and all the operations on it (i.e., the open/closed principle does not apply.) - For the same reason, you don't need dynamic dispatch, which is often how the visitor (and other) pattern(s) are implemented. - The code is much simpler to understand (and debug) because it's all there in once place. It's also faster than the dynamic dispatch version because it's all known at compile-time. - Personally: OOP is stupid, confusing, and inefficient; I think universities should only teach it as an optional course. These patterns are 50% lack of functional programming features and 50% sheer stupidity. Universities should go back to teaching real abstraction with Scheme and SICP, a MIPS-style assembly language, and stop confusing students.
- markus_zhang 1y agoI think I did something similar for an emulator. Instead of using a big switch I simply used a big array of function pointers. So if it is a BLAH opcode, the execution code simply call fp_list[BLAH](op). But I guess it is a bit too much for CPUs that have tons of operations.
- alabhyajindal 1y agoYou can choose to implement it differently based on your implementation language. Data Classes and If statements work really well for this in Python, for example. Statement Data Classes: https://github.com/alabhyajindal/plox/blob/main/stmt.py https://github.com/alabhyajindal/plox/blob/main/stmt.py If statements in the parser matching against them: https://github.com/alabhyajindal/plox/blob/main/parser.py#L38 https://github.com/alabhyajindal/plox/blob/main/parser.py#L3...
- billforsternz 1y agoI recall back in the day when I was an embedded systems programmer at the coal face I had similar antipathy towards a pattern. I think it was called the State pattern or similar. It involved a class hierarchy and virtual functions, one for basically every state, event pair. I preferred my simple C design whic used a lookup table to quickly access a structure for each state, event pair instead. The structure would provide an output state, a message to send, an action to emit, a bitmask to select zero or more other standard operations, and yes a function to run in those rare cases where something really special was needed. All fields optional. The point is I didn't need to write N x M functions, I just needed to edit a table. And I didn't need to understand any rocket science.