home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
lisp
/
interpre
/
apteryx
/
pasgen.lsp
< prev
next >
Wrap
Lisp/Scheme
|
1994-04-01
|
22KB
|
798 lines
;;; 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-type-fun procedure (arglist)
(princ "procedure " *pout*)
(print-args arglist) )
; (type (myproc (procedure ( (var i integer) (s PChar)))))
;;; 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 for-downto (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 " downto " *pout*) (print-value end)
(princ " do" *pout*)
(with-indent
(begin-block stmts) ) ) )
; (begin (for-downto (i 100 1) (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")