 |
AppletTalk.com Java discussions newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Stefan Matthias Aust Guest
|
Posted: Mon Nov 27, 2006 1:58 am Post subject: Smalltalk-Interpreter in Java |
|
|
[Beim Aufräumen gefunden... vielleicht interessiert es jemanden...]
Der folgende Text beschreibt das Laufzeitsystem und eine Maschinen-
sprache für einen nicht-reflexiven Smalltalk-Interpreter. Nicht reflexiv
bedeutet, dass Klassen keine Smalltalk-Objekte sind und so das Smalltalk
nichts über sich weiß.
Ein Smalltalk-System besteht aus Objekten, die durch den Austausch
(synchroner) Nachrichten miteinander kommunizieren. Jede Nachricht ist
an ein Empfängerobjekt gerichtet und kann null oder mehr Objekte als
Argumente tragen. Der Sender erhält ein Objekt als Antwort zurück.
Einige Nachrichten triggern Systemfunktionen des Laufzeitsystems, die
meisten jedoch normalen Methoden.
Alle Smalltalk-Objekte sind Exemplare von Smalltak-Klassen. Jedes
Exemplar hat null oder mehr Felder (a.k.a. Exemplarvariablen), die
Smalltalk-Objekte enthalten. Zu einfacheren Interaktion mit Java möchte
ich gerne direkt null, true, false, Zahlen, Strings und Arrays von Java
benutzen. Alle anderen Objekte sind durch die Java-Klasse StObject
repräsentiert.
class StObject {
final StClass stClass;
final Object[] fields;
StObject(StClass stClass) {
this.stClass = stClass;
this.fields = new Object[stClass.instanceSize()];
}
}
Eine Smalltalk-Klasse hat einen Namen, eine Oberklasse und kennt die
Namen (und damit auch die Menge) der Felder ihrer Exemplare. Außerdem
hält sie alle Methoden für ihre Exemplare.
class StClass {
final String name;
final StClass superclass;
final Object[] fieldNames;
final HashMap<Object, StMethod> methods;
StClass(String name, StClass superclass, Object... fieldNames) {
this.name = name;
this.superclass = superclass;
this.fieldNames = fieldNames;
this.methods = new HashMap<Object, StMethod>();
}
StClass add(Object selector, StMethod method) {
methods.put(selector, method);
return this;
}
int instanceSize() {
return (fieldNames != null ? fieldNames.length : 0)
+ (superclass != null ? superclass.instanceSize() : 0);
}
StMethod lookup(Object selector) {
StMethod method = methods.get(selector);
if (method == null && superclass != null) {
method = superclass.lookup(selector);
}
return method;
}
}
Smalltalk-Methoden werden durch durch die Java-Klasse StMethod
repräsentiert. Sie enthalten Anweisungen für eine einfache
Stack-basierte Maschinensprache, die später noch näher erläuert wird.
folgende Java-Klasse repräsentiert. Sie enthalten die Instruktionen der
Maschinensprache des Interpreters, die anschließend erläutert wird.
class StMethod {
final int primitive;
final Object[] instructions;
StMethod(int primitive, Object... instructions) {
this.primitive = primitive;
this.instructions = instructions;
}
}
Man könnte die verschiedenen Anweisungen des Maschinencodes durch
einzelne Klassen repräsentieren, was guter Stil wäre, jetzt aber dazu
führen würde, dass ich sehr viel Code für sehr viele neue Java-Klassen
schreiben müsste. Stattdessen benutze ich einen Zahlencode in Form von
Integer-Objekten, die ich in dem Object[] für die Anweisungen speichere.
Einige Anweisungen haben einen numerischen Parameter, anderen folgt ein
weiteres Objekt - das ist dann auch der Grund, warum es ein Object[] und
kein Integer[] ist.
Die Smalltalk-VM ist eine Stackmaschine, die eines kann: Nachrichten
verschicken. Pro zuzuführender Methode gibt es Argumente, lokale
Variablen und einen Stack für Zwischenergebnisse. Dies nenne ich einen
Kontext.
Der Interpreter ist in einem "continuation passing style" geschrieben,
eine Methode step() wird immer und immer wieder aufgerufen und gibt
jewels den nächsten Kontext zurück, der ausgeführt werden soll.
Dies ist die Hauptschleife:
class StSystem {
Object execute(StContext context) {
while (!(context instanceof StLastContext)) {
context = context.step(this);
}
return context.pop();
}
}
Hier ist die abstrakte Definition des Kontexts:
abstract class StContext {
abstract StContext step(StSystem system);
abstract StContext push(Object object);
abstract Object pop();
}
class StLastContext extends StContext {
Object result;
StContext step(StSystem system) {
return null;
}
StContext push(Object object) {
result = object;
return this;
}
Object pop() {
return result;
}
}
Dies ist der eigentliche Kontext, der definiert, wie Methoden ausgeführt
werden. Der Aufruf der Methoden push() und pop() funktioniert für
MethodContext und LastContext genau so, dass die letzte RETURN-Anweisung
das Ergebnis des Aufrufs von StSystem.execute() ist.
class StMethodContext extends StContext {
final StContext parent;
final StMethod method;
final Object receiver;
final Object[] arguments;
final Object[] temporaries;
final Object[] stack;
int ip; // instruction pointer
int sp; // stack pointer
StMethodContext returningContext;
StMethodContext(StContext parent, StMethod method,
Object receiver, Object... arguments) {
this.parent = parent;
this.method = method;
this.receiver = receiver;
this.arguments = arguments;
this.temporaries = StSystem.allocate(next());
this.stack = StSystem.allocate(next());
this.returningContext = this;
}
private int next() {
return (Integer) constant();
}
private Object constant() {
return method.instructions[ip++];
}
private Object[] fields() {
return ((StObject) receiver).fields;
}
StContext push(Object object) {
stack[sp++] = object;
return this;
}
Object pop() {
Object object = stack[--sp];
stack[sp] = null;
return object;
}
private Object top() {
return stack[sp - 1];
}
StContext step(StSystem system) {
switch (next()) {
case 0: // push method argument
return push(arguments[next()]);
case 1: // push temporary variable
return push(temporaries[next()]);
case 2: // push instance variable
return push(fields()[next()]);
case 3: // push constant
return push(constant());
case 4: // push receiver
return push(receiver);
case 5: // store temporary variable
temporaries[next()] = top();
return this;
case 6: // store instance variable
fields()[next()] = top();
return this;
case 7: // drop
pop();
return this;
case 8: // send method
return system.send(this, next(), constant(), null);
case 9: // super send method
return system.send(this, next(), constant(), constant());
case 10: // return
return parent.push(pop());
case 11: // non-local return
return returningContext.parent.push(pop());
case 12: // create block closure
return push(system.blockClosure(returningContext, constant()));
default:
throw new Error();
}
}
}
Es müssen eine Reihe vo Smalltalk-Klassen vordefiniert sein und - wer
genau hingesehen hat - muss jemand, BlockClosure-Objekte anlegen können.
Alle globalen Daten werden in einem Exemplar der Java-Klasse StSystem
gehalten. Aufgrund der Entscheidung, null, true, false, usw. direkt mit
Java-Objekten zu repräsentieren, ist die Ermittung der Klasse eines
Objekts nicht so einfach und kann nur von StSystem übernommen werden. Da
die Klasse auch zum Bestimmen der richtigen Methode zu einer Nachricht
benötigt wird, übernimmt StSystem auch diese Aufgabe.
public class StSystem {
StClass objectClass;
StClass nilClass;
StClass trueClass;
StClass falseClass;
StClass integerClass;
StClass stringClass;
StClass arrayClass;
StClass blockClosureClass;
StSystem() {
objectClass = new StClass("Object", null);
nilClass = new StClass("Nil", objectClass);
StClass booleanClass = new StClass("Boolean", objectClass);
trueClass = new StClass("True", booleanClass);
falseClass = new StClass("False", booleanClass);
integerClass = new StClass("Integer",
new StClass("Number", objectClass));
StClass collectionClass = new StClass("Collection", objectClass);
stringClass = new StClass("String", collectionClass);
arrayClass = new StClass("Array", collectionClass);
blockClosureClass = new StClass("BlockClosure", objectClass,
"returnContext", "blockMethod")
.add("value", new StMethod(4, 0, 0))
.add("value:", new StMethod(4, 0, 0))
.add("value:value:", new StMethod(4, 0, 0))
.add("value:value:value:", new StMethod(4, 0, 0));
}
StContext send(StContext context, int argumentCount,
Object selector, StClass startClass) {
Object[] arguments = allocate(argumentCount);
while (--argumentCount >= 0) {
arguments[argumentCount] = context.pop();
}
Object receiver = context.pop();
if (startClass == null) {
startClass = classOf(receiver);
}
StMethod method = startClass.lookup(selector);
if (method == null) {
throw new Error();
}
if (method.primitive != 0) {
try {
return primitive(context, method.primitive,
receiver, arguments);
} catch (RuntimeException e) {
}
}
return new StMethodContext(context, method, receiver, arguments);
}
StClass classOf(Object object) {
if (object == null) {
return nilClass;
} else if (object instanceof Boolean) {
return (Boolean) object ? trueClass : falseClass;
} else if (object instanceof Integer) {
return integerClass;
} else if (object instanceof String) {
return stringClass;
} else if (object instanceof Object[]) {
return arrayClass;
} else if (object instanceof StObject) {
return ((StObject) object).stClass;
} else {
throw new Error();
}
}
StContext primitive(StContext context, int primitive,
Object receiver, Object[] arguments) {
switch (primitive) {
case 1: {// "=="
return context.push(equals(receiver, arguments[0]));
}
case 2: {// "+"
Integer a = (Integer) receiver;
Integer b = (Integer) arguments[0];
return context.push(a + b);
}
...
default:
throw new Error();
}
}
}
Einige offensichtliche Optimierungen wurden nicht gemacht. Die
System-Funktionen habe ich weggelassen, hier müsste es einige dutzend
geben - je nachdem, wie mächtig das System sein soll. Das
Smalltalk-System hat zur Zeit keinen Zugriff auf globale Objekte oder
auch nur auf seine Klassen: Dies verhindert effektiv das Anlegen neuer
Objekte.
Ansonsten scheint mir die virtuelle Maschine aber recht vollständig zu
sein. Um bedingte Anweisungen ausführen zu können, müsste man z.B. die
folgenden Methoden dem System hinzufügen:
True>>ifTrue: aBlock ifFalse: anotherBlock
^aBlock value
False>>ifTrue: aBlock ifFalse: anotherBlock
^anotherBlock value
Also:
trueClass.add("ifTrue:ifFalse:", new StMethod(
0, /* normale Methode */
0, /* keine lokalen Variablen */
1, /* Stackgröße */
0, 0, /* push argument "aBlock" */
8, 0, "value", /* send "value" */
10));
falseClass.add(
"ifTrue:ifFalse:",
new StMethod(0, 0, 1, 0, 1, 8, 0, 10));
Für eine while-Schleife sollte dies reichen:
BlockClosure>>whileTrue: aBlock
self value ifTrue: [aBlock value. self whileTrue: aBlock].
^nil
wobei
Boolean>>ifTrue: aBlock
^self ifTrue: aBlock ifFalse: []
und das wäre dann:
trueClass.superclass.add(
"ifTrue:",
new StMethod(0, 0, 3, 4, 0, 0, 0, 12,
new StMethod(0, 0, 1, 3, null, 10),
8, 2, "ifTrue:ifFalse:", 10));
blockClosureClass.add(
"whileTrue:",
new StMethod(0, 0, 3, 4, 8, 0, "value", 12,
new StMethod(0, 0, 2, ?, 0, 8, 0, "value",
7, 4, ?, 0, 8, 1, "whileTrue:", 10), 7,
3, null, 10));
Ich sehe aber gerade, dass dort, wo "?" steht, ein Befehl in der VM
fehlt, der es ermöglicht, auf die Daten des äußeren Kontexts
zuzugreifen. Mein VM implementiert offentlicht keine Closures, sondern
nur anonyme Methoden :(
--
Stefan Matthias Aust |
|
| Back to top |
|
 |
Stefan Matthias Aust Guest
|
Posted: Wed Dec 06, 2006 11:28 pm Post subject: Re: Smalltalk-Interpreter in Java |
|
|
Stefan Matthias Aust schrieb:
| Quote: | Schalten Sie auch das nächste Mal wieder ein, wenn es heißt: Wozu eine
VM, ich kann doch einfach den AST evaluieren...
|
So schnell gebe ich mit meinem Pseudo-Blog hier nicht auf... mehr
Codefragmente zum Thema halbfertige Smalltalk-Interpreter...
Meine AST-Klassen vom letzten Mal erlauben es, Klassen- und
Methodendefinitionen sowie Codefragmente (Doits) hinzuschreiben.
Methoden und Doits bestehen aus Ausdrücken, die dann zur Laufzeit
ausgewertet werden können.
Es gilt:
abstract class Definition {
abstract void execute(Smalltalk smalltalk);
}
abstract class Expression {
abstract Object evaluate(Smalltalk smalltalk, Context context);
}
Smalltalk ist eine Java-Klasse, deren Exemplare Smalltalk-Systeme
repräsentieren und die für die Ausführung notwendige Umgebung kennen.
Ein Kontext ist ein Objekt, das zum Ausführen einer Methode (oder eines
Blocks) notwendig ist.
Eine Smalltalk-Klasse anlegen bedeutet, ein Smalltalk-Klassenobjekt
(Exemplar der Smalltalk-Klasse Class, repräsentiert durch ein Exemplar
der Java-Klasse StClass) zu erzeugen, zu initialisieren und in einer
globalen Variable mit dem angegebenen Namen abzulegen.
class ClassDefinition extends Definition {
...
void execute(Smalltalk smalltalk) {
smallalk.put(
className,
smaltalk.newClass(
className,
smalltalk.getClass(superclassName),
fieldNames,
smalltalk.newDictionary()));
}
}
class Smalltalk {
...
void put(Object key, Object value) {
systemDictionary.put(key, vaue);
}
Object get(Object key) {
return systemDictionary.get(key);
}
StClass getClass(Object key) {
StClass c = (StClass) get(key);
if (c == null) throw new SmalltalkException();
return c;
}
StClass newClass(String name, StClass superclass,
Object[] fieldNames, HashMap<Object, Object> methods) {
return new StClass(...);
}
HashMap<Object, Object> newDictionary() {
return new HashMap<Object, Object>();
}
...
}
Eine Methode anlegen bedeutet, das passende Smalltalk-Klassenobjekt
finden, ein neues Smalltalk-Methodenobjekt (Exemplar der
Smalltalk-Klasse Method, repräsentiert durch ein Exemplar der
Java-Klasse StMethod) zu erzeugen, zu initialisieren und dann dem
Methoden-Dictionary der Klasse hinzufügen.
class Method extends Definition {
...
void execute(Smalltalk smalltalk) {
smalltalk.getClass(className).addMethod(
name,
smalltalk.newMethod(
parameters,
temporaries,
primitive,
expressions));
}
}
class Smalltalk {
...
StMethod newMethod(Object[] parameters, Object[] temporaries,
int primitive, Expression[] expressions) {
return new StMethod(...);
}
...
}
Ein Doit ausführen bedeutet, die Ausdrücke im globalen Kontext
ausführen. Der Empfänger ist das Smalltalk-SystemDictionary, das alle
globalen Objekte hält.
class Doit extends Definition {
void execute(Smalltalk smalltalk) {
smalltalk.execute(
smalltalk.newMethod(
Smalltalk.NONE,
temporaries,
0,
expressions));
}
}
class Smalltalk {
...
void execute(StMethod method) {
new StContext(null, method, systemDictionary).evaluate(this);
}
...
}
Eine Methode wird wie gesagt von bzw. in einem Kontext ausgeführt.
Dieser definiert den Empfänger und die Argumente der Nachricht und hält
die lokalen Variablen während der Ausführung. Smalltalk kennt neben
normalen Methoden noch Blöcke, eine Form anonymer Methoden und Closures,
die auf die umgebenen lokalen Variablen und Methodenparameter zugreifen
können. Außerdem beendet "Answer" nicht nur die Auswertung eines Block,
sondern auch der Methode, die den Block definiert hat.
So wird ein Kontextobjekt ausgewertet:
class StContext {
final StContext home;
final StMethod method;
final Object receiver;
final Object[] arguments;
final Object[] temporaries;
StContext(StContext home, StMethod method,
Object receiver, Object... arguments) {
...
this.temporaries = new Object[method.temporaries.length];
}
Object evaluate(Smalltalk smalltalk) {
try {
for (Expression e : method.expressions) {
e.evaluate(smalltalk, this);
}
return receiver;
} catch (AnswerException e) {
if (e.home != this) throw e;
return e.result;
}
}
static class AnswerException extends RuntimeException {
final StContext home;
final Object result;
AnswerException(StContext home, Object result) {
this.home = go(home);
this.result = result;
}
private static StContext go(StContext ctx) {
return ctx.home != null ? go(ctx.home) : ctx;
}
}
}
Die Ausführung wird also an die Ausdrücke delegiert.
Um ein Objekt als Anwort zurückzugeben, wird eine Exception in Java
benutzt, um den Laufzeitstack von Java bis zur richtigen Stelle wieder
abzubauen.
class Answer extends Expression {
...
Object evaluate(Smalltalk smalltalk, StContext context) {
return context.answer(expression.evaluate(smalltalk, context));
}
}
class StContext {
...
Object answer(Object result) {
throw new AnswerException(this, result);
}
...
}
Um eine neue BlockClosure anzulegen, wird zunächst eine (anonyme)
Methode für den Block gebaut und diese zusammen mit den aktuellen
Kontext in einem Smalltalk-Objekt (Exemplar der Java-Klasse StObject)
welches ein Exemplar der Smalltalk-Klasse BlockClosure ist abgelegt.
class Block extends Expression {
...
Object evaluate(Smalltalk smalltalk, StContext context) {
return smalltalk.newBlockClosure(
context,
smalltalk.newMethod(parameters, temporaries, 0, expressions));
}
}
Man sieht, das Kontextobjekt ist sogar in Smalltalk zugreifbar -
allerdings in meiner Implementierung nicht veränderbar, da ich ja den
Java-Laufzeitstack für die Auswertung nutze.
Um auf das an eine Variable gebundene Objekt zuzugreifen, delegiere ich
an den Kontext und dieser macht die in dieser Implementierung doch recht
ineffiziente und dreckige Arbeit:
class Get extends Expression {
...
Object evaluate(Smalltalk smalltalk, StContext context) {
return context.get(smalltalk, name);
}
}
class StContext {
...
Object get(Smalltalk smalltalk, String name) {
StContext ctx = this;
while (ctx != null) {
int index;
if ((index = indexOf(ctx.method.temporaries, name)) != -1)
return ctx.temporaries[index];
if ((index = indexOf(ctx.method.parameters, name)) != -1)
return ctx.parameters[index];
ctx = ctx.home;
}
int index = smalltalk.classOf(receiver).indexOf(name);
if (index != -1) return ((StObject) receiver).fields[index];
throw new SmalltalkException();
}
static int indexOf(Object[] elements, Object element) {
for (int i = 0; i < elements.length; i++) {
if (elements[i].equals(element)) return i;
}
return -1;
}
}
class StClass {
...
int indexOf(String name) {
int index;
if (superclass != null) {
index = superclass.indexOf(name);
if (index != -1) return index;
}
return offset(StContext.indexOf(fieldNames, name));
}
private int offset(int index) {
if (index != -1 && superclass != null)
index += superclass.fieldCount();
return index;
}
int fieldCount() {
if (superclass == null) return fieldNames.length;
return supeclass.fieldCount() + fieldNames.length;
}
}
Für's Schreiben gilt das selbe in grün:
class Set extends Expression {
...
Object evaluate(Smalltalk smalltalk, StContext context) {
return context.set(smalltalk, name,
expression.evaluate(smalltalk, context);
}
}
class StContext {
...
Object set(Smalltalk smalltalk, String name, Object value) {
StContext ctx = this;
while (ctx != null) {
int index;
if ((index = indexOf(ctx.method.temporaries, name)) != -1)
return ctx.temporaries[index] = value;
ctx = ctx.home;
}
int index = smalltalk.classOf(receiver).indexOf(name);
if (index != -1)
return ((StObject) receiver).fields[index] = value;
throw new SmalltalkException();
}
}
Literale sind trivial:
class Literal extends Expression {
...
Object evaluate(Smalltalk smalltalk, StContext context) {
return value;
}
}
Der Rückgriff auf das Empfänger-Objekt ist ebenfalls trivial:
class Self extends Expression {
Object evaluate(Smalltalk smalltalk, StContext context) {
return context.receiver;
}
}
Bleibt das Senden einer Nachricht. Statt sofort einen neuen Kontext zu
erzeugen und diesen auszuwerten, delegiere ich an das Smalltalk-System,
denn für primitive Operationen kann ich mir den neuen Kontext
normalerweise sparen.
class Self extends Expression {
...
Object evaluate(Smalltalk smalltalk, StContext context) {
Object receiver = receiverExpression.evaluate(smalltalk, context);
int length = argumentExpressions.length;
Object[] arguments = new Object[length];
for (int i = 0; i < length; i++) {
arguments[i] =
argumentExpressions[i].evaluate(smalltalk, context);
}
return smalltalk.send(context, selector, receiver, arguments);
}
}
class Smalltalk {
...
Object send(StContext context, String selector, ...) {
StMethod method = classOf(receiver).lookup(selector);
if (methd == null) throw new SmalltalkException();
if (method.primitive != 0) {
try {
return primitive(context, method, receiver, arguments);
} catch (Exception e) {
// wenn ein primitive versagt, wird die Methode normal
// ausgeführt, um ggf. Fehlerbehandlung zu machen
}
}
return new StContext(null, method, receiver, arguments);
}
Object primitive(StContext context, ...) {
switch (method.primitive) {
case 1: // answer receiver's class
return classOf(receiver);
case 2: // make new instance
StClass c = (StClass) receiver;
return new StObject(c, new Object[c.fieldCount()]);
case 3: // make new array
return new Object[(Integer) arguments[0]];
case 4: // evaluate a block
StObject object = (StObject) receiver;
StContext home = (StContext) object.fields[0];
StMethod method = (StMethod) object.fields[1];
return new StContext(
context,
method,
context.receiver,
arguments).evalute(this);
...
}
}
}
Die meiste Funktionalität des Smalltalk-Systems steckt in der eben
gezeigten Methode primitive(). Exemplarisch sei näher erklärt, wie man
einen Block auswertet. Der BlockClosure wurde die Nachricht #value (oder
#value: bei einem Argument, #value:value: bei zwei Argumenten, usw.)
geschickt. Die zugehörige Methode ist ein primitive, der ein neues
Kontextobjekt baut und dieses auswertet. Der Kontext verweist auf den
Kontext aus der BlockClosure. Damit ist er ein Blockkontext. In der
BlockClosure wurde ja der Kontext eingetragen, in dem der Block
definiert wurde. Außerdem enthalten ist die Methode, die die Ausdrücke
aus dem Block definiert.
Hierbei fällt mir auf, dass StContext#evaluate() einen Fehler hat. Eine
Methode gibt, wenn keine explizite "answer" vorhanden ist, den Empfänger
zurück. Ein Block jedoch liefert entweder das Ergebnis des letzten
Ausdrucks oder "nil", falls gar kein Ausdruck vorhanden ist. Für einen
Blockkontext würde die Methode daher so aussehen:
Object evaluate(Smalltalk smalltalk) {
Object result = null;
for (Expression e : method.expressions) {
result = e.evaluate(smalltalk, this);
}
return result;
}
Ansonsten glaube ich, die obigen Fragmente ergeben zusammen einen
funktionierenden Smalltalk-Interpreter.
--
Stefan Matthias Aust |
|
| Back to top |
|
 |
Paul Ebermann Guest
|
Posted: Thu Dec 14, 2006 1:55 am Post subject: Re: Smalltalk-Interpreter in Java |
|
|
"Stefan Matthias Aust" skribis:
[...]
| Quote: | Der Rückgriff auf das Empfänger-Objekt ist ebenfalls trivial:
class Self extends Expression {
Object evaluate(Smalltalk smalltalk, StContext context) {
return context.receiver;
}
}
Bleibt das Senden einer Nachricht. Statt sofort einen neuen Kontext zu
erzeugen und diesen auszuwerten, delegiere ich an das Smalltalk-System,
denn für primitive Operationen kann ich mir den neuen Kontext
normalerweise sparen.
class Self extends Expression {
...
Object evaluate(Smalltalk smalltalk, StContext context) {
Object receiver = receiverExpression.evaluate(smalltalk, context);
int length = argumentExpressions.length;
Object[] arguments = new Object[length];
for (int i = 0; i < length; i++) {
arguments[i] =
argumentExpressions[i].evaluate(smalltalk, context);
}
return smalltalk.send(context, selector, receiver, arguments);
}
}
|
Die Klasse sollte Send heißen, nicht Self, oder?
[...]
| Quote: | Ansonsten glaube ich, die obigen Fragmente ergeben zusammen einen
funktionierenden Smalltalk-Interpreter.
|
Nett :-)
Paul
--
Eine Signatur sollte mit "-- " abgetrennt werden,
wobei OjE meist das " " verschluckt. Eine nicht
korrekt abgetrennte Signatur ist keine Signatur ... |
|
| Back to top |
|
 |
Stefan Matthias Aust Guest
|
Posted: Fri Dec 15, 2006 1:10 am Post subject: Re: Smalltalk-Interpreter in Java |
|
|
Paul Ebermann schrieb:
| Quote: | Die Klasse sollte Send heißen, nicht Self, oder?
|
Könnte jetzt sagen, dass ich das extra gemacht habe, um zu sehen, ob das
tatsächlich jemand liest, aber... nun... das muss beim Kürzen und
umformen im Editor passiert sein. ja, das ist die Klasse "Send"
| Quote: | [...]
Ansonsten glaube ich, die obigen Fragmente ergeben zusammen einen
funktionierenden Smalltalk-Interpreter.
Nett
|
Fehlt noch ein Parser für "echte" Smalltalk-Syntax, aber der Code wartet
auch noch irgendwo darauf, mal überarbeitet zu werden... dann kann ich
mich ran machen, das nochmal ordentlich aufzuschreiben.
--
Stefan Matthias Aust |
|
| Back to top |
|
 |
Paul Ebermann Guest
|
Posted: Fri Dec 15, 2006 3:59 am Post subject: Re: Smalltalk-Interpreter in Java |
|
|
"Stefan Matthias Aust" skribis:
| Quote: | Paul Ebermann schrieb:
Die Klasse sollte Send heißen, nicht Self, oder?
Könnte jetzt sagen, dass ich das extra gemacht habe, um zu sehen, ob das
tatsächlich jemand liest, aber... [...]
|
Ich habe auch hauptsächlich deswegen geantwortet, damit du
merkst, dass jemand mitliest ... und nichts anderes gefunden,
um darüber eine Bemerkung zu machen. :-)
Paul
--
The Java Virtual Machine Specification:
http://java.sun.com/docs/books/vmspec/2nd-edition/html/VMSpecTOC.doc.html |
|
| Back to top |
|
 |
