Testing new vm/language WIP

This commit is contained in:
Simon Robertshaw 2012-09-21 15:05:50 +01:00
parent 6e44ebc358
commit 939a04d3c7
17 changed files with 2031 additions and 10 deletions

View File

@ -20,11 +20,14 @@
#include "dialogues/TextPrompt.h"
#include "dialogues/ConfirmPrompt.h"
#include "simulation/Simulation.h"
#include "virtualmachine/VirtualMachine.h"
#include "game/GameModel.h"
#include "LuaScriptHelper.h"
#include "client/HTTP.h"
//#include "virtualmachine/VirtualMachine.h"
#include "pim/Parser.h"
#include "pim/Machine.h"
#include "LuaBit.h"
#include "LuaWindow.h"
@ -665,17 +668,24 @@ void LuaScriptInterface::initElementsAPI()
}
}
vm::VirtualMachine * LuaScriptInterface::updateVirtualMachines[PT_NUM];
pim::VirtualMachine * LuaScriptInterface::updateVirtualMachines[PT_NUM];
int LuaScriptInterface::updateVM(UPDATE_FUNC_ARGS)
{
vm::VirtualMachine * vMachine = updateVirtualMachines[parts[i].type];
pim::VirtualMachine * machine = updateVirtualMachines[parts[i].type];
machine->CSPush(i);
machine->CSPush(x);
machine->CSPush(y);
machine->Call(0);
/*vm::VirtualMachine * vMachine = updateVirtualMachines[parts[i].type];
vm::word w;
int argAddr = 0, argCount = 5;
vMachine->sim = sim;
/* Set up call. */
vMachine->OpPUSH(w); //Pointless null in stack
w.int4 = (argCount + 2) * sizeof(vm::word);
vMachine->OpENTER(w);
@ -696,7 +706,7 @@ int LuaScriptInterface::updateVM(UPDATE_FUNC_ARGS)
w.int4 = (argCount + 2) * sizeof(vm::word);
vMachine->OpLEAVE(w);
vMachine->OpPOP(w); //Pop pointless null
vMachine->End();
vMachine->End();*/
return 0;
}
@ -1017,7 +1027,7 @@ int LuaScriptInterface::elements_property(lua_State * l)
}
else if(lua_type(l, 3) == LUA_TLIGHTUSERDATA)
{
updateVirtualMachines[id] = (vm::VirtualMachine*)lua_touserdata(l, 3);
updateVirtualMachines[id] = (pim::VirtualMachine*)lua_touserdata(l, 3);
luacon_sim->elements[id].Update = &updateVM;
}
else if(lua_type(l, 3) == LUA_TBOOLEAN && !lua_toboolean(l, 3))
@ -1142,7 +1152,7 @@ void LuaScriptInterface::initVirtualMachineAPI()
int LuaScriptInterface::virtualMachine_loadProgram(lua_State * l)
{
luaL_checktype(l, 1, LUA_TSTRING);
/*luaL_checktype(l, 1, LUA_TSTRING);
vm::VirtualMachine * newVM = new vm::VirtualMachine(1);
try
@ -1156,7 +1166,19 @@ int LuaScriptInterface::virtualMachine_loadProgram(lua_State * l)
{
return luaL_error(l, "Unable to load program");
}
lua_pushlightuserdata(l, newVM);
lua_pushlightuserdata(l, newVM);*/
std::string programSource(lua_tostring(l, 1));
std::stringstream input(programSource);
pim::compiler::Parser * parser = new pim::compiler::Parser(input);
std::vector<unsigned char> programData = parser->Compile();
pim::VirtualMachine * machine = new pim::VirtualMachine(luacon_sim);
machine->LoadProgram(programData);
lua_pushlightuserdata(l, machine);
return 1;
}

View File

