I've been implementing the ANTLR BNF in Scheme.  So far, it's really 
straightforward, as expected.

I have *not* pushed it to the public yet, but I thought I'd give a heads-up and 
hear any early feedback.

The code is in readable/kernel.scm, but it is NOT enabled by default.  You have 
to set environment variable "SWEETNEW" to enable it, like this:
  make readable/kernel.scm && SWEETNEW="y" ./unsweeten

Currently it knows about the basic sweet-expression indenting rules, so it can 
do this:
aa bb cc
  dd ee
  ff

==>
(aa bb cc (dd ee) ff)

Each datum can be a neoteric-expression per SRFI-105.  It doesn't know about 
initial indents, scomments, GROUP_SPLIT or SUBLIST, abbreviation+hspace, or 
restarts, but those are just "more coding".

Below is the basics of it.  Notice that I am intentionally writing it so that 
the code is an obvious match to the BNF; you should be able to see a 1-to-1 
correspondence.  The big difference is that the routines tend to return 
2-elements lists; the first item is an indicator of next state (e.g., the 
stopper symbol or indent), while the second is the value returned so far.  This 
means that calls to productions become let* uses that call and decompose the 
results.

 --- David A. Wheeler

==============================================================

  ; Warning: For portability use eqv?/memv, not eq?/memq, to compare chars
  ; A "case" is okay since it uses "eqv?".

  (define initial_comment_eol '(#\; #\newline carriage-return))

  ; Consume 0+ spaces or tab
  (define (hspaces port)
    (cond
      ((char-horiz-whitespace? (my-peek-char port))
        (my-read-char port)
        (hspaces port))))

  (define (n_expr_first port)
    ; TODO - handle special cases
    (list 'normal (neoteric-read-nocomment port)))

  (define (n_expr port)
    ; TODO - handle special cases
    (n_expr_first port)
  )

  ; Consume ;-comment (if there), consume EOL, and return new indent.
  ; Skip ;-comment-only lines; a following indent-only line is empty.
  (define (comment_eol_read_indent port)
    (consume-to-eol port)
    (consume-end-of-line port)
    (let* ((indentation (list->string (accumulate-hspace port)))
           (c (my-peek-char port)))
      (cond
        ((eqv? c #\;)  ; A ;-only line, consume and try again.
          (consume-to-eol port)
          (consume-end-of-line port)
          (comment_eol_read_indent port))
        ((memv (my-peek-char port) initial_comment_eol) ; Indent-only line
          "")
        (#t indentation))))

  ; Utility function:
  ; If x is a 1-element list, return (car x), else return x
  (define (monify x)
    (cond
      ((not (pair? x)) x)
      ((null? (cdr x)) (car x))
      (#t x)))

  ; Returns (stopper computed_value); stopper may be 'normal, 'sublist, etc.
  (define (head port)
    (let* ((basic_full_results (n_expr_first port))
           (basic_special      (car basic_full_results))
           (basic_value        (cadr basic_full_results)))
      ; TODO: PERIOD and RESTART
      ; TODO: Assume no QUOTEH, scomment, etc... just normal.
      (cond
        ((char-horiz-whitespace? (my-peek-char port))
          (hspaces port)
          (if (not (memv (my-peek-char port) initial_comment_eol))
            (let* ((br_full_results (rest port))
                   (br_new_indent   (car br_full_results))
                   (br_value        (cadr br_full_results)))
              (list 'normal (cons basic_value br_value)))
            (list 'normal (list basic_value))))
        (#t 
          (list 'normal (list basic_value))))))

  ; Returns (stopper computed_value); stopper may be 'normal, 'sublist, etc.
  (define (rest port)
    (let* ((basic_full_results (n_expr port))
           (basic_special      (car basic_full_results))
           (basic_value        (cadr basic_full_results)))
      ; TODO: PERIOD and RESTART and scomment
      ; TODO: Assume no QUOTEH, scomment, etc... just normal.
      (cond
        ((char-horiz-whitespace? (my-peek-char port))
          (hspaces port)
          (if (not (memv (my-peek-char port) initial_comment_eol))
            (let* ((br_full_results (rest port))
                   (br_new_indent   (car br_full_results))
                   (br_value        (cadr br_full_results)))
              (list 'normal (cons basic_value br_value)))
            (list 'normal (list basic_value))))
        (#t (list 'normal (list basic_value))))))

  ; Returns (new_indent computed_value)
  (define (body port starting_indent)
    ; (display "DEBUG: Entering body")
    (let* ((it_full_results (it_expr port starting_indent))
           (it_new_indent   (car it_full_results))
           (it_value        (cadr it_full_results)))
      (if (string=? starting_indent it_new_indent)
        (let* ((body_full_results (body port it_new_indent))
               (body_new_indent   (car body_full_results))
               (body_value        (cadr body_full_results)))
          (list body_new_indent (cons it_value body_value)))
        (list it_new_indent (list it_value)))))

  ; Returns (new_indent computed_value)
  (define (it_expr port starting_indent)
    (let* ((head_full_results (head port))
           (head_stopper      (car head_full_results))
           (head_value        (cadr head_full_results)))
      (if (eq? head_stopper 'normal) ; non-empty head?
        (cond
          ((eq? head_stopper 'group_splice) "TODO2")
          ((eq? head_stopper 'sublist) "TODO3")
          ((eq? head_stopper 'restart-end) "TODO4")
          ((memv (my-peek-char port) initial_comment_eol)
            (let ((new_indent (comment_eol_read_indent port)))
              (if (indentation>? new_indent starting_indent)
                (let* ((body_full_results (body port new_indent))
                       (body_new_indent (car body_full_results))
                       (body_value      (cadr body_full_results)))
                  (list body_new_indent (append head_value body_value)))
                (list new_indent (monify head_value)))))
          (#t
            (read-error "Must end line with newline")))
        ; Head begins with something special like GROUP_SPLICE
        "TODO5"
    )))

  (define (t_expr port)
    (let* ((c (my-peek-char port)))
      (if (eof-object? c)
        c
        (cond
          ((memv c initial_comment_eol)
            ((consume-to-eol port)
             (consume-end-of-line port)
             (t_expr port)))
          ; TODO: FF/VT
          ; TODO: Initial_indent
          (#t (cadr (it_expr port "")))))))


------------------------------------------------------------------------------
Master Visual Studio, SharePoint, SQL, ASP.NET, C# 2012, HTML5, CSS,
MVC, Windows 8 Apps, JavaScript and much more. Keep your skills current
with LearnDevNow - 3,200 step-by-step video tutorials by Microsoft
MVPs and experts. ON SALE this month only -- learn more at:
http://p.sf.net/sfu/learnnow-d2d
_______________________________________________
Readable-discuss mailing list
Readable-discuss@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/readable-discuss

Reply via email to