Re: Regexp Alternatives (was Re: Wondering what I'm doing wrong?)

"David McClain (as dbm at refined-audiometrics dot com)" <[email protected]> Thu, 11 Jun 2026 18:05:29 -0700
Newsgroups gmane.lisp.lispworks.general
Message-ID <[email protected]>
Yes, I’ll give it a go. But there is no equivalent for SBCL, and I was trying for portability. Also, IIRC, the Parsergen in LW needs a lexical analyzer built for it. All my other parsers do the lexical analysis in stride as part of the parsing.

The one thing I found, about Parseq (dunno yet about ESRAP), unlike a regexp matcher where you can anchor the pattern to the end of the line, you have to manually do your anchoring in the parsing grammar. I do that with an EOS Rule:

(defrule eos () (* char)
  (:test (&rest es)
   (null es)))

And then my top level parsing is thus:

(defun select-first (&rest args)
  (car args))

(defrule sole-complex () (and pr-complex eos)
  (:function #'select-first))

(defrule sole-real () (and pr-real eos)
  (:function #'select-first))

(defrule sole-dashed () (and dashed-number eos)
  (:function #'select-first))

(defrule pr-number  () (or sole-complex
                           sole-dashed
                           sole-real))
So EOS matches the end of the string being parsed, and fails if any characters remain unexamined.

This mattes because there is only supposed to be one number token involved here, or else I default to Lisp Symbol. And because a COMPLEX can be composed of one or two REALs:

COMPLEX = [+-] REAL [jJiI] | [+-] REAL [+- REAL [jJiI]

ESRAP is a linear Packrat Parser with PEG Grammar, and it admits left-recursion. Parseq is strictly Recursive Descent, cannot handle left recursion, and uses backtracking. But it is faster overall, and the author talks about that very thing:

https://github.com/mrossini-ethz/parseq/wiki/Packrat-Parsing
Packrat Parsing
github.com


> On Jun 11, 2026, at 17:45, Adam Weaver (as adam at cleversure dot com dot au) <[email protected]> wrote:
> 
>> On 12/6/26 08:18, David McClain (as dbm at refined-audiometrics dot
> com) wrote:
>> CL-PPCRE
>> ;; About 84s for 10^5 iters, so 840μs/iter
>> ;; Allocation   = 38,992,235,512 bytes, or 389,922 bytes/iter
>> ;; 2292 Page faults
>> 
>> ESRAP (PEG Packrat?)
>> ;; About 68s for 10^5 iters, so 680μs/iter
>> ;; Allocation   = 34,755,853,968 bytes, or 347,558 bytes/iter
>> ;; 5181 Page faults
>> 
>> Parseq (PEG Non-Packrat)
>> ;; About 19s for 10^5 iters, so 190μs/iter
>> ;; Allocation   = 9,121,975,192 bytes, or 91,219 bytes/iter
>> ;; 209 Page faults
> 
> That is rather interesting! Never occurred to me to use anything other 
> than regexps
> 
> for stringy work.
> 
> Hmm.. I wonder how PARSERGEN:DEFPARSER fares?
> 
> I tend to use PARSERGEN:DEFPARSER for as much as I can, e.g. a JSON parser:
> 
> (parsergen:defparser json-dom-parser
>     ((<toplevel> <element>))
>   (<array-element*>
>    ((<element> #\, <array-element*>) (cons $1 $3))
>    ((<element>) (cons $1 nil)))
>   (<object-element*>
>    ((:string #\: <element> #\, <object-element*>) (list* $1 $3 $5))
>    ((:string #\: <element>) (list $1 $3)))
>   (<element>
>    ((:number) $1)
>    ((:string) $1)
>    ((:null) nil)
>    ((t) $1)
>    ((#\[ <array-element*> #\]) (coerce $2 'vector))
>    ((#\[ #\]) (vector))
>    ((#\{ <object-element*> #\}) (loop with hash = (make-hash-table 
> :test #'equalp)
>                                       for (key value) on $2 by #'cddr
>                                       do (setf (gethash key hash) value)
>                                       finally (return hash)))
>    ((#\{ #\}) (make-hash-table :test #'equalp))))
> 
> DM, I don't suppose you're interested in trying your number parser out 
> using LW's built-in PARSERGEN package?
> 
> 
> A.
> 
> 
> _______________________________________________
> Lisp Hug - the mailing list for LispWorks users
> [email protected]
> http://www.lispworks.com/support/lisp-hug.html