(defvar *ometa-class-name* 'ometa) (defvar *ometa-compiler-target* 'ometa-compiler) (defun read-grammar-file (file-name) "read a grammar from a text file. productions are terminated by a page break followed by a newline" (with-open-file (stream file-name :direction :input) (let (productions buffer) (block loop (loop do (let ((c (read-char stream))) (if (char= c (code-char 12)) (progn ; read the newline (read-char stream) (push (nreverse buffer) productions) (setf buffer nil)) (push c buffer)) (let ((e (read-char stream nil :eof))) (if (eq e :eof) (return-from loop nil) (unread-char e stream)))))) (nreverse productions)))) (defun parse-grammar-file (file-name) "runs the 'production' rule in the ometa-parser on each production in the file and collects the results" (loop for p in (read-grammar-file file-name) collect (let ((*ometa-class-name* 'ometa-parser)) (run-production 'production p)))) (defun compile-production (production) "runs the 'ocompile' rule in the ometa-compiler using the given production as input" (let ((*ometa-class-name* 'ometa-compiler)) (let ((result (run-production 'ocompile (list production)))) (if (o-fail? result) (error "failed to compile ~A" production) result)))) (defun compile-grammar-to-lisp (class-name grammar-file-name &optional (parser-class-name 'ometa-parser)) "parse a grammar file and run the compiler to produce lisp forms for each production" (let ((*ometa-compiler-target* class-name) (*ometa-class-name* parser-class-name)) (let* ((defs (parse-grammar-file grammar-file-name)) (lisp-forms (mapcar #'compile-production defs))) lisp-forms))) (defun install-grammar (class-name grammar-file-name &optional (parser-class-name 'ometa-parser)) "parse and compile the productions in a grammar file, then eval the lisp forms" (assert (subtypep class-name 'ometa-prim)) (mapcar #'eval (compile-grammar-to-lisp class-name grammar-file-name parser-class-name))) (defun run-production (name input) (let ((o (make-instance *ometa-class-name* :input input))) (apply name (list o)))) (defun generate-parser (class-name grammar-file-name parser-file-name) (with-open-file (stream parser-file-name :direction :output :if-exists :supersede) (loop for form in (compile-grammar-to-lisp class-name grammar-file-name 'ometa-parser) do (progn (format stream "~%") (let ((*print-readably* t)) (prin1 form stream)))))) (defclass ometa-parser (ometa) ((locals :initform nil :accessor locals))) (defclass ometa (ometa-prim) ()) (defclass ometa-compiler (ometa-parser) ())