summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSimon Robertshaw <simon@hardwired.org.uk>2012-09-21 14:05:50 (GMT)
committer Simon Robertshaw <simon@hardwired.org.uk>2012-09-21 14:05:50 (GMT)
commit939a04d3c77bf9aa8d54e912f5e12817de51756c (patch)
tree750119bf74b8fbcb409eaf02d03877c00056613d /src
parent6e44ebc358d1206c147f514225373da07b43c015 (diff)
downloadpowder-939a04d3c77bf9aa8d54e912f5e12817de51756c.zip
powder-939a04d3c77bf9aa8d54e912f5e12817de51756c.tar.gz
Testing new vm/language WIP
Diffstat (limited to 'src')
-rw-r--r--src/cat/LuaScriptInterface.cpp38
-rw-r--r--src/cat/LuaScriptInterface.h4
-rw-r--r--src/dialogues/LegacyDialogues.h11
-rw-r--r--src/interface/LuaProgressBar.h30
-rw-r--r--src/pim/Generator.cpp326
-rw-r--r--src/pim/Generator.h164
-rw-r--r--src/pim/Machine.cpp271
-rw-r--r--src/pim/Machine.h88
-rw-r--r--src/pim/Opcodes.h12
-rw-r--r--src/pim/Opcodes.inl26
-rw-r--r--src/pim/Parser.cpp646
-rw-r--r--src/pim/Parser.h78
-rw-r--r--src/pim/Scanner.cpp178
-rw-r--r--src/pim/Scanner.h22
-rw-r--r--src/pim/Token.cpp47
-rw-r--r--src/pim/Token.h79
-rw-r--r--src/tests/PowderInteractionMachine.cpp21
17 files changed, 2031 insertions, 10 deletions
diff --git a/src/cat/LuaScriptInterface.cpp b/src/cat/LuaScriptInterface.cpp
index ff282ff..19c9ac8 100644
--- a/src/cat/LuaScriptInterface.cpp
+++ b/src/cat/LuaScriptInterface.cpp
@@ -20,11 +20,14 @@
#include "dialogues/TextPrompt.h"
#include "dialogues/ConfirmPrompt.h"
#include "simulation/Simulation.h"
-#include "virtualmachine/VirtualMachine.h"
#include "game/GameModel.h"
#include "LuaScriptHelper.h"
#include "client/HTTP.h"
+//#include "virtualmachine/VirtualMachine.h"
+#include "pim/Parser.h"
+#include "pim/Machine.h"
+
#include "LuaBit.h"
#include "LuaWindow.h"
@@ -665,17 +668,24 @@ void LuaScriptInterface::initElementsAPI()
}
}
-vm::VirtualMachine * LuaScriptInterface::updateVirtualMachines[PT_NUM];
+pim::VirtualMachine * LuaScriptInterface::updateVirtualMachines[PT_NUM];
int LuaScriptInterface::updateVM(UPDATE_FUNC_ARGS)
{
- vm::VirtualMachine * vMachine = updateVirtualMachines[parts[i].type];
+ pim::VirtualMachine * machine = updateVirtualMachines[parts[i].type];
+
+ machine->CSPush(i);
+ machine->CSPush(x);
+ machine->CSPush(y);
+ machine->Call(0);
+
+
+ /*vm::VirtualMachine * vMachine = updateVirtualMachines[parts[i].type];
vm::word w;
int argAddr = 0, argCount = 5;
vMachine->sim = sim;
- /* Set up call. */
vMachine->OpPUSH(w); //Pointless null in stack
w.int4 = (argCount + 2) * sizeof(vm::word);
vMachine->OpENTER(w);
@@ -696,7 +706,7 @@ int LuaScriptInterface::updateVM(UPDATE_FUNC_ARGS)
w.int4 = (argCount + 2) * sizeof(vm::word);
vMachine->OpLEAVE(w);
vMachine->OpPOP(w); //Pop pointless null
- vMachine->End();
+ vMachine->End();*/
return 0;
}
@@ -1017,7 +1027,7 @@ int LuaScriptInterface::elements_property(lua_State * l)
}
else if(lua_type(l, 3) == LUA_TLIGHTUSERDATA)
{
- updateVirtualMachines[id] = (vm::VirtualMachine*)lua_touserdata(l, 3);
+ updateVirtualMachines[id] = (pim::VirtualMachine*)lua_touserdata(l, 3);
luacon_sim->elements[id].Update = &updateVM;
}
else if(lua_type(l, 3) == LUA_TBOOLEAN && !lua_toboolean(l, 3))
@@ -1142,7 +1152,7 @@ void LuaScriptInterface::initVirtualMachineAPI()
int LuaScriptInterface::virtualMachine_loadProgram(lua_State * l)
{
- luaL_checktype(l, 1, LUA_TSTRING);
+ /*luaL_checktype(l, 1, LUA_TSTRING);
vm::VirtualMachine * newVM = new vm::VirtualMachine(1);
try
@@ -1156,7 +1166,19 @@ int LuaScriptInterface::virtualMachine_loadProgram(lua_State * l)
{
return luaL_error(l, "Unable to load program");
}
- lua_pushlightuserdata(l, newVM);
+ lua_pushlightuserdata(l, newVM);*/
+ std::string programSource(lua_tostring(l, 1));
+ std::stringstream input(programSource);
+
+
+ pim::compiler::Parser * parser = new pim::compiler::Parser(input);
+
+ std::vector<unsigned char> programData = parser->Compile();
+
+ pim::VirtualMachine * machine = new pim::VirtualMachine(luacon_sim);
+ machine->LoadProgram(programData);
+
+ lua_pushlightuserdata(l, machine);
return 1;
}
diff --git a/src/cat/LuaScriptInterface.h b/src/cat/LuaScriptInterface.h
index c40728c..9758157 100644
--- a/src/cat/LuaScriptInterface.h
+++ b/src/cat/LuaScriptInterface.h
@@ -23,7 +23,7 @@ namespace ui
class Window;
}
-namespace vm
+namespace pim
{
class VirtualMachine;
}
@@ -65,7 +65,7 @@ class LuaScriptInterface: public CommandInterface {
static int renderer_colourMode(lua_State * l);
//Elements
- static vm::VirtualMachine * updateVirtualMachines[PT_NUM];
+ static pim::VirtualMachine * updateVirtualMachines[PT_NUM];
static int updateVM(UPDATE_FUNC_ARGS);
//
void initElementsAPI();
diff --git a/src/dialogues/LegacyDialogues.h b/src/dialogues/LegacyDialogues.h
new file mode 100644
index 0000000..7f6097d
--- /dev/null
+++ b/src/dialogues/LegacyDialogues.h
@@ -0,0 +1,11 @@
+#pragma once
+
+//Legacy blocking prompts
+//This are not implemented here, but rather in the engine bootstrapper
+bool ConfirmUI(std::string title, std::string message, std::string confirmText) {}
+
+void ErrorUI(std::string title, std::string message) {}
+
+void InformationUI(std::string title, std::string message) {}
+
+std::string MessagePromptUI(std::string title, std::string message, std::string text, std::string placeholder) {} \ No newline at end of file
diff --git a/src/interface/LuaProgressBar.h b/src/interface/LuaProgressBar.h
new file mode 100644
index 0000000..dc2ef4e
--- /dev/null
+++ b/src/interface/LuaProgressBar.h
@@ -0,0 +1,30 @@
+#pragma once
+
+extern "C" {
+ #include "lua.h"
+ #include "lauxlib.h"
+ #include "lualib.h"
+}
+
+#include "LuaLuna.h"
+#include "LuaComponent.h"
+
+namespace ui
+{
+ class ProgressBar;
+}
+
+class LuaScriptInterface;
+
+class LuaProgressBar: public LuaComponent
+{
+ ui::ProgressBar * progressBar;
+ int onValueChangedFunction;
+ int value(lua_State * l);
+public:
+ static const char className[];
+ static Luna<LuaProgressBar>::RegType methods[];
+
+ LuaProgressBar(lua_State * l);
+ ~LuaProgressBar();
+}; \ No newline at end of file
diff --git a/src/pim/Generator.cpp b/src/pim/Generator.cpp
new file mode 100644
index 0000000..b2ea84c
--- /dev/null
+++ b/src/pim/Generator.cpp
@@ -0,0 +1,326 @@
+//Code generator for bytecode
+#include <sstream>
+#include "Format.h"
+#include "Generator.h"
+#include "Opcodes.h"
+namespace pim
+{
+ namespace compiler
+ {
+ Generator::Generator() :
+ output(std::cout),
+ labelCounter(0),
+ programCounter(0)
+ {
+
+ }
+
+ void Generator::defineLabel(std::string label)
+ {
+ Label newLabel;
+ newLabel.Name = label;
+ newLabel.Position = programCounter;//program.size();
+ labelPositions.push_back(newLabel);
+ }
+
+ void Generator::writeOpcode(int opcode)
+ {
+ programCounter++;
+ program.push_back(opcode);
+ }
+
+ void Generator::writeConstant(std::string constant)
+ {
+ writeConstant(format::StringToNumber<int>(constant));
+ }
+
+ void Generator::writeConstant(int constant)
+ {
+ program.push_back(constant & 0xFF);
+ program.push_back((constant>>8) & 0xFF);
+ program.push_back((constant>>16) & 0xFF);
+ program.push_back((constant>>24) & 0xFF);
+ }
+
+ void Generator::writeConstantPlaceholder(std::string label)
+ {
+ placeholders.push_back(Placeholder(program.size(), label));
+ program.push_back(0);
+ program.push_back(0);
+ program.push_back(0);
+ program.push_back(0);
+ }
+
+ void Generator::writeConstantPlaceholder(int * value)
+ {
+ valuePlaceholders.push_back(ValuePlaceholder(program.size(), value));
+ program.push_back(0);
+ program.push_back(0);
+ program.push_back(0);
+ program.push_back(0);
+ }
+
+ std::vector<unsigned char> Generator::Finish()
+ {
+ for(std::vector<Placeholder>::iterator iter = placeholders.begin(), end = placeholders.end(); iter != end; ++iter)
+ {
+ bool found = false;
+ Placeholder cPosition = *iter;
+ for(std::vector<Label>::iterator iter2 = labelPositions.begin(), end2 = labelPositions.end(); iter2 != end2; ++iter2)
+ {
+ Label cLabel = *iter2;
+ if(cPosition.second == cLabel.Name)
+ {
+ std::cout << "Setting placeholder at " << cPosition.first << " with " << cLabel.Position << " for" << cPosition.second << std::endl;
+ found = true;
+ program[cPosition.first] = cLabel.Position & 0xFF;
+ program[cPosition.first+1] = (cLabel.Position >> 8) & 0xFF;
+ program[cPosition.first+2] = (cLabel.Position >> 16) & 0xFF;
+ program[cPosition.first+3] = (cLabel.Position >> 24) & 0xFF;
+ break;
+ }
+ }
+ if(!found)
+ throw SymbolNotFoundException(cPosition.second);
+ }
+
+ for(std::vector<ValuePlaceholder>::iterator iter = valuePlaceholders.begin(), end = valuePlaceholders.end(); iter != end; ++iter)
+ {
+ ValuePlaceholder cPosition = *iter;
+ int value = *cPosition.second;
+
+ std::cout << "Setting value placeholder at " << cPosition.first << " with " << value << std::endl;
+
+
+ program[cPosition.first] = value & 0xFF;
+ program[cPosition.first+1] = (value >> 8) & 0xFF;
+ program[cPosition.first+2] = (value >> 16) & 0xFF;
+ program[cPosition.first+3] = (value >> 24) & 0xFF;
+ }
+
+ return program;
+ }
+
+ std::string Generator::UniqueLabel(std::string prefix)
+ {
+ std::stringstream label;
+ label << prefix;
+ label << "_";
+ label << labelCounter;
+ label << "_";
+ return label.str();
+ }
+
+ void Generator::PushScope(std::string label)
+ {
+ scopes.push(currentScope);
+ Scope * prevScope = currentScope;
+ currentScope = new Scope();
+ defineLabel(label);
+ }
+
+ void Generator::PushLocalScope(std::string label)
+ {
+ scopes.push(currentScope);
+ Scope * prevScope = currentScope;
+ currentScope = new Scope();
+ currentScope->Definitions.insert(currentScope->Definitions.begin(), prevScope->Definitions.begin(), prevScope->Definitions.end());
+ currentScope->FrameSize = prevScope->FrameSize;
+ defineLabel(label);
+ }
+
+ void Generator::PopScope()
+ {
+
+ writeOpcode(Opcode::Return);
+ writeConstant(currentScope->LocalFrameSize);
+ currentScope = scopes.top();
+ scopes.pop();
+ }
+
+ void Generator::ScopeLabel(std::string label)
+ {
+ //defineLabelwriteOpcode("." << label);
+ defineLabel(label);
+ }
+
+ void Generator::LocalEnter()
+ {
+ writeOpcode(Opcode::LocalEnter);
+ writeConstantPlaceholder(&(currentScope->LocalFrameSize));
+ }
+
+ void Generator::ScopeVariableType(int type)
+ {
+ variableType = type;
+ }
+
+ void Generator::ScopeVariable(std::string label)
+ {
+ currentScope->Definitions.push_back(Definition(label, variableType, currentScope->FrameSize));
+ currentScope->FrameSize += 4;
+ currentScope->LocalFrameSize += 4;
+ }
+
+ void Generator::PushVariableAddress(std::string label)
+ {
+ //writeOpcode("address"); << " " << currentScope->GetDefinition(label).StackPosition
+ }
+
+ void Generator::LoadVariable(std::string label)
+ {
+ writeOpcode(Opcode::Load);
+ writeConstant(currentScope->GetDefinition(label).StackPosition);
+ }
+
+ void Generator::StoreVariable(std::string label)
+ {
+ writeOpcode(Opcode::Store);
+ writeConstant(currentScope->GetDefinition(label).StackPosition);
+ }
+
+ void Generator::Constant(std::string constant)
+ {
+ writeOpcode(Opcode::Constant);
+ writeConstant(constant);
+ }
+
+ void Generator::Increment(std::string constant)
+ {
+ writeOpcode(Opcode::Increment);
+ writeConstant(constant);
+ }
+
+ void Generator::Discard()
+ {
+ writeOpcode(Opcode::Discard);
+ }
+
+ void Generator::Duplicate()
+ {
+ writeOpcode(Opcode::Duplicate);
+ }
+
+ void Generator::Add()
+ {
+ writeOpcode(Opcode::Add);
+ }
+
+ void Generator::Subtract()
+ {
+ writeOpcode(Opcode::Subtract);
+ }
+
+ void Generator::Multiply()
+ {
+ writeOpcode(Opcode::Multiply);
+ }
+
+ void Generator::Divide()
+ {
+ writeOpcode(Opcode::Divide);
+ }
+
+ void Generator::Modulus()
+ {
+ writeOpcode(Opcode::Modulus);
+ }
+
+ void Generator::Negate()
+ {
+ writeOpcode(Opcode::Negate);
+ }
+
+ void Generator::CreateParticle()
+ {
+ writeOpcode(Opcode::Create);
+
+ }
+
+ void Generator::TransformParticle()
+ {
+ writeOpcode(Opcode::Transform);
+ }
+
+ void Generator::GetParticle()
+ {
+ writeOpcode(Opcode::Get);
+ }
+
+ void Generator::GetPosition()
+ {
+ writeOpcode(Opcode::Position);
+ }
+
+ void Generator::KillParticle()
+ {
+ writeOpcode(Opcode::Kill);
+ }
+
+
+ void Generator::IntegerToDecimal()
+ {
+
+ }
+
+ void Generator::DecimalToInteger()
+ {
+
+ }
+
+
+ void Generator::JumpEqual(std::string label)
+ {
+ writeOpcode(Opcode::JumpEqual);
+ writeConstantPlaceholder(label);
+ }
+
+ void Generator::JumpNotEqual(std::string label)
+ {
+ writeOpcode(Opcode::JumpNotEqual);
+ writeConstantPlaceholder(label);
+ }
+
+ void Generator::JumpGreater(std::string label)
+ {
+ writeOpcode(Opcode::JumpGreater);
+ writeConstantPlaceholder(label);
+ }
+
+ void Generator::JumpGreaterEqual(std::string label)
+ {
+ writeOpcode(Opcode::JumpGreaterEqual);
+ writeConstantPlaceholder(label);
+ }
+
+ void Generator::JumpLess(std::string label)
+ {
+ writeOpcode(Opcode::JumpLess);
+ writeConstantPlaceholder(label);
+ }
+
+ void Generator::JumpLessEqual(std::string label)
+ {
+ writeOpcode(Opcode::JumpLessEqual);
+ writeConstantPlaceholder(label);
+ }
+
+ void Generator::Jump(std::string label)
+ {
+ writeOpcode(Opcode::Jump);
+ writeConstantPlaceholder(label);
+ }
+
+
+ void Generator::Call(int arguments, std::string label)
+ {
+
+ }
+
+ void Generator::Return()
+ {
+
+ }
+
+ }
+} \ No newline at end of file
diff --git a/src/pim/Generator.h b/src/pim/Generator.h
new file mode 100644
index 0000000..0121c13
--- /dev/null
+++ b/src/pim/Generator.h
@@ -0,0 +1,164 @@
+#pragma once
+
+#include <cstring>
+#include <vector>
+#include <stack>
+#include <iostream>
+#include "Token.h"
+namespace pim
+{
+ namespace compiler
+ {
+ class VariableNotFoundException: public std::exception
+ {
+ char * error;
+ public:
+ VariableNotFoundException(std::string variable) {
+ error = strdup(std::string("Could not find the variable \""+variable+"\" in the current scope").c_str());
+ }
+ const char * what() const throw()
+ {
+ return error;
+ }
+ ~VariableNotFoundException() throw() {};
+ };
+
+ class SymbolNotFoundException: public std::exception
+ {
+ char * error;
+ public:
+ SymbolNotFoundException(std::string variable) {
+ error = strdup(std::string("Could not find the symbol \""+variable+"\".").c_str());
+ }
+ const char * what() const throw()
+ {
+ return error;
+ }
+ ~SymbolNotFoundException() throw() {};
+ };
+ class Definition
+ {
+ public:
+ enum { Integer = Token::IntegerSymbol, Decimal = Token::DecimalSymbol };
+ std::string Name;
+ int Type;
+ int StackPosition;
+ Definition(std::string name, int type, int position) :
+ Type(type),
+ Name(name),
+ StackPosition(position)
+ {
+
+ }
+ };
+
+ struct Label
+ {
+ std::string Name;
+ int Position;
+ };
+
+ class Scope
+ {
+ public:
+ std::vector<Definition> Definitions;
+ std::vector<Label> Labels;
+ int FrameSize;
+ int LocalFrameSize;
+ Scope():
+ FrameSize(0),
+ LocalFrameSize(0)
+ {
+
+ }
+ Definition GetDefinition(std::string name)
+ {
+ for(std::vector<Definition>::iterator iter = Definitions.begin(), end = Definitions.end(); iter != end; ++iter)
+ {
+ if((*iter).Name == name)
+ return *iter;
+ }
+ throw VariableNotFoundException(name);
+ }
+ };
+
+ class Generator
+ {
+ int variableType;
+ std::stack<Scope*> scopes;
+ Scope * currentScope;
+ std::ostream & output;
+ int labelCounter;
+ int programCounter;
+
+ typedef std::pair<int, std::string> Placeholder;
+ std::vector<Placeholder> placeholders;
+
+ typedef std::pair<int, int*> ValuePlaceholder;
+ std::vector<ValuePlaceholder> valuePlaceholders;
+
+ std::vector<Label> labelPositions;
+
+ std::vector<unsigned char> program;
+
+ void defineLabel(std::string label);
+ void writeOpcode(int opcode);
+ void writeConstant(std::string constant);
+ void writeConstant(int constant);
+ void writeConstantPlaceholder(std::string label);
+ void writeConstantPlaceholder(int * value);
+
+ public:
+ Generator();
+
+ std::vector<unsigned char> Finish();
+
+ std::string UniqueLabel(std::string prefix);
+
+ void PushScope(std::string label);
+ void PushLocalScope(std::string label);
+ void LocalEnter();
+ void PopScope();
+
+ void ScopeLabel(std::string label);
+ void ScopeVariableType(int type);
+ void ScopeVariable(std::string label);
+
+ void PushVariableAddress(std::string label);
+// void Store();
+ void LoadVariable(std::string label);
+ void StoreVariable(std::string label);
+
+ void Duplicate();
+ void Discard();
+ void Constant(std::string constant);
+ void Increment(std::string constant);
+ void Add();
+ void Subtract();
+ void Multiply();
+ void Divide();
+ void Modulus();
+ void Negate();
+
+ void TransformParticle();
+ void CreateParticle();
+ void GetParticle();
+ void GetPosition();
+ void KillParticle();
+
+ void IntegerToDecimal();
+ void DecimalToInteger();
+
+ void JumpEqual(std::string label);
+ void JumpNotEqual(std::string label);
+ void JumpGreater(std::string label);
+ void JumpGreaterEqual(std::string label);
+ void JumpLess(std::string label);
+ void JumpLessEqual(std::string label);
+ void Jump(std::string label);
+
+ void Call(int arguments, std::string label);
+ void Return();
+ };
+ }
+} \ No newline at end of file
diff --git a/src/pim/Machine.cpp b/src/pim/Machine.cpp
new file mode 100644
index 0000000..4c07514
--- /dev/null
+++ b/src/pim/Machine.cpp
@@ -0,0 +1,271 @@
+//Virtual machine
+
+#include <iostream>
+#include "Machine.h"
+#include "Opcodes.h"
+#include "simulation/Simulation.h"
+namespace pim
+{
+ /*unsigned char * rom;
+ int romSize;
+ int romMask;
+
+ unsigned char * ram;
+ int ramSize;
+ int ramMask;
+
+ int programStack;
+ int callStack;*/
+
+ VirtualMachine::VirtualMachine(Simulation * simulation) :
+ rom(NULL),
+ ram(NULL),
+ sim(simulation)
+ {
+
+ }
+
+ void VirtualMachine::LoadProgram(std::vector<unsigned char> programData)
+ {
+ int lastBit = 0;
+
+ romSize = programData.size();
+
+ for (lastBit = 0; romSize > (1 << lastBit); lastBit++ ) { }
+ romSize = 1 << lastBit;
+ romMask = romSize - 1;
+
+ rom = new Instruction[romSize];
+
+ int programPosition = 0;
+ int pc = 0;
+ while(programPosition < programData.size())
+ {
+ int argSize = 0;
+ Instruction instruction;
+ instruction.Opcode = programData[programPosition++];
+ if(argSize = OpcodeArgSize(instruction.Opcode))
+ {
+ if(argSize == 4)
+ {
+ int tempInt = 0;
+ tempInt |= programData[programPosition];
+ tempInt |= programData[programPosition+1] << 8;
+ tempInt |= programData[programPosition+2] << 16;
+ tempInt |= programData[programPosition+3] << 24;
+
+
+ std::cout << "Got integer " << tempInt << std::endl;
+ //std::cout << "Got byte " << (int)(programData[programPosition]) << std::endl;
+ //std::cout << "Got byte " << (int)(programData[programPosition+1]) << std::endl;
+ //std::cout << "Got byte " << (int)(programData[programPosition+2]) << std::endl;
+ //std::cout << "Got byte " << (int)(programData[programPosition+3]) << std::endl;
+
+ //*(int*)&rom[programPosition] = tempInt;
+ instruction.Parameter.Integer = tempInt;
+
+ programPosition += 4;
+ }
+ }
+ else
+ {
+ instruction.Parameter.Integer = 0;
+ }
+ rom[pc++] = instruction;
+ }
+ romSize = pc;
+ //std::copy(programData.begin(), programData.end(), rom);
+
+
+ ramSize = 1024;
+ ramMask = ramSize - 1;
+
+ ram = new unsigned char[ramSize];
+ programStack = ramSize-1;
+ callStack = ramSize-260;
+
+ framePointer = callStack;
+ callStack += WORDSIZE; //Since there's nothing on the stack, it shouldn't point to the item on the bottom
+ }
+
+ int VirtualMachine::OpcodeArgSize(int opcode)
+ {
+ switch(opcode)
+ {
+ case Opcode::Load:
+ case Opcode::Store:
+ case Opcode::Constant:
+ case Opcode::Increment:
+ case Opcode::JumpEqual:
+ case Opcode::JumpNotEqual:
+ case Opcode::JumpGreater:
+ case Opcode::JumpGreaterEqual:
+ case Opcode::JumpLess:
+ case Opcode::JumpLessEqual:
+ case Opcode::Jump:
+ case Opcode::Return:
+ case Opcode::LocalEnter:
+ return 4;
+ case Opcode::Discard:
+ case Opcode::Duplicate:
+ case Opcode::Add:
+ case Opcode::Subtract:
+ case Opcode::Multiply:
+ case Opcode::Divide:
+ case Opcode::Modulus:
+ case Opcode::Negate:
+ case Opcode::Create:
+ case Opcode::Transform:
+ case Opcode::Get:
+ case Opcode::Position:
+ case Opcode::Kill:
+ return 0;
+ }
+ }
+
+ void VirtualMachine::Run()
+ {
+ //std::cout << "CS: " << callStack << " PS: " << programStack << std::endl;
+ //std::string names[] = { "Load", "Store", "Constant", "Increment", "Discard", "Duplicate", "Add", "Subtract", "Multiply", "Divide", "Modulus", "Negate", "Create", "Transform", "Get", "Position", "Kill", "JumpEqual", "JumpNotEqual", "JumpGreater", "JumpGreaterEqual", "JumpLess", "JumpLessEqual", "Jump", "Return", "LocalEnter"};
+
+ Word temp1;
+ Word temp2;
+ Word temp3;
+ Word temp4;
+ int temp;
+ while(programCounter < romSize)
+ {
+ Word argument = rom[programCounter].Parameter;
+ //std::cerr << programCounter << "\t" << names[rom[programCounter].Opcode] << "\t" << argument.Integer << std::endl;//"\t";
+ switch(rom[programCounter].Opcode)
+ {
+ case Opcode::Load:
+ PSPush(CSA(argument.Integer));
+ break;
+ case Opcode::Store:
+ CSA(argument.Integer) = PSPop();
+ break;
+ case Opcode::Constant:
+ PSPush(argument);
+ break;
+ case Opcode::Increment:
+ PS().Integer += argument.Integer;
+ break;
+ case Opcode::Discard:
+ programStack += WORDSIZE;
+ break;
+ case Opcode::Duplicate:
+ PSPush(PS());
+ break;
+ case Opcode::Add:
+ PSPush(PSPop().Integer + PSPop().Integer);
+ break;
+ case Opcode::Subtract:
+ temp1 = PSPop();
+ PSPush(PSPop().Integer - temp1.Integer);
+ break;
+ case Opcode::Multiply:
+ PSPush(PSPop().Integer * PSPop().Integer);
+ break;
+ case Opcode::Divide:
+ temp1 = PSPop();
+ PSPush(PSPop().Integer / temp1.Integer);
+ break;
+ case Opcode::Modulus:
+ temp1 = PSPop();
+ PSPush(PSPop().Integer % temp1.Integer);
+ break;
+ case Opcode::Negate:
+ PS().Integer = -PS().Integer;
+ break;
+ case Opcode::Create:
+ temp1 = PSPop();
+ temp2 = PSPop();
+ temp3 = PSPop();
+ PSPush(sim->create_part(PSPop().Integer, temp3.Integer, temp2.Integer, temp1.Integer));
+ break;
+ case Opcode::Transform:
+ PSPop();
+ PSPop();
+ PSPush((Word)-1);
+ break;
+ case Opcode::Get:
+ temp1 = PSPop();
+ temp2 = PSPop();
+ if(temp1.Integer < 0 || temp1.Integer >= YRES || temp2.Integer < 0 || temp2.Integer >= XRES || !(temp = sim->pmap[temp1.Integer][temp2.Integer]))
+ {
+ PSPush(-1);
+ break;
+ }
+ PSPush(temp>>8);
+ break;
+ case Opcode::Position:
+ temp1 = PSPop();
+ if(temp1.Integer < 0 || temp1.Integer >= NPART || !sim->parts[temp1.Integer].type)
+ {
+ PSPush(-1);
+ PSPush(-1);
+ break;
+ }
+ PSPush((int)sim->parts[temp1.Integer].x);
+ PSPush((int)sim->parts[temp1.Integer].y);
+ break;
+ case Opcode::Kill:
+ sim->kill_part(PSPop().Integer);
+ PSPush((Word)0);
+ break;
+ case Opcode::JumpEqual:
+ if(PSPop().Integer == PSPop().Integer)
+ programCounter = argument.Integer-1;
+ break;
+ case Opcode::JumpNotEqual:
+ if(PSPop().Integer != PSPop().Integer)
+ programCounter = argument.Integer-1;
+ break;
+ case Opcode::JumpGreater:
+ temp1 = PSPop();
+ if(PSPop().Integer > temp1.Integer)
+ programCounter = argument.Integer-1;
+ break;
+ case Opcode::JumpGreaterEqual:
+ temp1 = PSPop();
+ if(PSPop().Integer >= temp1.Integer)
+ programCounter = argument.Integer-1;
+ break;
+ case Opcode::JumpLess:
+ temp1 = PSPop();
+ if(PSPop().Integer < temp1.Integer)
+ programCounter = argument.Integer-1;
+ break;
+ case Opcode::JumpLessEqual:
+ temp1 = PSPop();
+ if(PSPop().Integer <= temp1.Integer)
+ programCounter = argument.Integer-1;
+ break;
+ case Opcode::Jump:
+ programCounter = argument.Integer-1;
+ break;
+ case Opcode::Return:
+ callStack += argument.Integer;
+ break;
+ case Opcode::LocalEnter:
+ callStack -= argument.Integer;
+ break;
+ }
+ //std::cout << programStack << std::endl;
+ programCounter++;
+ }
+ //std::cout << "CS: " << callStack << " PS: " << programStack << std::endl;
+ }
+
+ void VirtualMachine::Call(std::string entryPoint)
+ {
+
+ }
+
+ void VirtualMachine::Call(int entryPoint)
+ {
+ programCounter = entryPoint;
+ Run();
+ }
+} \ No newline at end of file
diff --git a/src/pim/Machine.h b/src/pim/Machine.h
new file mode 100644
index 0000000..dcaef92
--- /dev/null
+++ b/src/pim/Machine.h
@@ -0,0 +1,88 @@
+#pragma once
+
+#include <vector>
+#include <string>
+
+class Simulation;
+namespace pim
+{
+ union Word
+ {
+ int Integer;
+ float Decimal;
+
+ Word(int integer) : Integer(integer) {}
+ Word(float decimal) : Decimal(decimal) {}
+ Word() {}
+ };
+ struct Instruction
+ {
+ int Opcode;
+ Word Parameter;
+ };
+ class VirtualMachine
+ {
+
+ #define WORDSIZE 4
+
+ //#define OPDEF(name) void op##name(int parameter);
+ //#include "Opcodes.inl"
+ //#undef OPDEF
+
+ Simulation * sim;
+
+ Instruction * rom;
+ int romSize;
+ int romMask;
+
+ unsigned char * ram;
+ int ramSize;
+ int ramMask;
+
+ #define CSA(argument) (*((Word*)&ram[framePointer-argument]))
+ #define CS() (*((Word*)&ram[callStack]))
+ #define PS() (*((Word*)&ram[programStack]))
+
+ int programStack; //Points to the item on top of the Program Stack
+ int callStack; //Points to the item on top of the call stack
+ int framePointer; //Points to the bottom (first item) on the current frame of the call stack
+
+ //Instruction * instructions;
+
+ int programCounter;
+
+
+ public:
+ VirtualMachine(Simulation * sim);
+ int OpcodeArgSize(int opcode);
+ void LoadProgram(std::vector<unsigned char> programData);
+ void Run();
+ void Call(std::string entryPoint);
+ void Call(int entryPoint);
+ inline void PSPush(Word word)
+ {
+ programStack -= WORDSIZE;
+ PS() = word;
+ }
+
+ inline Word PSPop()
+ {
+ Word word = PS();
+ programStack += WORDSIZE;
+ return word;
+ }
+
+ inline void CSPush(Word word)
+ {
+ callStack -= WORDSIZE;
+ CS() = word;
+ }
+
+ inline Word CSPop()
+ {
+ Word word = CS();
+ callStack += WORDSIZE;
+ return word;
+ }
+ };
+} \ No newline at end of file
diff --git a/src/pim/Opcodes.h b/src/pim/Opcodes.h
new file mode 100644
index 0000000..4e1a7ce
--- /dev/null
+++ b/src/pim/Opcodes.h
@@ -0,0 +1,12 @@
+namespace pim
+{
+ struct Opcode
+ {
+ enum
+ {
+ #define OPDEF(name) name,
+ #include "Opcodes.inl"
+ #undef OPDEF
+ };
+ };
+} \ No newline at end of file
diff --git a/src/pim/Opcodes.inl b/src/pim/Opcodes.inl
new file mode 100644
index 0000000..3c18da5
--- /dev/null
+++ b/src/pim/Opcodes.inl
@@ -0,0 +1,26 @@
+OPDEF(Load)
+OPDEF(Store)
+OPDEF(Constant)
+OPDEF(Increment)
+OPDEF(Discard)
+OPDEF(Duplicate)
+OPDEF(Add)
+OPDEF(Subtract)
+OPDEF(Multiply)
+OPDEF(Divide)
+OPDEF(Modulus)
+OPDEF(Negate)
+OPDEF(Create)
+OPDEF(Transform)
+OPDEF(Get)
+OPDEF(Position)
+OPDEF(Kill)
+OPDEF(JumpEqual)
+OPDEF(JumpNotEqual)
+OPDEF(JumpGreater)
+OPDEF(JumpGreaterEqual)
+OPDEF(JumpLess)
+OPDEF(JumpLessEqual)
+OPDEF(Jump)
+OPDEF(Return)
+OPDEF(LocalEnter) \ No newline at end of file
diff --git a/src/pim/Parser.cpp b/src/pim/Parser.cpp
new file mode 100644
index 0000000..75af21d
--- /dev/null
+++ b/src/pim/Parser.cpp
@@ -0,0 +1,646 @@
+//Syntax analyser
+#include "Parser.h"
+namespace pim
+{
+ namespace compiler
+ {
+ Parser::Parser(std::stringstream & source_) :
+ source(source_)
+ {
+ scanner = new Scanner(source);
+ generator = new Generator();
+
+ token = scanner->NextToken();
+
+ }
+
+ std::vector<unsigned char> Parser::Compile()
+ {
+ program();
+ return generator->Finish();
+ }
+
+ /*
+ <program> ::= <function list>
+ */
+ void Parser::program()
+ {
+ functionList();
+ }
+
+ /*
+ <function list> ::= <function> | <function> <function list>
+ */
+ void Parser::functionList()
+ {
+ function();
+ while(look(Token::FunctionSymbol))
+ function();
+ }
+
+ /*
+ <function> ::= function identifier ( <declaration list> ) <block> end
+ */
+ void Parser::function()
+ {
+ std::string functionName;
+
+ expect(Token::FunctionSymbol);
+
+ functionName = token.Source;
+ //generator->ScopeLabel(functionName); //Function name
+ generator->PushScope(functionName);
+ expect(Token::Identifier);
+
+ expect(Token::LeftBracket);
+ if(!accept(Token::RightBracket))
+ {
+ argumentList();
+ expect(Token::RightBracket);
+ }
+ block();
+ expect(Token::EndSymbol);
+ generator->Return();
+
+ generator->PopScope();
+ }
+
+ /*
+ <function call> ::= identifier ( <expression list> )
+ */
+ void Parser::functionCall()
+ {
+ std::string functionName;
+
+ functionName = token.Source;
+ expect(Token::Identifier);
+ expect(Token::LeftBracket);
+ expressionList();
+ expect(Token::RightBracket);
+ //generator->Call(functionName);
+ }
+
+ /*
+ <block> ::= <declaration list> <statement list>
+ */
+ void Parser::block()
+ {
+ if(look(Token::IntegerSymbol) || look(Token::DecimalSymbol) || look(Token::ParticleSymbol))
+ declarationList();
+ statementList();
+ }
+
+ /*
+ <argument list> ::= <argument> | <argument> , <argument list>
+ */
+ void Parser::argumentList()
+ {
+ argument();
+ while(accept(Token::CommaSymbol))
+ argument();
+ }
+
+ /*
+ <argument> ::= integer identifier | decimal identifier | particle identifier
+ */
+ void Parser::argument()
+ {
+ generator->ScopeVariableType(token.Symbol);
+ if(!accept(Token::IntegerSymbol))
+ if(!accept(Token::DecimalSymbol))
+ if(!accept(Token::ParticleSymbol))
+ throw ParserExpectException(token, "type name");
+ generator->ScopeVariable(token.Source);
+ expect(Token::Identifier);
+ }
+
+ /*
+ <declaration list> ::= <declaration> | <declaration> , <declaration list>
+ */
+ void Parser::declarationList()
+ {
+ declaration();
+ while(accept(Token::CommaSymbol))
+ declaration();
+ }
+
+ /*
+ <declaration> ::= integer <identifier list> | decimal <identifier list> | particle <identifier list>
+ */
+ void Parser::declaration()
+ {
+ generator->ScopeVariableType(token.Symbol);
+ if(!accept(Token::IntegerSymbol))
+ if(!accept(Token::DecimalSymbol))
+ if(!accept(Token::ParticleSymbol))
+ throw ParserExpectException(token, "type name");
+ identifierList();
+ }
+
+ /*
+ <identifier list> ::= identifier | identifier , <identifier list>
+ */
+ void Parser::identifierList()
+ {
+ generator->ScopeVariable(token.Source);
+ expect(Token::Identifier);
+ while(accept(Token::CommaSymbol))
+ {
+ generator->ScopeVariable(token.Source);
+ expect(Token::Identifier);
+ }
+ }
+
+ /*
+ <statement list> ::= <statement> | <statement> <statement list>
+ */
+ void Parser::statementList()
+ {
+ statement();
+ while(!look(Token::EndSymbol))
+ statement();
+ }
+
+ /*
+ <statement> ::= <neighbour statement> | <if statement> | <assignment statement> | <function call> | <particle action> | break | continue
+ */
+ void Parser::statement()
+ {
+ //generator->Begin(NonTerminal::Statement);
+ if(look(Token::NeighbourSymbol))
+ {
+ neighbourStatement();
+ }
+ else if(look(Token::IfSymbol))
+ {
+ ifStatement();
+ }
+ else if(look(Token::CreateSymbol) || look(Token::KillSymbol) || look(Token::GetSymbol) || look(Token::TransformSymbol))
+ {
+ particleAction();
+ generator->Discard();
+ }
+ else if(look(Token::BreakSymbol))
+ {
+ expect(Token::BreakSymbol);
+ generator->Jump(breakLabel);
+ }
+ else if(look(Token::ContinueSymbol))
+ {
+ expect(Token::ContinueSymbol);
+ generator->Jump(continueLabel);
+ }
+ else if(look(Token::Identifier))
+ {
+ assigmentStatement();
+ }
+ //generator->End(NonTerminal::Statement);
+ }
+
+ /*
+ <particle action> ::= <kill statement> | <create statement> | <transform statement>
+ */
+ void Parser::particleAction()
+ {
+ if(look(Token::KillSymbol))
+ {
+ killStatement();
+ }
+ else if(look(Token::CreateSymbol))
+ {
+ createStatement();
+ }
+ else if(look(Token::TransformSymbol))
+ {
+ transformStatement();
+ }
+
+ }
+
+ /*
+ <kill statement> ::= kill ( <expression> )
+ */
+ void Parser::killStatement()
+ {
+ expect(Token::KillSymbol);
+ expect(Token::LeftBracket);
+ expression();
+ expect(Token::RightBracket);
+ generator->KillParticle();
+ }
+
+ /*
+ <create statement> ::= create ( <expression>, <expression>, <expression>, <expression> )
+ */
+ void Parser::createStatement()
+ {
+ expect(Token::CreateSymbol);
+ expect(Token::LeftBracket);
+ expression();
+ expect(Token::CommaSymbol);
+ expression();
+ expect(Token::CommaSymbol);
+ expression();
+ expect(Token::CommaSymbol);
+ expression();
+ expect(Token::RightBracket);
+ generator->CreateParticle();
+ }
+
+ /*
+ <transform statement> ::= transform ( <expression>, <expression> )
+ */
+ void Parser::transformStatement()
+ {
+ expect(Token::TransformSymbol);
+ expect(Token::LeftBracket);
+ expression();
+ expect(Token::CommaSymbol);
+ expression();
+ expect(Token::RightBracket);
+ generator->TransformParticle();
+ }
+
+ /*
+ <get statement> ::= get ( <expression>, <expression> )
+ */
+ void Parser::getStatement()
+ {
+ expect(Token::GetSymbol);
+ expect(Token::LeftBracket);
+ expression();
+ expect(Token::CommaSymbol);
+ expression();
+ expect(Token::RightBracket);
+ generator->GetParticle();
+ }
+
+ /*
+ <neighbour statement> ::= neighbour identifier for <expression> do <block> end | neighbour identifier for <expression>, <expression> do <block> end
+ */
+ void Parser::neighbourStatement()
+ {
+ std::string neighbourVariable;
+ std::string loopLabel = generator->UniqueLabel("neighbour");
+ std::string xVar = loopLabel+"X";
+ std::string xMin = loopLabel+"minX";
+ std::string xMax = loopLabel+"maxX";
+ std::string yVar = loopLabel+"Y";
+ std::string yMax = loopLabel+"maxY";
+ breakLabel = loopLabel+"End";
+ continueLabel = loopLabel+"Next";
+
+ expect(Token::NeighbourSymbol);
+
+ generator->PushLocalScope(loopLabel+"Start");
+ neighbourVariable = token.Source;
+ expect(Token::Identifier);
+ generator->ScopeVariableType(Token::IntegerConstant);
+ generator->ScopeVariable(neighbourVariable);
+ generator->ScopeVariable(xVar);
+ generator->ScopeVariable(yVar);
+ generator->ScopeVariable(xMin);
+ generator->ScopeVariable(xMax);
+ generator->ScopeVariable(yMax);
+
+ generator->LocalEnter();
+
+ expect(Token::OfSymbol);
+
+ //Initialise position
+ expression();
+ generator->GetPosition();
+ generator->Duplicate();
+ generator->Increment("-1");
+ generator->StoreVariable(yVar);
+ generator->Increment("1");
+ generator->StoreVariable(yMax);
+
+ generator->Duplicate();
+ generator->Increment("-1");
+ generator->Duplicate();
+ generator->StoreVariable(xVar);
+ generator->StoreVariable(xMin);
+ generator->Increment("1");
+ generator->StoreVariable(xMax);
+
+ //if(accept(Token::CommaSymbol))
+ // expression();
+ expect(Token::DoSymbol);
+
+ generator->ScopeLabel(loopLabel+"Next");
+
+
+
+
+
+ //Check X
+ generator->LoadVariable(xVar);
+ generator->LoadVariable(xMax);
+ //generator->Duplicate(); //Duplicate xvar so it can be used for incrementing
+
+ generator->JumpLessEqual(loopLabel+"Begin");
+ //if(xVar > xMax) {
+
+ //Reset X, increment Y
+ generator->LoadVariable(xMin);
+ generator->StoreVariable(xVar);
+
+ generator->LoadVariable(yVar);
+ generator->Increment("1");
+ generator->Duplicate();
+ generator->StoreVariable(yVar);
+
+
+ //Check Y
+ generator->LoadVariable(yMax);
+ generator->JumpGreater(loopLabel+"End");
+
+ //}
+
+ //Start of loop
+ generator->ScopeLabel(loopLabel+"Begin");
+
+ generator->LoadVariable(xVar);
+ generator->LoadVariable(yVar);
+ generator->GetParticle();
+ generator->StoreVariable(neighbourVariable);
+
+ block();
+
+ //Increment X
+ generator->LoadVariable(xVar);
+ generator->Increment("1");
+ generator->StoreVariable(xVar);
+
+ //Next element
+ generator->Jump(loopLabel+"Next");
+
+ generator->ScopeLabel(loopLabel+"End");
+ generator->Return();
+ generator->PopScope();
+ expect(Token::EndSymbol);
+ }
+
+ /*
+ <if statement> ::= if <condition> then <block> end
+ */
+ void Parser::ifStatement()
+ {
+ //generator->Begin(NonTerminal::IfStatement);
+ expect(Token::IfSymbol);
+ condition();
+ expect(Token::ThenSymbol);
+ block();
+ expect(Token::EndSymbol);
+ //generator->End(NonTerminal::IfStatement);
+ }
+
+ /*
+ <condition> ::= identifier <conditional operator> identifier | identifier <conditional operator> numberConstant | numberConstant <conditional operator> identifier | numberConstant <conditional operator> numberConstant
+ */
+ void Parser::condition()
+ {
+ //generator->Begin(NonTerminal::Condition);
+ if(look(Token::Identifier))
+ {
+ conditionalOperator();
+ if(!accept(Token::Identifier) && !accept(Token::IntegerConstant) && !accept(Token::DecimalConstant))
+ throw ParserExpectException(token, "identifier or constant");
+ }
+ else if(look(Token::DecimalConstant) || look(Token::IntegerConstant))
+ {
+ conditionalOperator();
+ if(!accept(Token::Identifier) && !accept(Token::IntegerConstant) && !accept(Token::DecimalConstant))
+ throw ParserExpectException(token, "identifier or constant");
+ }
+ else
+ {
+ throw ParserExpectException(token, "condition");
+ }
+ //generator->End(NonTerminal::Condition);
+ }
+
+ /*
+ <conditional operator> ::= > | >= | == | != | < | <=
+ */
+ void Parser::conditionalOperator()
+ {
+ //generator->Begin(NonTerminal::ConditionalOperator);
+ if(!accept(Token::GreaterSymbol))
+ if(!accept(Token::GreaterEqualSymbol))
+ if(!accept(Token::EqualSymbol))
+ if(!accept(Token::NotEqualSymbol))
+ if(!accept(Token::LessSymbol))
+ if(!accept(Token::LessEqualSymbol))
+ throw ParserExpectException(token, "conditional operator");
+ //generator->End(NonTerminal::ConditionalOperator);
+ }
+
+ /*
+ <assigment statement> ::= identifier = <expression>
+ */
+ void Parser::assigmentStatement()
+ {
+ std::string variable = token.Source;
+ //generator->PushVariableAddress(token.Source);
+ expect(Token::Identifier);
+ expect(Token::AssignSymbol);
+ expression();
+ //generator->Store();
+ generator->StoreVariable(variable);
+ }
+
+ /*
+ <expression list> ::= <expression> | <expression> , <expression list>
+ */
+ void Parser::expressionList()
+ {
+ //generator->Begin(NonTerminal::ExpressionList);
+ expression();
+ while(accept(Token::CommaSymbol))
+ expression();
+ //generator->End(NonTerminal::ExpressionList);
+ }
+
+ /*
+ <expression> ::= <term> | <expression> + <term> | <expression> - <term>
+ */
+ void Parser::expression()
+ {
+ term();
+ int as = token.Symbol;
+ while(accept(Token::PlusSymbol) || accept(Token::MinusSymbol))
+ {
+ term();
+ if(as == Token::PlusSymbol)
+ generator->Add();
+ else if(as == Token::MinusSymbol)
+ generator->Subtract();
+ }
+ //generator->End(NonTerminal::Expression);
+ }
+
+ /*
+ <term> ::= <factor> | <term> * <factor> | <term> / <factor>
+ */
+ void Parser::term()
+ {
+ //generator->Begin(NonTerminal::Term);
+ factor();
+ int md = token.Symbol;
+ while(accept(Token::MultiplySymbol) || accept(Token::DivideSymbol))
+ {
+ factor();
+ if(md == Token::MultiplySymbol)
+ generator->Multiply();
+ else if(md == Token::DivideSymbol)
+ generator->Divide();
+ }
+ //generator->End(NonTerminal::Term);
+ }
+
+ /*
+ <factor> ::= <variable value> | - <variable value> | numberConstant | - numberConstant | ( <expression> ) | - ( <expression> )
+ */
+ void Parser::factor()
+ {
+ bool doNegate = false;
+ std::string factor = token.Source;
+ if(accept(Token::MinusSymbol))
+ {
+ factor = token.Source;
+ doNegate = true;
+ }
+ if(accept(Token::IntegerConstant) || accept(Token::DecimalConstant))
+ {
+ if(doNegate)
+ {
+ doNegate = false;
+ generator->Constant("-" + factor);
+ }
+ else
+ generator->Constant(factor);
+ }
+ else if(accept(Token::LeftBracket))
+ {
+ expression();
+ expect(Token::RightBracket);
+ }
+ else
+ {
+ variableValue();
+ }
+ if(doNegate)
+ generator->Negate();
+ /*if(!accept(Token::Identifier))
+ {
+ if(!accept(Token::IntegerConstant))
+ {
+ if(!accept(Token::DecimalConstant))
+ {
+ if(!accept(Token::LeftBracket))
+ {
+ throw ParserExpectException(token, "identifier or constant");
+ }
+ else
+ {
+ expression();
+ expect(Token::RightBracket);
+ }
+ }
+ else
+ {
+ if(doNegate)
+ {
+ doNegate = false;
+ generator->Constant("-" + factor);
+ }
+ else
+ generator->Constant(factor);
+ }
+ }
+ else
+ {
+ if(doNegate)
+ {
+ doNegate = false;
+ generator->Constant("-" + factor);
+ }
+ else
+ generator->Constant(factor);
+ }
+ }
+ else
+ {
+ generator->LoadVariable(factor);
+ }
+ if(doNegate)
+ {
+ generator->Negate();
+ }*/
+ }
+
+ /*
+ <variable value> ::= <function call> | identifier | <particle action>
+ */
+ void Parser::variableValue()
+ {
+ std::string variable = token.Source;
+ if(accept(Token::Identifier))
+ {
+ if(look(Token::LeftBracket))
+ {
+ back();
+ functionCall();
+ }
+ else
+ {
+ generator->LoadVariable(variable);
+ }
+ }
+ else
+ {
+ particleAction();
+ }
+ }
+
+ bool Parser::accept(int symbol)
+ {
+ if(symbol == token.Symbol)
+ {
+ //generator->Insert(token);
+ lastToken = token;
+ if(previousTokens.size())
+ {
+ token = previousTokens.top();
+ previousTokens.pop();
+ }
+ else
+ token = scanner->NextToken();
+ return true;
+ }
+ return false;
+ }
+
+
+ bool Parser::look(int symbol)
+ {
+ if(symbol == token.Symbol)
+ return true;
+ return false;
+ }
+
+ void Parser::back()
+ {
+ previousTokens.push(token);
+ token = lastToken;
+ }
+
+ void Parser::expect(int symbol)
+ {
+ if(!accept(symbol))
+ throw ParserExpectException(token, symbol);
+ }
+ }
+} \ No newline at end of file
diff --git a/src/pim/Parser.h b/src/pim/Parser.h
new file mode 100644
index 0000000..c66011e
--- /dev/null
+++ b/src/pim/Parser.h
@@ -0,0 +1,78 @@
+#pragma once
+
+#include <string>
+#include <cstring>
+#include <sstream>
+#include "Scanner.h"
+#include "Generator.h"
+#include "Token.h"
+namespace pim
+{
+ namespace compiler
+ {
+ class ParserExpectException: public std::exception
+ {
+ char * error;
+ public:
+ ParserExpectException(Token token, int expectingSymbol) {
+ error = strdup(std::string("Expecting " + Token::SymbolNames[expectingSymbol] + " got " + token.Source).c_str());
+ }
+ ParserExpectException(Token token, std::string expectingString) {
+ error = strdup(std::string("Expecting " + expectingString + " got " + token.Source).c_str());
+ }
+ const char * what() const throw()
+ {
+ return error;
+ }
+ ~ParserExpectException() throw() {};
+ };
+ class Parser
+ {
+ std::stringstream & source;
+ Generator * generator;
+ Scanner * scanner;
+ Token token;
+ Token lastToken;
+ std::string breakLabel;
+ std::string continueLabel;
+ std::stack<Token> previousTokens;
+
+ void program();
+ void functionList();
+ void function();
+ void functionCall();
+ void block();
+ void argumentList();
+ void argument();
+ void declarationList();
+ void declaration();
+ void identifierList();
+ void statementList();
+ void statement();
+ void neighbourStatement();
+ void ifStatement();
+ void condition();
+ void conditionalOperator();
+ void assigmentStatement();
+ void particleAction();
+ void killStatement();
+ void getStatement();
+ void createStatement();
+ void transformStatement();
+ void expressionList();
+ void expression();
+ void term();
+ void factor();
+ void variableValue();
+
+ bool accept(int symbol);
+ bool look(int symbol);
+ void back();
+ void expect(int symbol);
+ public:
+ Parser(std::stringstream & source_);
+
+ std::vector<unsigned char> Compile();
+ };
+ }
+} \ No newline at end of file
diff --git a/src/pim/Scanner.cpp b/src/pim/Scanner.cpp
new file mode 100644
index 0000000..32e64d0
--- /dev/null
+++ b/src/pim/Scanner.cpp
@@ -0,0 +1,178 @@
+//Lexical analyser
+#include <algorithm>
+#include "Scanner.h"
+
+namespace pim
+{
+ namespace compiler
+ {
+ Scanner::Scanner(std::stringstream & source_) :
+ source(source_)
+ {
+ nextCharacter();
+ }
+
+ Token Scanner::NextToken()
+ {
+ //Read whitespace, newlines and comments
+ while(
+ cChar == ' ' || cChar == '\t' ||
+ cChar == '\r' || cChar == '\n' ||
+ cChar == '/')
+ {
+ if(cChar == '/')
+ {
+ nextCharacter();
+ if(cChar == '/')
+ {
+ while(cChar != '\n' && cChar != '\r')
+ nextCharacter();
+ }
+ else
+ return Token(Token::DivideSymbol, "/", cLine);
+ }
+
+ if(cChar == '\r')
+ {
+ nextCharacter();
+ if(cChar == '\n')
+ cLine++;
+ else
+ continue;
+ }
+ else if(cChar == '\n')
+ cLine++;
+
+ nextCharacter();
+ }
+
+ if(std::isalpha(cChar)) //Read alphanumeric symbols
+ {
+ cToken.clear();
+ while(std::isalpha(cChar) || std::isdigit(cChar))
+ {
+ cToken.push_back(cChar);
+ nextCharacter();
+ }
+
+ std::transform(cToken.begin(), cToken.end(), cToken.begin(), ::tolower);
+
+ for(int i = 0; i < Token::SymbolNumber; i++)
+ if(Token::SymbolNames[i] == cToken)
+ return Token(i, cToken, cLine);
+ return Token(Token::Identifier, cToken, cLine);
+ }
+ else if(std::isdigit(cChar)) //Read numeric constants
+ {
+ bool decimal = false;
+ cToken.clear();
+ while(std::isdigit(cChar))
+ {
+ cToken.push_back(cChar);
+ nextCharacter();
+ }
+ if(cChar == '.')
+ {
+ decimal = true;
+ cToken.push_back(cChar);
+ nextCharacter();
+ while(std::isdigit(cChar))
+ {
+ cToken.push_back(cChar);
+ nextCharacter();
+ }
+ }
+ if(decimal)
+ return Token(Token::DecimalConstant, cToken, cLine);
+ return Token(Token::IntegerConstant, cToken, cLine);
+ }
+ else if(cChar == '=')
+ {
+ nextCharacter();
+ if(cChar == '=')
+ {
+ nextCharacter();
+ return Token(Token::EqualSymbol, "==", cLine);
+ }
+ return Token(Token::AssignSymbol, "=", cLine);
+ }
+ else if(cChar == '!')
+ {
+ nextCharacter();
+ if(cChar == '=')
+ return Token(Token::NotEqualSymbol, "==", cLine);
+ }
+ else if(cChar == '(')
+ {
+ nextCharacter();
+ return Token(Token::LeftBracket, "(", cLine);
+ }
+ else if(cChar == ')')
+ {
+ nextCharacter();
+ return Token(Token::RightBracket, ")", cLine);
+ }
+ else if(cChar == '/')
+ {
+ nextCharacter();
+ return Token(Token::DivideSymbol, "/", cLine);
+ }
+ else if(cChar == '*')
+ {
+ nextCharacter();
+ return Token(Token::MultiplySymbol, "*", cLine);
+ }
+ else if(cChar == '+')
+ {
+ nextCharacter();
+ return Token(Token::PlusSymbol, "+", cLine);
+ }
+ else if(cChar == '-')
+ {
+ nextCharacter();
+ return Token(Token::MinusSymbol, "-", cLine);
+ }
+ else if(cChar == '%')
+ {
+ nextCharacter();
+ return Token(Token::ModuloSymbol, "%", cLine);
+ }
+ else if(cChar == '<')
+ {
+ nextCharacter();
+ if(cChar == '=')
+ {
+ return Token(Token::LessEqualSymbol, "<=", cLine);
+ }
+ return Token(Token::LessSymbol, "<", cLine);
+ }
+ else if(cChar == '>')
+ {
+ nextCharacter();
+ if(cChar == '=')
+ {
+ return Token(Token::GreaterEqualSymbol, ">=", cLine);
+ }
+ return Token(Token::GreaterSymbol, ">", cLine);
+ }
+ else if(cChar == ',')
+ {
+ nextCharacter();
+ return Token(Token::CommaSymbol, ",", cLine);
+ }
+ else
+ {
+ nextCharacter();
+ return Token(Token::InvalidSymbol, std::string(1, cChar), cLine);
+ }
+ }
+
+ void Scanner::nextCharacter()
+ {
+ if(source.good())
+ cChar = source.get();
+ else
+ cChar = 0;
+ }
+ }
+} \ No newline at end of file
diff --git a/src/pim/Scanner.h b/src/pim/Scanner.h
new file mode 100644
index 0000000..2e8143c
--- /dev/null
+++ b/src/pim/Scanner.h
@@ -0,0 +1,22 @@
+#pragma once
+
+#include <string>
+#include <sstream>
+#include "Token.h"
+namespace pim
+{
+ namespace compiler
+ {
+ class Scanner
+ {
+ char cChar;
+ int cLine;
+ std::string cToken;
+ std::stringstream & source;
+ void nextCharacter();
+ public:
+ Scanner(std::stringstream & source_);
+ Token NextToken();
+ };
+ }
+} \ No newline at end of file
diff --git a/src/pim/Token.cpp b/src/pim/Token.cpp
new file mode 100644
index 0000000..2db451e
--- /dev/null
+++ b/src/pim/Token.cpp
@@ -0,0 +1,47 @@
+#include "Token.h"
+
+namespace pim
+{
+ namespace compiler
+ {
+ std::string Token::SymbolNames[] = {
+ "=",
+ "function",
+ "(",
+ ")",
+ "/",
+ "*",
+ "+",
+ "-",
+ "%",
+ "INTEGER",
+ "DECIMAL",
+ "PARTICLE",
+ "integer",
+ "decimal",
+ "particle",
+ "is",
+ "<",
+ "<=",
+ ">",
+ ">=",
+ "==",
+ "!=",
+ "neighbour",
+ "do",
+ "of",
+ "break",
+ "continue",
+ "if",
+ "then",
+ "end",
+ "kill",
+ "create",
+ "transform",
+ "get",
+ "IDENTIFIER",
+ ",",
+ "INVALID SYMBOL"
+ };
+ }
+} \ No newline at end of file
diff --git a/src/pim/Token.h b/src/pim/Token.h
new file mode 100644
index 0000000..6a80f49
--- /dev/null
+++ b/src/pim/Token.h
@@ -0,0 +1,79 @@
+#pragma once
+
+#include <string>
+namespace pim
+{
+ namespace compiler
+ {
+ class Token
+ {
+ public:
+ static std::string SymbolNames[];
+
+ enum
+ {
+ AssignSymbol = 0,
+ FunctionSymbol,
+
+ LeftBracket,
+ RightBracket,
+ DivideSymbol,
+ MultiplySymbol,
+ PlusSymbol,
+ MinusSymbol,
+ ModuloSymbol,
+
+ IntegerConstant,
+ DecimalConstant,
+ ParticleConstant,
+
+ IntegerSymbol,
+ DecimalSymbol,
+ ParticleSymbol,
+
+ IsSymbol,
+ LessSymbol,
+ LessEqualSymbol,
+ GreaterSymbol,
+ GreaterEqualSymbol,
+ NotEqualSymbol,
+ EqualSymbol,
+
+ NeighbourSymbol,
+ DoSymbol,
+ OfSymbol,
+ BreakSymbol,
+ ContinueSymbol,
+ IfSymbol,
+ ThenSymbol,
+ EndSymbol,
+
+ KillSymbol,
+ CreateSymbol,
+ TransformSymbol,
+ GetSymbol,
+
+ Identifier,
+
+ CommaSymbol,
+
+ InvalidSymbol,
+
+ SymbolNumber
+ };
+ int Symbol;
+ int LineNumber;
+ std::string Source;
+
+ Token(int symbol = InvalidSymbol, std::string source = "HERP DERP", int lineNumber = 0) :
+ Symbol(symbol),
+ Source(source),
+ LineNumber(lineNumber) {}
+
+ std::string GetName()
+ {
+ return SymbolNames[Symbol];
+ }
+ };
+ }
+} \ No newline at end of file
diff --git a/src/tests/PowderInteractionMachine.cpp b/src/tests/PowderInteractionMachine.cpp
new file mode 100644
index 0000000..c2b37a2
--- /dev/null
+++ b/src/tests/PowderInteractionMachine.cpp
@@ -0,0 +1,21 @@
+#ifdef TEST
+
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include "pim/Parser.h"
+
+int main(int argc, char * argv[])
+{
+ std::ifstream file("test.p");
+
+ std::stringstream buffer;
+
+ buffer << file.rdbuf();
+ file.close();
+
+ pim::compiler::Parser * parser = new pim::compiler::Parser(buffer);
+
+ parser->Compile();
+}
+#endif \ No newline at end of file