summaryrefslogtreecommitdiff
path: root/src/pim
diff options
context:
space:
mode:
authorSimon Robertshaw <simon@hardwired.org.uk>2012-11-17 19:44:09 (GMT)
committer Simon Robertshaw <simon@hardwired.org.uk>2012-11-17 19:44:09 (GMT)
commit058a2edd75debbd0297f92572316daa704bd379f (patch)
treead303f091f9a08b209b91eb34a9fcad996a3de69 /src/pim
parente3594aba9e05c6865d396418c028049cda92c2f3 (diff)
parent7a21ae192fe19868539956f3fe28e62b2c7c4429 (diff)
downloadpowder-058a2edd75debbd0297f92572316daa704bd379f.zip
powder-058a2edd75debbd0297f92572316daa704bd379f.tar.gz
Merge branch 'master' of github.com:FacialTurd/PowderToypp
Diffstat (limited to 'src/pim')
-rw-r--r--src/pim/Generator.cpp518
-rw-r--r--src/pim/Generator.h178
-rw-r--r--src/pim/Machine.cpp637
-rw-r--r--src/pim/Machine.h120
-rw-r--r--src/pim/Opcodes.h12
-rw-r--r--src/pim/Opcodes.inl28
-rw-r--r--src/pim/Parser.cpp653
-rw-r--r--src/pim/Parser.h79
-rw-r--r--src/pim/Scanner.cpp199
-rw-r--r--src/pim/Scanner.h22
-rw-r--r--src/pim/Token.cpp51
-rw-r--r--src/pim/Token.h83
12 files changed, 2580 insertions, 0 deletions
diff --git a/src/pim/Generator.cpp b/src/pim/Generator.cpp
new file mode 100644
index 0000000..a791211
--- /dev/null
+++ b/src/pim/Generator.cpp
@@ -0,0 +1,518 @@
+//Code generator for bytecode
+#include <sstream>
+#include <fstream>
+#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);
+ }
+
+ void Generator::writeConstantPropertyPlaceholder(std::string property)
+ {
+ propertyPlaceholders.push_back(PropertyPlaceholder(program.size(), property));
+ program.push_back(0);
+ program.push_back(0);
+ program.push_back(0);
+ program.push_back(0);
+ }
+
+ void Generator::writeConstantMacroPlaceholder(std::string macro)
+ {
+ macroPlaceholders.push_back(MacroPlaceholder(program.size(), macro));
+ program.push_back(0);
+ program.push_back(0);
+ program.push_back(0);
+ program.push_back(0);
+ }
+
+ std::vector<unsigned char> Generator::Finish()
+ {
+ //All compile time labels, macros, etc
+ 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;
+ }
+
+ //Build file
+ int macroSizePos, propSizePos, codeSizePos, macroSize = 0, propSize = 0, codeSize = program.size();
+ std::vector<unsigned char> file;
+ file.push_back('P');
+ file.push_back('V');
+ file.push_back('M');
+ file.push_back('1');
+
+
+ macroSizePos = file.size();
+ file.push_back(0);
+ file.push_back(0);
+ file.push_back(0);
+ file.push_back(0);
+
+ propSizePos = file.size();
+ file.push_back(0);
+ file.push_back(0);
+ file.push_back(0);
+ file.push_back(0);
+
+ codeSizePos = file.size();
+ file.push_back(0);
+ file.push_back(0);
+ file.push_back(0);
+ file.push_back(0);
+
+ //Macros
+ for(std::vector<MacroPlaceholder>::iterator iter = macroPlaceholders.begin(), end = macroPlaceholders.end(); iter != end; ++iter)
+ {
+ MacroPlaceholder cPosition = *iter;
+ int position = cPosition.first;
+
+ file.push_back(position & 0xFF);
+ file.push_back((position >> 8) & 0xFF);
+ file.push_back((position >> 16) & 0xFF);
+ file.push_back((position >> 24) & 0xFF);
+ macroSize += 4;
+
+ file.push_back(cPosition.second.length());
+ macroSize += 1;
+ file.insert(file.end(), cPosition.second.begin(), cPosition.second.end());
+ macroSize += cPosition.second.length();
+ }
+
+ file[macroSizePos] = macroSize & 0xFF;
+ file[macroSizePos+1] = (macroSize >> 8) & 0xFF;
+ file[macroSizePos+2] = (macroSize >> 16) & 0xFF;
+ file[macroSizePos+3] = (macroSize >> 24) & 0xFF;
+
+
+ //Macros
+ for(std::vector<PropertyPlaceholder>::iterator iter = propertyPlaceholders.begin(), end = propertyPlaceholders.end(); iter != end; ++iter)
+ {
+ PropertyPlaceholder cPosition = *iter;
+ int position = cPosition.first;
+
+ file.push_back(position & 0xFF);
+ file.push_back((position >> 8) & 0xFF);
+ file.push_back((position >> 16) & 0xFF);
+ file.push_back((position >> 24) & 0xFF);
+ propSize += 4;
+
+ file.push_back(cPosition.second.length());
+ propSize += 1;
+ file.insert(file.end(), cPosition.second.begin(), cPosition.second.end());
+ propSize += cPosition.second.length();
+ }
+
+ file[propSizePos] = propSize & 0xFF;
+ file[propSizePos+1] = (propSize >> 8) & 0xFF;
+ file[propSizePos+2] = (propSize >> 16) & 0xFF;
+ file[propSizePos+3] = (propSize >> 24) & 0xFF;
+
+ file.insert(file.end(), program.begin(), program.end());
+
+ file[codeSizePos] = codeSize & 0xFF;
+ file[codeSizePos+1] = (codeSize >> 8) & 0xFF;
+ file[codeSizePos+2] = (codeSize >> 16) & 0xFF;
+ file[codeSizePos+3] = (codeSize >> 24) & 0xFF;
+
+ std::ofstream newFile("test.pvm");
+ for(std::vector<unsigned char>::iterator iter = file.begin(), end = file.end(); iter != end; ++iter)
+ {
+ newFile.put(*iter);
+ }
+ newFile.close();
+
+ return file;
+ }
+
+ 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);
+
+ output << "." << label << std::endl;
+ }
+
+ 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);
+
+ output << "." << label << std::endl;
+ }
+
+ void Generator::PopScope()
+ {
+
+ writeOpcode(Opcode::Return);
+ writeConstant(currentScope->LocalFrameSize);
+
+ output << "return " << currentScope->LocalFrameSize << std::endl;
+
+ currentScope = scopes.top();
+ scopes.pop();
+ }
+
+ void Generator::ScopeLabel(std::string label)
+ {
+ //defineLabelwriteOpcode("." << label);
+ defineLabel(label);
+
+ output << "." << label << std::endl;
+ }
+
+ void Generator::LocalEnter()
+ {
+ writeOpcode(Opcode::LocalEnter);
+ writeConstantPlaceholder(&(currentScope->LocalFrameSize));
+
+ output << "enter " << "#" << std::endl;
+ }
+
+ 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;
+
+ output << "#declare " << label << " " << currentScope->FrameSize-4 << std::endl;
+ }
+
+ 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);
+
+ output << "load " << label << std::endl;
+ }
+
+ void Generator::StoreVariable(std::string label)
+ {
+ writeOpcode(Opcode::Store);
+ writeConstant(currentScope->GetDefinition(label).StackPosition);
+
+ output << "store " << label << std::endl;
+ }
+
+ void Generator::RTConstant(std::string name)
+ {
+ writeOpcode(Opcode::Constant);
+ writeConstantMacroPlaceholder(name);
+
+ output << "const " << name << std::endl;
+ }
+
+ void Generator::Constant(std::string constant)
+ {
+ writeOpcode(Opcode::Constant);
+ writeConstant(constant);
+
+ output << "const " << constant << std::endl;
+
+ }
+
+ void Generator::Increment(std::string constant)
+ {
+ writeOpcode(Opcode::Increment);
+ writeConstant(constant);
+
+ output << "inc " << constant << std::endl;
+ }
+
+ void Generator::Discard()
+ {
+ writeOpcode(Opcode::Discard);
+
+ output << "discard" << std::endl;
+ }
+
+ void Generator::Duplicate()
+ {
+ writeOpcode(Opcode::Duplicate);
+
+ output << "duplicate" << std::endl;
+ }
+
+ void Generator::Add()
+ {
+ writeOpcode(Opcode::Add);
+
+ output << "add" << std::endl;
+ }
+
+ void Generator::Subtract()
+ {
+ writeOpcode(Opcode::Subtract);
+
+ output << "sub" << std::endl;
+ }
+
+ void Generator::Multiply()
+ {
+ writeOpcode(Opcode::Multiply);
+
+ output << "mul" << std::endl;
+ }
+
+ void Generator::Divide()
+ {
+ writeOpcode(Opcode::Divide);
+
+ output << "div" << std::endl;
+ }
+
+ void Generator::Modulus()
+ {
+ writeOpcode(Opcode::Modulus);
+
+ output << "add" << std::endl;
+ }
+
+ void Generator::Negate()
+ {
+ writeOpcode(Opcode::Negate);
+
+ output << "neg" << std::endl;
+ }
+
+ void Generator::CreateParticle()
+ {
+ writeOpcode(Opcode::Create);
+
+ output << "create" << std::endl;
+ }
+
+ void Generator::TransformParticle()
+ {
+ writeOpcode(Opcode::Transform);
+
+ output << "transform" << std::endl;
+ }
+
+ void Generator::GetParticle()
+ {
+ writeOpcode(Opcode::Get);
+
+ output << "getpart" << std::endl;
+ }
+
+ void Generator::GetPosition()
+ {
+ writeOpcode(Opcode::Position);
+
+ output << "getpos" << std::endl;
+ }
+
+ void Generator::KillParticle()
+ {
+ writeOpcode(Opcode::Kill);
+
+ output << "kill" << std::endl;
+ }
+
+ void Generator::LoadProperty(std::string property)
+ {
+ writeOpcode(Opcode::LoadProperty);
+ writeConstantPropertyPlaceholder(property);
+
+ output << "loadprop " << property << std::endl;
+ }
+
+ void Generator::StoreProperty(std::string property)
+ {
+ writeOpcode(Opcode::StoreProperty);
+ writeConstantPropertyPlaceholder(property);
+
+ output << "storeprop " << property << std::endl;
+ }
+
+ void Generator::IntegerToDecimal()
+ {
+
+ }
+
+ void Generator::DecimalToInteger()
+ {
+
+ }
+
+
+ void Generator::JumpEqual(std::string label)
+ {
+ writeOpcode(Opcode::JumpEqual);
+ writeConstantPlaceholder(label);
+
+ output << "jumpe " << label << std::endl;
+ }
+
+ void Generator::JumpNotEqual(std::string label)
+ {
+ writeOpcode(Opcode::JumpNotEqual);
+ writeConstantPlaceholder(label);
+
+ output << "jumpne " << label << std::endl;
+ }
+
+ void Generator::JumpGreater(std::string label)
+ {
+ writeOpcode(Opcode::JumpGreater);
+ writeConstantPlaceholder(label);
+
+ output << "jumpg " << label << std::endl;
+ }
+
+ void Generator::JumpGreaterEqual(std::string label)
+ {
+ writeOpcode(Opcode::JumpGreaterEqual);
+ writeConstantPlaceholder(label);
+
+ output << "jumpge " << label << std::endl;
+ }
+
+ void Generator::JumpLess(std::string label)
+ {
+ writeOpcode(Opcode::JumpLess);
+ writeConstantPlaceholder(label);
+
+ output << "jumpl " << label << std::endl;
+ }
+
+ void Generator::JumpLessEqual(std::string label)
+ {
+ writeOpcode(Opcode::JumpLessEqual);
+ writeConstantPlaceholder(label);
+
+ output << "jumple " << label << std::endl;
+ }
+
+ void Generator::Jump(std::string label)
+ {
+ writeOpcode(Opcode::Jump);
+ writeConstantPlaceholder(label);
+
+ output << "jump " << label << std::endl;
+ }
+
+
+ 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..2eb1029
--- /dev/null
+++ b/src/pim/Generator.h
@@ -0,0 +1,178 @@
+#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 Type
+ {
+ enum { Integer = Token::IntegerSymbol, Decimal = Token::DecimalSymbol };
+ };
+ class Definition
+ {
+ public:
+ 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;
+
+ typedef std::pair<int, std::string> PropertyPlaceholder;
+ std::vector<PropertyPlaceholder> propertyPlaceholders;
+
+ typedef std::pair<int, std::string> MacroPlaceholder;
+ std::vector<MacroPlaceholder> macroPlaceholders;
+
+ 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);
+ void writeConstantMacroPlaceholder(std::string macro);
+ void writeConstantPropertyPlaceholder(std::string property);
+
+ 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 RTConstant(std::string name);
+ 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 LoadProperty(std::string property);
+ void StoreProperty(std::string property);
+
+ 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..a954d31
--- /dev/null
+++ b/src/pim/Machine.cpp
@@ -0,0 +1,637 @@
+//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> fileData)
+ {
+ int lastBit = 0;
+
+ if(!(fileData[0] == 'P' && fileData[1] == 'V' && fileData[2] == 'M' && fileData[3] == '1' && fileData.size() >= 16))
+ {
+ throw InvalidProgramException();
+ }
+
+ int macroSize = 0, propSize = 0, codeSize = 0;
+ macroSize = fileData[4];
+ macroSize |= fileData[5] << 8;
+ macroSize |= fileData[6] << 16;
+ macroSize |= fileData[7] << 24;
+
+ propSize = fileData[8];
+ propSize |= fileData[9] << 8;
+ propSize |= fileData[10] << 16;
+ propSize |= fileData[11] << 24;
+
+ codeSize = fileData[12];
+ codeSize |= fileData[13] << 8;
+ codeSize |= fileData[14] << 16;
+ codeSize |= fileData[15] << 24;
+
+ if(fileData.size() < 16 + macroSize + propSize + codeSize)
+ {
+ throw InvalidProgramException();
+ }
+
+ //std::vector<std::pair<int, int> > insertions;
+
+ int macroOffset = 16;
+ int propOffset = macroOffset+macroSize;
+ int codeOffset = propOffset+propSize;
+
+
+ int filePosition = macroOffset;
+ while(filePosition + 4 < macroSize + macroOffset)
+ {
+ std::string macro;
+ int macroPosition;
+ int macroValue;
+
+ macroPosition = fileData[filePosition++];
+ macroPosition |= fileData[filePosition++] << 8;
+ macroPosition |= fileData[filePosition++] << 16;
+ macroPosition |= fileData[filePosition++] << 24;
+
+ int stringLength = fileData[filePosition++];
+ if(filePosition + stringLength > macroSize + macroOffset)
+ {
+ throw InvalidProgramException();
+ }
+
+ macro.insert(macro.begin(), fileData.begin()+filePosition, fileData.begin()+filePosition+stringLength);
+ filePosition += stringLength;
+
+ bool resolved = false;
+ for(int i = 0; i < PT_NUM; i++)
+ {
+ if(sim->elements[i].Enabled && sim->elements[i].Identifier == macro)
+ {
+ macroValue = i;
+ resolved = true;
+ }
+ }
+ if(!resolved)
+ {
+ throw UnresolvedValueException(macro);
+ }
+
+ if(macroPosition + 3 >= codeSize)
+ {
+ throw InvalidProgramException();
+ }
+
+ std::cout << "Macro insertion [" << macro << "] at " << macroPosition << " with " << macroValue << std::endl;
+
+ fileData[codeOffset+macroPosition] = macroValue & 0xFF;
+ fileData[codeOffset+macroPosition+1] = (macroValue >> 8) & 0xFF;
+ fileData[codeOffset+macroPosition+2] = (macroValue >> 16) & 0xFF;
+ fileData[codeOffset+macroPosition+3] = (macroValue >> 24) & 0xFF;
+ //insertions.push_back(std::pair<int, int>(macroPosition, macroValue));
+ }
+
+ filePosition = propOffset;
+ while(filePosition + 4 < propSize + propOffset)
+ {
+ std::string prop;
+ int propPosition;
+ int propValue;
+
+ propPosition = fileData[filePosition++];
+ propPosition |= fileData[filePosition++] << 8;
+ propPosition |= fileData[filePosition++] << 16;
+ propPosition |= fileData[filePosition++] << 24;
+
+ int stringLength = fileData[filePosition++];
+ if(filePosition + stringLength > propSize + propOffset)
+ {
+ throw InvalidProgramException();
+ }
+
+ prop.insert(prop.begin(), fileData.begin()+filePosition, fileData.begin()+filePosition+stringLength);
+ filePosition += stringLength;
+
+ bool resolved = false;
+
+ std::vector<StructProperty> properties = Particle::GetProperties();
+ for(std::vector<StructProperty>::iterator iter = properties.begin(), end = properties.end(); iter != end; ++iter)
+ {
+ StructProperty property = *iter;
+ std::cout << property.Offset << std::endl;
+ if(property.Name == prop &&
+ (property.Type == StructProperty::ParticleType ||
+ property.Type == StructProperty::Colour ||
+ property.Type == StructProperty::Integer ||
+ property.Type == StructProperty::UInteger ||
+ property.Type == StructProperty::Float)
+ )
+ {
+ propValue = property.Offset;
+ resolved = true;
+ break;
+ }
+ }
+ if(!resolved)
+ {
+ throw UnresolvedValueException(prop);
+ }
+
+ if(propPosition + 3 >= codeSize)
+ {
+ throw InvalidProgramException();
+ }
+
+ std::cout << "Property insertion [" << prop << "] at " << propPosition << " with " << propValue << std::endl;
+
+ fileData[codeOffset+propPosition] = propValue & 0xFF;
+ fileData[codeOffset+propPosition+1] = (propValue >> 8) & 0xFF;
+ fileData[codeOffset+propPosition+2] = (propValue >> 16) & 0xFF;
+ fileData[codeOffset+propPosition+3] = (propValue >> 24) & 0xFF;
+ //insertions.push_back(std::pair<int, int>(macroPosition, macroValue));
+ }
+
+ std::vector<unsigned char> programData;
+ programData.insert(programData.begin(), fileData.begin()+codeOffset, fileData.begin()+codeOffset+codeSize);
+
+ romSize = programData.size();
+
+ for (lastBit = 0; romSize > (1 << lastBit); lastBit++ ) { }
+ romSize = 1 << lastBit;
+ romMask = romSize - 1;
+
+ rom = new Instruction[romSize];
+
+ int pc = 0;
+ int programPosition = 0;
+
+ while(programPosition < programData.size())
+ {
+ int argSize = 0;
+ Instruction instruction;
+ instruction.Opcode = programData[programPosition++];
+ if(argSize = OpcodeArgSize(instruction.Opcode))
+ {
+ if(argSize == 4 && programPosition+3 < programData.size())
+ {
+ 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;
+
+ if(instruction.Opcode == Opcode::LoadProperty || instruction.Opcode == Opcode::StoreProperty)
+ {
+ if(tempInt > offsetof(Particle, dcolour))
+ throw InvalidProgramException();
+ }
+
+ instruction.Parameter.Integer = tempInt;
+
+ programPosition += 4;
+ }
+ }
+ else
+ {
+ instruction.Parameter.Integer = 0;
+ }
+ rom[pc++] = instruction;
+ }
+ romSize = pc;
+
+ 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:
+ case Opcode::LoadProperty:
+ case Opcode::StoreProperty:
+ 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::LoadProperty:
+ PSPush(PPROP(PSPop().Integer, argument.Integer));
+ break;
+ case Opcode::StoreProperty:
+ temp1 = PSPop();
+ PPROP(temp1.Integer, argument.Integer) = PSPop();
+ 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::Compile()
+ {
+ while(programCounter < romSize)
+ {
+ Word argument = rom[programCounter].Parameter;
+ switch(rom[programCounter].Opcode)
+ {
+ case Opcode::Load:
+ emit("83 EF 04"); //sub edi 4
+
+ //Load value at base stack + offset into eax
+ emit("8B 85"); //mov eax [ebp+ram+offset]
+ emit((intptr_t) (ram - argument.Integer));
+
+ //Store value in eax onto top of program stack
+ emit("89 07"); //mov [edi], eax
+ emit((intptr_t) (ram));
+ break;
+ case Opcode::Store:
+ //Load value on top of the program stack into eax
+ emit("8B 07"); //mov eax [edi]
+ emit((intptr_t) (ram));
+
+ //Load value in eax onto top of program stack
+ emit("89 85"); //mov [ebp+ram+offset], eax
+ emit((intptr_t) (ram - argument.Integer));
+
+ emit("83 C7 04"); //add edi 4
+ break;
+ case Opcode::Constant:
+ emit("83 EF 04"); //sub edi 4
+
+ emit("C7 07"); //mov [edi] constant
+ emit((int) (argument.Integer));
+ break;
+ case Opcode::Increment:
+ emit("81 07"); //add [edi] constant
+ emit((int) (argument.Integer));
+ break;
+ case Opcode::Discard:
+ emit("83 C7 04"); //add edi 4
+ break;
+ case Opcode::Duplicate:
+ //Copy value on stack into register
+ emit("8B 07"); //mov eax [edi]
+ //Adjust program stack pointer
+ emit("83 EF 04"); //sub edi 4
+ //Move value in eax into program stack
+ emit("89 07"); //mov [edi], eax
+ break;
+ case Opcode::Add:
+ emit("8B 07"); //mov eax [edi]
+ emit("01 47 04"); //add [edi+4] eax
+ emit("83 C7 04"); //add edi 4
+ break;
+ case Opcode::Subtract:
+ emit("8B 07"); //mov eax [edi]
+ emit("29 47 04"); //sub [edi+4] eax
+ emit("83 C7 04"); //add edi 4
+ break;
+ case Opcode::Multiply:
+ emit("8B 47 04"); //mov eax [edi+4]
+ emit("F7 2F"); //imul [edi]
+ emit("89 47 04"); //mov [edi+4] eax
+ emit("83 C7 04"); //add edi 4
+ break;
+ case Opcode::Divide:
+ emit("8B 47 04");//mov eax [edi+4]
+ emit("99"); //cdq
+ emit("F7 3F"); //idiv [edi]
+ emit("89 47 04"); //mov [edi+4] eax
+ emit("83 C7 04"); //add edi 4
+ break;
+ case Opcode::Modulus:
+ emit("8B 47 04"); // mov eax [edi+4]
+ emit("99"); // cdq
+ emit("F7 3F"); // idiv [edi]
+ emit("89 57 04"); // mov [edi+4] edx
+ emit("83 C7 04"); //add edi 4
+ break;
+ case Opcode::Negate:
+ emit("F7 1F"); //neg [edi]
+ 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::LoadProperty:
+ //PSPush(PPROP(PSPop().Integer, argument.Integer));
+ break;
+ case Opcode::StoreProperty:
+ //temp1 = PSPop();
+ //PPROP(temp1.Integer, argument.Integer) = PSPop();
+ break;
+ case Opcode::JumpEqual:
+ emit("83 C7 04"); //add edi 8
+ emit("8B 47 FC"); //mov eax, dword ptr [edi-4]
+ emit("3B 47 F7"); //cmp eax, dword ptr [edi-8]
+ emit("75 06"); //jne +6
+ emit("FF 25"); //jmp [0x12345678]
+ emit(0);
+ break;
+ case Opcode::JumpNotEqual:
+ emit("83 C7 04"); //add edi 8
+ emit("8B 47 FC"); //mov eax, dword ptr [edi-4]
+ emit("3B 47 F7"); //cmp eax, dword ptr [edi-8]
+ emit("74 06"); //je +6
+ emit("FF 25"); //jmp [0x12345678]
+ emit(0);
+ break;
+ case Opcode::JumpGreater:
+ emit("83 C7 04"); //add edi 8
+ emit("8B 47 FC"); //mov eax, dword ptr [edi-4]
+ emit("3B 47 F7"); //cmp eax, dword ptr [edi-8]
+ emit("7E 06"); //jng +6
+ emit("FF 25"); //jmp [0x12345678]
+ emit(0);
+ break;
+ case Opcode::JumpGreaterEqual:
+ emit("83 C7 04"); //add edi 8
+ emit("8B 47 FC"); //mov eax, dword ptr [edi-4]
+ emit("3B 47 F7"); //cmp eax, dword ptr [edi-8]
+ emit("7C 06"); //jnge +6
+ emit("FF 25"); //jmp [0x12345678]
+ emit(0);
+ break;
+ case Opcode::JumpLess:
+ emit("83 C7 04"); //add edi 8
+ emit("8B 47 FC"); //mov eax, dword ptr [edi-4]
+ emit("3B 47 F7"); //cmp eax, dword ptr [edi-8]
+ emit("7D 06"); //jnl +6
+ emit("FF 25"); //jmp [0x12345678]
+ emit(0);
+ break;
+ case Opcode::JumpLessEqual:
+ emit("83 C7 04"); //add edi 8
+ emit("8B 47 FC"); //mov eax, dword ptr [edi-4]
+ emit("3B 47 F7"); //cmp eax, dword ptr [edi-8]
+ emit("7F 06"); //jnle +6
+ emit("FF 25"); //jmp [0x12345678]
+ emit(0);
+ break;
+ case Opcode::Jump:
+ //programCounter = argument.Integer-1;
+ break;
+ case Opcode::Return:
+ emit("81 C6"); //add esi constant
+ emit(argument.Integer);
+ break;
+ case Opcode::LocalEnter:
+ emit("81 EE"); //sub esi constant
+ emit(argument.Integer);
+ break;
+ }
+ //std::cout << programStack << std::endl;
+ programCounter++;
+ }
+ //std::cout << "CS: " << callStack << " PS: " << programStack << std::endl;
+ }
+
+ void VirtualMachine::emit(std::string opcode)
+ {
+
+ }
+
+ void VirtualMachine::emit(int constant)
+ {
+
+ }
+
+ void VirtualMachine::CallCompiled(std::string entryPoint)
+ {
+
+ }
+
+ void VirtualMachine::CallCompiled(int entryPoint)
+ {
+
+ }
+
+ void VirtualMachine::Call(std::string entryPoint)
+ {
+
+ }
+
+ void VirtualMachine::Call(int entryPoint)
+ {
+ programCounter = entryPoint;
+ Run();
+ }
+}
diff --git a/src/pim/Machine.h b/src/pim/Machine.h
new file mode 100644
index 0000000..3bf1131
--- /dev/null
+++ b/src/pim/Machine.h
@@ -0,0 +1,120 @@
+#pragma once
+
+#include <vector>
+#include <string>
+#include <cstring>
+
+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 InvalidProgramException: public std::exception
+ {
+ public:
+ InvalidProgramException() { }
+ const char * what() const throw()
+ {
+ return "Invalid program";
+ }
+ ~InvalidProgramException() throw() {};
+ };
+ class UnresolvedValueException: public std::exception
+ {
+ char * error;
+ public:
+ UnresolvedValueException(std::string value) {
+ error = strdup(std::string("Unresolved value: " + value).c_str());
+ }
+ const char * what() const throw()
+ {
+ return error;
+ }
+ ~UnresolvedValueException() throw() {};
+ };
+ 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 * compiledRom;
+ int compiledRomSize;
+
+ unsigned char * ram;
+ int ramSize;
+ int ramMask;
+
+ #define CSA(argument) (*((Word*)&ram[framePointer-argument]))
+ #define CS() (*((Word*)&ram[callStack]))
+ #define PS() (*((Word*)&ram[programStack]))
+ #define PPROP(index, property) (*((Word*)(((char*)&sim->parts[(index)])+property)))
+
+ 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;
+
+ void emit(std::string opcode);
+ void emit(int constant);
+ public:
+ VirtualMachine(Simulation * sim);
+ int OpcodeArgSize(int opcode);
+ void LoadProgram(std::vector<unsigned char> programData);
+ void Run();
+ void Compile();
+ void CallCompiled(std::string entryPoint);
+ void CallCompiled(int entryPoint);
+ 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..4b28294
--- /dev/null
+++ b/src/pim/Opcodes.inl
@@ -0,0 +1,28 @@
+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(LoadProperty)
+OPDEF(StoreProperty)
+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..4b164c8
--- /dev/null
+++ b/src/pim/Parser.cpp
@@ -0,0 +1,653 @@
+//Syntax analyser
+#include "Parser.h"
+#include "Format.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) && !look(Token::ElseIfSymbol))
+ 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()
+ {
+ std::string label = generator->UniqueLabel("if");
+ int blockNum = 0;
+ expect(Token::IfSymbol);
+ condition(label+format::NumberToString<int>(blockNum));
+ expect(Token::ThenSymbol);
+ block();
+ while(accept(Token::ElseIfSymbol))
+ {
+ generator->ScopeLabel(label+format::NumberToString<int>(blockNum++));
+ condition(label+format::NumberToString<int>(blockNum));
+ expect(Token::ThenSymbol);
+ block();
+ }
+ if(accept(Token::ElseSymbol))
+ {
+ generator->ScopeLabel(label+format::NumberToString<int>(blockNum++));
+ block();
+ }
+ else
+ {
+ generator->ScopeLabel(label+format::NumberToString<int>(blockNum++));
+ }
+ expect(Token::EndSymbol);
+ //generator->End(NonTerminal::IfStatement);
+ }
+
+ /*
+ <condition> ::= <expression> <conditional operator> <expression>
+ */
+ void Parser::condition(std::string jumpLabel)
+ {
+ expression();
+
+ Token token = forward();
+
+ expression();
+
+ if(token.Symbol == Token::GreaterSymbol)
+ {
+ generator->JumpLessEqual(jumpLabel);
+ }
+ else if(token.Symbol == Token::GreaterEqualSymbol)
+ {
+ generator->JumpLess(jumpLabel);
+ }
+ else if(token.Symbol == Token::EqualSymbol)
+ {
+ generator->JumpNotEqual(jumpLabel);
+ }
+ else if(token.Symbol == Token::NotEqualSymbol)
+ {
+ generator->JumpEqual(jumpLabel);
+ }
+ else if(token.Symbol == Token::LessSymbol)
+ {
+ generator->JumpGreaterEqual(jumpLabel);
+ }
+ else if(token.Symbol == Token::LessEqualSymbol)
+ {
+ generator->JumpGreater(jumpLabel);
+ }
+ else
+ throw ParserExpectException(token, "conditional operator");
+ }
+
+ /*
+ <assigment statement> ::= identifier = <expression> | identifier.property = <expression>
+ */
+ void Parser::assigmentStatement()
+ {
+ std::string variable = token.Source;
+ expect(Token::Identifier);
+ if(accept(Token::AssignSymbol))
+ {
+ expression();
+ generator->StoreVariable(variable);
+ }
+ else if(accept(Token::DotSymbol))
+ {
+ std::string property = token.Source;
+ expect(Token::Identifier);
+ expect(Token::AssignSymbol);
+ expression();
+ generator->LoadVariable(variable);
+ generator->StoreProperty(property);
+ }
+ }
+
+ /*
+ <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();
+ }
+
+ /*
+ <variable value> ::= <function call> | identifier | identifier.property | rtmacro | <particle action>
+ */
+ void Parser::variableValue()
+ {
+ std::string variable = token.Source;
+ if(accept(Token::Identifier))
+ {
+ if(look(Token::LeftBracket))
+ {
+ back();
+ functionCall();
+ }
+ else
+ {
+ if(accept(Token::DotSymbol))
+ {
+ std::string property = token.Source;
+ expect(Token::Identifier);
+ generator->LoadVariable(variable);
+ generator->LoadProperty(property);
+ }
+ else
+ {
+ generator->LoadVariable(variable);
+ }
+ }
+ }
+ else if(accept(Token::RTMacro))
+ {
+ generator->RTConstant(variable);
+ }
+ else
+ {
+ particleAction();
+ }
+ }
+
+ bool Parser::accept(int symbol)
+ {
+ if(symbol == token.Symbol)
+ {
+ lastToken = token;
+ if(previousTokens.size())
+ {
+ token = previousTokens.top();
+ previousTokens.pop();
+ }
+ else
+ token = scanner->NextToken();
+ //std::cout << "Symbol " << Token::SymbolNames[symbol] << " " << lastToken.Source << std::endl;
+ return true;
+ }
+ //std::cout << "Bad Symbol " << Token::SymbolNames[symbol] << " " << token.Source << " (" << token.GetName() << ")" << std::endl;
+ return false;
+ }
+
+
+ bool Parser::look(int symbol)
+ {
+ if(symbol == token.Symbol)
+ return true;
+ return false;
+ }
+
+ void Parser::back()
+ {
+ previousTokens.push(token);
+ token = lastToken;
+ }
+
+ Token Parser::forward()
+ {
+ lastToken = token;
+ if(previousTokens.size())
+ {
+ token = previousTokens.top();
+ previousTokens.pop();
+ }
+ else
+ token = scanner->NextToken();
+ return 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..9a4f736
--- /dev/null
+++ b/src/pim/Parser.h
@@ -0,0 +1,79 @@
+#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(std::string jumpLabel);
+ void assigmentStatement();
+ void particleAction();
+ void killStatement();
+ void getStatement();
+ void createStatement();
+ void transformStatement();
+ void expressionList();
+
+ void expression();
+ void term();
+ void factor();
+ void variableValue();
+
+ Token forward();
+ 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..e6d145a
--- /dev/null
+++ b/src/pim/Scanner.cpp
@@ -0,0 +1,199 @@
+//Lexical analyser
+#include <algorithm>
+#include <cctype>
+#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 == '[')
+ {
+ cToken.clear();
+ nextCharacter();
+ while(std::isalpha(cChar) || std::isdigit(cChar) || cChar == '_' || cChar == '-')
+ {
+ cToken.push_back(cChar);
+ nextCharacter();
+ }
+ nextCharacter();
+
+ std::transform(cToken.begin(), cToken.end(), cToken.begin(), ::toupper);
+
+ return Token(Token::RTMacro, 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 if(cChar == '.')
+ {
+ nextCharacter();
+ return Token(Token::DotSymbol, ".", 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..453e92f
--- /dev/null
+++ b/src/pim/Token.cpp
@@ -0,0 +1,51 @@
+#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",
+ "else",
+ "elseif",
+ "then",
+ "end",
+ "kill",
+ "create",
+ "transform",
+ "get",
+ "RUNTIMEMACRO",
+ "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..15cd48f
--- /dev/null
+++ b/src/pim/Token.h
@@ -0,0 +1,83 @@
+#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,
+ ElseSymbol,
+ ElseIfSymbol,
+ ThenSymbol,
+ EndSymbol,
+
+ KillSymbol,
+ CreateSymbol,
+ TransformSymbol,
+ GetSymbol,
+
+ RTMacro,
+ Identifier,
+
+ CommaSymbol,
+ DotSymbol,
+
+ 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