For the umpteenth time I've rewritten my parser combinators.
With any luck, they finally have all the necessary bells and
whistles added to be useful for other stuff.
The code is in these 3 files. Trimmed of testing gibberish,
it's about 200 lines of code.
https://github.com/luser-dr00g/pcomb/blob/5efeca34f410e8855eff9d38ba21f80983b45afd/ps/pc11are.ps
https://github.com/luser-dr00g/pcomb/blob/5efeca34f410e8855eff9d38ba21f80983b45afd/ps/pc11a.ps
https://github.com/luser-dr00g/pcomb/blob/5efeca34f410e8855eff9d38ba21f80983b45afd/ps/struct2.ps
A parser is a function that takes an <input-stream> type and
yields a <result-structure> type. The <input-stream> is a lazy
list of [char [row col]] structures. The <result-structure> is a
two element array, the first element of which will be /OK /Fail or
/Error. For an /OK result, the second element will be
[result remainder]. For a /Fail or /Error result, the second element
will be [message remainder].
So here's the regular expression parser with this new setup.
And some simple testing code and output, which should be
comprehensible using the above description of the input/output.
In effect, this is a syntax-directed compiler from regular expressions
to the syntax for constructing parsers using these same combinators.
errordict/typecheck{ps pe quit}put
%errordict/stackunderflow{pe quit}put
%errordict/stackunderflow{pq}put
%errordict/undefined{pq}put
%(../../debug.ps/db5.ps) run
(pc11a.ps)run {
fix { flatten clean }
clean { { dup zero eq { pop } if } map }
? { {maybe} compose }
+ { {some} compose }
* { {many} compose }
} pairs-begin
/Dot (.) char {pop {item} one} using def
/Meta (*+?) anyof def
/Character (*+?.|()) noneof {first {literal} curry one} using def /Expression {-777 exec} def
/Atom //Dot
(\() char //Expression executeonly xthen (\)) char thenx alt
//Character alt def
/Factor //Atom /A
//Meta {/A load first exch first load exec one } using
maybe {dup first zero eq {pop /A load} if } using
into def
/Term //Factor //Factor many then
{ fix { {then} compose compose } reduce one } using def //Expression 0 //Term (|) char //Term xthen many then
{ fix { {plus} compose compose } reduce one } using put
/regex { 0 0 3 2 roll string-input //Expression exec report } def
{
0 0 (ab) string-input //Dot maybe exec pc
0 0 (ab) string-input //Meta exec pc
0 0 (*) string-input //Meta exec pc
0 0 (ab) string-input //Character maybe exec pc
0 0 (ab) string-input //Atom maybe exec pc
0 0 (.) string-input //Atom maybe exec pc
%0 0 (a*) string-input //Atom //Meta then ==
0 0 (a*) string-input //Atom //Meta then exec pc
0 0 (ab) string-input Factor pc
0 0 (a*) string-input Factor pc
0 0 (ab) string-input Term pc
0 0 (ab|c) string-input Expression pc
(ab) regex
} exec
{
} pop
quit
$ gsnd -dNOSAFER pc11are.ps
GPL Ghostscript 9.52 (2020-03-19)
Copyright (C) 2020 Artifex Software, Inc. All rights reserved.
This software is supplied under the GNU AGPLv3 and comes with NO WARRANTY:
see the file COPYING for details.
stack:
[/OK [[[] []] [[(a) [0 0]] {0 1 (b) string-input}]]]
:stack
stack:
[/Fail [[{(*+?) within} (not satisfied)] [[(a) [0 0]] {0 1 (b) string-input}]]] :stack
stack:
[/OK [[(*) []] {0 1 () string-input}]]
:stack
stack:
[/OK [[{(a) literal} []] {0 1 (b) string-input}]]
:stack
stack:
[/OK [[{(a) literal} []] {0 1 (b) string-input}]]
:stack
stack:
[/OK [[{item} []] {0 1 () string-input}]]
:stack
stack:
[/OK [[{(a) literal} [(*) []]] {0 2 () string-input}]]
:stack
stack:
[/OK [[{(a) literal} []] [[(b) [0 1]] {0 2 () string-input}]]]
:stack
stack:
[/OK [[{(a) literal many} []] {0 2 () string-input}]]
:stack
stack:
[/OK [[{(a) literal (b) literal then} []] []]]
:stack
stack:
[/OK [[{(a) literal (b) literal then (c) literal plus} []] []]]
:stack
OK
[{(a) literal (b) literal then}]
remainder:[]
--- SoupGate-Win32 v1.05
* Origin: fsxNet Usenet Gateway (21:1/5)