Nachdem Saxony schon einen Interpreter für BrainF*ck zur Verfügung gestellt hat erlaube ich mir hiermit einen Interpreter für die Esoterische Sprache Cow zur Verfügung zu stellen.
package de.braincompiler.cow;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
/**
* @author VuuRWerK
*/
public class CowInterpreter
{
private static final class CowSpec
{
int Code;
String Instruction;
public CowSpec(int c, String i) {
Code = c;
Instruction = i;
}
}
private final class CodeVec
{
private int[] m_codes = new int[10];
private int m_size;
/*
* inspired by implementation of java.util.ArrayList#ensureCapacity
* and other
*/
private final void ensureCapacity(int min) {
int curCapacity = m_codes.length;
if(min > curCapacity) {
int newCapacity = (curCapacity * 3) / 2 + 1;
if(newCapacity < min)
newCapacity = min;
m_codes = Arrays.copyOf(m_codes, newCapacity);
}
}
public void pushBack(int i) {
ensureCapacity(m_size + 1);
m_codes[m_size++] = i;
}
public final void decrementCode(int idx) {
rangeCheck(idx);
m_codes[idx]--;
}
public final void incrementCode(int idx) {
rangeCheck(idx);
m_codes[idx]++;
}
public final void set(int idx, int value) {
rangeCheck(idx);
m_codes[idx] = value;
}
public final int get(int idx) {
rangeCheck(idx);
return(m_codes[idx]);
}
public final int size() {
return(m_size);
}
public final int endPos() {
return(m_size - 1);
}
private final void rangeCheck(int idx) {
if(idx >= m_size)
throw(new IndexOutOfBoundsException(idx + " >= " + m_size));
}
}
public static final CowSpec moo = new CowSpec(0, "moo");
public static final CowSpec mOo = new CowSpec(1, "mOo");
public static final CowSpec moO = new CowSpec(2, "moO");
public static final CowSpec mOO = new CowSpec(3, "mOO");
public static final CowSpec Moo = new CowSpec(4, "Moo");
public static final CowSpec MOo = new CowSpec(5, "MOo");
public static final CowSpec MoO = new CowSpec(6, "MoO");
public static final CowSpec MOO = new CowSpec(7, "MOO");
public static final CowSpec OOO = new CowSpec(8, "OOO");
public static final CowSpec MMM = new CowSpec(9, "MMM");
public static final CowSpec OOM = new CowSpec(10, "OOM");
public static final CowSpec oom = new CowSpec(11, "oom");
private static final int EOF = -1;
private static final char LF = '
';
private static final char CR = '\r';
private static final char SPACE = ' ';
private static final char TAB = ' ';
private final File m_srcFile;
private CodeVec m_program = new CodeVec();
private CodeVec m_memory = new CodeVec();
private int m_memPos;
private int m_progPos;
private boolean m_hasRegisterVal = false;
private int m_registerVal;
public CowInterpreter(String srcFilename) {
this(new File(srcFilename));
}
public CowInterpreter(File srcFile) {
m_srcFile = srcFile;
}
private void quit(final String msg) {
if(msg != null) {
System.out.println(msg);
return;
}
System.out.println("execution done.");
}
private final void readIn() throws IOException {
BufferedReader bufReader = new BufferedReader(new InputStreamReader(System.in));
System.out.println("> ");
m_memory.pushBack(Integer.parseInt(bufReader.readLine()));
}
private final void printOut(String format, int code) {
System.out.print(String.format(format, code));
}
private boolean exec(int code) throws IOException {
switch(code) {
// moo
case 0:
if(m_progPos == 0)
quit("error in moo at " + m_progPos + "!");
m_progPos--;
int lvl = 1;
while(lvl > 0) {
if(m_progPos == 0)
break;
m_progPos--;
if(m_program.get(m_progPos) == moo.Code)
lvl++;
else if(m_program.get(m_progPos) == MOO.Code)
lvl--;
}
if(lvl != 0)
quit("error in moo, lvl not 0!");
return(exec(m_program.get(m_progPos)));
// mOo
case 1:
if(m_memPos == 0)
quit("error in mOo, progPos == 0!");
else
m_memPos--;
break;
// moO
case 2:
m_memPos++;
if(m_memPos == m_memory.size()) {
m_memory.pushBack(0);
m_memPos = m_memory.size();
m_memPos--;
}
break;
// mOO
case 3:
if(m_memory.get(m_memPos) == mOO.Code)
quit("error in mOO, " + m_memory.get(m_memPos) + " == " + mOO.Code + "!");
return(exec(m_memory.get(m_memPos)));
// Moo
case 4:
if(m_memory.get(m_memPos) != 0)
printOut("%c", m_memory.get(m_memPos));
else
readIn(); // TODO: check whether it is better to read in a character instead of int
break;
// MOo
case 5:
m_memory.decrementCode(m_memPos);
break;
// MoO
case 6:
m_memory.incrementCode(m_memPos);
break;
// MOO
case 7:
if(m_memory.get(m_memPos) == moo.Code) {
int level = 1;
int prev = 0;
m_progPos++;
if(m_progPos == m_program.size())
break;
while(level > 0) {
prev = m_program.get(m_progPos);
m_progPos++;
if(m_progPos == m_program.size())
break;
if(m_program.get(m_progPos) == MOO.Code) {
level++;
} else if(m_program.get(m_progPos) == moo.Code) {
level--;
if(prev == MOO.Code)
level--;
}
}
if(level != 0)
quit("error in MOO, level not 0!");
}
break;
// OOO
case 8:
m_memory.set(m_memPos, 0);
break;
// MMM
case 9:
if(m_hasRegisterVal)
m_memory.set(m_memPos, m_registerVal);
else
m_registerVal = m_memory.get(m_memPos);
m_hasRegisterVal = !m_hasRegisterVal;
break;
// OOM
case 10:
printOut("%d
", m_memory.get(m_memPos));
break;
// oom
case 11:
readIn();
break;
default:
quit(String.format("error in CowScript: Undefined Code = %02d", code));
break;
}
return(true);
}
public void execute() throws FileNotFoundException, IOException {
parse();
m_memPos = 0;
m_memory.pushBack(0);
for(m_progPos = 0; m_progPos < m_program.size(); m_progPos++) {
if(!exec(m_program.get(m_progPos)))
break;
}
}
private void parse() throws FileNotFoundException, IOException {
final BufferedReader bufReader = new BufferedReader(new FileReader(m_srcFile));
char[] buf = new char[1], cmdBuf = new char[3];
int idx = 0;
while(bufReader.read(buf, 0, 1) != EOF) {
if(buf[0] == LF || buf[0] == CR || buf[0] == SPACE || buf[0] == TAB)
continue;
cmdBuf[idx++] = buf[0];
if(idx == 3) {
idx = 0;
String cmd = String.format("%c%c%c", cmdBuf[0], cmdBuf[1], cmdBuf[2]);
if(cmd.equals(moo.Instruction))
m_program.pushBack(moo.Code);
else if(cmd.equals(mOo.Instruction))
m_program.pushBack(mOo.Code);
else if(cmd.equals(moO.Instruction))
m_program.pushBack(moO.Code);
else if(cmd.equals(mOO.Instruction))
m_program.pushBack(mOO.Code);
else if(cmd.equals(Moo.Instruction))
m_program.pushBack(Moo.Code);
else if(cmd.equals(MOo.Instruction))
m_program.pushBack(MOo.Code);
else if(cmd.equals(MoO.Instruction))
m_program.pushBack(MoO.Code);
else if(cmd.equals(MOO.Instruction))
m_program.pushBack(MOO.Code);
else if(cmd.equals(OOO.Instruction))
m_program.pushBack(OOO.Code);
else if(cmd.equals(MMM.Instruction))
m_program.pushBack(MMM.Code);
else if(cmd.equals(OOM.Instruction))
m_program.pushBack(OOM.Code);
else if(cmd.equals(oom.Instruction))
m_program.pushBack(oom.Code);
}
}
}
}
Testen könnt Ihr es z.B. mit folgendem Script.
Viel Spaß damit, vielleicht brauch ihn ja mal einer
Wenn ich wieder etwas mehr Zeit habe werde ich den Interpreter ggf. noch weiter ausbauen denn im Moment hat er keine bis ganz schlechte Fehlerbehandlung. Ausserdem werde ich versuchen diesen Interpreter für Unix-Systeme zur Verfügung zu stellen damit man damit genauso Scripte schreiben kann wie mit Bash etc. Zudem ist das parsen noch völliger Käse aber es musste erstmal schnell gehen :o
Gut Schuß
VuuRWerK