


			Manuel de rfrence ORICLISP

			   (C) F.Francs 1986,1995





			     Table des matires

I. Une introduction au langage LISP................................  2
  I.1 Syntaxe......................................................  3
  I.2 L'interprte.................................................  3
  I.3 Les fonctions prdfinies....................................  4
        a) QUOTE...................................................  4
        b) Les slecteurs CAR et CDR...............................  4
        c) Les constructeurs.......................................  5
        d) Les prdicats...........................................  5
        e) La conditionnelle et les structures de contrle.........  6
        f) L'arithmtique..........................................  6
        g) L'affectation...........................................  6
        h) La dfinition de fonctions..............................  7

II. Prsentation d'OricLisp........................................  8
  II.1 Principales caractristiques................................  8
  II.2 Premier contact.............................................  8
        a) L'cran et le clavier...................................  9
        b) L'dition de lignes.....................................  9
  II.3 Les primitives OricLisp..................................... 10
        a) QUOTE................................................... 10
        b) Les slecteurs.......................................... 10
        c) Les constructeurs....................................... 11
        d) Les prdicats........................................... 12
        e) La conditionnelle et les structures de contrle......... 13
        f) L'arithmtique.......................................... 14
        g) Les modifications physiques
	     et les fonctions  effet de bord...................... 15
        h) La dfinition de fonction............................... 17
  II.4 Concepts avancs............................................ 18
        a) Fonctions sans valuation............................... 18
        b) Macro-caractres........................................ 19
        c) Macro-fonctions......................................... 19
        d) Fonctions d'ordre suprieur............................. 21

A. Annexe A: Copyright............................................. 21
B. Annexe B: Dfinitions formelles................................. 22
C. Annexe C: Portage de programmes MuLisp.......................... 24
D. Annexe D: Dtails d'implmentation.............................. 26
        a) Carte mmoire........................................... 26
        b) Structures de donnes................................... 26
        c) La pile virtuelle....................................... 27
        d) Le ramasse-miettes...................................... 27
E. Annexe E: Exemple............................................... 28


								- 1 -








I. Une introduction au langage LISP
-----------------------------------

	LISP est un langage cr en 1964 par John MacCarthy pour traiter des
informations organises en arbres binaires (formules mathmatiques, phrases de
la langue naturelle, connaissances...). Ces arbres sont reprsents par des
listes en LISP (qui est une abrviation de LISt-Processing).
	La capacit de LISP  traiter des informations symboliques en a fait
un des "langages machine" de domaines de l'informatique tels que l'Intelligence
Artificielle, la Robotique, le Calcul Formel, la Thorie de la Programmation
(les preuves de programme par exemple), la thorie des jeux, les diteurs 
syntaxiques (type Emacs) et plus gnralement les environnements de programma-
-tion, etc.
	Pour le situer par rapport aux autres langages, on a l'habitude de
considrer trois familles de langages (certains langages sont bien sr 
l'intersection de ces familles): les langages impratifs comme Fortran, Pascal,
Cobol, Basic, Ada, C... o une suite d'ordres permet de converger vers la
solution; les langages dclaratifs comme Prolog o l'on se contente de dcrire
le problme (c'est une logique dductive qui permet d'aller vers la solution);
les langages fonctionnels et applicatifs comme LISP, ML, FP o l'on applique
des fonctions au sens mathmatique du terme (il n'y a plus de "variables" dans
le programme). On peut considrer que les premiers langages  objets comme
SmallTalk descendent de LISP, et on trouve aussi son influence dans le langage
LOGO.
	Hormis cette classification, les principales caractristiques des 
langages fonctionnels de la famille LISP sont les suivantes (il n'y a en effet
pas un mais des dialectes LISP: InterLisp, MacLisp, VLisp, LeLisp, MuLisp,
FranzLisp...):
	- ils procdent par composition de fonctions rcursives alors que les
langages classiques (impratifs) procdent par rptition de squences
d'affectation.
	- ils manipulent des arborescences et un programme est un arbre de mme
nature qu'un arbre de donnes (un programme peut donc tre trait par un autre
programme !)
	- ils sont structurs et modulaires (par composition de fonctions)
	- ils sont interactifs (le dialogue avec l'interprte permet de
construire les programmes de manire incrmentale)
	- la gestion de la mmoire est dynamique et automatique (grce  un
"ramasse-miettes" qui rcupre les donnes qui ne sont plus utilises)












								- 2 -


I.1 Syntaxe
-----------
	Un programme LISP est un arbre binaire, soit, comment donc le
reprsenter avec une suite de caractres ASCII ? Bien sr, il n'est pas question
de faire un dessin, alors il a t choisi d'utiliser les parenthses, l'espace
et le point pour reprsenter ces arborescences. Ds que l'on aura remarqu que 
les deux branches d'un arbre binaire sont elles-mmes des arbres, on acceptera
sans peine la reprsentation suivante dite "paire pointe":  ( S1 . S2 )
o S1 et S2 sont aussi soit des paires pointes soit des feuilles de l'arbre,
que l'on appelle des "atomes".
	Les atomes, comme en physique, sont donc les lments constitutifs et
deux sortes sont distingues : les nombres entiers (parfois aussi des rels) et
les "symboles" qui sont des identificateurs et jouent le rle de donnes
abstraites. Par exemple, deux symboles sont utiliss pour reprsenter les
boolens classiques : NIL pour "Faux" et T pour "Vrai" (bien que tout ce qui
n'est pas NIL est aussi "Vrai"). De plus, NIL sert aussi pour dnoter le "Vide",
la liste vide plus prcisment...
	Puisque nous voquons le terme de "liste", prcisons que les listes sont
des arbres particuliers (les arbres sont appels "S-expressions" en LISP) : il a
t choisi de faire porter le premier lment d'une liste par la partie gauche
de la paire pointe et la suite de la liste par la partie droite, ce qui fait
qu'une liste de fruits s'crirait,  l'aide de paires pointes :
( pomme . ( poire . ( abricot . nil ) ) )
	Les listes sont tellement courantes que la notation ci-dessus est peu
pratique et l'on a bien sr une premire criture abrge :
	( pomme poire abricot . nil )
C'est une simplification d'criture qui donne une signification spciale
 la sparation par des espaces  l'intrieur de parenthses. On abrge encore
cette criture en donnant la signification de fin de liste au symbole NIL avec :
	( pomme poire abricot )
Voil qui est bien plus simple ! Mais pour compliquer un peu, rappelons
qu'une liste est une S-expression; rien n'empche donc un ou des lments d'une
liste d'tre eux-mmes des listes... Par exemple,
	( marcel (age 20) (enfants (lucie (age 2)) (alain (age 1)) ) )
est une liste de 3 lments ! Le premier est un atome, le second une liste de
deux atomes, le troisime une liste d'un atome et de deux listes... on commence
 comprendre que savoir compter les parenthses va tre important !

I.2 L'interprte
----------------
	Comment ? On change de paragraphe sans donner la syntaxe des programmes
LISP ? Eh oui, si vous savez construire des listes, vous savez programmer !
Un programme LISP, c'est une S-expression, disons plutt un atome ou une liste,
que l'interprte va "valuer". Par exemple, si vous donnez un nombre  valuer
 l'interprte, il vous renverra ce mme nombre (facile...). Si vous donnez un
symbole  valuer, l'interprte retournera la "valeur" de ce symbole s'il en a
une, par exemple : MON_DOCTEUR pourrait s'valuer en 
	(Dugenou Leon (23 chemin du cubitus))
Enfin, si vous donnez une liste  valuer, l'interprte considrera que le
premier lment de la liste est une fonction et que les autres lments sont les
arguments donns  la fonction. Par exemple : 
	(+ 2 2) renverra 4
	(CAR MON_DOCTEUR) renverra Dugenou, on verra en effet plus loin que CAR
est une fonction qui renvoie le premier lment d'une liste.



								- 3 -


	L'interprte LISP peut donc tre dcrit par l'application successive des
trois fonctions suivantes :
- READ qui lit une S-expression (nous dirons par la suite une expression pour 
simplifier) au clavier ou depuis un fichier.
- EVAL qui value la valeur d'une expression.
- PRINT qui affiche une expression sur l'cran ou dans un fichier.
Selon le dialecte LISP utilis, cet interprte peut tre une fonction standard
(TOPLEVEL ou DRIVER ou autre), dont la dfinition contient une composition des
trois fonctions prcdentes : (PRINT (EVAL (READ)))
On remarque que les arguments tant valus avant d'tre passs aux fonctions,
c'est la fonction READ qui est invoque d'abord, son rsultat est pass  la
fonction EVAL, et le rsultat d'EVAL est envoy  PRINT ! (on verra que la
plupart des fonctions valuent leurs arguments, c'est l'appel par valeur, seules
quelques fonctions ne les valuent pas, comme les structures de controles, on
parle alors d'appel par nom).
	C'est donc la fonction EVAL qui est au coeur du langage LISP: lorsque
vous demandez (+ 2 2), c'est elle qui invoquera le code de la fonction addition.


I.3 Les fonctions prdfinies
-------------------------
	Tous les dialectes LISP partagent un mme noyau minimal de fonctions qui
est suffisant pour crire n'importe quel programme. Les dialectes se diffren-
-cient par des jeux de fonctions tendus, plus ou moins riches, qui permettent
d'crire les programmes de manire plus concise. Nous dcrivons ici un noyau
minimal:

a) QUOTE
--------
	QUOTE est une fonction qui permet de protger son argument de l'valua-
