Cow Interpreter

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 :slight_smile:
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 :wink:

ROFL, wollt ihr jetzt alle Sprachen durchmachen oder nur die ganz exotischen?

Ich würde sagen nur die exotischen, sind einfach interessanter und gibts noch nicht so oft. :slight_smile:

Gut Schuß
VuuRWerK :wink:

P.S.: Wie siehts aus: Eine IDE die nur solche Sprachen unterstützt? Wer macht mit? :smiley:

Ganz vergessen, ein kleine Test-Programm:

package de.braincompiler.cow;

import java.io.FileNotFoundException;
import java.io.IOException;

public class CowInterpreterTest
{
	public static void main(String[] args) throws FileNotFoundException, IOException {
		CowInterpreter ci = new CowInterpreter("bin/test.cow");
		ci.execute();
	}
}

Gut Schuß
VuuRWerK :wink:

Hiho,

feine Sache! Scheint etwas aufw(alt:e/neu:ä)ndiger zu sein als BrainFuck.
Hmm wir können ja zu BF und Cow nen Eclipse Plugin schreiben. :smiley:

Für WhiteSpace natürlich dann auch mit Syntax Highlighting!

Übrigens gibts im BF Thread nen Update - nun wird die Interpretierung vom BF Source noch optimiert! :wink:

bye Saxony

Oder ich hab es einfach nur zu aufwändig gemacht :smiley: Zudem hat Cow einen etwas erweiterten „Befehlssatz“.

Das ist gar nicht mal so abwegig. Tabs bekommen als Hintergrundfarbe Gelb, Spaces Blau und NewLines Grün :stuck_out_tongue_winking_eye:
AutoCompletion wird ebenfalls extrem einfach :slight_smile:

Ich werd den Cow-Interpreter auch noch ein wenig optimieren, gerade das parsen und auch das ausführen des Codes, weiß schon wie muss nur mal Zeit dafür finden ^^

Gut Schuß
VuuRWerK :wink: