diff interps/glass/parseq.cc @ 996:859f9b4339e6

<Gregor> tar xf egobot.tar.xz
author HackBot
date Sun, 09 Dec 2012 19:30:08 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/interps/glass/parseq.cc	Sun Dec 09 19:30:08 2012 +0000
@@ -0,0 +1,601 @@
+/*
+ * 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 &copy)
+{
+    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];
+    }
+}