diff options
| author | Simon 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) |
| commit | 058a2edd75debbd0297f92572316daa704bd379f (patch) | |
| tree | ad303f091f9a08b209b91eb34a9fcad996a3de69 /src/pim | |
| parent | e3594aba9e05c6865d396418c028049cda92c2f3 (diff) | |
| parent | 7a21ae192fe19868539956f3fe28e62b2c7c4429 (diff) | |
| download | powder-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.cpp | 518 | ||||
| -rw-r--r-- | src/pim/Generator.h | 178 | ||||
| -rw-r--r-- | src/pim/Machine.cpp | 637 | ||||
| -rw-r--r-- | src/pim/Machine.h | 120 | ||||
| -rw-r--r-- | src/pim/Opcodes.h | 12 | ||||
| -rw-r--r-- | src/pim/Opcodes.inl | 28 | ||||
| -rw-r--r-- | src/pim/Parser.cpp | 653 | ||||
| -rw-r--r-- | src/pim/Parser.h | 79 | ||||
| -rw-r--r-- | src/pim/Scanner.cpp | 199 | ||||
| -rw-r--r-- | src/pim/Scanner.h | 22 | ||||
| -rw-r--r-- | src/pim/Token.cpp | 51 | ||||
| -rw-r--r-- | src/pim/Token.h | 83 |
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 |