@ -23,7 +23,7 @@ namespace ui
class Window;
}
namespace vm
namespace pim
{
class VirtualMachine;
}
@ -65,7 +65,7 @@ class LuaScriptInterface: public CommandInterface {
static int renderer_colourMode(lua_State * l);
//Elements
static vm::VirtualMachine * updateVirtualMachines[PT_NUM];
static pim::VirtualMachine * updateVirtualMachines[PT_NUM];
static int updateVM(UPDATE_FUNC_ARGS);
//
void initElementsAPI();

View File

@ -0,0 +1,11 @@
#pragma once
//Legacy blocking prompts
//This are not implemented here, but rather in the engine bootstrapper
bool ConfirmUI(std::string title, std::string message, std::string confirmText) {}
void ErrorUI(std::string title, std::string message) {}
void InformationUI(std::string title, std::string message) {}
std::string MessagePromptUI(std::string title, std::string message, std::string text, std::string placeholder) {}

View File

@ -0,0 +1,30 @@
#pragma once
extern "C" {
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
}
#include "LuaLuna.h"
#include "LuaComponent.h"
namespace ui
{
class ProgressBar;
}
class LuaScriptInterface;
class LuaProgressBar: public LuaComponent
{
ui::ProgressBar * progressBar;
int onValueChangedFunction;
int value(lua_State * l);
public:
static const char className[];
static Luna<LuaProgressBar>::RegType methods[];
LuaProgressBar(lua_State * l);
~LuaProgressBar();
};

326
src/pim/Generator.cpp Normal file
View File

@ -0,0 +1,326 @@
//Code generator for bytecode
#include <sstream>
#include "Format.h"
#include "Generator.h"
#include "Opcodes.h"
namespace pim
{
namespace compiler
{
Generator::Generator() :
output(std::cout),
labelCounter(0),
programCounter(0)
{
}
void Generator::defineLabel(std::string label)
{
Label newLabel;
newLabel.Name = label;
newLabel.Position = programCounter;//program.size();
labelPositions.push_back(newLabel);
}
void Generator::writeOpcode(int opcode)
{
programCounter++;
program.push_back(opcode);
}
void Generator::writeConstant(std::string constant)
{
writeConstant(format::StringToNumber<int>(constant));
}
void Generator::writeConstant(int constant)
{
program.push_back(constant & 0xFF);
program.push_back((constant>>8) & 0xFF);
program.push_back((constant>>16) & 0xFF);
program.push_back((constant>>24) & 0xFF);
}
void Generator::writeConstantPlaceholder(std::string label)
{
placeholders.push_back(Placeholder(program.size(), label));
program.push_back(0);
program.push_back(0);
program.push_back(0);
program.push_back(0);
}
void Generator::writeConstantPlaceholder(int * value)
{
valuePlaceholders.push_back(ValuePlaceholder(program.size(), value));
program.push_back(0);
program.push_back(0);
program.push_back(0);
program.push_back(0);
}
std::vector<unsigned char> Generator::Finish()
{
for(std::vector<Placeholder>::iterator iter = placeholders.begin(), end = placeholders.end(); iter != end; ++iter)
{
bool found = false;
Placeholder cPosition = *iter;
for(std::vector<Label>::iterator iter2 = labelPositions.begin(), end2 = labelPositions.end(); iter2 != end2; ++iter2)
{
Label cLabel = *iter2;
if(cPosition.second == cLabel.Name)
{
std::cout << "Setting placeholder at " << cPosition.first << " with " << cLabel.Position << " for" << cPosition.second << std::endl;
found = true;
program[cPosition.first] = cLabel.Position & 0xFF;
program[cPosition.first+1] = (cLabel.Position >> 8) & 0xFF;
program[cPosition.first+2] = (cLabel.Position >> 16) & 0xFF;
program[cPosition.first+3] = (cLabel.Position >> 24) & 0xFF;
break;
}
}
if(!found)
throw SymbolNotFoundException(cPosition.second);
}
for(std::vector<ValuePlaceholder>::iterator iter = valuePlaceholders.begin(), end = valuePlaceholders.end(); iter != end; ++iter)
{
ValuePlaceholder cPosition = *iter;
int value = *cPosition.second;
std::cout << "Setting value placeholder at " << cPosition.first << " with " << value << std::endl;
program[cPosition.first] = value & 0xFF;
program[cPosition.first+1] = (value >> 8) & 0xFF;
program[cPosition.first+2] = (value >> 16) & 0xFF;
program[cPosition.first+3] = (value >> 24) & 0xFF;
}
return program;
}
std::string Generator::UniqueLabel(std::string prefix)
{
std::stringstream label;
label << prefix;
label << "_";
label << labelCounter;
label << "_";
return label.str();
}
void Generator::PushScope(std::string label)
{
scopes.push(currentScope);
Scope * prevScope = currentScope;
currentScope = new Scope();
defineLabel(label);
}
void Generator::PushLocalScope(std::string label)
{
scopes.push(currentScope);
Scope * prevScope = currentScope;
currentScope = new Scope();
currentScope->Definitions.insert(currentScope->Definitions.begin(), prevScope->Definitions.begin(), prevScope->Definitions.end());
currentScope->FrameSize = prevScope->FrameSize;
defineLabel(label);
}
void Generator::PopScope()
{
writeOpcode(Opcode::Return);
writeConstant(currentScope->LocalFrameSize);
currentScope = scopes.top();
scopes.pop();
}
void Generator::ScopeLabel(std::string label)
{
//defineLabelwriteOpcode("." << label);
defineLabel(label);
}
void Generator::LocalEnter()
{
writeOpcode(Opcode::LocalEnter);
writeConstantPlaceholder(&(currentScope->LocalFrameSize));
}
void Generator::ScopeVariableType(int type)
{
variableType = type;
}
void Generator::ScopeVariable(std::string label)
{
currentScope->Definitions.push_back(Definition(label, variableType, currentScope->FrameSize));
currentScope->FrameSize += 4;
currentScope->LocalFrameSize += 4;
}
void Generator::PushVariableAddress(std::string label)
{
//writeOpcode("address"); << " " << currentScope->GetDefinition(label).StackPosition
}
void Generator::LoadVariable(std::string label)
{
writeOpcode(Opcode::Load);
writeConstant(currentScope->GetDefinition(label).StackPosition);
}
void Generator::StoreVariable(std::string label)
{
writeOpcode(Opcode::Store);
writeConstant(currentScope->GetDefinition(label).StackPosition);
}
void Generator::Constant(std::string constant)
{
writeOpcode(Opcode::Constant);
writeConstant(constant);
}
void Generator::Increment(std::string constant)
{
writeOpcode(Opcode::Increment);
writeConstant(constant);
}
void Generator::Discard()
{
writeOpcode(Opcode::Discard);
}
void Generator::Duplicate()
{
writeOpcode(Opcode::Duplicate);
}
void Generator::Add()
{
writeOpcode(Opcode::Add);
}
void Generator::Subtract()
{
writeOpcode(Opcode::Subtract);
}
void Generator::Multiply()
{
writeOpcode(Opcode::Multiply);
}
void Generator::Divide()
{
writeOpcode(Opcode::Divide);
}
void Generator::Modulus()
{
writeOpcode(Opcode::Modulus);
}
void Generator::Negate()
{
writeOpcode(Opcode::Negate);
}
void Generator::CreateParticle()
{
writeOpcode(Opcode::Create);
}
void Generator::TransformParticle()
{
writeOpcode(Opcode::Transform);
}
void Generator::GetParticle()
{
writeOpcode(Opcode::Get);
}
void Generator::GetPosition()
{
writeOpcode(Opcode::Position);
}
void Generator::KillParticle()
{
writeOpcode(Opcode::Kill);
}
void Generator::IntegerToDecimal()
{
}
void Generator::DecimalToInteger()
{
}
void Generator::JumpEqual(std::string label)
{
writeOpcode(Opcode::JumpEqual);
writeConstantPlaceholder(label);
}
void Generator::JumpNotEqual(std::string label)
{
writeOpcode(Opcode::JumpNotEqual);
writeConstantPlaceholder(label);
}
void Generator::JumpGreater(std::string label)
{
writeOpcode(Opcode::JumpGreater);
writeConstantPlaceholder(label);
}
void Generator::JumpGreaterEqual(std::string label)
{
writeOpcode(Opcode::JumpGreaterEqual);
writeConstantPlaceholder(label);
}
void Generator::JumpLess(std::string label)
{
writeOpcode(Opcode::JumpLess);
writeConstantPlaceholder(label);
}
void Generator::JumpLessEqual(std::string label)
{
writeOpcode(Opcode::JumpLessEqual);
writeConstantPlaceholder(label);
}
void Generator::Jump(std::string label)
{
writeOpcode(Opcode::Jump);
writeConstantPlaceholder(label);
}
void Generator::Call(int arguments, std::string label)
{
}
void Generator::Return()
{
}
}
}

164
src/pim/Generator.h Normal file
View File

@ -0,0 +1,164 @@
#pragma once
#include <cstring>
#include <vector>
#include <stack>
#include <iostream>
#include "Token.h"
namespace pim
{
namespace compiler
{
class VariableNotFoundException: public std::exception
{
char * error;
public:
VariableNotFoundException(std::string variable) {
error = strdup(std::string("Could not find the variable \""+variable+"\" in the current scope").c_str());
}
const char * what() const throw()
{
return error;
}
~VariableNotFoundException() throw() {};
};
class SymbolNotFoundException: public std::exception
{
char * error;
public:
SymbolNotFoundException(std::string variable) {
error = strdup(std::string("Could not find the symbol \""+variable+"\".").c_str());
}
const char * what() const throw()
{
return error;
}
~SymbolNotFoundException() throw() {};
};
class Definition
{
public:
enum { Integer = Token::IntegerSymbol, Decimal = Token::DecimalSymbol };
std::string Name;
int Type;
int StackPosition;
Definition(std::string name, int type, int position) :
Type(type),
Name(name),
StackPosition(position)
{
}
};
struct Label
{
std::string Name;
int Position;
};
class Scope
{
public:
std::vector<Definition> Definitions;
std::vector<Label> Labels;
int FrameSize;
int LocalFrameSize;
Scope():
FrameSize(0),
LocalFrameSize(0)
{
}
Definition GetDefinition(std::string name)
{
for(std::vector<Definition>::iterator iter = Definitions.begin(), end = Definitions.end(); iter != end; ++iter)
{
if((*iter).Name == name)
return *iter;
}
throw VariableNotFoundException(name);
}
};
class Generator
{
int variableType;
std::stack<Scope*> scopes;
Scope * currentScope;
std::ostream & output;
int labelCounter;
int programCounter;
typedef std::pair<int, std::string> Placeholder;
std::vector<Placeholder> placeholders;
typedef std::pair<int, int*> ValuePlaceholder;
std::vector<ValuePlaceholder> valuePlaceholders;
std::vector<Label> labelPositions;
std::vector<unsigned char> program;
void defineLabel(std::string label);
void writeOpcode(int opcode);
void writeConstant(std::string constant);
void writeConstant(int constant);
void writeConstantPlaceholder(std::string label);
void writeConstantPlaceholder(int * value);
public:
Generator();
std::vector<unsigned char> Finish();
std::string UniqueLabel(std::string prefix);
void PushScope(std::string label);
void PushLocalScope(std::string label);
void LocalEnter();
void PopScope();
void ScopeLabel(std::string label);
void ScopeVariableType(int type);
void ScopeVariable(std::string label);
void PushVariableAddress(std::string label);
// void Store();
void LoadVariable(std::string label);
void StoreVariable(std::string label);
void Duplicate();
void Discard();
void Constant(std::string constant);
void Increment(std::string constant);
void Add();
void Subtract();
void Multiply();
void Divide();
void Modulus();
void Negate();
void TransformParticle();
void CreateParticle();
void GetParticle();
void GetPosition();
void KillParticle();
void IntegerToDecimal();
void DecimalToInteger();
void JumpEqual(std::string label);
void JumpNotEqual(std::string label);
void JumpGreater(std::string label);
void JumpGreaterEqual(std::string label);
void JumpLess(std::string label);
void JumpLessEqual(std::string label);
void Jump(std::string label);
void Call(int arguments, std::string label);
void Return();
};
}
}

271
src/pim/Machine.cpp Normal file
View File

@ -0,0 +1,271 @@
//Virtual machine
#include <iostream>
#include "Machine.h"
#include "Opcodes.h"
#include "simulation/Simulation.h"
namespace pim
{
/*unsigned char * rom;
int romSize;
int romMask;
unsigned char * ram;
int ramSize;
int ramMask;
int programStack;
int callStack;*/
VirtualMachine::VirtualMachine(Simulation * simulation) :
rom(NULL),
ram(NULL),
sim(simulation)
{
}
void VirtualMachine::LoadProgram(std::vector<unsigned char> programData)
{
int lastBit = 0;
romSize = programData.size();
for (lastBit = 0; romSize > (1 << lastBit); lastBit++ ) { }
romSize = 1 << lastBit;
romMask = romSize - 1;
rom = new Instruction[romSize];
int programPosition = 0;
int pc = 0;
while(programPosition < programData.size())
{
int argSize = 0;
Instruction instruction;
instruction.Opcode = programData[programPosition++];
if(argSize = OpcodeArgSize(instruction.Opcode))
{
if(argSize == 4)
{
int tempInt = 0;
tempInt |= programData[programPosition];
tempInt |= programData[programPosition+1] << 8;
tempInt |= programData[programPosition+2] << 16;
tempInt |= programData[programPosition+3] << 24;
std::cout << "Got integer " << tempInt << std::endl;
//std::cout << "Got byte " << (int)(programData[programPosition]) << std::endl;
//std::cout << "Got byte " << (int)(programData[programPosition+1]) << std::endl;
//std::cout << "Got byte " << (int)(programData[programPosition+2]) << std::endl;
//std::cout << "Got byte " << (int)(programData[programPosition+3]) << std::endl;
//*(int*)&rom[programPosition] = tempInt;
instruction.Parameter.Integer = tempInt;
programPosition += 4;
}
}
else
{
instruction.Parameter.Integer = 0;
}
rom[pc++] = instruction;
}
romSize = pc;
//std::copy(programData.begin(), programData.end(), rom);
ramSize = 1024;
ramMask = ramSize - 1;
ram = new unsigned char[ramSize];
programStack = ramSize-1;
callStack = ramSize-260;
framePointer = callStack;
callStack += WORDSIZE; //Since there's nothing on the stack, it shouldn't point to the item on the bottom
}
int VirtualMachine::OpcodeArgSize(int opcode)
{
switch(opcode)
{
case Opcode::Load:
case Opcode::Store:
case Opcode::Constant:
case Opcode::Increment:
case Opcode::JumpEqual:
case Opcode::JumpNotEqual:
case Opcode::JumpGreater:
case Opcode::JumpGreaterEqual:
case Opcode::JumpLess:
case Opcode::JumpLessEqual:
case Opcode::Jump:
case Opcode::Return:
case Opcode::LocalEnter:
return 4;
case Opcode::Discard:
case Opcode::Duplicate:
case Opcode::Add:
case Opcode::Subtract:
case Opcode::Multiply:
case Opcode::Divide:
case Opcode::Modulus:
case Opcode::Negate:
case Opcode::Create:
case Opcode::Transform:
case Opcode::Get:
case Opcode::Position:
case Opcode::Kill:
return 0;
}
}
void VirtualMachine::Run()
{
//std::cout << "CS: " << callStack << " PS: " << programStack << std::endl;
//std::string names[] = { "Load", "Store", "Constant", "Increment", "Discard", "Duplicate", "Add", "Subtract", "Multiply", "Divide", "Modulus", "Negate", "Create", "Transform", "Get", "Position", "Kill", "JumpEqual", "JumpNotEqual", "JumpGreater", "JumpGreaterEqual", "JumpLess", "JumpLessEqual", "Jump", "Return", "LocalEnter"};
Word temp1;
Word temp2;
Word temp3;
Word temp4;
int temp;
while(programCounter < romSize)
{
Word argument = rom[programCounter].Parameter;
//std::cerr << programCounter << "\t" << names[rom[programCounter].Opcode] << "\t" << argument.Integer << std::endl;//"\t";
switch(rom[programCounter].Opcode)
{
case Opcode::Load:
PSPush(CSA(argument.Integer));
break;
case Opcode::Store:
CSA(argument.Integer) = PSPop();
break;
case Opcode::Constant:
PSPush(argument);
break;
case Opcode::Increment:
PS().Integer += argument.Integer;
break;
case Opcode::Discard:
programStack += WORDSIZE;
break;
case Opcode::Duplicate:
PSPush(PS());
break;
case Opcode::Add:
PSPush(PSPop().Integer + PSPop().Integer);
break;
case Opcode::Subtract:
temp1 = PSPop();
PSPush(PSPop().Integer - temp1.Integer);
break;
case Opcode::Multiply:
PSPush(PSPop().Integer * PSPop().Integer);
break;
case Opcode::Divide:
temp1 = PSPop();
PSPush(PSPop().Integer / temp1.Integer);
break;
case Opcode::Modulus:
temp1 = PSPop();
PSPush(PSPop().Integer % temp1.Integer);
break;
case Opcode::Negate:
PS().Integer = -PS().Integer;
break;
case Opcode::Create:
temp1 = PSPop();
temp2 = PSPop();
temp3 = PSPop();
PSPush(sim->create_part(PSPop().Integer, temp3.Integer, temp2.Integer, temp1.Integer));
break;
case Opcode::Transform:
PSPop();
PSPop();
PSPush((Word)-1);
break;
case Opcode::Get:
temp1 = PSPop();
temp2 = PSPop();
if(temp1.Integer < 0 || temp1.Integer >= YRES || temp2.Integer < 0 || temp2.Integer >= XRES || !(temp = sim->pmap[temp1.Integer][temp2.Integer]))
{
PSPush(-1);
break;
}
PSPush(temp>>8);
break;
case Opcode::Position:
temp1 = PSPop();
if(temp1.Integer < 0 || temp1.Integer >= NPART || !sim->parts[temp1.Integer].type)
{
PSPush(-1);
PSPush(-1);
break;
}
PSPush((int)sim->parts[temp1.Integer].x);
PSPush((int)sim->parts[temp1.Integer].y);
break;
case Opcode::Kill:
sim->kill_part(PSPop().Integer);
PSPush((Word)0);
break;
case Opcode::JumpEqual:
if(PSPop().Integer == PSPop().Integer)
programCounter = argument.Integer-1;
break;
case Opcode::JumpNotEqual:
if(PSPop().Integer != PSPop().Integer)
programCounter = argument.Integer-1;
break;
case Opcode::JumpGreater:
temp1 = PSPop();
if(PSPop().Integer > temp1.Integer)
programCounter = argument.Integer-1;
break;
case Opcode::JumpGreaterEqual:
temp1 = PSPop();
if(PSPop().Integer >= temp1.Integer)
programCounter = argument.Integer-1;
break;
case Opcode::JumpLess:
temp1 = PSPop();
if(PSPop().Integer < temp1.Integer)
programCounter = argument.Integer-1;
break;
case Opcode::JumpLessEqual:
temp1 = PSPop();
if(PSPop().Integer <= temp1.Integer)
programCounter = argument.Integer-1;
break;
case Opcode::Jump:
programCounter = argument.Integer-1;
break;
case Opcode::Return:
callStack += argument.Integer;
break;
case Opcode::LocalEnter:
callStack -= argument.Integer;
break;
}
//std::cout << programStack << std::endl;
programCounter++;
}
//std::cout << "CS: " << callStack << " PS: " << programStack << std::endl;
}
void VirtualMachine::Call(std::string entryPoint)
{
}
void VirtualMachine::Call(int entryPoint)
{
programCounter = entryPoint;
Run();
}
}

88
src/pim/Machine.h Normal file
View File

@ -0,0 +1,88 @@
#pragma once
#include <vector>
#include <string>
class Simulation;
namespace pim
{
union Word
{
int Integer;
float Decimal;
Word(int integer) : Integer(integer) {}
Word(float decimal) : Decimal(decimal) {}
Word() {}
};
struct Instruction
{
int Opcode;
Word Parameter;
};
class VirtualMachine
{
#define WORDSIZE 4
//#define OPDEF(name) void op##name(int parameter);
//#include "Opcodes.inl"
//#undef OPDEF
Simulation * sim;
Instruction * rom;
int romSize;
int romMask;
unsigned char * ram;
int ramSize;
int ramMask;
#define CSA(argument) (*((Word*)&ram[framePointer-argument]))
#define CS() (*((Word*)&ram[callStack]))
#define PS() (*((Word*)&ram[programStack]))
int programStack; //Points to the item on top of the Program Stack
int callStack; //Points to the item on top of the call stack
int framePointer; //Points to the bottom (first item) on the current frame of the call stack
//Instruction * instructions;
int programCounter;
public:
VirtualMachine(Simulation * sim);
int OpcodeArgSize(int opcode);
void LoadProgram(std::vector<unsigned char> programData);
void Run();
void Call(std::string entryPoint);
void Call(int entryPoint);
inline void PSPush(Word word)
{
programStack -= WORDSIZE;
PS() = word;
}
inline Word PSPop()
{
Word word = PS();
programStack += WORDSIZE;
return word;
}
inline void CSPush(Word word)
{
callStack -= WORDSIZE;
CS() = word;
}
inline Word CSPop()
{
Word word = CS();
callStack += WORDSIZE;
return word;
}
};
}

12
src/pim/Opcodes.h Normal file
View File

@ -0,0 +1,12 @@
namespace pim
{
struct Opcode
{
enum
{
#define OPDEF(name) name,
#include "Opcodes.inl"
#undef OPDEF
};
};
}

26
src/pim/Opcodes.inl Normal file
View File

@ -0,0 +1,26 @@
OPDEF(Load)
OPDEF(Store)
OPDEF(Constant)
OPDEF(Increment)
OPDEF(Discard)
OPDEF(Duplicate)
OPDEF(Add)
OPDEF(Subtract)
OPDEF(Multiply)
OPDEF(Divide)
OPDEF(Modulus)
OPDEF(Negate)
OPDEF(Create)
OPDEF(Transform)
OPDEF(Get)
OPDEF(Position)
OPDEF(Kill)
OPDEF(JumpEqual)
OPDEF(JumpNotEqual)
OPDEF(JumpGreater)
OPDEF(JumpGreaterEqual)
OPDEF(JumpLess)
OPDEF(JumpLessEqual)
OPDEF(Jump)
OPDEF(Return)
OPDEF(LocalEnter)

646
src/pim/Parser.cpp Normal file
View File

@ -0,0 +1,646 @@
//Syntax analyser
#include "Parser.h"
namespace pim
{
namespace compiler
{
Parser::Parser(std::stringstream & source_) :
source(source_)
{
scanner = new Scanner(source);
generator = new Generator();
token = scanner->NextToken();
}
std::vector<unsigned char> Parser::Compile()
{
program();
return generator->Finish();
}
/*
<program> ::= <function list>
*/
void Parser::program()
{
functionList();
}
/*
<function list> ::= <function> | <function> <function list>
*/
void Parser::functionList()
{
function();
while(look(Token::FunctionSymbol))
function();
}
/*
<function> ::= function identifier ( <declaration list> ) <block> end
*/
void Parser::function()
{
std::string functionName;
expect(Token::FunctionSymbol);
functionName = token.Source;
//generator->ScopeLabel(functionName); //Function name
generator->PushScope(functionName);
expect(Token::Identifier);
expect(Token::LeftBracket);
if(!accept(Token::RightBracket))
{
argumentList();
expect(Token::RightBracket);
}
block();
expect(Token::EndSymbol);
generator->Return();
generator->PopScope();
}
/*
<function call> ::= identifier ( <expression list> )
*/
void Parser::functionCall()
{
std::string functionName;
functionName = token.Source;
expect(Token::Identifier);
expect(Token::LeftBracket);
expressionList();
expect(Token::RightBracket);
//generator->Call(functionName);
}
/*
<block> ::= <declaration list> <statement list>
*/
void Parser::block()
{
if(look(Token::IntegerSymbol) || look(Token::DecimalSymbol) || look(Token::ParticleSymbol))
declarationList();
statementList();
}
/*
<argument list> ::= <argument> | <argument> , <argument list>
*/
void Parser::argumentList()
{
argument();
while(accept(Token::CommaSymbol))
argument();
}
/*
<argument> ::= integer identifier | decimal identifier | particle identifier
*/
void Parser::argument()
{
generator->ScopeVariableType(token.Symbol);
if(!accept(Token::IntegerSymbol))
if(!accept(Token::DecimalSymbol))
if(!accept(Token::ParticleSymbol))
throw ParserExpectException(token, "type name");
generator->ScopeVariable(token.Source);
expect(Token::Identifier);
}
/*
<declaration list> ::= <declaration> | <declaration> , <declaration list>
*/
void Parser::declarationList()
{
declaration();
while(accept(Token::CommaSymbol))
declaration();
}
/*
<declaration> ::= integer <identifier list> | decimal <identifier list> | particle <identifier list>
*/
void Parser::declaration()
{
generator->ScopeVariableType(token.Symbol);
if(!accept(Token::IntegerSymbol))
if(!accept(Token::DecimalSymbol))
if(!accept(Token::ParticleSymbol))
throw ParserExpectException(token, "type name");
identifierList();
}
/*
<identifier list> ::= identifier | identifier , <identifier list>
*/
void Parser::identifierList()
{
generator->ScopeVariable(token.Source);
expect(Token::Identifier);
while(accept(Token::CommaSymbol))
{
generator->ScopeVariable(token.Source);
expect(Token::Identifier);
}
}
/*
<statement list> ::= <statement> | <statement> <statement list>
*/
void Parser::statementList()
{
statement();
while(!look(Token::EndSymbol))
statement();
}
/*
<statement> ::= <neighbour statement> | <if statement> | <assignment statement> | <function call> | <particle action> | break | continue
*/
void Parser::statement()
{
//generator->Begin(NonTerminal::Statement);
if(look(Token::NeighbourSymbol))
{
neighbourStatement();
}
else if(look(Token::IfSymbol))
{
ifStatement();
}
else if(look(Token::CreateSymbol) || look(Token::KillSymbol) || look(Token::GetSymbol) || look(Token::TransformSymbol))
{
particleAction();
generator->Discard();
}
else if(look(Token::BreakSymbol))
{
expect(Token::BreakSymbol);
generator->Jump(breakLabel);
}
else if(look(Token::ContinueSymbol))
{
expect(Token::ContinueSymbol);
generator->Jump(continueLabel);
}
else if(look(Token::Identifier))
{
assigmentStatement();
}
//generator->End(NonTerminal::Statement);
}
/*
<particle action> ::= <kill statement> | <create statement> | <transform statement>
*/
void Parser::particleAction()
{
if(look(Token::KillSymbol))
{
killStatement();
}
else if(look(Token::CreateSymbol))
{
createStatement();
}
else if(look(Token::TransformSymbol))
{
transformStatement();
}
}
/*
<kill statement> ::= kill ( <expression> )
*/
void Parser::killStatement()
{
expect(Token::KillSymbol);
expect(Token::LeftBracket);
expression();
expect(Token::RightBracket);
generator->KillParticle();
}
/*
<create statement> ::= create ( <expression>, <expression>, <expression>, <expression> )
*/
void Parser::createStatement()
{
expect(Token::CreateSymbol);
expect(Token::LeftBracket);
expression();
expect(Token::CommaSymbol);
expression();
expect(Token::CommaSymbol);
expression();
expect(Token::CommaSymbol);
expression();
expect(Token::RightBracket);
generator->CreateParticle();
}
/*
<transform statement> ::= transform ( <expression>, <expression> )
*/
void Parser::transformStatement()
{
expect(Token::TransformSymbol);
expect(Token::LeftBracket);
expression();
expect(Token::CommaSymbol);
expression();
expect(Token::RightBracket);
generator->TransformParticle();
}
/*
<get statement> ::= get ( <expression>, <expression> )
*/
void Parser::getStatement()
{
expect(Token::GetSymbol);
expect(Token::LeftBracket);
expression();
expect(Token::CommaSymbol);
expression();
expect(Token::RightBracket);
generator->GetParticle();
}
/*
<neighbour statement> ::= neighbour identifier for <expression> do <block> end | neighbour identifier for <expression>, <expression> do <block> end
*/
void Parser::neighbourStatement()
{
std::string neighbourVariable;
std::string loopLabel = generator->UniqueLabel("neighbour");
std::string xVar = loopLabel+"X";
std::string xMin = loopLabel+"minX";
std::string xMax = loopLabel+"maxX";
std::string yVar = loopLabel+"Y";
std::string yMax = loopLabel+"maxY";
breakLabel = loopLabel+"End";
continueLabel = loopLabel+"Next";
expect(Token::NeighbourSymbol);
generator->PushLocalScope(loopLabel+"Start");
neighbourVariable = token.Source;
expect(Token::Identifier);
generator->ScopeVariableType(Token::IntegerConstant);
generator->ScopeVariable(neighbourVariable);
generator->ScopeVariable(xVar);
generator->ScopeVariable(yVar);
generator->ScopeVariable(xMin);
generator->ScopeVariable(xMax);
generator->ScopeVariable(yMax);
generator->LocalEnter();
expect(Token::OfSymbol);
//Initialise position
expression();
generator->GetPosition();
generator->Duplicate();
generator->Increment("-1");
generator->StoreVariable(yVar);
generator->Increment("1");
generator->StoreVariable(yMax);
generator->Duplicate();
generator->Increment("-1");
generator->Duplicate();
generator->StoreVariable(xVar);
generator->StoreVariable(xMin);
generator->Increment("1");
generator->StoreVariable(xMax);
//if(accept(Token::CommaSymbol))
// expression();
expect(Token::DoSymbol);
generator->ScopeLabel(loopLabel+"Next");
//Check X
generator->LoadVariable(xVar);
generator->LoadVariable(xMax);
//generator->Duplicate(); //Duplicate xvar so it can be used for incrementing
generator->JumpLessEqual(loopLabel+"Begin");
//if(xVar > xMax) {
//Reset X, increment Y
generator->LoadVariable(xMin);
generator->StoreVariable(xVar);
generator->LoadVariable(yVar);
generator->Increment("1");
generator->Duplicate();
generator->StoreVariable(yVar);
//Check Y
generator->LoadVariable(yMax);
generator->JumpGreater(loopLabel+"End");
//}
//Start of loop
generator->ScopeLabel(loopLabel+"Begin");
generator->LoadVariable(xVar);
generator->LoadVariable(yVar);
generator->GetParticle();
generator->StoreVariable(neighbourVariable);
block();
//Increment X
generator->LoadVariable(xVar);
generator->Increment("1");
generator->StoreVariable(xVar);
//Next element
generator->Jump(loopLabel+"Next");
generator->ScopeLabel(loopLabel+"End");
generator->Return();
generator->PopScope();
expect(Token::EndSymbol);
}
/*
<if statement> ::= if <condition> then <block> end
*/
void Parser::ifStatement()
{
//generator->Begin(NonTerminal::IfStatement);
expect(Token::IfSymbol);
condition();
expect(Token::ThenSymbol);
block();
expect(Token::EndSymbol);
//generator->End(NonTerminal::IfStatement);
}
/*
<condition> ::= identifier <conditional operator> identifier | identifier <conditional operator> numberConstant | numberConstant <conditional operator> identifier | numberConstant <conditional operator> numberConstant
*/
void Parser::condition()
{
//generator->Begin(NonTerminal::Condition);
if(look(Token::Identifier))
{
conditionalOperator();
if(!accept(Token::Identifier) && !accept(Token::IntegerConstant) && !accept(Token::DecimalConstant))
throw ParserExpectException(token, "identifier or constant");
}
else if(look(Token::DecimalConstant) || look(Token::IntegerConstant))
{
conditionalOperator();
if(!accept(Token::Identifier) && !accept(Token::IntegerConstant) && !accept(Token::DecimalConstant))
throw ParserExpectException(token, "identifier or constant");
}
else
{
throw ParserExpectException(token, "condition");
}
//generator->End(NonTerminal::Condition);
}
/*
<conditional operator> ::= > | >= | == | != | < | <=
*/
void Parser::conditionalOperator()
{
//generator->Begin(NonTerminal::ConditionalOperator);
if(!accept(Token::GreaterSymbol))
if(!accept(Token::GreaterEqualSymbol))
if(!accept(Token::EqualSymbol))
if(!accept(Token::NotEqualSymbol))
if(!accept(Token::LessSymbol))
if(!accept(Token::LessEqualSymbol))
throw ParserExpectException(token, "conditional operator");
//generator->End(NonTerminal::ConditionalOperator);
}
/*
<assigment statement> ::= identifier = <expression>
*/
void Parser::assigmentStatement()
{
std::string variable = token.Source;
//generator->PushVariableAddress(token.Source);
expect(Token::Identifier);
expect(Token::AssignSymbol);
expression();
//generator->Store();
generator->StoreVariable(variable);
}
/*
<expression list> ::= <expression> | <expression> , <expression list>
*/
void Parser::expressionList()
{
//generator->Begin(NonTerminal::ExpressionList);
expression();
while(accept(Token::CommaSymbol))
expression();
//generator->End(NonTerminal::ExpressionList);
}
/*
<expression> ::= <term> | <expression> + <term> | <expression> - <term>
*/
void Parser::expression()
{
term();
int as = token.Symbol;
while(accept(Token::PlusSymbol) || accept(Token::MinusSymbol))
{
term();
if(as == Token::PlusSymbol)
generator->Add();
else if(as == Token::MinusSymbol)
generator->Subtract();
}
//generator->End(NonTerminal::Expression);
}
/*
<term> ::= <factor> | <term> * <factor> | <term> / <factor>
*/
void Parser::term()
{
//generator->Begin(NonTerminal::Term);
factor();
int md = token.Symbol;
while(accept(Token::MultiplySymbol) || accept(Token::DivideSymbol))
{
factor();
if(md == Token::MultiplySymbol)
generator->Multiply();
else if(md == Token::DivideSymbol)
generator->Divide();
}
//generator->End(NonTerminal::Term);
}
/*
<factor> ::= <variable value> | - <variable value> | numberConstant | - numberConstant | ( <expression> ) | - ( <expression> )
*/
void Parser::factor()
{
bool doNegate = false;
std::string factor = token.Source;
if(accept(Token::MinusSymbol))
{
factor = token.Source;
doNegate = true;
}
if(accept(Token::IntegerConstant) || accept(Token::DecimalConstant))
{
if(doNegate)
{
doNegate = false;
generator->Constant("-" + factor);
}
else
generator->Constant(factor);
}
else if(accept(Token::LeftBracket))
{
expression();
expect(Token::RightBracket);
}
else
{
variableValue();
}
if(doNegate)
generator->Negate();
/*if(!accept(Token::Identifier))
{
if(!accept(Token::IntegerConstant))
{
if(!accept(Token::DecimalConstant))
{
if(!accept(Token::LeftBracket))
{
throw ParserExpectException(token, "identifier or constant");
}
else
{
expression();
expect(Token::RightBracket);
}
}
else
{
if(doNegate)
{
doNegate = false;
generator->Constant("-" + factor);
}
else
generator->Constant(factor);
}
}
else
{
if(doNegate)
{
doNegate = false;
generator->Constant("-" + factor);
}
else
generator->Constant(factor);
}
}
else
{
generator->LoadVariable(factor);
}
if(doNegate)
{
generator->Negate();
}*/
}
/*
<variable value> ::= <function call> | identifier | <particle action>
*/
void Parser::variableValue()
{
std::string variable = token.Source;
if(accept(Token::Identifier))
{
if(look(Token::LeftBracket))
{
back();
functionCall();
}
else
{
generator->LoadVariable(variable);
}
}
else
{
particleAction();
}
}
bool Parser::accept(int symbol)
{
if(symbol == token.Symbol)
{
//generator->Insert(token);
lastToken = token;
if(previousTokens.size())
{
token = previousTokens.top();
previousTokens.pop();
}
else
token = scanner->NextToken();
return true;
}
return false;
}
bool Parser::look(int symbol)
{
if(symbol == token.Symbol)
return true;
return false;
}
void Parser::back()
{
previousTokens.push(token);
token = lastToken;
}
void Parser::expect(int symbol)
{
if(!accept(symbol))
throw ParserExpectException(token, symbol);
}
}
}

78
src/pim/Parser.h Normal file
View File

@ -0,0 +1,78 @@
#pragma once
#include <string>
#include <cstring>
#include <sstream>
#include "Scanner.h"
#include "Generator.h"
#include "Token.h"
namespace pim
{
namespace compiler
{
class ParserExpectException: public std::exception
{
char * error;
public:
ParserExpectException(Token token, int expectingSymbol) {
error = strdup(std::string("Expecting " + Token::SymbolNames[expectingSymbol] + " got " + token.Source).c_str());
}
ParserExpectException(Token token, std::string expectingString) {
error = strdup(std::string("Expecting " + expectingString + " got " + token.Source).c_str());
}
const char * what() const throw()
{
return error;
}
~ParserExpectException() throw() {};
};
class Parser
{
std::stringstream & source;
Generator * generator;
Scanner * scanner;
Token token;
Token lastToken;
std::string breakLabel;
std::string continueLabel;
std::stack<Token> previousTokens;
void program();
void functionList();
void function();
void functionCall();
void block();
void argumentList();
void argument();
void declarationList();
void declaration();
void identifierList();
void statementList();
void statement();
void neighbourStatement();
void ifStatement();
void condition();
void conditionalOperator();
void assigmentStatement();
void particleAction();
void killStatement();
void getStatement();
void createStatement();
void transformStatement();
void expressionList();
void expression();
void term();
void factor();
void variableValue();
bool accept(int symbol);
bool look(int symbol);
void back();
void expect(int symbol);
public:
Parser(std::stringstream & source_);
std::vector<unsigned char> Compile();
};
}
}

178
src/pim/Scanner.cpp Normal file
View File

@ -0,0 +1,178 @@
//Lexical analyser
#include <algorithm>
#include "Scanner.h"
namespace pim
{
namespace compiler
{
Scanner::Scanner(std::stringstream & source_) :
source(source_)
{
nextCharacter();
}
Token Scanner::NextToken()
{
//Read whitespace, newlines and comments
while(
cChar == ' ' || cChar == '\t' ||
cChar == '\r' || cChar == '\n' ||
cChar == '/')
{
if(cChar == '/')
{
nextCharacter();
if(cChar == '/')
{
while(cChar != '\n' && cChar != '\r')
nextCharacter();
}
else
return Token(Token::DivideSymbol, "/", cLine);
}
if(cChar == '\r')
{
nextCharacter();
if(cChar == '\n')
cLine++;
else
continue;
}
else if(cChar == '\n')
cLine++;
nextCharacter();
}
if(std::isalpha(cChar)) //Read alphanumeric symbols
{
cToken.clear();
while(std::isalpha(cChar) || std::isdigit(cChar))
{
cToken.push_back(cChar);
nextCharacter();
}
std::transform(cToken.begin(), cToken.end(), cToken.begin(), ::tolower);
for(int i = 0; i < Token::SymbolNumber; i++)
if(Token::SymbolNames[i] == cToken)
return Token(i, cToken, cLine);
return Token(Token::Identifier, cToken, cLine);
}
else if(std::isdigit(cChar)) //Read numeric constants
{
bool decimal = false;
cToken.clear();
while(std::isdigit(cChar))
{
cToken.push_back(cChar);
nextCharacter();
}
if(cChar == '.')
{
decimal = true;
cToken.push_back(cChar);
nextCharacter();
while(std::isdigit(cChar))
{
cToken.push_back(cChar);
nextCharacter();
}
}
if(decimal)
return Token(Token::DecimalConstant, cToken, cLine);
return Token(Token::IntegerConstant, cToken, cLine);
}
else if(cChar == '=')
{
nextCharacter();
if(cChar == '=')
{
nextCharacter();
return Token(Token::EqualSymbol, "==", cLine);
}
return Token(Token::AssignSymbol, "=", cLine);
}
else if(cChar == '!')
{
nextCharacter();
if(cChar == '=')
return Token(Token::NotEqualSymbol, "==", cLine);
}
else if(cChar == '(')
{
nextCharacter();
return Token(Token::LeftBracket, "(", cLine);
}
else if(cChar == ')')
{
nextCharacter();
return Token(Token::RightBracket, ")", cLine);
}
else if(cChar == '/')
{
nextCharacter();
return Token(Token::DivideSymbol, "/", cLine);
}
else if(cChar == '*')
{
nextCharacter();
return Token(Token::MultiplySymbol, "*", cLine);
}
else if(cChar == '+')
{
nextCharacter();
return Token(Token::PlusSymbol, "+", cLine);
}
else if(cChar == '-')
{
nextCharacter();
return Token(Token::MinusSymbol, "-", cLine);
}
else if(cChar == '%')
{
nextCharacter();
return Token(Token::ModuloSymbol, "%", cLine);
}
else if(cChar == '<')
{
nextCharacter();
if(cChar == '=')
{
return Token(Token::LessEqualSymbol, "<=", cLine);
}
return Token(Token::LessSymbol, "<", cLine);
}
else if(cChar == '>')
{
nextCharacter();
if(cChar == '=')
{
return Token(Token::GreaterEqualSymbol, ">=", cLine);
}
return Token(Token::GreaterSymbol, ">", cLine);
}
else if(cChar == ',')
{
nextCharacter();
return Token(Token::CommaSymbol, ",", cLine);
}
else
{
nextCharacter();
return Token(Token::InvalidSymbol, std::string(1, cChar), cLine);
}
}
void Scanner::nextCharacter()
{
if(source.good())
cChar = source.get();
else
cChar = 0;
}
}
}

22
src/pim/Scanner.h Normal file
View File

@ -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();
};
}
}

