#! /usr/bin/env mzscheme #lang scheme ;tested in PLT Scheme 4.1 ;; ;; om.scm -- OMeta parser generator script ;; (require mzlib/defmacro) (require mzlib/compat) ;1+ 1- (require mzlib/string) ;read-from-string (include "om-core.scm") ;; ----------------------------------------------- ;; OMeta grammar definition ;(include "handwritten-ometa.scm") (include "generated9.scm") ;; XXX: These two functions don't quite belong here. ;; They're part of the OMeta grammar definition, NOT this parser generator. (define (declare-locals n rs a) (let ((locals `(let ,(append '((__start *i*)) (map (lambda (n) (list n #f)) (extract-locals rs)) )) )) (when a (set! rs (append rs (list a)))) `(define (,n) ,(append locals (list rs))) )) (define (extract-locals e) "Find all variables assigned by SETFs in 'e'. Returns a possibly-empty list of symbols. NOTE: We're taking shortcuts because 'e' is generated code where all SETFs are relevant. This is NOT reusable code!" (if (pair? e) (case (car e) ((setf) (list (cadr e))) (else (remove-duplicates (flatten (filter pair? (map extract-locals (cdr e)) ))) )) '() )) ;; ----------------------------------------------- ;; This is basically I/O plumbing.... (define (transform-grammar input-file output-file) ;(when (>= *LOGLEVEL* 2) ; (printf ";GIVEN:~%~a~%" *s*) ; (printf ";PARSING...~%") ) (let* ((output (parse-from-file input-file)) (outfile (open-output-file output-file #:exists 'replace))) (pretty-print-columns 80) (for-each (lambda (expr) (pretty-print expr outfile) (newline outfile)) output) ) (let ((remaining (substring *s* *i*))) (if (equal? remaining "") (when (>= *LOGLEVEL* 1) (printf "~%All input was parsed.~%")) (printf "~%WARNING: UNPARSED INPUT REMAINING:~%~a~%" remaining) )) ) ;; ----------------------------------------------- ;; Command line interface ;; (This is PLT-Scheme-specific; also, R6RS offers a command-line parser) ;; (define verbosity (make-parameter 0)) (define includes (make-parameter null)) (command-line #:multi [("-v" "--verbose") "Verbose messages (-vv, -vvv for voluminous debug messages)" (verbosity (1+ (verbosity)))] ; I don't think this is really necessary... and besides, I don't think ; (include) works at runtime; we'd have to (load) all the interdependent ; parser parts, or deal with namespaces... [("-i" "--include") scheme-file "Include ..." (includes (cons scheme-file (includes)))] #:args (input-grammar-file output-scheme-file) (begin (set! *LOGLEVEL* (verbosity)) (transform-grammar input-grammar-file output-scheme-file) ))