Jochen Theodorou Guest
|
Posted: Fri Dec 15, 2006 6:48 am Post subject: Re: Smalltalk-Interpreter in Java |
|
|
Paul Ebermann schrieb:
| Quote: | "Stefan Matthias Aust" skribis:
Paul Ebermann schrieb:
Die Klasse sollte Send heißen, nicht Self, oder?
Könnte jetzt sagen, dass ich das extra gemacht habe, um zu sehen, ob das
tatsächlich jemand liest, aber... [...]
Ich habe auch hauptsächlich deswegen geantwortet, damit du
merkst, dass jemand mitliest ... und nichts anderes gefunden,
um darüber eine Bemerkung zu machen.
|
also ich hab mir vorgenommen einfach mal einen kleinen Interpreter in
Groovy zu schreiben. Allerdings erst nach Silvester, vorher hab ich
keine Zeit, Groovy 1.0 muss noch raus ;)
Grus theo
--
Jochen "blackdrag" Theodorou
Groovy Tech Lead (http://groovy.codehaus.org)
http://blackdragsview.blogspot.com/ |
|
| Back to top |
|
 |
Jochen Theodorou Guest
|
Posted: Mon Dec 18, 2006 2:40 am Post subject: Re: Smalltalk-Interpreter in Java |
|
|
Wanja Gayk schrieb:
| Quote: | blackdrag (AT) uni (DOT) de said...
Stefan Matthias Aust schrieb:
Jochen Theodorou schrieb:
also ich hab mir vorgenommen einfach mal einen kleinen Interpreter in
Groovy zu schreiben.
Mit der Motivation, dass es in Groovy einfacher als in Java wäre?
Jein, das möchte ich ja gerade ehrausfinden. Ich denke schon, aber ich
möchte es genauer wissen ;)
Und wenn ihr dann richtig irre seid, schreibt ihr in Smalltalk wieder
einen Groovy-Interpreter, nur um zu sehen, ob das jetzt in Smalltalk
oder Java einfacher gewesen wäre.
Dann könnt ihr auf einer Java-VM Groovy-Programme laufen lassen und zwar
in einem, in Groovy implementierten, Smalltalk-Interpreter.
Damit wären dann alle Klarheiten beseitigt .
|
lol ;)
Gruss theo
--
Jochen "blackdrag" Theodorou
Groovy Tech Lead (http://groovy.codehaus.org)
http://blackdragsview.blogspot.com/ |
|
| Back to top |
|
 |
Stefan Matthias Aust Guest
|
Posted: Wed Dec 20, 2006 3:54 am Post subject: Re: Smalltalk-Interpreter in Java |
|
|
Wanja Gayk schrieb:
| Quote: | nobody (AT) 3plus4 (DOT) de said...
[..]
String parseParameter() {
if (at("identifier")) return string();
throw error("identifier expected");
}
[..]
Hmmm.. sehe ich das recht, dass du in der Methode "at(String)" deines
compilers z.B. auf eine "Map<String, String>" zugreifst, wobei der key
"Identifier", "Keyword", etc.. wäre und der value der aktuelle token dem
Quelltext?
|
Nein. Mit at() schaue ich auf das aktuelle Token. Statt irgendwelcher
Token-Klassen oder einer Enumeration nehme ich aus Bequemlichkeit
einfach Strings. Die Methode ist so implementiert:
boolean at(String token) {
return this.token.equals(token);
}
wobei
void advance() {
this.token = nextToken();
}
und
String nextToken() {
char c = next();
...
if (Character.isLetter(c)) {
StringBuilder b = new StringBuilder();
...
this.value = b.toString();
return "identifier";
}
...
}
Das ist alles recht simpel und pragmatisch gestrickt.
--
Stefan Matthias Aust |
|
| Back to top |
|
 |
Stefan Matthias Aust Guest
|
Posted: Wed May 16, 2007 4:35 pm Post subject: Re: Smalltalk-Interpreter in Java |
|
|
Stefan Ram schrieb:
| Quote: | Dann solltest Du dich also bei einem »SqF board member« melden.
|
Wie OT das auch immer hier ist: Die sollten schon längst meine
Unterschrift vorliegen haben...
--
Stefan Matthias Aust |
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|