Smalltalk - Can write the Java program in Smalltalk?
-
03-06-2021 - |
Question
I am trying to convert this Java interpreter I wrote for my compiler to a Smalltalk interpreter. Is it possible? If so, what would be a good resources to look at? I am completely new to Smalltalk, looks weird to me for now. I would appreciate any help, thanks. Some more info on the program: The input would be an intermediate code file a sample of which is as below.
Intermediate code file, which computes the factorial of a number:
read
store x
push x
store i
push 1.0
store fact
push i
push 1.0
greater
testfgoto 21
push fact
push i
multiply
store fact
push i
push 1.0
minus
store i
push 1.0
testtgoto 7
push fact
print
end
JavaExecutor.java Program :
public void executor(){
String operation = null;
StringTokenizer tokens = null;
String key,value = null;
Double tempVar = null;
// Traverse the Arraylist to get the operations
for(int i=0; i < operations.size(); i++){
operation = (String)operations.get(i);
System.out.println("Operation -------"+ operation);
tokens = new StringTokenizer(operation);
while(tokens.hasMoreTokens()){
key = tokens.nextToken();
//System.out.println("KEY "+ key);
if(key.toUpperCase().equals("PUSH")){
//System.out.println("Push Operation");
value = (String)tokens.nextToken();
//System.out.println("value "+ value);
if(checkforVaribaleName(value)){
stack.push((Double)assignments.get(value));
System.out.println("PUSH"+ (Double)assignments.get(value));
}
else if(value != null){
stack.push(Double.parseDouble(value));
System.out.println("PUSH" + value);
} else{
stack.push(0.0);
System.out.println("PUSH" + 0.0);
}
break;
}else if(key.toUpperCase().equals("POP")){
//NO LOGIC
break;
}else if(key.toUpperCase().equals("READ")){
//System.out.println("Read Operation");
tempVar = readDoubleFromConsole();
stack.push(tempVar);
System.out.println("PUSHP :"+tempVar);
break;
}else if(key.toUpperCase().equals("WRITE")){
break;
}else if(key.toUpperCase().equals("MULTIPLY")){
//System.out.println("MULTIPLY operation");
Double first = (Double)stack.pop();
Double second = (Double)stack.pop();
stack.push(first*second);
System.out.println("PUSH "+ first*second);
break;
}else if(key.toUpperCase().equals("DIVIDE")){
Double first = (Double)stack.pop();
Double second = (Double)stack.pop();
stack.push(second/first);
break;
}else if(key.toUpperCase().equals("PLUS")){
Double first = (Double)stack.pop();
Double second = (Double)stack.pop();
stack.push(second+first);
break;
}else if(key.toUpperCase().equals("MINUS")){
Double first = (Double)stack.pop();
Double second = (Double)stack.pop();
stack.push(second-first);
System.out.println("PUSH "+ (second-first));
break;
}else if(key.toUpperCase().equals("GREATER")){
//System.out.println("GREATER operation");
Double first = (Double)stack.pop();
System.out.println("POP :"+first);
Double second = (Double)stack.pop();
System.out.println("POP "+ second);
if(second>first){
stack.push(1.0);
}
else{
stack.push(0.0);
}
break;
}else if(key.toUpperCase().equals("LESS")){
Double first = (Double)stack.pop();
Double second = (Double)stack.pop();
if(second<first){
stack.push(1.0);
}
else{
stack.push(0.0);
}
break;
}else if(key.toUpperCase().equals("EQUAL")){
Double first = (Double)stack.pop();
Double second = (Double)stack.pop();
if(second==first){
stack.push(1.0);
}
else{
stack.push(0.0);
}
break;
}else if(key.toUpperCase().equals("STORE")){
//System.out.println("Store operation");
value = (String)tokens.nextToken();
assignments.put(value, (Double)stack.pop());
System.out.println("POP :"+assignments.get(value));
break;
}else if(key.toUpperCase().equals("TESTFGOTO")){
value = (String)tokens.nextToken();
if((Double)stack.pop() == 0.0){
System.out.println("POP " +0.0);
i = Integer.parseInt(value)-2;
}
break;
}else if(key.toUpperCase().equals("TESTTGOTO")){
value = (String)tokens.nextToken();
if((Double)stack.pop() == 1.0){
System.out.println("POP " +1.0);
i = (Integer.parseInt(value)-2);
System.out.println(i);
}
break;
}else if(key.toUpperCase().equals("PRINT")){
//System.out.println("PRINT operation");
System.out.println("Result "+stack.pop());
break;
}else if(key.toUpperCase().equals("END")){
System.out.println("Execution Completed");
System.exit(0);
}
}
}
}
public static void main(String args[])
{
String fileName = null;
if(args.length > 0)
{
fileName = args[0];
}
else{
System.out.println("Usage : JavaExecutor fileName.inp");
System.exit(0);
}
JavaExecutor j = new JavaExecutor(fileName);
j.readFromFile();
j.executor();
}
}
Solution
Here's a VisualWorks Smalltalk version of the interpreter:
'From VisualWorks, 7.8 of March 30, 2011 on May 1, 2012 at 9:47:31 PM'!
CodeComponent create: #package named: 'IntermediateInterpreter'!"Package IntermediateInterpreter*"!
CodeComponent create: #package named: 'IntermediateInterpreter'!
Smalltalk defineClass: #IntermediateInterpreter
superclass: #{Core.Object}
indexedType: #none
private: false
instanceVariableNames: 'lines currentLineNumber variables stack commands '
classInstanceVariableNames: ''
imports: ''
category: ''!
!IntermediateInterpreter class methodsFor: 'instance creation'!
new
^super new initialize
! !
!IntermediateInterpreter methodsFor: 'initialize-release'!
initialize
stack := OrderedCollection new.
variables := Dictionary new.
lines := OrderedCollection new.
self initializeCommands
!
initializeCommands
commands := Dictionary new.
commands
at: 'READ' put: [:values | stack add: (self tokenize: (Dialog request: 'value?' initialAnswer: ''))];
at: 'STORE' put: [:values | variables at: values second put: stack removeLast];
at: 'PUSH' put: [:values | stack add: ((self isVariableName: values second) ifTrue: [variables at: values second] ifFalse: [values second])];
at: 'GREATER' put: [:values | | a b | b := stack removeLast. a := stack removeLast. stack add: (a > b ifTrue: [1.0] ifFalse: [0.0])];
at: 'MULTIPLY' put: [:values | | a b | b := stack removeLast. a := stack removeLast. stack add: a * b ];
at: 'MINUS' put: [:values | | a b | b := stack removeLast. a := stack removeLast. stack add: a - b ];
at: 'TESTFGOTO' put: [:values | (stack removeLast - 0.0) abs < 0.01 ifTrue: [currentLineNumber := values second]];
at: 'TESTTGOTO' put: [:values | (stack removeLast - 1.0) abs < 0.01 ifTrue: [currentLineNumber := values second]];
at: 'PRINT' put: [:values | Transcript show: stack removeLast printString; cr];
at: 'END' put: [:values | currentLineNumber := 0]! !
!IntermediateInterpreter methodsFor: 'testing'!
isVariableName: aString
(aString isKindOf: String) ifFalse: [^false].
^aString first isAlphabetic! !
!IntermediateInterpreter methodsFor: 'interpreting'!
interpret: aString
self createLinesFrom: aString.
currentLineNumber := 1.
self interpret!
interpret
| tokens |
[currentLineNumber = 0] whileFalse:
[tokens := lines at: currentLineNumber.
Transcript show: tokens printString; cr.
currentLineNumber := currentLineNumber + 1.
(commands at: tokens first asUppercase
ifAbsent: [self error: 'Unknown command']) value: tokens]!
tokenizeLine: aString
^(((aString tokensBasedOn: Character space)
reject: [:each | each isEmpty]) collect: [:each | self tokenize: each]) asArray!
tokenizeCurrentLine
^(((lines at: currentLineNumber) tokensBasedOn: Character space)
reject: [:each | each isEmpty]) collect: [:each | self tokenize: each]!
createLinesFrom: aString
| stream |
stream := aString readStream.
[stream atEnd] whileFalse: [lines add: (self tokenizeLine: (stream upTo: Character cr))]!
tokenize: each
^(self isVariableName: each)
ifTrue: [each]
ifFalse: [Number readFrom: each readStream]! !
OTHER TIPS
It should not be to hard at all to implement interpreter for your intermediate code in Smalltalk, but you need to know at least basics of Smalltalk: Collection classes, Stream classes, and making yourself comfortable in IDE.
Stephane Ducasse has great collection of free Smalltalk books
Automated translation between programming languages is possible in theory, feasible only in a small number of circumstances, efficient in very few of those. Even automated translation of virtual machine bytecode is usually not efficient (and the JVM is rather Java-specific; translating to/from Smalltalk bytecode may not go well).