#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 == ' ' || 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(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 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 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(*i); if (cname->value == name) { MemoryData* value = new MemoryData(*static_cast(*(--i))); pushToWork(mem, value, inFile); break; } } } cout << mem.vars.size(); // 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 }