Prolog has historically been used for setting up parsers for various languages and has an extensible expression parser where one congigure the operator handling. We continue in this tradition to produce elements to do backtracking enabled parsing for guile. With this, one can explore the new interesting constructs in guile-log to enable new features with respect to parsing.
Generally in guile-log a parser is a function that follows a certain call semantics. It is a guile log function e.g. it takes the standard arguments
S P CC. But ontop of this it takes
X XL N M e.g. current char on line (
X), current line in stream of lines (
XL), current line column (
N) and current line number (
M). Typically in code these elements are hidden in return values as calling signatures and hence the resulting code is less littered with standard ideoms and tons of variables. This design allows the programmer to easier spot errors and also produce fewer of them and we belive that it is a boon for productivity when writing parsers. Ontop of this semantics an extra output stream field in both imputt and output may be supplied e.g. the tool needed to produce a syntax tree. Code look typically like this, when using this tool to produce a parser function
(<p-lambda> (c) (.. (c) (ws c)) ;; Match whitespace (<let> ((n N) (m M)) ;; store M and N (.. (c) (exponent c)) ;; The actual number (.. (q) (ws c)) ;; Match whitespace (<p-cc> `(#:number ,(string->number c) ,n ,m)))) ;; Ret value
We see that we use
<p-lambda> in stead of
..’ is a special
<values> form that has the effect to rebind
X,XL,N,M to the new returned values. We also see the technique to bind e.g.
N,M to different values. this code would look like this if we did use pure guile-log.
(<lambda> (x xl n m c) (<values> (x xl nn mm c) (ws x xl n m c)) (<values> (x xl n m c) (exponent x xl nn mm c)) (<values> (x xl n m q) (ws x xl n m c)) (<cc> x xl n m `(#:number ,(string->number c) ,nn ,mm))))
Not nice on the eye’s right. Anyway a bonus point is that we have a framework to create stream like translaters like parsing this through a little macrology and hence it is a ’notime’ thingie to change the call idioms. This is the power of guile in action. Ontop of this we build parser combinators which is a functional kanren influenced way of combining parser functions. If we have parser functions
f,g we would like to combine them into new parser functions, there are typical ideoms suitable for all translators of sequences e.g. combinators that can be employed e.g.
(f-and f g) that successes if both does and outputs the last translation into the value stream. Se the combinators subsection to find out more.
The parsing lib is structured in subnodes according to,
|• stream ideom:||How to create arbritrary streams in generality|
|• parser combinators:||Constructing parser using higher order functions|
|• expressions:||Configurable Expression Parser|
|• parser tooling:||How to setup a parser generating tool.|
|• parser debugging:||How to trace the parser.|