Manual by Dirk Van Deun
I: De Scheme interpreter
Scheme evalueren met deze evaluator doet men met 'java Scheme
<file>.scm';
De Scheme interpreter die we gebruiken ondersteunt slechts drie
elementaire datatypes: symbols, strings en 4 byte integers. Verder kan
men cons-celletjes, lijsten en vectoren vormen. De lege lijst doet
dienst als Booleaanse False; aangezien alles wat niet False is, True
is, wordt meestal de integerwaarde 1 als True geretourneerd.
NOOT: In dit Scheme zijn door luiheid van de Scheme-implementator
dingen hard gecodeerd, zoals
scheme/runtime/PortMailer.java bevat de positie van de sendmailport van
de VUB
Overzicht van de ondersteunde syntax: (als er geen commentaar bij
gegeven wordt, werd de R4RS standaard gevolgd; let ook steeds op de
ondersteunde vormen en aantallen parameters):
(QUOTE expr)
(LAMBDA (parms) body)
(LAMBDA (parms . parm) body)
(LET ((name_1 value1) ... (name_n value_n)) body)
(LET* ((name_1 value1) ... (name_n value_n)) body)
(IF pred truebody)
(IF pred truebody falsebody)
(COND ((pred_1 body1) ... (pred_n body_n))
(COND ((pred_1 body1) ... (pred_n body_n) (else body))
(DEFINE name expr)
(DEFINE (name parms) body)
(DEFINE (name . parm) body)
(DEFINE (name parms . parm) body)
(SET! name expr)
(AND expr_1 ... expr_n)
(OR expr_1 ... expr_n)
zoals standaard Scheme maar niet te vertrouwen met nul argumenten
(BEGIN expr_1 ... expr_n)
(DO ((var1 init1 increment1) ... (var_n init_n increment_n))
(pred result) body)
er is een goede kans dat dit overeenkomt met de standaard DO; de
implementator is er zelf niet zo zeker van...
(WHILE pred body)
body wordt uitgevoerd totdat pred naar '() evalueert; functieresultaat
ongedefinieerd
(DEFINED var)
geeft de inhoud van de variabele indien die gedefinieerd is, anders
'(). Trek uw plan als de variabele de inhoud '() heeft.
Overzicht van ondersteunde functies:
(! expr) = (NOT expr)
(CONS expr expr)
(CAR list)
(CDR list)
(CADR list)
(MEMBER object list) = (MEMQ object list)
= de memq van standaard Scheme
(ADD numeric_expr_1 ... numeric_expr_n), (+ numeric_expr_1 ...
numeric_expr_n)
(MUL numeric_expr_1 ... numeric_expr_n), (* numeric_expr_1 ...
numeric_expr_n)
(SUB numeric_expr_1 numeric_expr_2), (- numeric_expr_1 numeric_expr_2)
(DIV numeric_expr_1 numeric_expr_2), (/ numeric_expr_1 numeric_expr_2)
(= numeric_expr_1 numeric_expr_2)
(< numeric_expr_1 numeric_expr_2), (> numeric_expr_1
numeric_expr_2)
(<= numeric_expr_1 numeric_expr_2), (>= numeric_expr_1
numeric_expr_2)
(<> numeric_expr_1 numeric_expr_2), (!= numeric_expr_1
numeric_expr_2)
(EQ? expr expr)
(= string_expr_1 string_expr_2), (string=? string_expr_1 string_expr_2)
(< string_expr_1 string_expr_2), (> string_expr_1 string_expr_2)
(<= string_expr_1 string_expr_2), (>= string_expr_1 string_expr_2)
(<> string_expr_1 string_expr_2), (!= string_expr_1 string_expr_2)
case sensitive stringvergelijkingen
(STRING? expr)
(VECTOR? expr)
(NULL? obj)
controleert of object '() is; is dus eigenlijk equivalent met NOT in
deze versie omdat '() gebruikt wordt als False
(LIST? obj)
de PAIR? van standaard Scheme
(LENGTH list)
(LIST-REF list el)
(STRING-REF str pos)
retourneert een enkelkarakterige string bij gebrek aan chars
(STRING-SET! str1 pos str2)
als str2 enkelkarakterig is, komt dit overeen met de klassieke
string-set!; maar str2 kan ook een andere lengte hebben, en dan wordt 1
karakter op de geviseerde positie weggenomen, en de hele tweede string
ingevoegd. Motivatie: Werner is nu eenmaal zo.
(STRING-NULL? string-expr)
controleert of een string leeg is
(STRING->SYMBOL string)
(SYMBOL->STRING symbol)
wijken af van de standaard doordat symbol->string altijd een
upper case resultaat teruggeeft
(STRING->LIST string)
zet string om in een lijst van *strings* van lengte 1
(er zijn geen chars in dit dialect) (zeer onperformante functie)
(STRING->NUMBER string)
(NUMBER->STRING integer)
conversie tussen strings en integers
(LIST->VECTOR list)
(VECTOR->LIST vector)
(LIST expr_1 ... expr_n)
(VECTOR expr_1 ... expr_n)
(MAKE-VECTOR lengte)
(MAKE-VECTOR lengte init)
als geen init wordt opgegeven wordt '() gebruikt
(VECTOR-LENGTH vector)
(STRING-LENGTH string)
(VECTOR-SET! vector pos expr)
(VECTOR-REF vector pos)
(APPLY function parmlist)
(EVAL expr)
evalueert de expressie in de huidige environment
(STRING-APPEND str1 str2 ...)
(SUBSTRING beginpos eindpos string)
evident
(GETCHAR pos string)
geeft het karakter op de aangegeven positie in de string weer
(REPLACE string substring1 substring2)
geeft de string terug na vervanging van substring1 door substring2
gebruikt om HTML-templates in te vullen
(INDEX-OF string substring)
(INDEX-OF string substring startpos)
zoekt een substring in een string, eventueel vanaf een bepaalde
startpositie, en geeft zijn positie weer (een integer vanaf nul)
(OPEN-INPUT-FILE string)
(OPEN-OUTPUT-FILE string)
evident; functieresultaat is een port of '() (bij fout)
(CLOSE port)
evident; functieresultaat is '()
(READSTRING port)
leest alle beschikbare tekst van een beschikbare poort
en geeft dit weer als een enkele lange string
(WRITESTRING string port)
(WRITESTRING string)
evident; functieresultaat is weer de string
(DISPLAY expr)
(NEWLINE)
(LOAD string)
II: Het toevoegen van natives aan de Scheme interpreter
Men voegt Scheme-natives toe in scheme.java door middel van een
instructie volgens het volgende patroon:
installNative(d,"/","native_divide",false,2,false)
- d: rootdictionary (gewoon kopieren)
- "/": naam binnen Scheme-environment
- "native_divide": methodenaam in de
Runtime-klasse
- false: zegt dat de parameters voor deze
functie op voorhand geevalueerd moeten worden (dus geen delayed
evaluation). Voor de if functie zijn deze bijvoorbeeld wel delayed
- 2: parameterpassing-conventie voor Java. Het
getal 2 wil zeggen dat er 2 parameters verwacht worden. Voor een
variabel aantal parameters zijn er Native.LIST en Native.ARRAY, te
gebruiken naar smaak van de implementator van de primitieve functie
- false: geeft aan of de caller-environment
interessant is
Om het voorbeeld af te maken is hier de functie native_divide:
public Object native_divide(Object a, Object b, Environment e)
{ return new Integer(((Integer)a).intValue()/((Integer)b).intValue()); }
Als we zouden werken met de conventie Native.ARRAY krijgen we:
public Object native_divide(Object p[], Environment e)
{ return new
Integer(((Integer)p[0]).intValue()/((Integer)p[1]).intValue()); }
En als we met de lijstrepresentatie zouden werken geeft dat:
public Object native_divide(Object o, Environment e)
{ Cons l=(Cons)o;
return new
Integer(((Integer)l.car()).intValue()/((Integer)l.cadr()).intValue()); }
Noot: mapping van datatypes:
Scheme Java-klasse
-------------------------------------------
string String
symbol Identifier
number Integer
cons-cel Cons
vector Object[]
#f / lege lijst null