;; mif.ol -- the Frame MIF class (require 'objective-lisp) (require 'stream) (defClass MIF () (out PgfCatalog FontCatalog VariableFormats XRefFormats TextFlows MasterPages AFrames body hyper) ) (defClassMethod MIF :reader (in) [MIFReader :new in] ) (defMethod MIF :isnew (o) (setq out o) ) (defClass MIFReader IStream () (table) ) (defMethod MIFReader :read () [self :set-readtable [self :readtable]] (prog1 (send-super :read) [self :set-readtable]) ) ;;;;;;;;;;;;;;; ;;; MIF Syntax (defun read-mif-statement (f c &aux ex ret) ;; like (read stream) but uses <> in stead of () (flet ((non-comment-char (comm) ;; skip whitespace. skip comm...newline ;; return next char (do ((c (peek-char t f) (peek-char t f)) ) ((not (eql c comm)) c) (read-line f) ) ) ) (do () ((eq (non-comment-char #\#) #\>)) (let ((cell (cons (read f) nil)) ) (if ex (setf (cdr ex) cell) (setf ret cell)) (setf ex cell))) ) (read-char f) ; toss the trailing #\> (cons ret NIL) ) (defun read-mif-string (f c &aux ex ret nonascii) ;; MIF strings look like `lksdjf \n \t \q \Q \x80 lksjdf' ;; aka "lksdjf \n \009 ` ' \200lksjdf" ;; returns a string if all chars are printable ASCII. ;; returns a list of characters otherwise (labels ((hex-digit (d) (or (digit-char-p d) (+ 10 (- (char-int (char-upcase d)) (char-int #\A)))) ) (read-mif-char (f) ;; interpret mif escapes (let ((c (read-char f)) ) (if (eq c #\\) (case (read-char f) (#\> #\>) (#\q #\') (#\Q #\`) (#\\ #\\) (#\t (setq nonascii t) (int-char 9)) (#\x (setq nonascii t) (let ((d1 (read-char f)) (d2 (read-char f)) ) (read-char f) ;; skip trailing blank (int-char (+ (* 16 (hex-digit d1)) (hex-digit d2) )) )) ) c) ) ) ) (do () ((eq (peek-char nil f) #\')) (let ((cell (cons (read-mif-char f) nil)) ) (if ex (setf (cdr ex) cell) (setf ret cell)) (setf ex cell))) (read-char f) ; toss the trailing #\' (cons (concatenate (if nonascii 'cons 'string) ret) NIL) ) ) (defun read-mif-inset (f c &aux ex ret) ;; a mif inset looks like: ;; =FrameImage ;; &lksjdflskdjflsdkj ;; &lksdjflsdkjflsdkjf ;; =EndInset ;; (setf ret (setf ex (cons (read f) nil))) ;; read =symbol (do () ((not (eq (peek-char t f) #\&))) (read-char f) ;; skip & (let ((cell (cons (read-line f) nil)) ) (setf (cdr ex) cell) (setf ex cell))) (cons ret NIL)) (defMethod MifReader :readtable () (or table (progn (setq table (subseq *readtable* 0)) (flet ((setchar (c v) (setf (aref table (char-int c)) v) ) ) (setchar #\< (cons :tmacro #'read-mif-statement)) (setchar #\` (cons :tmacro #'read-mif-string)) (setchar #\= (cons :tmacro #'read-mif-inset)) ; # is the MIF comment char (setchar #\# (aref table (char-int #\;))) ; signal errors on >'s (setchar #\> (cons :tmacro (lambda (f c) (error "misplaced right angle bracket"))) ) ; quote is short for IN, i.e. inch (setchar #\" (cons :tmacro (lambda (f c) (cons 'in nil) ) )) ) table ) ) ) (provide 'Mif)