3 ms·
Well, the practical answer that all languages I know of have separate lexical and grammatical structure. It's just easier to write if you separate them. Thoug
by chubot 10y ago
Well, the practical answer that all languages I know of have separate lexical and grammatical structure. It's just easier to write if you separate them. Though it's baroque, even bash has clear lexical structure.
In my code, the lexer is the foundation and doing a lot of useful work. It's a map from the 13 modes to a list of regexes, which is a lot of logic that is kept out of the parser.
https://github.com/oilshell/oil/blob/master/osh/lex.py https://github.com/oilshell/oil/blob/master/osh/lex.py
The parser just calls lexer.Read(lex_mode), which hides the complexity of all these regexes.
(The lexer might look weird, but I wrote it in a style to port to C, and in particular using re2c. This is an awesome tool which I've mentioned in my blog a couple times, but not written about yet. It combines regular expressions and turns them into a bunch of gotos in C.
http://www.oilshell.org/cross-ref.html?tag=re2c#re2c http://www.oilshell.org/cross-ref.html?tag=re2c#re2c
)
-----------
For a more theoretical answer: I've had this discussion before, and I would claim that lexing and parsing should be separate because they differ in both computational power and running time.
Lexing is fast but not that powerful -- you are structuring the input stream with (at most) regular expressions. It can be done in linear time, without backtracking. On the other hand, parsing is slow but more powerful, e.g. CFGs or PEGs can recognize more than regular expressions, but they require backtracking/memoization/lookahead/etc.
In other words, why not do the easy work with the fast algorithm, and then do the harder work with the more complicated, expensive algorithm -- on a shorter input?
I came to the conclusion several years ago that PEGs only combined lexing and parsing for reasons of academic presentation and proof. I don't think it actually helps you in practice.
Hope that answered the question! I think my shell lexer is somewhat interesting so I plan to blog about it. Honestly re2c was almost the thing that inspired me to write the shell -- it would have been intractable otherwise.
- aidenn0 10y agoThanks for that. Indeed it makes sense. I would enjoy reading blog posts about your lexer. What through me is that the BNF presented in the POSIX standard treats words as individual tokens and that's obviously not something you want to do only in a lexer.
- chubot 10y agoYes, so bash is unique in that there is a two level structure. Tokens turn are parsed into words. And then words are used as "tokens" for the "command sublanguage", the grammar for which is given in POSIX. I mention that in a few places -- there are 4 sublanguages, arith/bool/word/command, but POSIX only covers the command sublanguage. http://www.oilshell.org/blog/2016/10/26.html http://www.oilshell.org/blog/2016/10/26.html This is one of the reasons parser generators as "frameworks" don't work for shell. I have a diagram in mind for the parser architecture which I think will be illuminating. The command language uses the words as "tokens", but they're also mutually recursive, because an entire subprogram can fit inside a word/string, like "prefix $(my-func() { echo hi; }; my-func) suffix" That is defining a function and calling it inside a string.