#include "PolishNotationParser.h" #include "MemoryData.h" #include 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 != EOF && (ch <= ' ' || ch == '\t'); } 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(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(mem.work.top()); mem.work.pop(); Function* func = static_cast(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(mem.work.top()); mem.work.pop(); func = static_cast(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 (inFile.peek() == EOF) break; /* If value is an atom (not a Name) */ for (auto i = ++this->atoms.begin(); i != this->atoms.end(); ++i) { if (i->isAtomChar(inFile.peek())) { pushToWork(mem, i->absorb(inFile), inFile); absorbed = true; break; } } if (absorbed) { absorbed = false; continue; } // Then value will be a Name Name* name = static_cast(this->atoms[0].absorb(inFile)); /* If value is a built-in function */ for (int i = instr.size() - 1; i >= 0; i--) { if (instr[i].name == name->value) { list 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(); mem.vars.size() > 0 && i++ != mem.vars.rend(); ++i) { cname = static_cast(*i); if (cname->value == name->value) { MemoryData* value = new MemoryData(*static_cast(*(--i))); pushToWork(mem, value, inFile); absorbed = true; break; } } if (absorbed) { absorbed = false; continue; } /* Else value is just a Name that will be given */ pushToWork(mem, name, inFile); } cout << static_cast(mem.vars.back())->value << endl; // cout << static_cast(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 }