home *** CD-ROM | disk | FTP | other *** search
- ;;; Start
- ; Lisp Program. Copyright 1993,1994 Apteryx Lisp Ltd.
-
- ; Pascal code generator. Examples of individual code
- ; macro useage are given after their definitions. A file
- ; generation example is given at the bottom of this file.
-
-
- (load "gen.lsp" :print nil)
-
- ;;; Layout
-
- ; This means that you can generate individual expressions
- ; into standard output to see what result they produce.
- (setq *pout* *standard-output*)
-
- (setq *ind* 0)
-
- (if (not (fboundp 'print-indent))
- (defun print-indent (n out)
- (dotimes (i n)
- (princ " " out) ) ) )
-
- (defun indent ()
- (print-indent *ind* *pout*) )
-
- (defun semicolon ()
- (princ ";" *pout*)
- (terpri *pout*) )
-
- (defun nl ()
- (terpri *pout*) (indent) )
-
- (defmacro with-indent (&rest stmts)
- `(progn
- (setq *ind* (+ *ind* 2))
- ,@stmts
- (setq *ind* (- *ind* 2)) ) )
-
- (defun /* (line1 &rest lines)
- (nl) (princ "{ " *pout*) (princ line1 *pout*)
- (dolist (line lines)
- (nl) (princ " " *pout*) (princ line *pout*) )
- (princ " }" *pout*) (terpri *pout*)
- `(comment ,@lines) )
-
- (defun comment-producer ()
- (/* "Produced using Apteryx Lisp") )
-
- ;;; Declarations
-
- (defmacro program (name)
- `(progn
- (princ "program " *pout*)
- (prin1 ',name *pout*)
- (semicolon) (terpri *pout*)
- '(program ,name) ) )
-
- ; (program myprog)
-
-
- (defmacro unit (name)
- `(progn
- (princ "unit " *pout*)
- (prin1 ',name *pout*)
- (semicolon) (terpri *pout*)
- '(unit ,name) ) )
-
- ; (unit myunit)
-
-
- ; Use to print an arbitrary string to Pascal file
- (defmacro p (string)
- (princ string *pout*) (terpri *pout*) )
-
- (defmacro interface ()
- `(progn
- (princ "interface" *pout*)
- (terpri *pout*) (terpri *pout*)
- 'interface ) )
-
- ; (interface)
-
- (defmacro implementation ()
- `(progn
- (princ "implementation" *pout*)
- (terpri *pout*) (terpri *pout*)
- 'implementation ) )
-
- ; (implementation)
-
- (defmacro uses (&rest modules)
- `(progn
- (princ "uses " *pout*)
- (prin1 (car ',modules) *pout*)
- (dolist (module (cdr ',modules))
- (if (eq module :nl)
- (progn (terpri *pout*) (indent) )
- (progn
- (princ ", " *pout*)
- (prin1 module *pout*) ) ) )
- (semicolon) (terpri *pout*)
- '(uses ,@ modules) ) )
-
- ; (uses unit1 unit2)
-
- (defun print-proc-name (name)
- (cond
- ( (symbolp name)
- (prin1 name *pout*) )
- ( (and (listp name) (eql 3 (length name)) (eq (car name) '%) )
- (format *pout* "~A.~A" (second name) (third name)) )
- (t
- (error "Invalid proc/func name" name) ) ) )
-
- (defmacro proc (name args &rest decs)
- `(progn
- (princ "procedure " *pout*)
- (print-proc-name ',name)
- (print-args ',args)
- (princ "; " *pout*)
- (with-indent
- (progn ,@decs) )
- (terpri *pout*)
- '(procedure ,name) ) )
-
- ; (proc dosomething ( (var n integer) ) (begin (writeln "hello")))
-
- (defmacro constructor (name args &rest decs)
- `(progn
- (princ "constructor " *pout*)
- (print-proc-name ',name)
- (print-args ',args)
- (princ "; " *pout*)
- (with-indent
- (progn ,@decs) )
- (terpri *pout*)
- '(procedure ,name) ) )
-
- ; (constructor (% TThing Doit) ( (n integer) (i word) ) (begin (writeln)))
-
- (defmacro destructor (name args &rest decs)
- `(progn
- (princ "destructor " *pout*)
- (print-proc-name ',name)
- (print-args ',args)
- (princ "; " *pout*)
- (with-indent
- (progn ,@decs) )
- (terpri *pout*)
- '(procedure ,name) ) )
-
- ; (constructor (% TThing Done) () (begin (writeln "Gone")))
-
- (defmacro func (name args type &rest decs)
- `(progn
- (princ "function " *pout*)
- (print-proc-name ',name)
- (print-args ',args)
- (princ " : " *pout*)
- (prin1 ',type *pout*)
- (princ "; " *pout*)
- (with-indent
- (progn ,@decs) )
- (terpri *pout*)
- '(procedure ,name) ) )
-
- ; (func myfunc ( (var n integer) ) integer (begin (= myfunc (+ n 2))))
-
- (defun print-const-dec (dec)
- (indent)
- (case (length dec)
- (2 (prin1 (first dec) *pout*)
- (princ " = " *pout*)
- (print-value (second dec))
- (semicolon) )
- (3 (prin1 (first dec) *pout*) (princ " :" *pout*)
- (print-type (second dec))
- (princ " = " *pout*)
- (print-value (third dec))
- (semicolon) )
- (t (error "invalid const declaration" dec)) ) )
-
- (defmacro const (&rest const-decs)
- `(progn
- (nl) (princ "const " *pout*) (terpri *pout*)
- (with-indent
- (dolist (dec ',const-decs)
- (print-const-dec dec) ) )
- '(const ,@const-decs) ) )
-
- ; (const (i 2) (n "Fred"))
-
- (defun print-type-dec (type-dec)
- (let ( (name (car type-dec))
- (type (second type-dec)) )
- (indent)
- (prin1 name *pout*)
- (princ " = " *pout*)
- (with-indent
- (print-type type)
- (semicolon) ) ) )
-
- (defmacro type (&rest type-decs)
- `(progn
- (nl) (princ "type " *pout*) (terpri *pout*)
- (with-indent
- (dolist (dec ',type-decs)
- (print-type-dec dec) ) )
- '(type ,@type-decs) ) )
-
- ; (type (mytype integer) (myarray (array ( (.. 1 20) ) integer)))
-
- (defmacro begin (&rest stmts)
- `(progn
- (print-stmt (cons 'begin ',stmts))
- (semicolon) ) )
-
- ; (begin (= i 1) (writeln "hello" goodbye_string))
-
- (defmacro far ()
- `(princ " far; " *pout*) )
-
- ; (proc myproc ( (i integer) ) (far) (begin (writeln "hello")))
-
- (defmacro module-begin (&rest stmts)
- `(progn
- (print-stmt (cons 'begin ',stmts))
- (princ "." *pout*) (terpri *pout*)
- 'module-begin ) )
-
- ; (module-begin (= i 1) (writeln "hello"))
-
- (defun print-args (args)
- (when args
- (princ " (" *pout*)
- (print-arg (car args))
- (dolist (arg (cdr args))
- (if (eq :nl arg)
- (progn (terpri *pout*) (indent) )
- (progn
- (princ "; " *pout*)
- (print-arg arg) ) ) )
- (princ ")" *pout*) ) )
-
- (defun print-arg (arg)
- (let ( (rest arg) num-vars)
- (case (car rest)
- ((var invar outvar inoutvar)
- (princ "var " *pout*)
- (setq rest (cdr rest)) )
- (in
- (setq rest (cdr rest)) ) )
- (setq num-vars (1- (length rest)))
- (dotimes (i num-vars)
- (if (> i 0) (princ ", " *pout*))
- (prin1 (nth i rest) *pout*) )
- (princ " :" *pout*)
- (prin1 (nth num-vars rest) *pout*) ) )
-
- (defmacro var (&rest decs)
- `(progn
- (nl) (princ "var" *pout*) (terpri *pout*)
- (with-indent
- (dolist (dec ',decs)
- (print-var dec) ) )
- '(vars ,@decs) ) )
-
- ; (var (i integer) (n word))
-
- (defun print-var (dec)
- (indent)
- (let* ( (rev-dec (reverse dec))
- (type (car rev-dec))
- (vars (reverse (cdr rev-dec))) )
- (prin1 (car vars) *pout*)
- (dolist (var (cdr vars))
- (princ ", " *pout*)
- (prin1 var *pout*) )
- (princ " :" *pout*)
- (print-type type)
- (semicolon) ) )
-
- (defun print-virtual (dec)
- (princ ";" *pout*)
- (cond
- ( (eq dec 'virtual)
- (princ " virtual" *pout*) )
- ( (and (listp dec) (eq (car dec) 'virtual) (eql 2 (length dec)))
- (princ " virtual " *pout*)
- (print-value (second dec)) )
- ( t
- (error "Invalid virtual dec" dec) ) ) )
-
- (defun print-method (dec)
- (indent)
- (let* ( (method-type (first dec))
- (name (second dec))
- (arglist (third dec))
- (virtual-dec (nthcdr 3 dec)) )
- (format *pout* "~A ~A " method-type name)
- (print-args arglist)
- (if (not (null virtual-dec))
- (print-virtual (car virtual-dec)) )
- (semicolon) ) )
-
- ; (print-method '(procedure jim ( (var tom integer) (fred char)) (virtual (+ 5 6)) ))
-
- (defun print-type (type)
- (case (type-of type)
- (symbol (prin1 type *pout*))
- (cons
- (let ( (fun (get (car type) 'type-fun)) )
- (if fun
- (apply fun (cdr type))
- (error "Unknown type function" (car type)) ) ) )
- (t (error "invalid print-type arg" type)) ) )
-
- ;;; def-type-fun
-
- (defmacro def-type-fun (name args &rest body)
- `(progn
- (setf (get ',name 'type-fun )
- #'(lambda ,args ,@body) )
- '(type-fun ,name) ) )
-
- (defmacro def-type-macro (name args expr)
- `(progn
- (setf (get ',name 'type-fun )
- #'(lambda ,args (print-type ,expr)) )
- '(type-macro ,name) ) )
-
- (def-type-fun record (&rest var-decs)
- (terpri) (indent) (princ "record" *pout*) (terpri *pout*)
- (with-indent
- (dolist (var-dec var-decs)
- (print-var var-dec) ) )
- (indent) (princ "end" *pout*) )
-
- ; (var (n (record (i integer) (w word))))
-
- (def-type-fun object (parent &rest members)
- (terpri) (indent) (princ "object" *pout*)
- (if (not (null parent))
- (format *pout* " (~A) " parent) )
- (terpri *pout*)
- (with-indent
- (let ( (member-type 'var) )
- (dolist (member members)
- (cond
- ((eq member 'methods) (setq member-type 'method))
- ((eq member-type 'var) (print-var member))
- ((eq member-type 'method) (print-method member)) ) ) ) )
- (indent) (princ "end" *pout*) )
-
- '(var (z (object nil
- (x integer) (y char)
- methods
- (procedure jim ( (x integer) )
- (virtual (+ wm_first wmMouseDown)) ) )) )
-
- (def-type-fun .. (first last)
- (print-value first) (princ ".." *pout*) (print-value last) )
-
- ; (var (n (.. 1 10)))
-
- (def-type-fun array (indexes type)
- (princ "array [" *pout*)
- (print-type (car indexes))
- (dolist (index (cdr indexes))
- (princ ", " *pout*)
- (print-type index) )
- (princ "] of " *pout*);
- (print-type type) )
-
- ; (var (n (array ( (.. 1 10) (.. 2 45) ) word)))
-
- (def-type-fun ^ (type)
- (princ "^" *pout*)
- (print-type type) )
-
- ; (var (p (^ TObject)))
-
- ;;; def-value-fun
-
- (defun print-value (value)
- (case (type-of value)
- (nil (princ "nil" *pout*))
- (symbol (prin1 value *pout*))
- (fixnum (prin1 value *pout*))
- (integer (prin1 value *pout*))
- (string
- (princ "'" *pout*) (princ value *pout*)
- (princ "'" *pout*) )
- (flonum (prin1 value *pout*))
- (float (prin1 value *pout*))
- (cons
- (let ( (fun (if (symbolp (car value)) (get (car value) 'value-fun) nil)) )
- (if fun
- (apply fun (cdr value))
- (progn
- (print-value (car value))
- (let ( (args (cdr value)) )
- (when args
- (princ " (" *pout*)
- (print-value (car args))
- (dolist (arg (cdr args))
- (if (eq arg :nl)
- (progn
- (terpri *pout*) (indent) )
- (progn
- (princ ", " *pout*)
- (print-value arg) ) ) )
- (princ ")" *pout*) ) ) ) ) ) )
- (t (error "invalid print-value arg" value)) ) )
-
- (defmacro def-value-fun (name args &rest body)
- `(progn
- (setf (get ',name 'value-fun)
- #'(lambda ,args ,@body) )
- '(value-fun ,name) ) )
-
- (defmacro def-value-macro (name args expr)
- `(progn
- (setf (get ',name 'value-fun)
- #'(lambda ,args (print-value ,expr)) )
- '(value-macro ,name) ) )
-
- (def-value-fun ch (number)
- (princ "#" *pout*) (print-value number) )
-
- ; (begin (= ch (ch 13)))
-
- (def-value-fun @ (name)
- (princ "@" *pout*) (print-value name) )
-
- ; (begin (= ptr (@ variable)))
-
- (def-value-fun ^ (name)
- (print-value name) (princ "^" *pout*) )
-
- ; (begin (= value (^ ptr)))
-
- (def-value-fun concat (&rest vals)
- (dolist (val vals)
- (if (symbolp val)
- (prin1 val *pout*)
- (princ val *pout*) ) ) )
-
- ; (begin (= string (concat #\' "jim " tom " and fred" #\')))
-
- (def-value-fun not (name)
- (princ "(not " *pout*)
- (print-value name)
- (princ ")" *pout*) )
-
- ; (begin (= test (not (< 2 3))))
-
- (def-value-fun [] (array &rest indexes)
- (print-value array)
- (princ "[" *pout*)
- (print-value (car indexes))
- (dolist (index (cdr indexes))
- (princ "," *pout*)
- (print-value index) )
- (princ "]" *pout*) )
-
- ; (begin (= i ([] arr n)))
-
- (def-value-fun % (record field)
- (print-value record)
- (princ "." *pout*)
- (print-value field) )
-
- ; (begin (= val (% rec field)))
-
- (def-value-macro []^ (array_ptr &rest indexes)
- `([] (^ ,array_ptr) ,@indexes) )
-
- ; (begin (= val ([]^ arr_ptr index)))
-
- ;;; operators
-
- (defmacro def-operator1 (name)
- `(def-value-fun ,name (arg1 arg2)
- (princ "(" *pout*)
- (print-value arg1)
- (princ " " *pout*)
- (prin1 ',name *pout*)
- (princ " " *pout*)
- (print-value arg2)
- (princ ")" *pout*) ) )
-
- (defun def-operator (name)
- (eval `(def-operator1 ,name)) )
-
- (defmacro def-n-operator1 (name)
- `(def-value-fun ,name (arg1 &rest args)
- (princ "(" *pout*)
- (print-value arg1)
- (dolist (arg args)
- (if (eq :nl arg)
- (progn (terpri *pout*) (indent))
- (progn
- (princ " " *pout*)
- (prin1 ',name *pout*)
- (princ " " *pout*)
- (print-value arg) ) ) )
- (princ ")" *pout*) ) )
-
- (defun def-n-operator (name)
- (eval `(def-n-operator1 ,name)) )
-
- (dolist (x '( - / div mod rem shl shr in < > <= >= <> =))
- (def-operator x) )
-
- ; (begin (= i (+ (* n 20) 45)))
-
- (dolist (x '(+ * and or xor))
- (def-n-operator x) )
-
- ; (begin (= i (+ 1 2 3 4 (* 5 6 7))))
-
- ;;; def-stmt-fun
-
- (defun print-stmt (stmt)
- (case (type-of stmt)
- (nil)
- (cons
- (let ( (fun (if (symbolp (car stmt)) (get (car stmt) 'stmt-fun) nil) ) )
- (if fun
- (apply fun (cdr stmt))
- (progn
- (print-value (car stmt))
- (let ( (args (cdr stmt)) )
- (when args
- (princ " (" *pout*)
- (print-value (car args))
- (dolist (arg (cdr args))
- (if (eq arg :nl)
- (progn (terpri *pout*) (indent))
- (progn
- (princ ", " *pout*)
- (print-value arg) ) ) )
- (princ ")" *pout*) ) ) ) ) ) )
- (t (error "invalid print-stmt arg" stmt)) ) )
-
- (defmacro def-stmt-fun (name args &rest body)
- `(progn
- (setf (get ',name 'stmt-fun)
- #'(lambda ,args ,@body) )
- '(stmt-fun ,name) ) )
-
- (defmacro def-stmt-macro (name args expr)
- `(progn
- (setf (get ',name 'stmt-fun)
- #'(lambda ,args (print-stmt ,expr)) )
- '(stmt-macro ,name) ) )
-
- (defun begin-block (stmts)
- (nl) (princ "begin" *pout*) (terpri *pout*)
- (with-indent
- (dolist (stmt stmts)
- (indent) (print-stmt stmt) (semicolon) ) )
- (indent) (princ "end" *pout*) )
-
- (def-stmt-fun = (var val)
- (print-value var) (princ " := " *pout*)
- (print-value val) )
-
- ; (begin (= i (+ n 2)))
-
- (def-stmt-fun begin (&rest stmts)
- (begin-block stmts) )
-
- ; (begin (= i n) (= y x) (writeln "hello"))
-
- (def-stmt-fun for (header &rest stmts)
- (let ( (var (first header))
- (start (second header))
- (end (third header)) )
- (princ "for " *pout*) (print-value var)
- (princ " := " *pout*) (print-value start)
- (princ " to " *pout*) (print-value end)
- (princ " do" *pout*)
- (with-indent
- (begin-block stmts) ) ) )
-
- ; (begin (for (i 1 100) (writeln i) (= n (+ n i))))
-
- (def-stmt-fun with (var &rest stmts)
- (princ "with " *pout*)
- (print-value var)
- (princ " do " *pout*)
- (with-indent
- (begin-block stmts) ) )
-
- ; (begin (with (^ ptr) (writeln field1) (writeln field2)))
-
- (def-stmt-fun block (&rest stmts)
- (print-stmt
- (if (= (length stmts) 1)
- (first stmts)
- (cons 'begin stmts) ) ) )
-
- ; (begin (block (writeln "hello")))
-
- ; (begin (block (writeln "hello") (writeln "hello")))
-
- ; call is not usually necessary, but it forces interpretation of
- ; first argument as a procedure or function
-
- (def-stmt-fun call (proc-fun &rest args)
- (print-value proc-fun)
- (when args
- (princ " (" *pout*)
- (print-value (car args))
- (dolist (arg (cdr args))
- (princ ", " *pout*)
- (print-value arg))
- (princ ")" *pout*) ) )
-
- ; (begin (call function n i))
-
- (def-stmt-fun null-statement () )
-
- ; (begin (for (i 1 10) (null-statement)))
-
- (defun print-case-clause (values stmts)
- (indent)
- (if (eq values 'else)
- (princ "else " *pout*)
- (progn
- (if (or (numberp values) (symbolp values) (stringp values))
- (setq values (list values)) )
- (print-value (car values))
- (dolist (value (cdr values))
- (princ ", " *pout*)
- (print-value value) )
- (princ ": " *pout*) ) )
- (with-indent
- (print-stmt (cons 'block stmts)) )
- (semicolon) )
-
- (def-stmt-fun case (val &rest clauses)
- (princ "case " *pout*)
- (print-value val)
- (princ " of " *pout*) (terpri *pout*)
- (with-indent
- (dolist (clause clauses)
- (print-case-clause (car clause) (cdr clause)) ) )
- (indent) (princ "end" *pout*) )
-
- ; (begin (case (+ i 2) (3 (writeln "three")) (21 (= i 3) (= y 4))))
-
- ; (begin (case (+ i 2) (3 (writeln "three")) (else (= i 3) (= y 4))))
-
- (def-stmt-fun while (var &rest stmts)
- (princ "while " *pout*)
- (print-value var)
- (princ " do " *pout*)
- (with-indent
- (begin-block stmts) ) )
-
- ; (begin (while (< i 5) (= i (+ i 1))))
-
- (def-stmt-fun repeat-until (var &rest stmts)
- (princ "repeat" *pout*) (terpri *pout*)
- (with-indent
- (dolist (stmt stmts)
- (indent) (print-stmt stmt) (semicolon) ) )
- (indent) (princ " until " *pout*) (print-value var) )
-
- ; (begin (repeat-until (< i 5) (= i (+ i 1))))
-
- (def-stmt-fun if (test then-stmt &optional else-stmt)
- (princ "if " *pout*) (print-value test)
- (nl) (princ " then " *pout*)
- (with-indent
- (print-stmt then-stmt) )
- (when else-stmt
- (progn (nl) (princ " else " *pout*))
- (with-indent
- (print-stmt else-stmt) ) ) )
-
- ; (begin (if (< i 2) (writeln "less than 2") (writeln ">= 2")))
-
- (def-stmt-macro addf (var value)
- `(= ,var (+ ,var ,value)) )
-
- ; (begin (addf i n))
-
- (def-stmt-macro incf (var)
- `(= ,var (+ ,var 1)) )
-
- ; (begin (incf i))
-
- ;;; string tables
-
- ; The following code is for automatically generating string resource
- ; tables. It is desirable to use it for large programs because
- ; constant strings use up precious data segment.
-
- ; Call this function explicitly in the pascal file before any use of
- ; str. Choose start-no and limit-no to avoid clashes in different
- ; string tables.
-
- (defun open-string-table (name start-no &optional limit-no)
- (setq *string-index* start-no)
- (setq *string-index-limit*
- (if limit-no limit-no (+ start-no 1000)) )
- (setq *string-file-name* name)
- (setq *string-file* (open (strcat name ".rc") :direction :output))
- (format *pout* "{$R ~A.res}~%" name)
- (princ "STRINGTABLE LOADONCALL MOVEABLE DISCARDABLE" *string-file*)
- (terpri *string-file*)
- (princ "BEGIN" *string-file*)
- (terpri *string-file*) )
-
- ; Calls rc.exe program provided with Borland Pascal to compile
- ; generated .rc file into a .res file. (Automatically called by
- ; gen-pascal function.)
-
- (defun finish-any-string-file ()
- (when *string-file*
- (princ "END" *string-file*)
- (terpri *string-file*)
- (close *string-file*)
- (setq *string-file* nil)
- (run-program (strcat "rc -r " *string-file-name* ".rc")) ) )
-
- (setq *string-file* nil)
-
- ; use (str "string") instead of "string" to generate a reference to a
- ; resource string. Used with copy = nil, uses LString to retrieve
- ; resource, used with copy = t uses LStringCopy to retrieve string.
- ; (You have to write LString and LStringCopy.)
-
- (def-value-fun str (x &key copy)
- (if *string-file*
- (progn
- (format *string-file* " ~A, ~S~%" *string-index* x)
- (if copy
- (format *pout* "LStringCopy (~A)" *string-index*)
- (format *pout* "LString (~A)" *string-index*) )
- (setq *string-index* (1+ *string-index*))
- (if (>= *string-index* *string-index-limit*)
- (error "String index limit exceeded" *string-index*) ) )
- (print-value x) ) )
-
- ; Example doesn't generate LString call because *string-file* = nil
- ; (begin (= a (str "Jim")))
-
- ;;; gen-pascal
-
- (defun gen-pascal (infile outfile)
- (princ "Generating ") (prin1 outfile)
- (princ " from ") (print infile)
- (setq *string-file* nil)
- (setq *ind* 1)
- (let ( (pout-save *pout*)
- (new-pout (open outfile :direction :output)) )
- (unwind-protect
- (progn
- (setq *pout* new-pout)
- (load infile :print t) )
- (finish-any-string-file)
- (close *pout*)
- (setq *pout* pout-save) )
- outfile) )
-
- ; To see how this works, load this buffer and
- ; evaluate the example below. Then compile
- ; the newly generated example.pas in Turbo Pascal for Windows
- ; (registered Trademark of Borland)
-
- ; (gen-pascal "example.ps" "example.pas")
-
-