47
src/pim/Token.cpp Normal file
View File

@ -0,0 +1,47 @@
#include "Token.h"
namespace pim
{
namespace compiler
{
std::string Token::SymbolNames[] = {
"=",
"function",
"(",
")",
"/",
"*",
"+",
"-",
"%",
"INTEGER",
"DECIMAL",
"PARTICLE",
"integer",
"decimal",
"particle",
"is",
"<",
"<=",
">",
">=",
"==",
"!=",
"neighbour",
"do",
"of",
"break",
"continue",
"if",
"then",
"end",
"kill",
"create",
"transform",
"get",
"IDENTIFIER",
",",
"INVALID SYMBOL"
};
}
}

79
src/pim/Token.h Normal file
View File

@ -0,0 +1,79 @@
#pragma once
#include <string>
namespace pim
{
namespace compiler
{
class Token
{
public:
static std::string SymbolNames[];
enum
{
AssignSymbol = 0,
FunctionSymbol,
LeftBracket,
RightBracket,
DivideSymbol,
MultiplySymbol,
PlusSymbol,
MinusSymbol,
ModuloSymbol,
IntegerConstant,
DecimalConstant,
ParticleConstant,
IntegerSymbol,
DecimalSymbol,
ParticleSymbol,
IsSymbol,
LessSymbol,
LessEqualSymbol,
GreaterSymbol,
GreaterEqualSymbol,
NotEqualSymbol,
EqualSymbol,
NeighbourSymbol,
DoSymbol,
OfSymbol,
BreakSymbol,
ContinueSymbol,
IfSymbol,
ThenSymbol,
EndSymbol,
KillSymbol,
CreateSymbol,
TransformSymbol,
GetSymbol,
Identifier,
CommaSymbol,
InvalidSymbol,
SymbolNumber
};
int Symbol;
int LineNumber;
std::string Source;
Token(int symbol = InvalidSymbol, std::string source = "HERP DERP", int lineNumber = 0) :
Symbol(symbol),
Source(source),
LineNumber(lineNumber) {}
std::string GetName()
{
return SymbolNames[Symbol];
}
};
}
}

View File

@ -0,0 +1,21 @@
#ifdef TEST
#include <iostream>
#include <fstream>
#include <sstream>
#include "pim/Parser.h"
int main(int argc, char * argv[])
{
std::ifstream file("test.p");
std::stringstream buffer;
buffer << file.rdbuf();
file.close();
pim::compiler::Parser * parser = new pim::compiler::Parser(buffer);
parser->Compile();
}
#endif