Mercurial > repo
view interps/glass/parseq.cc @ 12518:2d8fe55c6e65 draft default tip
<int-e> learn The password of the month is release incident pilot.
author | HackEso <hackeso@esolangs.org> |
---|---|
date | Sun, 03 Nov 2024 00:31:02 +0000 |
parents | 859f9b4339e6 |
children |
line wrap: on
line source
/* * Copyright (c) 2005 Gregor Richards * * This file is part of Glass. * * Glass is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Glass is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Glass; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include <iostream> #include <map> #include <string> using namespace std; #include <stdlib.h> #include "builtins.h" #include "func.h" #include "glass.h" #include "klass.h" #include "klassi.h" #include "parseq.h" #include "variable.h" ParseQElement::ParseQElement() { type = PQT_GLOBAL; value = ""; next = NULL; } ParseQElement::ParseQElement(int st, string sv) { type = st; value = sv; next = NULL; } ParseQElement::ParseQElement(int st, char sv) { string svs; svs += sv; type = st; value = svs; next = NULL; } ParseQElement::ParseQElement(ParseQElement ©) { type = copy.type; value = copy.value; next = NULL; } ParseQ::ParseQ() { head = NULL; } ParseQ::~ParseQ() { ParseQElement *cur, *pre; cur = head; pre = head; while (cur) { cur = cur->next; delete pre; pre = cur; } } int ParseQ::len() { int i; ParseQElement *cur; cur = head; i = 0; while (cur) { i++; cur = cur->next; } return i; } ParseQElement *ParseQ::get(int n) { ParseQElement *cur = head; for (; cur && n; n--) cur = cur->next; return cur; } void ParseQ::add(ParseQElement *a) { ParseQElement *cur; if (!head) { head = a; } else { cur = head; while (cur->next) cur = cur->next; cur->next = a; a->next = NULL; } } string ParseQ::dump() { string toret; ParseQElement *cur = head; while (cur) { switch (cur->type) { case PQT_GLOBAL: case PQT_CLASSWIDE: case PQT_LOCAL: case PQT_STACK: if (cur->value.length() == 1) { toret += cur->value; } else { toret += "(" + cur->value + ")"; } break; case PQT_NUMBER: toret += "<" + cur->value + ">"; break; case PQT_STRING: toret += "\"" + cur->value + "\""; break; case PQT_COMMAND: toret += cur->value; break; case PQT_BUILTIN: toret += "~" + cur->value + "~"; break; } cur = cur->next; } return toret; } ParseQ *ParseQ::cutParseQ(int s, int l) { ParseQ *toret = new ParseQ; ParseQElement *cur; int i; // there are two very different cases: // 1) s is 0 (need to change head) // 2) s is >0 (need to find it, not change head) if (s == 0) { cur = head; for (i = 1; cur && i < l; i++) cur = cur->next; if (!cur) return toret; // now we're on top of the last element toret->head = head; head = cur->next; cur->next = NULL; return toret; } else { ParseQElement *top; cur = head; for (i = 1; cur && i < s; i++) cur = cur->next; if (!cur) return toret; // now we're immediately before the first element top = cur; cur = cur->next; // now find the last element for (i = 1; cur && i < l; i++) cur = cur->next; if (!cur) return toret; // now we're on top of the last element toret->head = top->next; top->next = cur->next; cur->next = NULL; return toret; } } void ParseQ::parseKlasses() { int i, topi; ParseQElement *cur, *top; ParseQ *klass; // look for a { while (true) { cur = head; for (i = 0; cur && (cur->type != PQT_COMMAND || cur->value != "{"); i++) cur = cur->next; if (!cur) break; // we are now on top of the {, one further is the actual start point cur->value = ""; i++; cur = cur->next; if (!cur) break; topi = i; top = cur; // now find the end for (; cur && (cur->type != PQT_COMMAND || cur->value != "}"); i++) cur = cur->next; if (!cur) break; // we are now on top of the } klass = cutParseQ(topi, i - topi); klass->parseKlass(); delete klass; } } void ParseQ::parseKlass() { ParseQElement *origh, *cur, *top; Func *func; ParseQ *funcpq; string var; Klass *klass; Variable *kvar; int i, topi; // the first element should be a global variable name if (!head || head->type != PQT_GLOBAL) return; // get rid of the current head var = head->value; origh = head; head = head->next; delete origh; // now start making the actual class klass = new Klass(); kvar = new Variable(); klass->name = var; kvar->type = VAR_KLASS; kvar->kval = klass; // delete the current one if necessary if (globalVars.find(var) != globalVars.end()) { if (globalVars[var]->type == VAR_KLASS) { delete globalVars[var]->kval; } delete globalVars[var]; globalVars.erase(var); } while (true) { // look for a [ cur = head; for (i = 0; cur && (cur->type != PQT_COMMAND || cur->value != "["); i++) cur = cur->next; if (!cur) break; // we are now on top of the [, one further is the actual start point cur->value = ""; i++; cur = cur->next; if (!cur) break; topi = i; top = cur; // now find the end for (; cur && (cur->type != PQT_COMMAND || cur->value != "]"); i++) cur = cur->next; if (!cur) break; // we are now on top of the ] funcpq = cutParseQ(topi, i - topi); // turn it into a function if (!funcpq->head || funcpq->head->type != PQT_CLASSWIDE) { delete funcpq; continue; } func = new Func(); func->name = funcpq->head->value; origh = funcpq->head; funcpq->head = origh->next; func->contents = funcpq; klass->functions[origh->value] = func; delete origh; } // only add this to the class list if there are functions if (klass->functions.size() > 0) { globalVars[var] = kvar; } else { delete kvar; delete klass; } } #define POP \ { \ if (mainStack.size() != 0) { \ delete mainStack[0]; \ mainStack.pop_front(); \ } \ } void ParseQ::runFunc(KlassI *of, Func *which) { map<string,Variable *> locals; map<string,Variable *>::iterator locali; vector<KlassI *> localInstant; ParseQElement *cur; unsigned int sloc; int depth; Variable *toset, *kvar, *fvar; KlassI *klassi; Func *funci; bool doadvance; char fchar; // just run through the elements int i; cur = head; for (i = 0; cur; i++) { doadvance = true; //cout << cur->type << " " << cur->value << endl; // do something different for each type switch (cur->type) { case PQT_GLOBAL: case PQT_CLASSWIDE: case PQT_LOCAL: mainStack.push_front(new Variable(VAR_VARIABLEP, cur->value)); break; case PQT_STACK: // copy a stack location sloc = atoi(cur->value.c_str()); if (mainStack.size() <= sloc) { mainStack.push_front(new Variable()); } else { mainStack.push_front(new Variable(*mainStack[sloc])); } break; case PQT_NUMBER: mainStack.push_front(new Variable(VAR_NUMBER, atof(cur->value.c_str()))); break; case PQT_STRING: mainStack.push_front(new Variable(VAR_STRING, cur->value)); break; case PQT_BUILTIN: doBuiltin(cur->value); break; case PQT_COMMAND: // now we have to switch for each command if (cur->value == ",") { // pop if (mainStack.size() > 0) POP; break; } else if (cur->value == "^") { // return goto runFuncReturn; } else if (cur->value == "=") { // set if (mainStack.size() > 1) { toset = mainStack[1]; if (toset->type != VAR_VARIABLEP) { // ERROR return; } toset = getVar(of, &locals, toset->sval); toset->mkcopy(*mainStack[0]); POP; POP; } } else if (cur->value == "!") { // instantiate if (mainStack.size() > 1) { // two variable pointers ... if (mainStack[0]->type != VAR_VARIABLEP || mainStack[1]->type != VAR_VARIABLEP) { // ERROR return; } // the second should be to a class kvar = getVar(of, &locals, mainStack[0]->sval); if (kvar->type != VAR_KLASS) { // ERROR return; } // now make a klassi ... klassi = new KlassI(); klassi->of = kvar->kval; // and set up the reference toset = getVar(of, &locals, mainStack[1]->sval); toset->type = VAR_KLASSI; toset->kival = klassi; // mark the ownership of the klassi fchar = mainStack[1]->sval[0]; if (fchar == '_') { localInstant.push_back(klassi); } else if (fchar >= 'a' && fchar <= 'z') { of->localInstant.push_back(klassi); } else if (fchar >= 'A' && fchar <= 'Z') { globalInstant.push_back(klassi); } POP; POP; // run the constructor if (kvar->kval->functions.find("c__") != kvar->kval->functions.end()) { kvar->kval->functions["c__"]->contents->runFunc(klassi, kvar->kval->functions["c__"]); } } break; } else if (cur->value == ".") { // function pointer if (mainStack.size() > 1) { // two variable pointers ... if (mainStack[0]->type != VAR_VARIABLEP || mainStack[1]->type != VAR_VARIABLEP) { // ERROR return; } // the first should be a klassi kvar = getVar(of, &locals, mainStack[1]->sval); if (kvar->type != VAR_KLASSI) { // ERROR return; } // the second should be a function in that klassi fvar = getVar(kvar->kival, &locals, mainStack[0]->sval); if (fvar->type != VAR_FUNC) { // ERROR return; } // now make the pointer to the funci toset = new Variable(VAR_FUNCI, kvar->kival, fvar->fval); POP; POP; mainStack.push_front(toset); } break; } else if (cur->value == "?") { // execute if (mainStack.size() > 0) { // one funci pointer if (mainStack[0]->type != VAR_FUNCI) { // ERROR return; } funci = mainStack[0]->fval; klassi = mainStack[0]->kival; POP; funci->contents->runFunc(klassi, funci); } break; } else if (cur->value == "*") { // dereference if (mainStack.size() > 0) { // one variable pointer if (mainStack[0]->type != VAR_VARIABLEP) { // ERROR return; } toset = new Variable(*getVar(of, &locals, mainStack[0]->sval)); POP; mainStack.push_front(toset); } break; } else if (cur->value == "$") { // make a variable point to "this" if (mainStack.size() > 0) { // one variable pointer if (mainStack[0]->type != VAR_VARIABLEP) { // ERROR return; } toset = getVar(of, &locals, mainStack[0]->sval); toset->type = VAR_KLASSI; toset->kival = of; POP; } break; } else if (cur->value == "/") { // loop open, one of the most difficult ones i++; cur = cur->next; if (cur->type > PQT_LOCAL) { // ERROR return; } // skip if the value of this variable is 0/"" toset = getVar(of, &locals, cur->value); if ((toset->type == VAR_NUMBER && toset->nval == 0.0) || (toset->type == VAR_STRING && toset->sval == "") || (toset->type != VAR_NUMBER && toset->type != VAR_STRING)) { // the really hard part: find the matching backslash depth = 0; i++; cur = cur->next; for (; i < len(); i++) { if (cur->type == PQT_COMMAND) { if (cur->value == "/") { depth++; } else if (cur->value == "\\") { if (depth == 0) { break; } else { depth--; } } } cur = cur->next; } if (i == len()) { // ERROR return; } } break; } else if (cur->value == "\\") { // end of loop // just jump back (very inefficient) depth = 0; i--; for (; i >= 0; i--) { cur = get(i); if (cur->type == PQT_COMMAND) { if (cur->value == "\\") { depth++; } else if (cur->value == "/") { if (depth == 0) { break; } else { depth--; } } } } if (i == -1) { // ERROR return; } // we are now pointing to the beginning - so don't advance yet doadvance = false; } } if (doadvance) { cur = cur->next; } else { i--; } #ifdef IRC // IRC users have a maximum alotted time if (progTimer <= 1) { progTimer = 0; IRC_o = "Maximum time exceeded."; goto runFuncReturn; } progTimer--; #endif } runFuncReturn: // clean up garbage for (locali = locals.begin(); locali != locals.end(); locali++) { delete locali->second; } for (unsigned int ui = 0; ui < localInstant.size(); ui++) { delete localInstant[ui]; } }