summaryrefslogtreecommitdiff
path: root/src/PolishNotationParser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/PolishNotationParser.cpp')
-rw-r--r--src/PolishNotationParser.cpp145
1 files changed, 145 insertions, 0 deletions
diff --git a/src/PolishNotationParser.cpp b/src/PolishNotationParser.cpp
new file mode 100644
index 0000000..f99f404
--- /dev/null
+++ b/src/PolishNotationParser.cpp
@@ -0,0 +1,145 @@
+#include "PolishNotationParser.h"
+#include "MemoryData.h"
+
+#include <iostream>
+
+Instruction::Instruction(const char* str, unsigned argc, void (*exec)(Memory&)) : name(str), argc(argc), exec(exec) {}
+
+Atom::Atom(bool (*isAtomChar)(char), MemoryData* (*absorb)(ifstream&)) : isAtomChar(isAtomChar), absorb(absorb) {}
+
+void PNParser::addInstr(Instruction i) {
+ this->instr.push_back(i);
+}
+
+void PNParser::addAtom(Atom a) {
+ this->atoms.push_back(a);
+}
+
+bool isSpacing(char ch) {
+ return ch == ' ' || ch == '\t' || ch == EOF;
+}
+
+void skipSpacing(ifstream& inFile) {
+ while(isSpacing(inFile.peek()))
+ inFile.get();
+}
+
+void PNParser::evaluateFunction(Memory& mem, Function* func, ifstream& inFile) {
+ if (func->scopeEnd < 0) {
+ instr[func->scopeStart].exec(mem);
+ delete func;
+ return;
+ }
+
+ for (auto i = func->argumentNames.rbegin(); i != func->argumentNames.rend(); ++i) {
+ mem.vars.push_back(new Name(*i));
+ mem.vars.push_back(mem.work.top());
+ mem.work.pop();
+ }
+ mem.scopeVars.push(func->argumentNames.size());
+
+ this->parseScope(inFile, mem, func->scopeStart, func->scopeEnd);
+}
+
+void PNParser::pushToWork(Memory& mem, MemoryData* data, ifstream& inFile) {
+ if (data->get_type() == MemoryData::TFunc) {
+ Function* func = static_cast<Function*>(data);
+ mem.work.push(data);
+ mem.work.push(new Int(func->argumentNames.size()));
+ return;
+ }
+
+ // We keep the amount of required arguments and the function
+ // on the top of the stack at all times
+ Int* argc = static_cast<Int*>(mem.work.top());
+ mem.work.pop();
+ Function* func = static_cast<Function*>(mem.work.top());
+ mem.work.pop();
+
+ mem.work.push(data);
+ argc->value--;
+
+ while (argc->value == 0) {
+ delete argc;
+ evaluateFunction(mem, func, inFile);
+
+ if (mem.work.size() == 1) return;
+
+ data = mem.work.top();
+ mem.work.pop();
+ argc = static_cast<Int*>(mem.work.top());
+ mem.work.pop();
+ func = static_cast<Function*>(mem.work.top());
+ mem.work.pop();
+
+ mem.work.push(data);
+ argc->value--;
+ }
+
+ mem.work.push(func);
+ mem.work.push(argc);
+}
+
+void PNParser::parseScope(ifstream& inFile, Memory& mem, int start, int end) {
+ mem.scopeVars.push(0);
+ bool absorbed = false;
+ while (start < inFile.tellg() && inFile.tellg() < end && inFile.peek() != EOF) {
+ skipSpacing(inFile);
+
+ /* If value is an atom */
+
+ for (Atom& a : this->atoms) {
+ if (a.isAtomChar(inFile.peek())) {
+ pushToWork(mem, a.absorb(inFile), inFile);
+ absorbed = true;
+ break;
+ }
+ }
+
+ if (absorbed) { absorbed = false; continue; }
+
+ /* If value is a built-in function */
+
+ string name;
+ while (!isSpacing(inFile.peek()))
+ name.push_back(inFile.get());
+
+ for (int i = instr.size() - 1; i >= 0; i--) {
+ if (instr[i].name == name) {
+ list<string> temp;
+ temp.resize(instr[i].argc);
+ pushToWork(mem, new Function(temp, i, -1), inFile);
+ absorbed = true;
+ break;
+ }
+ }
+
+ if (absorbed) { absorbed = false; continue; }
+
+ /* If value is a variable */
+
+ Name* cname;
+ for (auto i = ++mem.vars.rbegin(); i != mem.vars.rend(); ++(++i)) {
+ cname = static_cast<Name*>(*i);
+ if (cname->value == name) {
+ MemoryData* value = new MemoryData(*static_cast<MemoryData*>(*(--i)));
+ pushToWork(mem, value, inFile);
+ break;
+ }
+ }
+ }
+ cout << mem.vars.size();
+ // cout << static_cast<Int*>(mem.work.top())->value << endl;
+
+ for (int i = mem.scopeVars.top(); i > 0; i--) {
+ delete mem.vars.back();
+ mem.vars.pop_back();
+ delete mem.vars.back();
+ mem.vars.pop_back();
+ }
+ mem.scopeVars.pop();
+}
+
+void PNParser::parse(ifstream& inFile, Memory& mem) {
+ parseScope(inFile, mem, -1, 100000); // global scope
+}