chicken-users
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Chicken-users] Mutual recursion w/ comparse


From: Matt Gushee
Subject: Re: [Chicken-users] Mutual recursion w/ comparse
Date: Thu, 28 May 2015 18:24:45 -0600

Okay, well, I found a solution. I'm using this simple macro:

    (define-syntax mrp
        (syntax-rules ()
             ((_ fn) (lambda args (apply function args)))))

Actually, this is just a copy of the 'vac' macro from json-abnf; I changed the name because I had no idea what 'vac' means - whereas 'mrp' stands for 'mutually recursive parser'.

So, I wrap the body of the first parser definition in the mutually recursive group, like so:

    (define dict-value
        (mrp
            (any-of integer float number boolean string~ list~ dict)))

... and everything's good.

I also saw that comparse provides a similar macro called 'recursive-parser', but for some reason that didn't work when I tried it. Maybe I was using it wrong.

I'd still be interested to know if my solution here is the best one, or if there are other good ways to handle this type of situation.

--
Matt Gushee



On Wed, May 27, 2015 at 6:30 PM, Matt Gushee <address@hidden> wrote:
Hello--

I'm trying to write my first real parser with comparse, but I'm running into some difficulty with mutual recursion. Here's the problematic portion of my code:

    (define-values (dict dict-content dict-entry dict-value)
      (let ()
        (define dict~
          (enclosed-by (is #\{) dict-content~ (is #\})))
        (define dict-content~
          (sequence (maybe whitespace)
                    (maybe (sequence dict-entry~
                                     (zero-or-more (sequence separator
                                                             dict-entry~))))
                    (maybe whitespace)))
        (define dict-entry~
          (sequence dict-key
                    (maybe whitespace)
                    (is #\:)
                    (maybe whitespace)
                    dict-value~))
        (define dict-value~
          (any-of integer float number boolean string~ list~ dict~))
        (values dict~ dict-content~ dict-entry~ dict-value~)))

But when I try to use these parsers, e.g.

     (with-input-from-file "examples/basic.rsc"
         (lambda ()
              (let-values (((result rest)
                  (parse dict-content (read-all (current-input-port))))))))

I get this error:

Error: call of non-procedure: #<unspecified>

    Call history:

    rascl-parser.scm:166: comparse#sequence     
    rascl-parser.scm:166: comparse#zero-or-more     
    rascl-parser.scm:165: comparse#sequence     
    rascl-parser.scm:165: comparse#maybe     
    rascl-parser.scm:168: comparse#maybe     
    rascl-parser.scm:164: comparse#sequence     
    rascl-parser.scm:171: comparse#maybe     
    rascl-parser.scm:172: comparse#is     
    rascl-parser.scm:173: comparse#maybe     
    rascl-parser.scm:170: comparse#sequence     
    rascl-parser.scm:176: comparse#any-of     
    rascl-parser.scm:177: values     
    parse-basic.scm:13: with-input-from-file     
    parse-basic.scm:14: ##sys#call-with-values     
    parse-basic.scm:16: read-all     
    parse-basic.scm:16: comparse#parse         

I'm pretty sure the cause is not any of the individual parsers, but rather the way I'm trying to implement mutual recursion. I tried a version with

        (define dict-value
          (any-of integer float number boolean string~ list~))

i.e., non-recursive, with all parsers defined with a simple sequence of top-level (define)s, and it worked fine.

However, the actual grammar I'm trying to parse is similar, but not identical, to JSON, and calls for nested dictionaries. I looked at the medea source code and tried the approach used there (or as close as I could come), and several other variations, but I always get the same error, or else this one:

    Error: bad argument count - received 1 but expected 0: #<procedure (rascl-parser#dict-content)>.

Obviously I'm doing something wrong, but I can't see what.

BTW, I have a closely related but more general question:

At first I tried to use top-level defines for all the parsers, and that didn't work at all. I was surprised because I have used mutually recursive procedures many times. But I think I understand now. I think it's because in

    (define (NAME ARG ...)  BODY ...)

the BODY expressions are evaluated at runtime, while in

    (define NAME BODY ...)

[which is the form typically used to define comparse parsers], the BODY expressions are evaluated at compile time; thus any symbols referenced in BODY must be previously (in lexical order) defined. Have I got that right?

Thanks for any help.

--
Matt Gushee


reply via email to

[Prev in Thread] Current Thread [Next in Thread]