[comp.lang.lisp] Franz to Common Lisp Translation

adams@crcge1.UUCP (Drew Adams) (09/15/87)

We have a Franz-TO-Common Lisp translation program (FTOC) written three
years ago.  It's written in Common Lisp and has run under Kyoto CL and
Sun CL.  It's basically a macro expander and consists of a (*large*) 
collection of rewrite rules in the form of macros.  A rule specifies 
the CL form that corresponds to a given input Franz Lisp form.  These 
defining macros have not been tested out completely, and there may of 
course be more than one "correct" or desirable translation for any given 
form.  A few definitions are known to be incorrect.  It is in general a 
simple matter to change such translation rules.  Aside from the correction
of particular definitions, the general functioning of the program
has been tested.  FTOC was written for an older Franz version (38, 39, 
40?), before Franz included such things as packages and keywords.

Naturally, completely automatic translation Franz -> Common is
impossible.  FTOC tries to remain conservative and not second-guess
the programmer's original intent, which means that the resultant CL
code is often unduly wordy, (simulating Franz's type-checking of
numbers etc.)  The bottom line is that FTOC may be useful for a first 
pass (i.e. an *aid* to translation).  It may also be useful interactively 
as an aid to Franz programmers converting to Common habits: typing in 
a Franz expression allows a quick view of a possible Common correspondant.

Example of wordiness: (+ 2 (+ 3 (+ 4 1))) in Franz is translated to:

(flet ((franz.+ (&optional (n 1 0) &rest n2etc)
	"equivalent to Franz Lisp '+'."
	(check-type n fixnum)
	(mapc #'(lambda (n) (check-type n fixnum)) n2etc)
	(if (endp n2etc) n1 (+ n1 (reduce #'+ n2etc)))))
      (franz.+  2
                (flet ((franz.+ (&optional (n 1 0
		         .... and so on ...
		
		      (franz.+  3
		                (flet ((  ... and so on ....
				
				      (franz.+  4 1))))))
				
Such a translation is of course generally absurd, or at least of 
questionable utility.  At least it's possible to easily locate such 
absurdities (via the name "franz.+") and replace them by whatever 
the programmer really did intend.  As the translation is done via 
rewrite rules, it would of course be easy to replace such conservative 
translation by rules assuming a little "common sense" at the risk of 
occasional blunders.  

Whenever an expression translation is straightforward and the input 
may clearly be recognized in the output, simple replacement is done, 
rather than creating a temporary (flet) function such as "franz.+".  
Thus, e.g., "(typep ...)" is simply translated to "(type-of...)".  
Some expressions are simply untranslatable and a translation error 
is signalled.  Examples of such functions are UNIX system calls etc..

An example of a rewrite rule is:

	(typep type-of NIL
	       ((x)
	        `(type-of  ,x)))

	The items in this list are:
	1. The FL function name					typep
	2. The corresponding CL name or "nil" if no simple 	type-of
	   correspondance holds (used in translations of
	   "quote" and "function")
	3. A flag indicating whether ("t") or not ("nil") 	nil
	   the CL calling sequence is different from the FL
	   sequence (e.g. different argument order)
	   (used in translations of "quote" and "function")
	4. The parameter list of the FL function		(x)
	5. The translation rule proper			     `(type-of ,x)

The macros used as rewrite rules are local (similar to "macrolet"
definitions), so that there is no problem of interference with CL
names in the current environment that may be the same as Franz names
(but e.g. with different arguments).  

Aside from function (macro etc.) applications, special symbols are
translated via lookup in a separate table.  Thus, e.g., "errport"
is translated to "*error-output*".

Some general translation problems include: 

	* STATIC VS. DYNAMIC SCOPING: This is of course the single
	  biggest headache and FTOC makes no attempt to wrestle 
	  with the problem.  It is (wisely?) ignored; i.e. it must 
	  be dealt with manually.
	  
	* TYPE PREDICATES, after translation, refer to *CL* types.
	  E.g. Franz's "(bigp...)" is translated to CL's 
	  "(typep bignum...)".  

	* CODE WHICH CREATES CODE ETC.: Macros in the code may
	  optionally by expanded at translation time.  Otherwise,
	  code-creating code continues to create *Franz* code at 
	  execution time.
	  
	* FUNCTION NAMES AS ARGUMENTS ETC.: Translating mapped etc. 
	  named functions is straightforward as long as the function 
	  name itself may be simply translated.  Thus, "typep" goes
	  over into "type-of", but "+" has no single named function
	  equivalent.  Such translation of function names is done while
	  translating "quote" and "function" expressions.  If no
	  single name applies no translation of the name occurs and
	  a warning is issued.  

	* USER-DEFINED RESERVED NAMES: A Franz programmer may have
	  defined her own function or other object with a name which
	  is reserved (predefined) in CL (e.g. "write").  FTOC does
	  not currently check for such names.  Such detection could 
	  easily be added, but it would surely be costly in
	  translation time.  Such a check might better be done in a
	  separate pass only when it is suspected to be necessary.

Various modes of use of FTOC are available.

FTOC is made freely available for "test purposes", which means it
can be used, isn't guaranteed and won't be maintained by us and 
can't be sold, copied, distributed etc. by others.  The source is 
copyrighted.

Comments on and improvements to the program are welcomed.

----------
Drew ADAMS, Laboratoires de Marcoussis, Centre de Recherche de la Compagnie 
            Generale d'Electricite, Route de Nozay, 91460 MARCOUSSIS, FRANCE
            Tel. 64.49.11.54, adams@crcge1.cge.fr

-- 
Drew ADAMS, Laboratoires de Marcoussis, Centre de Recherche de la Compagnie 
            Generale d'Electricite, Route de Nozay, 91460 MARCOUSSIS, FRANCE
            Tel. 64.49.11.54, adams@crcge1.cge.fr