mirror of
https://github.com/The-Powder-Toy/The-Powder-Toy.git
synced 2025-09-01 20:12:50 +02:00
Testing new vm/language WIP
This commit is contained in:
@@ -20,11 +20,14 @@
|
|||||||
#include "dialogues/TextPrompt.h"
|
#include "dialogues/TextPrompt.h"
|
||||||
#include "dialogues/ConfirmPrompt.h"
|
#include "dialogues/ConfirmPrompt.h"
|
||||||
#include "simulation/Simulation.h"
|
#include "simulation/Simulation.h"
|
||||||
#include "virtualmachine/VirtualMachine.h"
|
|
||||||
#include "game/GameModel.h"
|
#include "game/GameModel.h"
|
||||||
#include "LuaScriptHelper.h"
|
#include "LuaScriptHelper.h"
|
||||||
#include "client/HTTP.h"
|
#include "client/HTTP.h"
|
||||||
|
|
||||||
|
//#include "virtualmachine/VirtualMachine.h"
|
||||||
|
#include "pim/Parser.h"
|
||||||
|
#include "pim/Machine.h"
|
||||||
|
|
||||||
#include "LuaBit.h"
|
#include "LuaBit.h"
|
||||||
|
|
||||||
#include "LuaWindow.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)
|
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;
|
vm::word w;
|
||||||
int argAddr = 0, argCount = 5;
|
int argAddr = 0, argCount = 5;
|
||||||
vMachine->sim = sim;
|
vMachine->sim = sim;
|
||||||
|
|
||||||
/* Set up call. */
|
|
||||||
vMachine->OpPUSH(w); //Pointless null in stack
|
vMachine->OpPUSH(w); //Pointless null in stack
|
||||||
w.int4 = (argCount + 2) * sizeof(vm::word);
|
w.int4 = (argCount + 2) * sizeof(vm::word);
|
||||||
vMachine->OpENTER(w);
|
vMachine->OpENTER(w);
|
||||||
@@ -696,7 +706,7 @@ int LuaScriptInterface::updateVM(UPDATE_FUNC_ARGS)
|
|||||||
w.int4 = (argCount + 2) * sizeof(vm::word);
|
w.int4 = (argCount + 2) * sizeof(vm::word);
|
||||||
vMachine->OpLEAVE(w);
|
vMachine->OpLEAVE(w);
|
||||||
vMachine->OpPOP(w); //Pop pointless null
|
vMachine->OpPOP(w); //Pop pointless null
|
||||||
vMachine->End();
|
vMachine->End();*/
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1017,7 +1027,7 @@ int LuaScriptInterface::elements_property(lua_State * l)
|
|||||||
}
|
}
|
||||||
else if(lua_type(l, 3) == LUA_TLIGHTUSERDATA)
|
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;
|
luacon_sim->elements[id].Update = &updateVM;
|
||||||
}
|
}
|
||||||
else if(lua_type(l, 3) == LUA_TBOOLEAN && !lua_toboolean(l, 3))
|
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)
|
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);
|
vm::VirtualMachine * newVM = new vm::VirtualMachine(1);
|
||||||
try
|
try
|
||||||
@@ -1156,7 +1166,19 @@ int LuaScriptInterface::virtualMachine_loadProgram(lua_State * l)
|
|||||||
{
|
{
|
||||||
return luaL_error(l, "Unable to load program");
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -23,7 +23,7 @@ namespace ui
|
|||||||
class Window;
|
class Window;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace vm
|
namespace pim
|
||||||
{
|
{
|
||||||
class VirtualMachine;
|
class VirtualMachine;
|
||||||
}
|
}
|
||||||
@@ -65,7 +65,7 @@ class LuaScriptInterface: public CommandInterface {
|
|||||||
static int renderer_colourMode(lua_State * l);
|
static int renderer_colourMode(lua_State * l);
|
||||||
|
|
||||||
//Elements
|
//Elements
|
||||||
static vm::VirtualMachine * updateVirtualMachines[PT_NUM];
|
static pim::VirtualMachine * updateVirtualMachines[PT_NUM];
|
||||||
static int updateVM(UPDATE_FUNC_ARGS);
|
static int updateVM(UPDATE_FUNC_ARGS);
|
||||||
//
|
//
|
||||||
void initElementsAPI();
|
void initElementsAPI();
|
||||||
|
11
src/dialogues/LegacyDialogues.h
Normal file
11
src/dialogues/LegacyDialogues.h
Normal 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) {}
|
30
src/interface/LuaProgressBar.h
Normal file
30
src/interface/LuaProgressBar.h
Normal 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
326
src/pim/Generator.cpp
Normal 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
164
src/pim/Generator.h
Normal 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
271
src/pim/Machine.cpp
Normal 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
88
src/pim/Machine.h
Normal 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
12
src/pim/Opcodes.h
Normal 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
26
src/pim/Opcodes.inl
Normal 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
646
src/pim/Parser.cpp
Normal 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
78
src/pim/Parser.h
Normal 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
178
src/pim/Scanner.cpp
Normal 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
22
src/pim/Scanner.h
Normal 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
47
src/pim/Token.cpp
Normal 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
79
src/pim/Token.h
Normal 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];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
21
src/tests/PowderInteractionMachine.cpp
Normal file
21
src/tests/PowderInteractionMachine.cpp
Normal 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
|
Reference in New Issue
Block a user