Earlier quoted context omitted.
My favorite example, due to Douglas Hofstadter: Politicians lie. Cast iron sinks. Politicians lie in cast iron sinks. It's not actually ambiguous, but I think it's a lovely illustration of the subtleties of the problem. An actually ambiguous example: I saw a politician lying in a cast iron sink.
Ambiguous parses aren't even the worst of it -- the worst are the ones that require real world knowledge. "I couldn't fit the trophy in my suitcase because it was too big." "I couldn't fit the trophy in my suitcase because it was too small."
Parsing: The Solved Problem That Isn't (2011)
81–90 of 90 posts
Re: Parsing: The Solved Problem That Isn't (2011)
#82Parsing computer languages is an entirely self-inflicted problem. You can easily design a language so it doesn't require any parsing techniques that were not known and practical in 1965, and it will greatly benefit the readability also.
> and it will greatly benefit the readability also This is the controversial part, Lisp aficionados to the contrary.
You can parse quite a lot more than Lisp with techniques from 1965.
Re: Parsing: The Solved Problem That Isn't (2011)
#83Earlier quoted context omitted.
> and it will greatly benefit the readability also This is the controversial part, Lisp aficionados to the contrary.
People are misunderstanding my original comment. You can parse quite a lot more than Lisp with techniques from 1965.
Like using a hyperlink to code example.
Re: Parsing: The Solved Problem That Isn't (2011)
#84Earlier quoted context omitted.
In my experience incremental parsing doesn't really make much sense. Non-incremental parsing can easily parse huge documents in milliseconds. Also Tree Sitter only does half the parsing job - you get a tree on nodes, but you have to do your own parse of that tree to get useful structures out. I prefer Chumsky or Nom which go all the way.
What do you mean by “parse of that tree to get useful structures out”? Can you provide some concrete examples?
let a = 12;
let b = a + 5;
...
Tree-Sitter will give you a tree like Node(type="file", range=..., children=[
Node(name="let_item", range=... children=[
Node(name="identifier", range=...)
Node(name="expression", range=..., children=[
Node(name="integer_literal", range=...)
...
Whereas Nom/Chumsky will give you: struct File {
let_items: Vec,
..
};
struct LetItem {
name: String,
expression: Expression,
};
...
Essentially Tree-Sitter's output is untyped, and ad-hoc, whereas Nom/Chumksy's is fully validated and statically typed.In some cases Tree-Sitter's output is totally fine (e.g. for syntax highlighting, or rough code intelligence). But if you're going to want to do stuff with the data like actually process/compile it, or provide 100% accurate code intelligence then I think Nom/Chumksy make more sense.
The downsides of Nom/Chunksy are: pretty advanced Rust with lots of generics (error messages can be quite something!), and keeping track of source code spans (where did the `LetItem` come from) can be a bit of a pain, whereas Tree-Sitter does that automatically.
Re: Parsing: The Solved Problem That Isn't (2011)
#85Earlier quoted context omitted.
Only if you want to refer to it literally as a closing quote rather than having it act as a closing quote. That case is extremely rare.
Its definitely rarer than double or single quotes occurring in string. But I was wondering about the parent comment's concern of passing a string through multiple levels of escaping. > until you need to get your string through several levels of escape. how many backslashes to add? depends on how deep your pipe is and how each of those layers is defined
When the same character is used as both an open and close delimiter, you have to disambiguate between three possibilities: opening a new string, closing the current string (which may or may not be embedded) and a literal character as a constituent of the current string. By convention, an unescaped double-quote inside a string indicates closing that string, so you need different escapes to indicate opening embedded strings and constituents.
You could have done that by using two different escape characters, but for historical reasons there is only one escape character: the backslash. So that one character has to do double-duty to disambiguate two different cases. But in fact it's even worse than that because string parsers have a very shallow understanding of backslashes. To a string parser, a backslash followed by another character means only that the following character should be treated as a constituent. So you still need to disambiguate between actual constituents and opening an embedded string, and the only way to do that, because all you have is the backslash, is with more backslashes. The whole mess is just a stupid historical accident.
If you used balanced quotes you only have one case that needs to be escaped: constituents. So you never need multiple escapes.
Note that I made a mistake when I wrote:
> Only if you want to refer to [a close-quote character] literally as a closing quote rather than having it act as a closing quote.
You have to escape both open and close quotes to refer to them as constituents. In other words you would need to write something like this:
«Here is an example of a «nested string». The start of a nested string is denoted by a \« character. The end of a nested string is denoted by a \» character.»
Note that it doesn't matter how many levels deep you are:
«Even when you write «a nested string that refers to \« or \» characters» you only need one level of escape.»
Note that when you refer to quote characters as balanced pairs as in the examples above you don't actually need the escapes. The above strings will parse just fine even without the backslashes, and they will print out exactly as you expect. The only "problem" will be that they will contain embedded strings that you probably did not intend. The only time escapes are actually required is when referring to an quote characters as constituents without balancing them. This will always be the case if you refer to a close-quote without a corresponding preceding open-quote, which is the reason I got it wrong: escaping close-quotes will be more common than escaping open-quotes, but both will be needed occasionally.
Re: Parsing: The Solved Problem That Isn't (2011)
#86Earlier quoted context omitted.
What do you mean by “parse of that tree to get useful structures out”? Can you provide some concrete examples?
Yeah suppose you write a simple config language like: let a = 12; let b = a + 5; ... Tree-Sitter will give you a tree like Node(type="file", range=..., children=[ Node(name="let_item", range=... children=[ Node(name="identifier", range=...) Node(name="expression", range=..., children=[ Node(name="integer_literal", range=...) ... Whereas Nom/Chumsky will give you: struct File { let_items: Vec , .. }; struct LetItem {…
Tree-sitter's output is closer to being "dynamic" than "untyped", though.
It's not too hard to build a layer on top of tree-sitter (out of the core lib) to generate statically typed APIs. I haven't felt the need for that yet, but it may be worth exploring.
> actually process/compile it
At work, I built a custom embedded DSL, using tree-sitter for parsing. It has worked well enough so far. The dynamically-typed nature of tree-sitter actually made it easier to port the DSL to multiple runtimes.
> provide 100% accurate code intelligence
Totally agree that tree-sitter cannot be used for this, if we are aiming for 100%.
Re: Parsing: The Solved Problem That Isn't (2011)
#87Earlier quoted context omitted.
People are misunderstanding my original comment. You can parse quite a lot more than Lisp with techniques from 1965.
People would misunderstand you less if you made yourself better understood. Like using a hyperlink to code example.
[0]: 1963 operator precedence description: https://dl.acm.org/doi/10.1145/321172.321179
Re: Parsing: The Solved Problem That Isn't (2011)
#88Earlier quoted context omitted.
Its definitely rarer than double or single quotes occurring in string. But I was wondering about the parent comment's concern of passing a string through multiple levels of escaping. > until you need to get your string through several levels of escape. how many backslashes to add? depends on how deep your pipe is and how each of those layers is defined
This is the beauty of balanced quotes: they completely eliminate the need for multiple escapes. When the same character is used as both an open and close delimiter, you have to disambiguate between three possibilities: opening a new string, closing the current string (which may or may not be embedded) and a literal character as a constituent of the current string. By convention, an unescaped double-quote inside a str…
I would also advocate the principle that you don't escape the escape character by doubling it. There are two problems with replacing \ with \\: firstly the length of the string doubles with each nested quotation; secondly you can't tell at a glance whether \\\\\\\\\\\\\\\\\\\n contains a newline character or an n because it depends on whether the number of backslashes is odd or even.
Another useful principle is to escape a quote character with a sequence that does not contain that character: then it is much easier to check whether the quotes are balanced because you don't need to check whether any of them are escaped.
So here's a possible algorithm for quoting a string: first identify the top-level quote characters that don't match (this is not totally trivial but it isn't difficult or computationally expensive); then, in parts of the string that are not inside nested quotes, but only there, replace « with \, and \ with \_ (say). Does that work?
Re: Parsing: The Solved Problem That Isn't (2011)
#89Earlier quoted context omitted.
This is the beauty of balanced quotes: they completely eliminate the need for multiple escapes. When the same character is used as both an open and close delimiter, you have to disambiguate between three possibilities: opening a new string, closing the current string (which may or may not be embedded) and a literal character as a constituent of the current string. By convention, an unescaped double-quote inside a str…
I totally agree with the idea that balanced quotes are needed to make quoting sane. If the quotes in a string are balanced then it should be possible to quote it with no changes. I would also advocate the principle that you don't escape the escape character by doubling it. There are two problems with replacing \ with \\: firstly the length of the string doubles with each nested quotation; secondly you can't tell at a…
That leaves only the problem of escaping the escape character, and here again there is no need to constrain ourselves to ascii. There is no reason that the escape character needs to be backslash. In fact, that is a particularly poor choice because backslash, being an ascii character, is extremely precious real estate. In fact, it is doubly precious because it actually has a balanced partner in the forward slash, so if you are going to use backslash for any special purpose it should be partnered with forward slash as a balanced set (which open up the problem of what to use for the directory delimiter in your operating system, but that's another can o' worms).
I think the Right Answer is simply to choose a different character to serve as the escape character inside balanced strings. My first pick would probably be ␛, but there are obviously a lot of other possibilities.
This points to a potential danger of this approach: there are a lot of unicode characters that render very similarly, like U and ᑌ. You would need to choose the unicode characters with special meanings very judiciously, and make sure that when you are writing code you have an editor that renders them in some distinctive way so you can be sure you're typing what you think you're typing. But that seems doable.
Re: Parsing: The Solved Problem That Isn't (2011)
#90Earlier quoted context omitted.
This is entirely the case. Given a sensible grammar stated in a sensible way, it's very easy to write a nice recursive decent parser. They are fast and easy to maintain. It doesn't limit the expressiveness of your grammar unduly. Both GCC and LLVM implement recursive decent parsers for their C compilers. Parser generators are an abomination inflicted upon us by academia, solving a non problem, and poorly.
Agree completely. Having used a bunch of parser generators (Antlr and bison most extensively) and written a parser combinator library, I came to the conclusion that they're a complete waste of time for practical applications. A hand-written recursive descent parser (with an embedded Pratt parser to handle expressions/operators) solves all the problems that parser generators struggle with. The big/tricky "issue" menti…
I think you cover that with "debuggability" remark.
Here is something else. Yacc/Bison parsing uses its own stack for the symbols. Whereas recursive descent uses the regular run-time stack.
Pop quiz: which stack is visible to your garbage collector, and which isn't?
In TXR Lisp, which uses a Bison/Byacc generated parser, GC is suspended while yyparse() executes. Otherwise it would prematurely collect anything that is only stored in the Yacc stack, and so there would have to be a GC hook to traverse that stack (which would depend on undocumented features of the generated code, and likely have to have some separate coding for Bison versus Byacc.)