diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..2847237
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+bin
+*.pidb
+*.userprefs
\ No newline at end of file
diff --git a/Lang/Expression.cs b/Lang/Expression.cs
new file mode 100644
index 0000000..f425be1
--- /dev/null
+++ b/Lang/Expression.cs
@@ -0,0 +1,142 @@
+// ROBOLOGO
+// Copyright (C) 2011 max.kaufmann@gmail.com
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+using System;
+namespace RoboLogo.Lang {
+
+ ///
+ /// Interface for all instructions. Conditional expressions are treated as expr!=0 numeric expressions
+ ///
+ public abstract class Expression {
+ public abstract int Compute(Interpreter interp);
+ }
+
+ ///
+ /// Implemented Binary Operations
+ ///
+ public enum BinaryOperation { Add, Subtract, Multiply, Divide, And, Or, Equals, GreaterThan, LessThan }
+
+ ///
+ /// Implemented Unary Operations
+ ///
+ public enum UnaryOperation { Negate, Complement }
+
+ ///
+ /// Null expression just returns 0
+ ///
+ public class NullExpression : Expression {
+ override public int Compute(Interpreter interp) {
+ return 0;
+ }
+ }
+
+ ///
+ /// A literal expression evaluates to a constant
+ ///
+ public class LiteralExpression : Expression {
+ int mValue;
+
+ public LiteralExpression(int val) {
+ mValue = val;
+ }
+
+ override public int Compute(Interpreter interp) {
+ return mValue;
+ }
+ }
+
+ ///
+ /// A variable expression looks up a value in the current executing context
+ ///
+ public class VariableExpression : Expression {
+ string mName;
+
+ public VariableExpression(string name) {
+ mName = name;
+ }
+
+ override public int Compute(Interpreter interp) {
+ int result;
+ if (!interp.GetVariable(mName, out result)) {
+ Console.WriteLine("Undefined Variable Expression");
+ }
+ return result;
+ }
+ }
+
+ ///
+ /// Implementation of all binary operations
+ ///
+ public class BinaryOperationExpression : Expression {
+ BinaryOperation mOp;
+ Expression mLeft;
+ Expression mRight;
+
+ public BinaryOperationExpression(BinaryOperation op, Expression left, Expression right) {
+ mOp = op;
+ mLeft = left;
+ mRight = right;
+
+ }
+
+ override public int Compute(Interpreter interp) {
+ switch(mOp) {
+ case BinaryOperation.Add: return mLeft.Compute(interp) + mRight.Compute(interp);
+ case BinaryOperation.Subtract: return mLeft.Compute(interp) - mRight.Compute(interp);
+ case BinaryOperation.Multiply: return mLeft.Compute(interp) * mRight.Compute(interp);
+ case BinaryOperation.Divide:
+ int r = mRight.Compute(interp);
+ if (r == 0) {
+ Console.WriteLine("Divide By Zero");
+ return 0;
+ } else {
+ return mLeft.Compute(interp) / r;
+ }
+ case BinaryOperation.And: return (mLeft.Compute(interp) != 0) && (mRight.Compute(interp) != 0) ? 1 : 0;
+ case BinaryOperation.Or: return (mLeft.Compute(interp) != 0) || (mRight.Compute(interp) != 0) ? 1 : 0;
+ case BinaryOperation.Equals: return mLeft.Compute(interp) == mRight.Compute(interp) ? 1 : 0;
+ case BinaryOperation.GreaterThan: return mLeft.Compute(interp) > mRight.Compute(interp) ? 1 : 0;
+ case BinaryOperation.LessThan: return mLeft.Compute(interp) < mRight.Compute(interp) ? 1 : 0;
+ default: return 0;
+ }
+ }
+ }
+
+ ///
+ /// Implementation of all unary operations
+ ///
+ public class UnaryOperationExpression : Expression {
+ UnaryOperation mOp;
+ Expression mExpr;
+
+ public UnaryOperationExpression(UnaryOperation op, Expression exp) {
+ mOp = op;
+ mExpr = exp;
+ }
+
+ override public int Compute(Interpreter interp) {
+ switch(mOp) {
+ case UnaryOperation.Negate: return -mExpr.Compute(interp);
+ case UnaryOperation.Complement: return mExpr.Compute(interp) != 0 ? 0 : 1;
+ default: return 0;
+ }
+ }
+ }
+
+
+
+}
+
diff --git a/Lang/Instruction.cs b/Lang/Instruction.cs
new file mode 100644
index 0000000..30c81c0
--- /dev/null
+++ b/Lang/Instruction.cs
@@ -0,0 +1,97 @@
+// ROBOLOGO
+// Copyright (C) 2011 max.kaufmann@gmail.com
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+using System;
+
+namespace RoboLogo.Lang {
+
+ ///
+ /// Interface for all instructions.
+ ///
+ public abstract class Instruction {
+ public abstract void Execute(Interpreter interp);
+ }
+
+ ///
+ /// Implementation of a goto instruction
+ ///
+ public class GotoInstruction : Instruction {
+ int mIndex;
+
+ public GotoInstruction(int index) {
+ mIndex = index;
+ }
+
+ override public void Execute(Interpreter interp) {
+ interp.Goto(mIndex);
+ }
+ }
+
+ ///
+ /// Implementation of a set-global variable instruction
+ ///
+ public class SetInstruction : Instruction {
+ string mName;
+ Expression mExpr;
+
+ public SetInstruction(string name, Expression exp) {
+ mName = name;
+ mExpr = exp;
+ }
+
+ override public void Execute(Interpreter interp) {
+ interp.SetVariable(mName, mExpr.Compute(interp));
+ }
+ }
+
+ ///
+ /// Implemention of a branch instruciton, used to implement conditionals and loops
+ ///
+ public class BranchInstruction : Instruction {
+ Expression mCondition;
+ int mTrueIndex;
+ int mFalseIndex;
+
+ public BranchInstruction(Expression condition, int trueIndex, int falseIndex) {
+ mCondition = condition;
+ mTrueIndex = trueIndex;
+ mFalseIndex = falseIndex;
+ }
+
+ override public void Execute(Interpreter interp) {
+ interp.Goto(mCondition.Compute(interp) == 0 ? mFalseIndex : mTrueIndex);
+ }
+ }
+
+ ///
+ /// Implementation of a custom action instruction, for binding to user-space C# code
+ ///
+ public class ActionInstruction : Instruction {
+ Action mAction;
+ Expression mExpr;
+
+ public ActionInstruction(Action action, Expression exp) {
+ mAction = action;
+ mExpr = exp;
+ }
+
+ override public void Execute(Interpreter interp) {
+ mAction(mExpr.Compute(interp));
+ }
+ }
+
+}
+
diff --git a/Lang/Interpreter.cs b/Lang/Interpreter.cs
new file mode 100644
index 0000000..789b49b
--- /dev/null
+++ b/Lang/Interpreter.cs
@@ -0,0 +1,70 @@
+// ROBOLOGO
+// Copyright (C) 2011 max.kaufmann@gmail.com
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+using System;
+using System.Collections.Generic;
+
+namespace RoboLogo.Lang {
+
+ ///
+ /// The interpreter is the facade-class for the virtual machine. It maintains an instruciton buffer,
+ /// an instruction pointer, and a dictionary of global variables.
+ ///
+
+ public class Interpreter {
+ Instruction[] mInstructions;
+ int mCurrentInstruction;
+ int mNextInstruction;
+ Dictionary mEnvironment = new Dictionary();
+
+ public Interpreter (Instruction[] instructions) {
+ mInstructions = instructions;
+ mCurrentInstruction = 0;
+ }
+
+ public bool ExecuteNextInstruction() {
+ if (mCurrentInstruction >= mInstructions.Length) { return false; }
+ mNextInstruction = mCurrentInstruction + 1;
+ mInstructions[mCurrentInstruction].Execute(this);
+ mCurrentInstruction = mNextInstruction;
+ return true;
+ }
+
+ internal void Goto(int n) {
+ mNextInstruction = n;
+ }
+
+ internal void SetVariable(string name, int val) {
+ if (!mEnvironment.ContainsKey(name)) {
+ mEnvironment.Add(name, val);
+ } else {
+ mEnvironment[name] = val;
+ }
+ }
+
+ internal bool GetVariable(string name, out int val) {
+ if (!mEnvironment.ContainsKey(name)) {
+ val = 0;
+ return false;
+ } else {
+ val = mEnvironment[name];
+ return true;
+ }
+ }
+ }
+
+}
+
diff --git a/Main.cs b/Main.cs
new file mode 100644
index 0000000..524b11b
--- /dev/null
+++ b/Main.cs
@@ -0,0 +1,99 @@
+// ROBOLOGO
+// Copyright (C) 2011 max.kaufmann@gmail.com
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+using RoboLogo.Lang;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace RoboLogo {
+ class MainClass {
+
+ public static void Main (string[] args) {
+ // a quick interpreter test program (for-loop)
+ var interpreter = new Interpreter(StupidCompiler(@"
+ set i 0
+ hello
+ set i i+1
+ branch i<10 1 4
+ "));
+ while(interpreter.ExecuteNextInstruction()) {}
+ }
+
+ //---------------------------------------------------------------------
+ // Implementation of a "stupid" assembly compiler for testing the
+ // interpreter separate from the regular compiler
+ //---------------------------------------------------------------------
+
+ static Instruction[] StupidCompiler(string src) {
+ var buffer = new List();
+ foreach(var line in src.Split('\n')) {
+ var trim = line.Trim();
+ if (trim.Length > 0) {
+ var tokens = trim.Split(' ');
+ switch(tokens[0]) {
+ case "set":
+ buffer.Add( new SetInstruction(tokens[1], StupidExpressionParser(tokens[2])) );
+ break;
+ case "hello":
+ buffer.Add( new ActionInstruction(arg=>Console.WriteLine("Hello, World"), new NullExpression()) );
+ break;
+ case "branch":
+ buffer.Add( new BranchInstruction(StupidExpressionParser(tokens[1]), int.Parse(tokens[2]), int.Parse(tokens[3])) );
+ break;
+ }
+ }
+ }
+ return buffer.ToArray();
+ }
+
+ static readonly Dictionary kOpLookup = InitOpTable();
+
+ static Dictionary InitOpTable() {
+ var result = new Dictionary();
+ result.Add('+', BinaryOperation.Add);
+ result.Add('-', BinaryOperation.Subtract);
+ result.Add('*', BinaryOperation.Multiply);
+ result.Add('/', BinaryOperation.Divide);
+ result.Add('&', BinaryOperation.And);
+ result.Add('|', BinaryOperation.Or);
+ result.Add('=', BinaryOperation.Equals);
+ result.Add('>', BinaryOperation.GreaterThan);
+ result.Add('<', BinaryOperation.LessThan);
+ return result;
+ }
+
+ static Expression StupidExpressionParser(string expr) {
+ int index = 0;
+ int literal;
+ while(!kOpLookup.ContainsKey(expr[index])) {
+ index++;
+ if (index == expr.Length) {
+ // not a binary operation
+ return int.TryParse(expr, out literal) ? (Expression) new LiteralExpression(literal) : (Expression) new VariableExpression(expr);
+ }
+ }
+ var left = expr.Substring(0, index);
+ var right = expr.Substring(index+1);
+ return new BinaryOperationExpression(
+ kOpLookup[expr[index]],
+ int.TryParse(left, out literal) ? (Expression) new LiteralExpression(literal) : (Expression) new VariableExpression(left),
+ int.TryParse(right, out literal) ? (Expression) new LiteralExpression(literal) : (Expression) new VariableExpression(right)
+ );
+ }
+ }
+}
+
diff --git a/README b/README
new file mode 100644
index 0000000..47a8ce4
--- /dev/null
+++ b/README
@@ -0,0 +1,20 @@
+// ROBOLOGO
+// Copyright (C) 2011 max.kaufmann@gmail.com
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+An academic implementation of a LOGO-like scripting language for C#. I don't require optimization, so I'm designing for customizability and maintainability rather than performance.
+
+Comments/Questions welcome: max.kaufmann@gmail.com
+
diff --git a/RoboLogo.csproj b/RoboLogo.csproj
new file mode 100644
index 0000000..74dddb6
--- /dev/null
+++ b/RoboLogo.csproj
@@ -0,0 +1,47 @@
+
+
+
+ Debug
+ x86
+ 9.0.21022
+ 2.0
+ {2D2D601A-4CC0-4FFF-931D-CC8575CF4930}
+ Exe
+ RoboLogo
+ RoboLogo
+ v3.5
+
+
+ true
+ full
+ false
+ bin\Debug
+ DEBUG
+ prompt
+ 4
+ x86
+ true
+
+
+ none
+ false
+ bin\Release
+ prompt
+ 4
+ x86
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/RoboLogo.sln b/RoboLogo.sln
new file mode 100644
index 0000000..7643e58
--- /dev/null
+++ b/RoboLogo.sln
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RoboLogo", "RoboLogo.csproj", "{2D2D601A-4CC0-4FFF-931D-CC8575CF4930}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|x86 = Debug|x86
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {2D2D601A-4CC0-4FFF-931D-CC8575CF4930}.Debug|x86.ActiveCfg = Debug|x86
+ {2D2D601A-4CC0-4FFF-931D-CC8575CF4930}.Debug|x86.Build.0 = Debug|x86
+ {2D2D601A-4CC0-4FFF-931D-CC8575CF4930}.Release|x86.ActiveCfg = Release|x86
+ {2D2D601A-4CC0-4FFF-931D-CC8575CF4930}.Release|x86.Build.0 = Release|x86
+ EndGlobalSection
+ GlobalSection(MonoDevelopProperties) = preSolution
+ StartupItem = RoboLogo.csproj
+ EndGlobalSection
+EndGlobal