-tion. Elle n'value donc pas son argument et le renvoie tel quel en rsultat.
Exemple:
	(QUOTE (+ 2 2))    -->    (+ 2 2)
Son usage trs courant fait qu'une abrviation a t dfinie :
	'A     -->   A
	'(CAR MON_DOCTEUR)    -->   (CAR MON_DOCTEUR)

Pour les curieux, le caractre ' est un "macro-caractre", c.a.d que c'est en
fait une fonction qui s'value ds qu'elle est rencontre dans le flot de
caractres venant du clavier (l'action du macro-caractre ' est d'invoquer la
fonction READ pour lire l'expression suivante, puis de construire une liste avec
QUOTE en premier lment et cette expression en second lment, et enfin de
renvoyer cette liste !)


b) Les slecteurs CAR et CDR
----------------------------
	Ces fonctions valuent leur argument, CAR prend la partie gauche de la
paire pointe donne en argument et CDR la partie droite (les noms de ces
fonctions viennent hlas de l'appellation A et D de registres de la premire
machine ayant implment LISP...)
Exemple:
	(CAR '(+ 2 3))    -->  +
	(CAR '((A B) C))  -->  (A B)
	(CDR '(+ 2 3))    -->  (2 3)
	(CDR '((A B) C))  -->  (C)

								- 4 -


Suivant les dialectes LISP, appliquer la fonction CAR  un atome peut renvoyer
une erreur ou la valeur de cet atome. De mme, la fonction CDR applique  un
atome peut retourner une erreur ou une liste de proprits associes  l'atome
(ces deuximes possibilits permettent d'appliquer CAR et CDR  n'importe quelle
expression LISP, mais il vaut mieux rserver ces fonctions aux paires pointes 
(listes ou arbres) par souci de portabilit).



c) Les constructeurs
--------------------
	CONS est la fonction constructeur de base : elle construit une paire
pointe  partir de deux expressions.
Exemple:
	(CONS 'A 'B)       -->  (A.B)
	(CONS 'A '(B C))   -->  (A B C)
	(CONS '(A B) '(C)) -->  ((A B) C)
	(CONS 'A NIL)      -->  (A)
	(CONS NIL '(A))    -->  (NIL A)

LIST existe toujours pour simplifier la construction de listes de longueur
quelconque. La fonction LIST accepte un nombre quelconque d'arguments.
Exemple:
	(LIST 'a 'b 'c 'd)    -->  (a b c d)
	(LIST 'a '(b c) 'd)   -->  (a (b c) d)


d) Les prdicats
----------------
	Ce sont des fonctions renvoyant une valeur boolenne (NIL reprsente la
valeur "Faux", tout autre rsultat est "Vrai"), elles valuent leurs arguments.
ATOM 	renvoie T si son argument est un atome,    sinon NIL.
NUMBERP	renvoie T si son argument est un nombre,   sinon NIL.
CONSP	renvoie T si son argument est une liste,   sinon NIL.
NULL	renvoie T si son argument est NIL,         sinon NIL.
EQUAL	renvoie T si ses arguments sont gaux,     sinon NIL.
EQ	renvoie T si ses arguments sont les mmes, sinon NIL.

Ces deux derniers mritent une petite explication: EQ teste si les deux objets
donns en argument ne font qu'un en mmoire (galit physique) tandis que EQUAL
compare toutes les branches des objets pour vrifier qu'ils ont mme reprsenta-
-tion externe.
Exemple:
	(ATOM 'A)       -->  T
	(ATOM '(A))     -->  NIL
	(ATOM '())      -->  T  en effet, () est la liste vide reprsente par
				l'atome NIL !
	(NULL 'A)	-->  NIL
	(NULL '(A))	-->  NIL
	(NULL NIL)	-->  T
	(EQUAL '(A (B C) D)  '(A (B C) D))	-->  T
	(EQ    '(A (B C) D)  '(A (B C) D))	-->  NIL
	(EQUAL 'A 'A)	-->  T
	(EQ    'A 'A)	-->  T	car les atomes sont prsents de manire unique
				en mmoire...


								- 5 -


e) La CONDitionnelle
--------------------
	COND accepte en paramtre un nombre quelconque de clauses (non values)
de la forme "(prdicat expression)". COND n'value pas ses arguments  priori,
mais value squentiellement les prdicats dans les clauses jusqu' en trouver
un "Vrai" (non NIL), dans ce cas il value l'expression associe dans la clause 
et la renvoie en rsultat. Sinon (tous les prdicats ont t valus  NIL), 
COND renvoie NIL.
Exemple:
	(COND ((EQ 'A 'A) 'OUI))  -->  OUI
	(COND ((EQ 'A 'B) 'OUI))  -->  NON
	(COND	((EQ 'A 'B) 'OUI)
		(T	    'NON))       -->  NON
			ce qui montre l'utilisation de T comme dernier prdicat,
			mais on peut s'en passer comme suit :
	(COND	((EQ X 1) 'PREMIER)
		((EQ X 2) 'DEUXIEME)
		((EQ X 3) 'TROISIEME)
		(         'AUTRE))    --> PREMIER, DEUXIEME, TROISIEME ou AUTRE
					suivant la valeur de X...



f) L'arithmtique
-----------------
	Les noms de fonction varient d'un dialecte  un autre, mais on trouvera
toujours les 4 oprations et des prdicats d'ordre.
Exemple:
	(- 239 (* 7 (/ 239 7)))    -->  1
	(< 3 7)			   -->  T



g) L'affectation
----------------
	Pour les puristes, c'est une horreur comme un GOTO dans un langage
structur. En pratique, on rserve souvent son usage au niveau le plus haut d'un
programme pour associer un nom  une valeur, comme on peut le faire en mathma-
-tique, mais on se garde de modifier cette association (les symboles ne sont
pas des variables !) pour viter les effets de bord.
Exemple:
	(SETQ A '(1 2 3))       -->  (1 2 3)
	A			-->  (1 2 3)
SETQ n'value pas son premier argument (symbole), et renvoie son second argument
aprs l'avoir associ au symbole. SET est encore plus dangereux car il value
aussi le premier argument:
	(SETQ B 'A)	-->  A
	B		-->  A
	(SET B '(A B))	-->  (A B)
	B		-->  A
	A		-->  (A B)






								- 6 -


h) La dfinition de fonctions
-----------------------------
	Une fonction LISP est une expression de la forme
		(LAMBDA (param1 param2 ... paramN) expr)
o param1, param2 ... paramN sont les noms des paramtres formels et expr le
corps de la fonction.
Exemple:
	(LAMBDA (X) X)	est la fonction identit (elle renvoie son argument)
	(LAMBDA (X Y)
	  (COND	((ATOM X) (CONS X Y))
		(T	  (CONS (CAR X) Y))))
			est une fonction qui rajoute X en tte de la liste Y si
			X est un atome, sinon rajoute le CAR de X en tte de la
			liste Y.

La manire d'associer une dfinition de fonction  un nom n'est pas standard,
LeLisp utilise la fonction DE (par exemple: "(DE IDENTITE(X) X)" ), VLisp range
la dfinition dans la liste de proprit d'un atome, d'autres associent la
dfinition  la valeur d'un atome. Pour la suite, nous utiliserons la fonction
MuLisp PUTD.
Exemple:
	(PUTD 'IDENTITE '(LAMBDA(X) X))
En MuLisp, les atomes ont par dfaut pour valeur eux-mmes, ce qui permet de
supprimer l'apostrophe (quote) devant le nom de fonction lorsque aucune valeur
ne lui est associe. Allez, quelques classiques :

	(PUTD LENGTH
	  '(LAMBDA (X)
	     (COND ((NULL X) 0)
		   (T	     (+ 1 (LENGTH (CDR X))))
	)  ) )
		calcule la longueur d'une liste: (LENGTH '(A B C)) --> 3
	(PUTD MEMBER
	  '(LAMBDA (X L)
	     (COND ((NULL L)          NIL)
		   ((EQUAL X (CAR L)) T)
		   (T		      (MEMBER X (CDR L)))
	)  ) )
		cherche si une expression est prsente dans une liste :
			(MEMBER '(A B) '(A B (A (A B)) (B A) (A B))  --> T
		car on trouve (A B) en quatrieme position.
	(PUTD FACT
	  '(LAMBDA (N)
	     (COND ((EQ N 0) 1)
		   (T        (* N (FACT (- N 1))))
	)  ) )
		calcule la factorielle d'un nombre...










								- 7 -


II. Prsentation d'OricLisp
---------------------------
	OricLisp est un dialecte LISP inspir de LeLisp (Jrme Chailloux) pour
les fonctions dfinies par l'utilisateur (LAMBDA, FLAMBDA, MLAMBDA, cf plus bas)
et de MuLisp (Albert D.Rich, David R.Stoutemyer, Roy Feldman) pour tout le reste
mme si l'implmentation est trs diffrente (MuLisp a t implment sur les
processeurs Intel 8080 et 8086).
Un nombre relativement faible de fonctions sont prdfinies (plus de 60 tout de
mme !) afin de laisser le maximum d'espace disponible  l'utilisateur, mais
ses caractristiques puissantes permettent de dvelopper des applications trs
consquentes.
	OricLisp a t crit en 1986 (mais ce manuel ne l'a suivi qu'en 1995 !).



II.1 Principales caractristiques:
----------------------------------
* sauvegarde d'images mmoire permettant de reprendre une session au point
exact o elle a t sauve, ou d'enrichir le langage par des dfinitions
personnalises, ou de produire des applications Lisp dmarrant automatiquement.
* arithmtique entire sur 32 bits, exprime dans une base arbitraire (de la
base 2  la base 36)
* symboles de taille arbitraire (jusqu' 256 caractres) et pouvant comporter
n'importe quel caractre ascii (mme l'espace). Les symboles peuvent ainsi
jouer le rle de chanes de caractres.
* pile virtuelle segmente permettant au processeur d'utiliser une pile de prs
de 3 Ko avec la rapidit de la pile habituelle de 256 octets.
* espace utilisateur important avec en standard 16 Ko pour les paires pointes
et les chanes de caractres (soit plus de 4000 paires pointes), et prs de 
12 Ko pour les atomes. Cette rpartition peut tre change.
* ramasse-miettes transparent pour l'utilisateur, compactant tous les espaces
utilisateurs (chanes, paires, nombres, symboles).
* fonctions valuant ou n'valuant pas leurs arguments, plus macro-fonctions
et macro-caractres !
* espace clos de pointeurs et donnes types par leur adresse pour une plus
grande efficacit.



II.2 Premier contact :
----------------------
	Taper CLOAD"ORICLISP" depuis le Basic 1.1 de l'Oric pour charger et
excuter le systme (ou LOAD"ORICLISP" pour un systme  disquettes, mais
attention, les images mmoires ne sont sauves que sur cassette). La ligne
suprieure de l'Oric affiche le copyright, et le prompt "point d'interrogation"
signale que le systme attend des caractres taps au clavier. Entrer des 
expressions montre que l'interprte est actif:
Exemple:
	? 'HELLO
	=HELLO
	? (+ 2 2)
	=4





								- 8 -


a) L'cran et le clavier
------------------------
	Pour plus de rapidit, les routines d'crans ont t redfinies, elles
permettent de travailler avec 38 ou 40 colonnes et affichent sur la totalit des
28 lignes en mode rouleau avec une routine de dfilement rapide.
	La scrutation du clavier s'adapte au travail de l'utilisateur: lorsqu'il
est en phase d'entre de caractres, elle est effectue tous les 3/100e de
seconde, alors qu'elle n'est effectue qu'une fois par seconde lorsque le
systme calcule, et une fois tous les 1/10e de seconde lorsque le systme
affiche. Ceci permet d'allier performance et confort d'utilisation, un programme
peut toujours tre stopp en cours de calcul par un Ctrl-C (appuy 1 seconde)
et gagne ainsi environ 15% en vitesse d'excution.



b) L'dition de lignes
----------------------
	Elle est trs diffrente de celle du Basic et gre un buffer de 128
caractres (plus de 3 lignes cran). La dernire entre (termine par la touche
RETURN) est conserve dans le buffer pour permettre une correction aise de 
celle-ci.
	Deux modes sont grs: insertion et suppression, par dfaut le mode
suppression est actif et Ctrl-I permet de basculer du mode suppression au mode
insertion et vice-versa.
	En mode suppression, tout caractre ASCII tap vient remplacer le
caractre qui occupe la mme position dans le buffer (donc remplace un caractre
de l'entre prcdente).
	En mode insertion, tout caractre ASCII tap vient s'insrer  la
position courante du buffer, dcalant ainsi vers la droite le reste du buffer.
	Le dernier caractre ASCII (127) a une signification spciale puisqu'il 
s'agit de DEL qui dtruit le dernier caractre tap (et revient donc une 
position plus  gauche dans le buffer). Deux caractres de contrle sont dfinis
en plus de la bascule insertion/suppression pour utiliser l'entre prcedente
conserve dans le buffer :
	- Ctrl-A rcupre en effet le caractre courant de l'entre prcdente,
laisser un Ctrl-A appuy permet de recopier une entre jusqu'au dernier
caractre dsir.
	- Ctrl-D dtruit le prochain caractre du buffer. Le rsultat de cette
action est malheureusement invisible pour l'utilisateur (tant qu'il n'entre pas
un Ctrl-A).

Exemple: supposons que l'utilisateur ait tap la ligne suivante:
	? (PUTD FACT '(LAMBDA(N) COND ((EQ N 0) 1)) (T (* N (FACT (- N 1))))))
	=(LAMBDA(N) COND ((EQ N 0) 1))
Il s'aperoit alors sans peine qu'il a oubli une parenthse ouvrante avant le
COND et tap une parenthse de trop aprs la premire clause. Pour corriger son
entre, il suffit qu'il appuie sur Ctrl-A jusqu' ce que
	? (PUTD FACT '(LAMBDA(N)
soit affich, puis passer en mode insertion avec Ctrl-I, taper une parenthse
ouvrante, de nouveau enfoncer Ctrl-A jusqu' ce que
	? (PUTD FACT '(LAMBDA(N) (COND ((EQ N 0) 1)
soit affich, puis dtruire la parenthse fermante superflue de l'entre
prcdente par Ctrl-D, et terminer en laissant Ctrl-A enfonc...




								- 9 -


II.3 Les primitives OricLisp
----------------------------

a) QUOTE
--------
la fonction QUOTE classique, protge son argument de l'valuation.
		? (QUOTE (+ 2 2))
		=(+ 2 2)
Remarque : le macro-caractre ' a le mme effet
		? '(+ 2 2)
		=(+ 2 2)


b) Les slecteurs
-----------------
* les slecteurs CAR et CDR sont prsents, ainsi que les compositions de 2 ou 3
CAR ou CDR (par exemple, "(CADR X)" est l'quivalent de "(CAR (CDR X))" ).
OricLisp possde un espace clos de pointeurs, on peut toujours appliquer un CAR
ou un CDR sans erreur; dans le cas d'un atome, CAR renvoie la valeur associe 
l'atome et CDR la liste de proprits associe  l'atome. La valeur d'un symbole
est par dfaut lui-mme (tant qu'aucune valeur ne lui a t lie), celle d'un
nombre est toujours le mme nombre. La liste de proprits d'un symbole est vide
par dfaut (elle vaut NIL), celle d'un nombre reflte son signe : T pour un
nombre positif ou nul, NIL pour un nombre ngatif.
Exemple:
	? (CAR '(A.B))
	=A
	? (CADR '(A B C))
	=B
	? (CDDR '(A B C D))
	=(C D)

* LAST renvoie la dernire paire pointe de premier niveau de son argument (et
non le dernier lment) ou NIL si l'argument est un atome. Renvoyer la dernire
paire pointe plutt que le dernier lment permet de modifier cette paire
pointe (pour ajouter en fin de liste avec RPLACD par exemple, mais attention
aux effets de ces modifications physiques), et le dernier lment peut tre
facilement obtenu avec un CAR supplmentaire.
Exemple:
	? (LAST '(A B C D))
	=(D)
	? (LAST '(A B.C))
	=(B.C)
	? (CAR (LAST '(A B C D)))
	=D


* ASSOC cherche le premier argument (la clef) dans la A-liste fournie par le
deuxime argument. Une A-liste (liste associative) est une liste de la forme
	((clef1.val1) (clef2.val2) ... (clefN.valN))
ASSOC compare (avec EQUAL) le premier argument avec chacune des clefs (les
lments atomiques de la A-liste sont sauts) et renvoie l'lment complet de
la premire comparaison avec succs, sinon NIL. Certains Lisp ne renvoient que
la partie valeur de la paire pointe, il suffit de rajouter un CDR pour obtenir
le mme rsultat (tandis que renvoyer l'ensemble permet de modifier la valeur
associe  la clef).

								- 10 -


Exemple:
	? (ASSOC 'MARTIN '((DUPONT JEAN 61586273) (MARTIN JACQUES 61483922)
				(DUPONT ALAIN 61289019)))
	=(MARTIN JACQUES 61483922)

* MEMBER cherche (avec EQUAL) le premier argument dans la liste fournie par le
second argument et renvoie la fin de liste commenant  l'lment trouv, ou
NIL s'il n'est pas trouv. Certains Lisp ne renvoient qu'une valeur boolenne T
ou NIL, ici le rsultat peut servir (pour dtruire l'lment de la liste, par
exemple).
Exemple:
	? (MEMBER '(MARTIN JACQUES 61483922)
		  '((DUPONT JEAN 61586273) (MARTIN JACQUES 61483922)
				(DUPONT ALAIN 61289019)))
	=((MARTIN JACQUES 61483922) (DUPONT ALAIN 61289019)))


c) Les constructeurs
--------------------
* CONS construit une paire pointe avec les deux arguments fournis.
Exemple:
	? (CONS 'A 'B)
	=(A.B)
	? (CONS 'A '(B C))
	=(A B C)

* LIST construit une liste avec tous les arguments fournis.
	? (LIST 'a '(b c) 'd)
	=(a (b c) d)

* OBLIST construit une liste de tous les symboles
	? (OBLIST)
	=(LAST OBLIST DIV MOD ................... LAMBDA T NIL)

* APPEND construit une liste qui est la concatnation des deux listes passes
en argument. De nouvelles paires pointes sont cres pour le dbut de cette
liste, contrairement  NCONC. Remarque : APPEND avec un seul argument peut tre
utilis pour copier une liste.
	? (APPEND '(A (B C) D) '(E F (G H)))
	=(A (B C) D E F (G H))

* REVERSE construit une nouvelle liste qui est une liste renverse de son
premier argument (l'implmentation utilise un deuxime paramtre pour cumuler
le rsultat partiel. De ce fait, si un deuxime argument est fourni, il sera
concatn  la liste renverse)
	? (REVERSE '(A (B C) D))
	=(D (B C) A)
	? (REVERSE '(A (B C) D) '(E F))
	=(D (B C) A E F)

* GC n'est pas un constructeur comme CONS, LIST, OBLIST, APPEND ou REVERSE. Mais
il intervient lui aussi dans la gestion de l'espace mmoire. Tous les construc-
-teurs font appel  CONS pour allouer une paire pointe. Lorsque plus aucune
paire ne peut tre alloue, le ramasse-miettes (Garbage Collector) est invoqu
automatiquement. Il peut aussi tre appel explicitement avec la fonction GC.


								- 11 -


d) Les prdicats
----------------
* EQUAL renvoie T si ses deux arguments sont gaux. Toutes les branches sont
compares.
	? (EQUAL '(A (B C) D) '(A (B C) D))
	=T

* EQ renvoie T si ses deux arguments ne sont qu'un mme objet en mmoire. Il ne
peut exister deux symboles de mme nom. Il peut exister plusieurs nombres de
mme valeur mais EQ considre que ce sont les mmes. Lorsque l'on partage des
paires pointes, EQ est un test intressant, parce qu'il est trs rapide (il ne
regarde pas les branches)
	? (EQ '(A (B C) D) '(A (B C) D))
	=NIL

* ATOM renvoie T si son argument est un atome (donc pas une paire pointe)
	? (ATOM 'A)
	=T
	? (ATOM '(A B))
	=NIL
	? (ATOM '())
	=T

* NULL renvoie T si son argument est NIL (la liste vide)
	? (NULL 'A)
	=NIL
	? (NULL '(A B))
	=NIL
	? (NULL '())
	=T

* PLUSP renvoie T si son argument est un nombre positif ou nul.
	? (PLUSP 0)
	=T
	? (PLUSP 'A)
	=NIL

* MINUSP renvoie T si son argument est un nombre ngatif
	? (MINUSP -3)
	=T
	? (MINUSP '(A B))
	=NIL

* ZEROP renvoie T si son argument est le nombre 0
	? (ZEROP NIL)
	=NIL
	? (ZEROP 0)
	=T

Remarque : n'importe quelle expression peut servir de prdicat puisque toute
valeur non NIL est considre comme "Vrai". Par exemple, T est le prdicat
toujours vrai, utile pour la dernire clause d'une conditionnelle.





								- 12 -


e) La conditionnelle et les structures de contrle
--------------------------------------------------
* COND est la conditionnelle classique de la forme suivante :
	(COND (pred1 exp11 exp12 ... exp1N)
	      (pred2 exp21 exp22 ... exp2M)
		....
	)
Chaque prdicat pred1, pred2 ... est valu squentiellement jusqu' trouver
une valeur non NIL pour un prdicat predI, alors les expressions associes
expI1, expI2... sont values en squence, la dernire donnant la valeur de
retour du COND (si aucune expression n'est associe au prdicat, c'est la valeur
du prdicat qui est renvoye). Avoir plusieurs expressions au lieu d'une  la
suite du prdicat n'est utile que si les expressions ont des effets de bord.
Exemple:
	? (COND ((< A B) A) (B)) renvoie le minimum des nombres A et B

* PROGN value squentiellement tous ses arguments et renvoie la valeur du
dernier. PROGN n'a d'intrt que si les expressions font des effets de bord et
peut tre gnralement omis du fait du PROGN implicite dans les dfinitions de
fonction et dans la conditionnelle COND.
Exemple:
	? (PROGN (PRIN '(FACT 5)) (FACT 5))
	(FACT 5)=120

* PROG1 value squentiellement tous ses arguments et renvoie la valeur du
premier. Son usage est de mme li aux effets de bord.
Exemple:
	? (SETQ A (PROG1 B (SETQ B A))) change les valeurs associes  A et B

* AND est  la fois le "et" logique classique et une structure de contrle
(quivalente  des "si...alors..." imbriqus). Les arguments sont valus en
squence jusqu' ce qu'une valeur NIL soit trouve, auquel cas le rsultat est
NIL et les arguments suivants sont "court-circuits". Si tous les arguments
s'valuent  une valeur non NIL, la valeur du dernier est renvoye, le rsultat
est donc "Vrai".
Exemple:
	? (AND (ZEROP 1) (PRINT 'ARGH))
	=NIL	et on remarque que le deuxime argument n'est pas valu
	? (AND A B C) est quivalent  (COND (A (COND (B (COND (C))))))

* OR est  la fois le "ou" logique classique et une structure de contrle (une
suite de "si...alors...sinon si"). Les arguments sont valus en squence
jusqu' ce qu'une valeur non NIL soit trouve (cette valeur est alors retourne
et l'valuation des arguments restants est court-circuite). Si tous les
arguments sont NIL, NIL est renvoy.
Exemple:
	? (OR NIL '() 'A (PRINT 'ARGH))
	=A
	? (OR A B C) est quivalent  (COND (A) (B) (C))

* NOT est le "non" logique (ce n'est pas une structure de contrle mais il
permet d'inverser la signification de prdicats) et renvoie T si son argument
est NIL, sinon NIL. NOT est donc identique au prdicat NULL.
Exemple:
	? (NOT NIL)
	=T

								- 13 -


* WHILE est une structure de contrle de style impratif de la forme
	(WHILE pred exp1 exp2 ... expN)
Tant que pred s'value  "Vrai" (non NIL), WHILE itre sur l'valuation de exp1,
exp2 ... expN (il faut donc ncessairement un effet de bord pour que la valeur
de pred devienne NIL). WHILE est implment sans rcursivit et permet donc des
boucles importantes (ou infinies) sans saturation de la pile.
Exemple:
	? (WHILE T (PRINT (EVAL (READ)))
		une boucle infinie pour un nouvel interprte !
	? (WHILE (NOT (ZEROP N)) (SETQ N (- N 1)))
	=NIL
		dcrmente N jusqu' 0



f) L'arithmtique
-----------------
* RADIX change la base pour la reprsentation des nombres entrs au clavier et
affichs  l'cran. La nouvelle base est donne en argument et doit tre
comprise entre 2 et 36 (au del de la base 10, jusqu' 26 lettres peuvent tre
employes). RADIX renvoie la nouvelle base en rsultat (mais on peut remarquer
que l'affichage d'une base est toujours "10"). Si un argument non numrique est
fourni, la base n'est pas change et est renvoye en rsultat.
Exemple:
	? (RADIX 8)
	=10
	? (+ 6 7)
	=15
	? (RADIX 12)
	=10
	? (+ 6 7)
	=13


* les 4 oprations entires sont +,-,*,/. Elles prennent deux nombres en
argument et renvoient le rsultat. Une erreur NONNUMERIC est leve si un
oprande n'est pas un nombre et l'erreur DIVBYZERO est leve en cas de division
par 0. / renvoie le quotient de la division entire tandis que MOD renvoie le
reste. Souvent, quotient et reste sont tous deux utiles, DIV permet de ne faire
qu'une fois la division et renvoie un paire pointe (quotient.reste)
Exemple:
	? (DIV 10 3)
	=(3.1)


* les prdicats d'ordre sont < et >. Ils renvoient T si l'ordre est vrifi
entre les deux arguments et NIL sinon. Les comparaisons au sens large (galit
incluse) ne sont pas des primitives, il faut inverser le test.
Exemple:
	? (NOT (< A B))
		renvoie T si A>=B, et NIL sinon.






								- 14 -


g) Les modifications physiques et les fonctions  effet de bord
---------------------------------------------------------------

* SETQ lie la valeur fournie par le second argument au symbole spcifi par
le premier (le premier argument n'est pas valu). Si le symbole tait local
 une fonction, la liaison est perdue  la sortie de la fonction.
Exemple:	
	? (SETQ A '(1 2))
	=(1 2)
	? A
	=(1 2)
	? (SETQ A 'B)
	=B
	? A
	=B


* SET lie la valeur fournie par le second argument au symbole spcifi par le
premier (les deux arguments sont valus).
Exemple:
	? (SETQ A 'B)
	=B
	? (SET A 3)
	=3
	? B
	=3
	? A
	=B


* RPLACA et RPLACD remplacent respectivement le CAR et le CDR de la paire 
pointe donne en premier argument par le deuxime argument, et renvoient la 
paire modifie.
Exemple:
	? (SETQ A '(1 2))
	=(1 2)
	? (RPLACA A 0)
	=(0 2)
	? A
	(0 2)
	? (RPLACD A '(3 4))
	=(0 3 4)
	? A
	(0 3 4)


* NCONC est la concatnation de liste, comme APPEND mais sans consommation de
paire pointe. NCONC modifie la fin de la liste donne par son premier argument
pour lui faire suivre la deuxime liste.
Exemple:
	? (SETQ A '(1 2))
	=(1 2)
	? (NCONC A '(3 4 5))
	=(1 2 3 4 5)
	? A
	=(1 2 3 4 5)

								- 15 -


* MEMORY permet de lire ou d'crire un octet en mmoire. Si un seul argument est
donn, c'est une adresse dont MEMORY renverra le contenu. Si deux arguments
numriques sont donns, MEMORY change l'adresse mmoire avec l'octet donn en
second argument, et renvoie l'ancienne valeur.
Exemple:
	? (RADIX 16)
	=10
	? (MEMORY 26B 1)
	=7	change la couleur de papier...

* TIME renvoie la valeur d'une horloge en 1/100e de secondes et peut donc servir
 mesurer le temps d'excution d'un programme.
Exemple:
	? (SETQ T1 (TIME)) (GC) (- (TIME) T1)
	=5

* PRINT affiche l'expression donne en paramtre, et retourne cette expression
en rsultat. PRIN fait la mme chose mais sans terminer par un retour charriot.
Exemple:
	? (PRINT 'HELLO)
	HELLO
	=HELLO
	? (PRINT '(A (B C) D))
	(A (B C) D)
	=(A (B C) D)
	? (PRIN 0)
	0=0

* READ lit une expression au clavier et la renvoie en rsultat. Si plus d'une
expression est donne, les autres restent dans le buffer clavier  la disposi-
-tion d'un READ ultrieur.
Exemple:
	? (PRIN '(+ 2 2)) (+ 2 2)
	(+ 2 2)=(+ 2 2)
	=4
	? (SETQ A (READ)) (+ 2 2)
	=(+ 2 2)
		On remarque que (+ 2 2) n'a pas t lu par l'interprte mais
		bien par le READ.

* SAVE produit sur cassette une image mmoire du nom de l'argument donn en
paramtre. Il n'y a pas de fonction LOAD, une image mmoire contient le noyau
OricLisp et dmarre automatiquement au point exact du SAVE en tapant la commande
CLOAD du Basic de l'Oric.
Exemple:
	? (PROGN (SAVE 'IMAGE1) 'HELLO)
	=HELLO	et un fichier IMAGE1 est crit sur cassette que l'on lancera
		depuis le Basic :
	CLOAD"IMAGE1"
	=HELLO
	?






								- 16 -


h) La dfinition de fonction
----------------------------
* Une fonction OricLisp valuant ses arguments est une expression de la forme
	(LAMBDA (param1 ... paramN) exp1 exp2 ... expM)
o param1 ... paramN sont les noms des paramtres formels et exp1, exp2 ... expM
le corps de la fonction (l'valuation d'une LAMBDA comporte donc un PROGN
implicite).
Exemple:
	(LAMBDA () (/ (TIME) 100))
		une fonction sans paramtres qui renvoie l'horloge en secondes
	(LAMBDA (N) (+ N 1))
		une fonction qui renvoie le nombre successeur de son argument

Attention ! le deuxime lment de la liste de la fonction (les paramtres
formels) doit imprativement tre une liste (ventuellement vide).

Les LAMBDA sont des fonctions "sans nom" qui peuvent tre utilises de la mme
faon que les primitives du langage.
Exemple:
	? ( (LAMBDA(N)(+ N 1)) 3)
	=4
Pour associer un nom  une LAMBDA, on utilise la primitive PUTD.
	? (PUTD 'INCR '(LAMBDA(N)(+ N 1)))
	=(LAMBDA (N) (+ N 1))
	? (INCR 3)
	=4
Remarque : un symbole peut simultanment avoir une valeur, une liste de
proprits et une dfinition de fonction associes.
Exemple:	
	? (SETQ INCR '(1 2))
	=(1 2)
	? (INCR 3)
	=4
	? INCR
	=(1 2)

* GETD permet de lire la dfinition de fonction d'un symbole. GETD renvoie la
LAMBDA d'une fonction dfinie en LISP, T pour une fonction en langage machine
et NIL si la fonction n'est pas dfinie.
Exemple:
	? (GETD 'T)
	=NIL
	? (GETD 'EVAL)
	=T
	? (GETD 'INCR)
	=(LAMBDA (N) (+ N 1))

* MOVD permet de copier la dfinition de fonction d'un symbole dans un autre
symbole, dfinissant un synonyme pour une fonction sans consommer d'espace
mmoire supplmentaire (en dehors du symbole).
Exemple:
	? (MOVD 'APPEND 'COPY)
	=T
	? (COPY '(A B (C D) E))
	=(A B (C D) E)


								- 17 -


II.4 Concepts avancs
---------------------


a) Fonctions sans valuation
----------------------------

	OricLisp permet de dfinir des fonctions n'valuant pas leurs
arguments, une telle fonction est de la forme
	(FLAMBDA param exp1 exp2 ... expM)
Un seul symbole est fourni en paramtre formel, il sera li  la liste de tous
les paramtres non-valus.
Les fonctions n'valuant pas leurs arguments permettent de dfinir de
nouvelles structures de contrle (elles sont parfois aussi utilises
pour dfinir des fonctions dont le nombre de paramtres est indtermin)
Exemple:
	(FLAMBDA L
	  (COND ((EVAL (CAR L)) (EVAL (CADR L))) 
		(T              (EVAL (CADDR L)))
	) )				dfinit un IF X THEN Y ELSE Z !!
que l'on liera bien sr de la faon suivante:
	? (PUTD 'IF '(FLAMBDA L
	?              (COND ((EVAL (CAR L)) (EVAL (CADR L)))
	?                    (T              (EVAL (CADDR L))) )))
	=(FLAMBDA L (COND ((EVAL (CAR L))(EVAL (CADR L))) (T (EVAL (CADDR L)))))
	? (IF NIL (PRINT 'ARGH) (PRINT 'OK))
	OK
	=OK	et on constate qu'effectivement, le "alors" n'est pas valu,
		contrairement  ce qui serait arriv si on avait dfini le IF
		par (LAMBDA (X Y Z) (COND (X Y) (Z)))

Exemple:
	(PUTD 'PLUS '(FLAMBDA L
	  (COND ((NULL L) 0)
		((+ (EVAL (CAR L)) (PLUS (CDR L))))
	)))
		dfinit une opration PLUS qui somme tous ses arguments
	? (PLUS 1 2 3 4 5 6 7)
	=28


















								- 18 -


b) Macro-caractres
-------------------

	Les macro-caractres sont des caractres qui ont une fonction associe
appele lorsqu'ils sont rencontrs durant une lecture clavier. Le caractre
apostrophe (quote) est le seul macro-caractre dfini par dfaut. READ consulte
une table ( l'adresse $8000) pour savoir si un caractre est un macro-
caractre. Pour dfinir un macro-caractre, il suffit de positionner un octet
dans cette table et d'associer une fonction au caractre choisi.

Exemple:
	? (PUTD '"#" '(LAMBDA () (EVAL (READ))))
	=(LAMBDA NIL (EVAL (READ)))
	? (RADIX 16) (MEMORY (+ 8000 3) FF)
	=10
	=0	# a pour code ASCII 23h, la table commence au caractre 20h...
	? (SETQ N 8) (PUTD 'TEST '(LAMBDA (X) (/ X #(* N N))))
	=8
	=(LAMBDA (X) (/ X 64))
		et on constate que l'expression prcde de # a t value...
	? (QUOTE # (+ 2 2))
	=4	... mme  l'intrieur d'une expression protge





c) Macro-fonctions
------------------

	Les macro-fonctions sont des fonctions  double valuation dfinies
ainsi :
		(MLAMBDA param exp1 exp2 ... expN)

Un seul symbole est fourni en paramtre formel;  l'excution il est li 
l'ensemble de la liste invoquant la macro (sans valuation), y compris la
fonction qui apparat en tte de liste. Le corps de la macro est excut (les
expressions exp1 ... expN) et le rsultat est de nouveau fourni  l'valuation !
Le but d'une macro est donc le suivant : remplacer l'appel  la macro par une
autre expression.

Exemple:
	(PUTD 'IF '(MLAMBDA L
	  (LIST 'COND
		(LIST (CADR L) (CADDR L))
		(LIST (CAR (CDDDR L)))
	)))
		dfinit une macro "IF" qui va construire une expression COND
		contenant les arguments du IF.

Ainsi,
	(IF (PLUSP N) N (- 0 N))
va construire la liste
	(COND ((PLUSP N) N) ((- 0 N)))
puis celle-ci sera value, donnant la valeur absolue de N.


								- 19 -


Ce mcanisme puissant qui peut paratre bien inefficace pour dfinir une
fonction IF (appel de la macro, parcours des arguments et allocation de paires
pointes pour construire une expression COND, avant d'enfin valuer cette
dernire), surtout lorsque l'on compare  la version du IF avec FLAMBDA, rvle
tout son intrt dans le cadre des macro-fonctions "crasantes". Modifions
lgrement la dfinition du IF ainsi :
	(PUTD 'IF '(MLAMBDA L
	  (RPLACA L 'COND)
	  (RPLACD L (LIST (LIST (CADR L) (CADDR L))
			  (LIST (CAR (CDDDR L)))))
	))
		et maintenant le IF va se remplacer une fois pour toute par un
		COND  la premire excution.
Exemple:
	? (PUTD 'FACT '(LAMBDA (N)
	?    (IF (ZEROP N) 1 (* N (FACT (- N 1))))))
	=(LAMBDA (N) (IF (ZEROP N) 1 (* N (FACT (- N 1)))))
	? (FACT 3)
	=6
	? (GETD 'FACT)
	=(LAMBDA (N) (COND ((ZEROP N) 1) ((* N (FACT (- N 1))))))
 la premire excution du IF, le code de FACT s'est modifi ! Le code est
maintenant plus efficace que si on utilisait un IF implment avec une FLAMBDA !

Ce genre de manipulation est intressant dans le cadre de portage de programmes
LISP d'une machine  une autre (par exemple, ici, lorsque le IF n'existe pas)
ou pour dfinir efficacement des fonctions. Les macros ne sont jamais trs
lisibles, et plus dlicates  crire que des LAMBDA normales, mais utiliser des
macros rend souvent un programme plus lisible sans perdre en efficacit.
Exemple:
	la construction LET existe dans de nombreux LISP pour dfinir des
symboles locaux  un bloc. Ainsi, le IF prcdent s'crirait plus lisiblement :
	(PUTD 'IF '(MLAMBDA L
	  (LET (
		(X (CADR L))
		(Y (CADDR L))
		(Z (CAR (CDDDR L)))
	       )
	     (RPLACA L 'COND)
	     (RPLACD L (LIST (LIST X Y) (LIST Z)))
	)))

le LET peut tre dfini efficacement par une macro le remplaant en LAMBDA :
	(PUTD 'LET '(MLAMBDA L
	  (RPLACA L (CONS 'LAMBDA
			  (CONS (ALLCAR (CADR L))
				(CDDR L))))
	  (RPLACD L (ALLCADR (CADR L)))
	))
o ALLCAR et ALLCADR permettent de rcuprer respectivement les paramtres
formels et les arguments effectifs :
	(PUTD 'ALLCAR '(LAMBDA (L)
	 (COND ((NULL L) NIL)
	       ((CONS (CAAR L) (ALLCAR (CDR L)))))))
	(PUTD 'ALLCADR '(LAMBDA (L)
	 (COND ((NULL L) NIL)
	       ((CONS (CADAR L) (ALLCADR (CDR L)))))))
								- 20 -


d) Fonctions d'ordre suprieur
------------------------------
OricLisp permet de passer une fonction en paramtre d'une autre fonction.
Toutefois, le premier lment d'une liste (la fonction) n'est jamais valu par
la fonction EVAL, on ne peut donc invoquer directement une fonction obtenue en
argument. Par exemple, la fonctionnelle classique MAP (qui applique une fonction
 tous les lments d'une liste et renvoie la liste des rsultats) ne peut
s'crire ainsi avec OricLisp :
	(PUTD 'MAP '(LAMBDA (F L)
	  (COND ((NULL L) NIL)
		((CONS (F (CAR L))
		       (MAP F (CDR L)))))))
parce que le symbole F en position de fonction ne sera pas valu (Remarque :
dans beaucoup de dialectes LISP, cette dfinition de MAP ne marche que si F n'a
pas de dfinition associe).
De plus, OricLisp n'a pas de fonction APPLY mais les constructions de type
(APPLY F ARGS) peuvent tre facilement remplaces par (EVAL (CONS F ARGS)).
Ainsi, le MAP peut s'crire :
	(PUTD 'MAP '(LAMBDA (F L)
	  (COND ((NULL L) NIL)
		((CONS (APPLY F (LIST (CAR L)))
		       (MAP F (CDR L)))))))
et cette dfinition marche sans restriction. APPLY peut tre dfini par une
simple (LAMBDA (F L) (EVAL (CONS F L)))
ou par une macro :
	(MLAMBDA L
	  (RPLACA L 'EVAL)
	  (RPLACD L (LIST (LIST 'CONS (EVAL (CADR L)) (EVAL (CADDR L)))))).
Exemple:
	? (MAP '(LAMBDA(X)(* X X)) '(1 2 3 4 5))
	=(1 4 9 16 25)
	? (MAP 'PLUSP '(1 8 -2 6 -3))
	=(T T NIL T NIL)










A. Annexe A: Copyright
----------------------
Le programme OricLisp et le prsent manuel sont Copyright Fabrice Francs.
Ils sont distribus gratuitement et vous ne devez avoir pay que le prix
du support pour les avoir: il y a de meilleurs moyens de dpenser votre
argent, par exemple en me l'envoyant ! J'accepte les donations envoyes
 l'adresse suivante :

	Fabrice Francs
	16, alle du Vaucluse
	31770 COLOMIERS
	FRANCE


								- 21 -


B. Annexe B: Dfinitions formelles
----------------------------------
	Pour le "LISPien", une fonction LISP vaut mieux qu'un long discours,
comment mieux dcrire le comportement d'une primitive sinon avec son code crit
en LISP ? Bon nombre des fonctions implmentes en langage machine dans OricLisp
peuvent tre crites en LISP, mais elle seraient alors moins efficaces et
souvent trs consommatrices d'espace de pile ( cause des rcursivits).
	Le noyau vraiment minimal est compos des dfinitions LAMBDA, FLAMBDA,
MLAMBDA et des primitives READ, EVAL, PRIN, COND, CAR, CDR, CONS, PUTD, GETD,
NULL, ATOM, RPLACA, RPLACD, EQ, TIME, MEMORY, RADIX, <, >, +, -, *, /, MOD.
Les autres peuvent s'crire en fonction de ces primitives de base. Les dfini-
-tions qui suivent ont exactement le mme comportement que les routines en
langage machine (elles renvoient les mmes rsultats en toutes circonstances),
mme si l'implmentation effective est diffrente pour des raisons de
performance. Les seules primitives implmentes de faon rcursive sont LIST et
APPEND (elles ne le devraient pas...). Enfin, APPLY n'est pas un symbole dfini
dans OricLisp, mais il existe en interne; il peut tre dfini par
(PUTD 'APPLY '(LAMBDA (F ARGS) (EVAL (CONS F ARGS))))
mme si l'implmentation relle ne consomme pas de paire pointe.

(PUTD 'AND
  '(FLAMBDA L
	(COND ((ATOM L) T)
	      ((ATOM (CDR L)) (EVAL (CAR L)))
	      ((EVAL (CAR L)) (APPLY 'AND (CDR L))))))

(PUTD 'APPEND
  '(LAMBDA (X Y)
      (COND ((ATOM X) Y)
	    ((CONS (CAR X) (APPEND (CDR X) Y))))))

(PUTD 'ASSOC '(LAMBDA (X L)
		(COND	((ATOM L) NIL)
	      		((ATOM (CAR L)) (ASSOC X (CDR L))
	      		((EQUAL X (CAAR L)) (CAR L))
	      		((ASSOC X (CDR L))))))

(PUTD 'CAAAR '(LAMBDA (X) (CAAR (CAR X))))
(PUTD 'CAADR '(LAMBDA (X) (CAAR (CDR X))))
(PUTD 'CADAR '(LAMBDA (X) (CADR (CAR X))))
(PUTD 'CADDR '(LAMBDA (X) (CADR (CDR X))))
(PUTD 'CDAAR '(LAMBDA (X) (CDAR (CAR X))))
(PUTD 'CDADR '(LAMBDA (X) (CDAR (CDR X))))
(PUTD 'CDDAR '(LAMBDA (X) (CDDR (CAR X))))
(PUTD 'CDDDR '(LAMBDA (X) (CDDR (CDR X))))
(PUTD 'CAAR '(LAMBDA (X) (CAR (CAR X))))
(PUTD 'CADR '(LAMBDA (X) (CAR (CDR X))))
(PUTD 'CDAR '(LAMBDA (X) (CDR (CAR X))))
(PUTD 'CDDR '(LAMBDA (X) (CDR (CDR X))))

(PUTD 'DIV '(LAMBDA (X Y) (CONS (/ X Y) (MOD X Y))))

(PUTD 'EQUAL
  '(LAMBDA (X Y)
       (COND ((ATOM X) (EQ X Y))
	     ((ATOM Y) NIL)
	     ((EQUAL (CAR X) (CAR Y)) (EQUAL (CDR X) (CDR Y))))))
								- 22 -


(PUTD 'LAST '(LAMBDA (L)
		(COND	((ATOM L) NIL)
	      		((ATOM (CDR L)) L)
	      		((LAST (CDR L))))))

(PUTD 'LENGTH '(LAMBDA (L)
		 (COND	((ATOM L) 0)
	      		((+ 1 (LENGTH (CDR L)))))))

(PUTD 'LIST 
  '(FLAMBDA L 
      (COND ((ATOM L) NIL)
	    ((CONS (EVAL (CAR L)) (APPLY 'LIST (CDR L)))))))
	
(PUTD 'MEMBER 
  '(LAMBDA (X L)
	(COND ((ATOM L) NIL)
	      ((EQUAL X (CAR L)) L)
	      ((MEMBER X (CDR L))))))

(PUTD 'NCONC '(LAMBDA (X Y)
       		(COND ((ATOM X) Y)
		      (T (RPLACD (LAST X) Y) X))))

(PUTD 'OR '(FLAMBDA L
		(COND	((ATOM L) NIL)
	      		((EVAL (CAR L)))
	      		((APPLY 'OR (CDR L))))))

(PUTD 'PROG1
  '(FLAMBDA L
	(COND ((ATOM L) NIL)
	      (T ((LAMBDA (X) (APPLY 'PROGN (CDR L)) X) (EVAL (CAR L)))))))

(PUTD 'PROGN 
  '(FLAMBDA L
	(COND ((ATOM L) NIL)
	      ((ATOM (CDR L)) (EVAL (CAR L)))
	      (T (EVAL (CAR L)) (APPLY 'PROGN (CDR L))))))

(PUTD 'QUOTE '(FLAMBDA L (CAR L)))

(PUTD 'REVERSE
  '(LAMBDA (X Y)
	(COND ((ATOM X) NIL)
	      ((ATOM (CDR X)) (CONS (CAR X) Y))
	      ((REVERSE (CDR X) (CONS (CAR X) Y))))))

(PUTD 'SET '(LAMBDA (X Y) (RPLACA X Y) Y)))

(PUTD 'SETQ '(FLAMBDA L (COND ((NAME (CAR L)) (SET (CAR L) (EVAL (CADR L)))))))

(PUTD 'WHILE 
  '(FLAMBDA L
      (COND ((EVAL (CAR L)) 
		(APPLY 'PROGN (CDR L)) 
		(APPLY 'WHILE L)))))
								- 23 -


C. Annexe C: portage de programmes MuLisp
-----------------------------------------

En dehors de l'valuation des fonctions utilisateurs (LAMBDA, FLAMBDA, MLAMBDA),
OricLisp possde des primitives trs proches de celles de MuLisp, il est donc
ais de porter des programmes de MuLisp vers OricLisp (et vice-versa). Pour
laisser plus de place  l'utilisateur, OricLisp ne dfinit pas toutes les
fonctions qui existent dans MuLisp. 
On pourra utiliser les dfinitions suivantes qui fournissent un quivalent
exact :


(PUTD 'NTH '(LAMBDA (N L)
	(COND	((ZEROP N) (CAR L))
		((ATOM L) NIL)
		((NTH (- N 1) (CDR L)))))) pour une version  la MacLisp

(PUTD 'NTH '(LAMBDA (L N)
	(COND	((EQ N 1) L)
		((ATOM L) NIL)
		((NTH (CDR L) (- N 1)))))) pour une version  la InterLisp

(PUTD 'TCONC '(LAMBDA (PTR OBJ)
	(SETQ OBJ (LIST OBJ))
	(COND	((ATOM PTR) (CONS OBJ OBJ))
		((ATOM (CDR PTR)) (RPLACA PTR OBJ) (RPLACD PTR OBJ))
		(T (RPLACD (CDR PTR) OBJ) (RPLACD PTR OBJ)))))

(PUTD 'LCONC '(LAMBDA (PTR L)
	(COND	((ATOM L) PTR)
		((ATOM PTR) (CONS L (LAST L)))
		((ATOM (CDR PTR)) (RPLACA PTR L) (RPLACD PTR (LAST L)))
		(T (RPLACD (CDR PTR) L) (RPLACD PTR (LAST L))))))

(PUTD 'EVENP '(LAMBDA (N) (COND ((NUMBERP N) (ZEROP (MOD N 2))))))

(PUTD 'POP '(FLAMBDA P
	(COND	((NOT (NAME (CAR P))) NIL)
		((ATOM (CAAR P)) NIL)
		((PROG1 (CAAAR P) (SET (CAR P) (CDAAR P)))))))

(PUTD 'PUSH '(FLAMBDA P
	(COND	((NULL (CADR P)) NIL)
		((NAME (CADR P)) (SET (CADR P) (CONS (EVAL (CAR P)) 
						     (CADR P)))))))

(PUTD 'PUT '(LAMBDA (NAM KEY OBJ)
  ((LAMBDA(ELEM) 
	(COND ((NULL ELEM) (RPLACD NAM (CONS (CONS KEY OBJ) (CDR NAM))) OBJ)
	      (T (RPLACD ELEM OBJ) OBJ)))  (ASSOC KEY (CDR NAM)))))

(PUTD 'GET '(LAMBDA (NAM KEY) (CDR (ASSOC KEY (CDR NAM)))))





								- 24 -


(PUTD 'REMPROP '(LAMBDA (NAM KEY)
	(COND ((ATOM (CDR NAM)) NIL)
	      ((EQUAL (CAADR NAM) KEY)
			(SETQ KEY (CDADR NAM))
			(RPLACD NAM (CDDR NAM))
			KEY)
	      ((REMPROP (CDR NAM) KEY)))))

(PUTD 'FLAGP '(LAMBDA (NAM ATT) (MEMBER ATT (CDR NAM))))

(PUTD 'FLAG '(LAMBDA (NAM ATT)
	(COND ((FLAGP NAM ATT) ATT)
	      (T (RPLACD NAM (CONS ATT (CDR NAM))) ATT))))

(PUTD 'REMFLAG '(LAMBDA (NAM ATT)
	(COND ((ATOM (CDR NAM)) NIL)
	      ((EQUAL ATT (CADR NAM)) (RPLACD NAM (CDDR NAM)) T)
	      ((REMFLAG (CDR NAM) ATT)))))

(PUTD 'GCD '(LAMBDA (X Y)
	(COND	((NOT (ZEROP Y)) (GCD Y (MOD X Y)))
		((PLUSP X) X)
		((- 0 X)))))

(PUTD 'COMMENT '(FLAMBDA L NIL))

Les diffrences suivantes peuvent apparatre lors d'un portage :

* le corps d'une fonction MuLisp et d'une fonction OricLisp sont valus
diffremment. MuLisp implmente un COND/PROGN implicite au lieu d'un PROGN
implicite dans les corps de fonction (et les clauses de COND), ce qui permet
de rduire la taille du code mais introduit une ambigut dans le cas de 
LAMBDAs qui sont alors prises pour des prdicats. Le COND est obligatoire dans
les corps de fonction OricLisp.

* PLUSP renvoie NIL pour 0 dans MuLisp et T dans OricLisp. De plus, le CDR
d'un nombre (la liste de proprits)  une signification inverse : il vaut T
pour un nombre positif ou nul dans OricLisp, tandis qu'il vaut T pour un nombre
ngatif dans MuLisp.
GREATERP et LESSP acceptent plus de deux arguments dans MuLisp, de telles
expressions doivent tre crites avec plusieurs > et < dans OricLisp. De mme,
PLUS, DIFFERENCE, TIMES admettent plus de deux arguments dans MuLisp, il est
facile de rcrire ces expressions avec plusieurs +, - ou *.

* les fonctions sur les chanes de caractres de MuLisp (SUBSTRING, FINDSTRING,
PACK, UNPACK, LENGTH, ASCII) ne sont pas implmentables avec OricLisp.

* les chappements de MuLisp (CATCH, THROW) ne sont pas implmentables avec 
OricLisp, le traitement d'erreur non plus.

* les fonctions de lecture/criture sur fichier ne sont pas disponibles avec
OricLisp.

* les puissantes macro-fonctions d'OricLisp n'existent pas avec MuLisp, si un
programme OricLisp les utilise intensivement, on prfrera alors porter vers
un autre dialecte comme LeLisp.

								- 25 -


D. Annexe D: Dtails d'implmentation
-------------------------------------

a) Carte mmoire
----------------
0000 ------------+----------------------------+
                 |    variables systmes      |
0100 ------------+----------------------------+
                 | quatre segments de pile    |
0200 ------------+----------------------------+
                 |    variables systmes      |
0300 ------------+----------------------------+
                 |      entres-sorties       |
0400 ------------+----------------------------+
                 |  buffer d'entre clavier   |
                 |   + zone de conversion     |
0500 ------------+----------------------------+-------- BOTTOM
                 |    pile des liaisons       |
                 |\/\/\/\/\/\/\/\/\/\/\/\/\/\/|
                 |                            |
                 |/\/\/\/\/\/\/\/\/\/\/\/\/\/\|
                 | segments de pile virtuelle |
1000 ------------+----------------------------+-------- SYSTEM
                 |   chanes de caractres    |
                 |\/\/\/\/\/\/\/\/\/\/\/\/\/\/|
                 |                            |
                 |/\/\/\/\/\/\/\/\/\/\/\/\/\/\|
                 |      paires pointes       |
5000 ------------+----------------------------+-------- ATOMS
                 |        nombres             |
                 |\/\/\/\/\/\/\/\/\/\/\/\/\/\/|
                 |                            |
                 |/\/\/\/\/\/\/\/\/\/\/\/\/\/\|
                 |        symboles            |
8000 ------------+----------------------------+-------- TOPATOM
                 |          noyau             |
                 +----------------------------+

Les adresses BOTTOM, SYSTEM et ATOMS peuvent tre modifies pour s'adapter aux
consommations diffrentes en nombres et symboles, paires pointes ou rcursivit
d'une application. Malheureusement, cette transformation doit se faire en
modifiant des adresses du noyau AVANT qu'il ne s'excute...
La page de BOTTOM peut tre change en modifiant l'adresse 9AA6, la page de
SYSTEM  l'adresse 9AAA et la page d'ATOMS  l'adresse 9AB0.

b) Structures de donnes
------------------------

Les paires pointes ont la structure suivante:
	+----------+------------+
        |   CAR    |    CDR     |
	+----------+------------+

Les symboles ont la structure suivante :
	+----------+------------+----------+-------------+
	|  Valeur  | Proprits | Fonction | Nom externe |  
        +----------+------------+----------+-------------+
								- 26 -


Le CAR d'un symbole donne donc sa valeur, un symbole n'ayant pas reu de valeur
a pour valeur lui mme (la valeur pointe vers le mme symbole).
Le CDR d'un symbole porte la liste de proprits associe au symbole, elle est
NIL par dfaut et peut tre change par RPLACD.
Le champ fonction du symbole est NIL si aucune fonction n'est associe, il
pointe vers la liste LAMBDA (ou FLAMBDA ou MLAMBDA) pour une fonction
utilisateur, et contient l'adresse de dbut pour une fonction en langage
machine (les deux derniers sont diffrencis par le bit de poids fort, il est 
1 pour une routine en langage machine au del de l'adresse 8000h et  0 pour
une fonction utilisateur)
Le champ nom externe (ou Print-name) pointe vers la chane de caractres
reprsentant le symbole.

Les nombres ont la structure suivante:
	+----------+------------+------------------------+
	|  Valeur  | Proprits | reprsentation 32 bits |  
        +----------+------------+------------------------+

Le CAR d'un nombre (sa valeur) pointe toujours sur lui-mme.
Le CDR d'un nombre (sa proprit) est T s'il est positif ou nul, NIL si ngatif.


c) La pile virtuelle
--------------------

Le langage LISP est par dfinition rcursif et ceci pose problme pour
l'implmentation sur le processeur 6502 qui possde un pointeur de pile 8 bits.
OricLisp implmente une pile virtuelle indite qui lui dispense de simuler une
pile 16 bits, et lui permet d'utiliser les instructions normales de pile du
6502 : JSR, RTS, PHA, PLA...
La pile virtuelle est constitue de segments de 64 octets, 4 segments sont
donc prsents dans la pile physique du 6502. De temps  autre (dans la routine
EVAL par exemple), la position du pointeur de pile est vrifie afin de dtecter
si une frontire de segment a t franchie. Ce franchissement peut provoquer la
sauvegarde d'un segment de la pile physique vers la pile virtuelle, ou la
rcupration d'un segment de la pile virtuelle, mais l'algorithme utilis est
adapt au parcours rcursif d'arbres binaires et fait que le transfert d'un
segment est peu courant (il n'y a pas de transfert lorsque le pointeur oscille
de part et d'autre d'une frontire de segment).


d) Le ramasse-miettes
---------------------

Une premire passe marque les paires et les atomes accessibles  partir des
champs valeur, proprits et fonction des symboles (on ne marque pas un
symbole dont la valeur pointe sur lui-mme et qui n'a pas dfinition de
fonction), ou  partir de la pile des liaisons.
Une deuxime passe supprime les paires, les symboles et les nombres non marqus
et les compacte.
Une troisime passe enlve le marquage des objets et ajuste les pointeurs vers
des objets dplacs par le compactage.
Une dernire passe compacte les chanes des symboles qui n'ont pas t limins
par le ramasse-miettes.



								- 27 -


E. Annexe E: Exemple du parcours du cavalier
--------------------------------------------

Le parcours du cavalier sur un chiquier est un problme classique qui consiste
 parcourir toutes les cases de l'chiquier une fois et une seule en respectant
la marche du cavalier aux checs. LISP est bien adapt  ce genre de recherche
de solution, en voici une rsolution assez concise pour un chiquier de taille
N quelconque:

; une liste des 8 sauts possibles du cavalier, classs par une heuristique :
(SETQ DIR '((-2 1)(-2 -1)(-1 -2)(1 -2)(2 -1)(2 1)(1 2)(-1 2)))

; d'abord une petite fonction qui construit la liste des entiers M,M-1...1
(PUTD REBOURS '(LAMBDA (M) (COND ((ZEROP M) NIL) ((CONS M (REBOURS (- M 1)))))))

; puis une autre qui teste si une case n'est pas en dehors de l'chiquier
(PUTD TEST '(LAMBDA (X Y) (AND (< -1 X) (< X N) (< -1 Y) (< Y N))))

; pour construire la liste des positions atteignables  partir de M
(PUTD SAUTS '(LAMBDA (PAS)
  (COND ((NULL PAS) NIL)
	((TEST (+ (CAAR PAS) (MOD (- M 1) N)) (+ (CADAR PAS) (/ (- M 1) N)))
	   (CONS (+ (+ M (CAAR PAS)) (* N (CADAR PAS))) (SAUTS (CDR PAS))))
	((SAUTS (CDR PAS))))))

; on construit en effet une table de ces listes pour l'ensemble des cases
(PUTD TABLE '(LAMBDA (M)
  (COND	((ZEROP M) NIL)
	((CONS (CONS M (SAUTS DIR)) (TABLE (- M 1)))))

; maintenant le programme lui-mme: cherche un chemin par toutes les cases
(PUTD CHEMIN '(LAMBDA (CASES RESTE PARCOURS)
  (COND	((ZEROP RESTE) PARCOURS)		; trouv !
	((NULL CASES) NIL)			; une impasse...
	((MEMBER (CAR CASES) PARCOURS)		; dj pass par ici...
		(CHEMIN (CDR CASES) RESTE PARCOURS))
	((CHEMIN (CDR (ASSOC (CAR CASES) TAB))
		 (- REST 1)
		 (CONS (CAR CASES) PARC)))	; on essaie par l...
	((CHEMIN (CDR CASES) REST PARC)))))	; et les autres aussi...

; un programme principal pour lancer le tout, et c'est fini !
(PUTD PARCOURS '(LAMBDA (N TAB)
  (SETQ TAB (TABLE (* N N)))		; on calcule la table une seule fois
  (CHEMIN (REBOURS (* N N)) (* N N))))	; puis on cherche

Remarque: Pour trouver toutes les solutions, il suffit de remplacer la
premire clause de la fonction chemin par :
(COND ((ZEROP RESTE) (PRINT PARCOURS) NIL)

Remarque2: Une image mmoire est fournie avec OricLisp, contenant une version
amliore de ce programme pour trouver plus rapidement une solution.





								- 28 -
