📄 interp.cpp
字号:
// Copyright (C) 1999-2005 Open Source Telecom Corporation.// // This program 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.// // This program 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 this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.// // As a special exception, you may use this file as part of a free software// library without restriction. Specifically, if other files instantiate// templates or use macros or inline functions from this file, or you compile// this file and link it with other files to produce an executable, this// file does not by itself cause the resulting executable to be covered by// the GNU General Public License. This exception does not however// invalidate any other reasons why the executable file might be covered by// the GNU General Public License.//// This exception applies only to the code released under the name GNU// ccScript. If you copy code from other releases into a copy of GNU// ccScript, as the General Public License permits, the exception does// not apply to the code that you add in this way. To avoid misleading// anyone as to the status of such modified files, you must delete// this exception notice from them.//// If you write modifications of your own for GNU ccScript, it is your choice// whether to permit this exception to apply to your modifications.// If you do not wish that, delete this exception notice.//#include "engine.h"using namespace std;using namespace ost;ScriptInterp::ScriptInterp() :Mutex(), ScriptSymbols(){ stack = 0; cmd = NULL; image = NULL; memset(temps, 0, sizeof(temps)); tempidx = 0; session = this; thread = NULL; trace = false; lock = NULL; sequence = 0; setString(logname, sizeof(logname), "ccscript");}unsigned ScriptInterp::getTempSize(void){ return symsize + 1;}char *ScriptInterp::getTemp(void){ char *tmp = temps[tempidx++]; if(tempidx >= SCRIPT_TEMP_SPACE) tempidx = 0; return tmp;}ScriptInterp *ScriptInterp::getInterp(const char *id){ if(!atoi(id)) return this; return NULL;}unsigned ScriptInterp::getId(void){ return 0;}bool ScriptInterp::isLocked(const char *id){ if(!strnicmp(id, "script.", 7) && initialized) return true; if(!strnicmp(id, "initial.", 8) && initialized) return true; return false;} void ScriptInterp::setFrame(void){ frame[stack].index = 0; updated = false;}const char *ScriptInterp::remapLocal(void){ return "script";}const char *ScriptInterp::getExternal(const char *opt){ char *cp, *p; Line *line; unsigned idx; if(!cmd) return NULL; if(!stricmp(opt, "script.id")) { cp = getTemp(); snprintf(cp, symsize, "%d", getId()); return cp; } else if(!stricmp(opt, "script.index")) { if(!stack) return ""; line = frame[stack - 1].line; idx = frame[stack - 1].index; cp = getTemp(); snprintf(cp, symsize, "%u", idx - 1); return cp; } else if(!stricmp(opt, "script.basename")) { cp = getTemp(); setString(cp, symsize, frame[stack].script->name); p = strstr(cp, "::"); if(p) *p = 0; return cp; } else if(!stricmp(opt, "script.subname")) { cp = getTemp(); setString(cp, symsize, frame[stack].script->name); p = strstr(cp, "::"); if(p) return p + 2; return cp; } else if(!stricmp(opt, "script.name")) return frame[stack].script->name; else if(!stricmp(opt, "script.stack")) { cp = getTemp(); snprintf(cp, symsize, "%d", stack); return cp; } else if(!stricmp(opt, "script.base")) { cp = getTemp(); snprintf(cp, symsize, "%d", frame[stack].base); } return cmd->getExternal(opt);}void ScriptInterp::initialize(void){}bool ScriptInterp::execute(Method method){ return (this->*(method))();}void ScriptInterp::branching(void){}Script::Name *ScriptInterp::getScript(const char *name){ if(!image) return NULL; Name *scr = image->getScript(name); return scr;}void ScriptInterp::release(void){ if(lock) { lock->leaveMutex(); lock = NULL; }}ScriptSymbols *ScriptInterp::getSymbols(const char *id){ if(strchr(id, '.') && session != this) { if(lock) lock->leaveMutex(); session->enterMutex(); lock = dynamic_cast<Mutex *>(session); } else release(); if(strchr(id, '.')) return dynamic_cast<ScriptSymbols*>(session); if(!frame[stack].local) return dynamic_cast<ScriptSymbols*>(this); return frame[stack].local;}ScriptSymbols *ScriptInterp::getLocal(void){ if(frame[stack].local) return frame[stack].local; return dynamic_cast<ScriptSymbols*>(this);}bool ScriptInterp::setConst(const char *id, const char *value){ MutexLock lock(*this); Symbol *sym; unsigned short len; if(!value) return false; len = (unsigned short)strlen(value); if(!len) ++len; sym = mapSymbol(id, len); if(!sym) return false; if(sym->type != symINITIAL) return false; sym->type = symCONST; setString(sym->data, sym->size + 1, value); return true;}char ScriptInterp::getPackToken(void){ const char *sym = extract(mapSymbol("script.token")); if(!sym) sym = ","; if(!*sym) sym = ","; return *sym;}Script::Symbol *ScriptInterp::mapSymbol(const char *id, unsigned short size){ Symbol *sym; if(*id != '@') return mapDirect(id, size); sym = mapDirect(++id); if(!sym) return NULL; id = extract(sym); if(!id) return NULL; if(!*id) return NULL; return mapDirect(id, size);}Script::Symbol *ScriptInterp::mapDirect(const char *id, unsigned short size){ Symbol *sym; ScriptSymbols *syms; unsigned count = 1; char partial[70]; char *cp; const char *p; if(!id) return NULL; if(*id == '%' || *id == '&') ++id; if(*id == '.' && frame[stack].script) { cp = (char *)strchr(frame[stack].script->filename, '.'); if(cp && !stricmp(cp, ".mod")) setString(partial, sizeof(partial), "mod."); else setString(partial, sizeof(partial), "scr."); addString(partial, sizeof(partial), frame[stack].script->name); cp = (char *)strstr("::", partial); if(cp) *cp = 0; addString(partial, sizeof(partial), id); id = partial; }retry: if(!isalpha(*id) && *id != '_') { logmissing(id, "invalid"); return NULL; } while(count < 64) { if(!id[count]) break; if(!strchr("abcdefghijklmnopqrstuvwxyz01234567890._", tolower(id[count]))) { logmissing(id, "invalid"); return NULL; } ++count; } if(count == 64) { logmissing(id, "invalid"); return NULL; } if(size && isLocked(id)) size = 0; syms = getSymbols(id); if(!syms) return NULL; sym = deref(syms->find(id, size)); if(!sym && !strchr(id, '.')) { p = remapLocal(); if(!p) return NULL; snprintf(partial, sizeof(partial), "%s.%s", p, id); id = partial; goto retry; } return sym;}bool ScriptInterp::setNumber(const char *id, const char *value, unsigned dec){ Symbol *sym; if(!dec) dec = 11; else dec += 12; sym = mapSymbol(id, dec); if(!sym) return false; if(!value) return true; if(sym->type == symINITIAL) sym->type = symNUMBER; return commit(sym, value);}bool ScriptInterp::setSymbol(const char *id, const char *value, unsigned short size){ Symbol *sym; if(!size) size = symsize; sym = mapSymbol(id, size); if(!sym) return false; if(!value) return true; return commit(sym, value);}void ScriptInterp::trap(const char *trapid){ unsigned trap = cmd->getTrapId(trapid); if(!trap) { if(!image) return; if(!stricmp(trapid, "first") || !stricmp(trapid, "top")) { frame[stack].tranflag = frame[stack].caseflag = false; frame[stack].line = frame[stack].first; return; } } ScriptInterp::trap(trap);}void ScriptInterp::trap(unsigned id){ Line *trap = NULL; unsigned base = frame[stack].base; if(!image) return; // we can inherit traps at lower levels for(;;) { trap = frame[stack].script->trap[id]; if(trap == frame[stack].first) { advance(); return; } if(!trap && !cmd->isInherited(id)) { advance(); return; } if(trap || stack == base) break; pull(); } // when doing a trap, always unwind loop or recursive stack frames clearStack(); frame[stack].tranflag = frame[stack].caseflag = false; frame[stack].line = frame[stack].first = trap; if(!id) { if(!trap) redirect("::exit"); exiting = true; }}bool ScriptInterp::pull(void) { if(!stack) { error("stack-underflow"); return false; } if(frame[stack].local && frame[stack - 1].local != frame[stack].local) delete frame[stack].local; --stack; return true;}bool ScriptInterp::push(void) { if(stack >= (SCRIPT_STACK_SIZE - 1)) { error("stack-overflow"); return false; } frame[stack + 1] = frame[stack]; frame[stack + 1].caseflag = frame[stack + 1].tranflag = false; ++stack; return true;}void ScriptInterp::clearStack(void){ unsigned indexes[SCRIPT_STACK_SIZE]; unsigned idx = 0, len = 0; char values[SCRIPT_STACK_SIZE * 6]; while(stack) { if(frame[stack - 1].script != frame[stack].script) break; pull(); indexes[idx++] = frame[stack].index; } snprintf(values, 3, "%d", idx); setSymbol("script.stack", values, 4); values[1] = 0; while(idx--) { snprintf(values + len, sizeof(values) - len, ",%d", indexes[idx]); len = (unsigned)strlen(values); } setSymbol("script.index", values + 1, 3);}void ScriptInterp::skip(void){ frame[stack].line = frame[stack].line->next;}void ScriptInterp::advance(void){ if(updated) return; frame[stack].line = frame[stack].line->next; updated = true;}void ScriptInterp::error(const char *errmsg){ char evtname[128]; setSymbol("script.error", errmsg); snprintf(evtname, sizeof(evtname), "error:%s", errmsg); if(scriptEvent(evtname)) return; if((frame[stack].script->mask & 0x02) && frame[stack].script->trap[1]) { trap(1); return; } advance();}bool ScriptInterp::tryCatch(const char *id){ Name *scr; char namebuf[160]; char *cp; unsigned stk = frame[stack].base; setString(namebuf, sizeof(namebuf), frame[stk].script->name); cp = strstr(namebuf, "::"); if(cp) *(cp + 2) = 0; else addString(namebuf, sizeof(namebuf), "::"); addString(namebuf, sizeof(namebuf), id); scr = getScript(namebuf); if(!scr || !push()) return false; branching(); frame[stack].script = scr; frame[stack].line = frame[stack].first = scr->first; frame[stack].caseflag = frame[stack].tranflag = 0; frame[stack].index = 0; frame[stack].mask = getMask(); image->fastBranch(this); return true;}void ScriptInterp::gotoEvent(NamedEvent *evt){ clearStack(); branching(); frame[stack].tranflag = frame[stack].caseflag = false; frame[stack].line = frame[stack].first = evt->line; image->fastBranch(this);}bool ScriptInterp::scriptEvent(const char *name, bool inhereted){ char evtname[128]; const char *savname = name; NamedEvent *evt, *top = frame[stack].script->events; unsigned base = frame[stack].base; const char *chkname = name; unsigned current = stack; bool found = false;#ifdef HAVE_REGEX_H regex_t *regex;#endifretry: evt = frame[current].script->events; while(evt) { switch(evt->type) { case '@': if(!stricmp(evt->name, chkname)) found = true; break;#ifdef HAVE_REGEX_H case '~': regex = new regex_t; memset(regex, 0, sizeof(regex_t)); if(!regcomp(regex, evt->name, REG_ICASE|REG_NOSUB|REG_NEWLINE)) if(!regexec(regex, chkname, 0, NULL, 0)) found = true; regfree(regex); delete regex; break;#endif } if(found) break; evt = evt->next; } if(!evt && NULL != (chkname = strchr(chkname, ':'))) { ++chkname; goto retry; } if(evt) { while(stack > current) pull(); gotoEvent(evt); return true; } while(current > base && frame[current].script->events == top && inhereted) --current; if(frame[current].script->events != top) { top = frame[current].script->events; chkname = name; goto retry; } if(*savname == '@') ++savname; snprintf(evtname, sizeof(evtname), "-catch-%s", savname); if(tryCatch(evtname)) return true; return false;}void ScriptInterp::initRuntime(Name *scr){ MutexLock lock(*this); while(stack) pull(); frame[stack].script = scr; frame[stack].line = frame[stack].first = frame[stack].script->first; frame[stack].index = 0; frame[stack].caseflag = frame[stack].tranflag = false; frame[stack].decimal = 0; frame[stack].base = 0; frame[stack].mask = frame[stack].script->mask;}bool ScriptInterp::attach(ScriptCommand *cmdref, const char *scrname){ Name *scr; char msg[65]; cmd = cmdref; enterMutex(); purge(); cmd->enterMutex(); image = cmd->active; if(!image) { cmd->leaveMutex(); leaveMutex(); return false; } scr = getScript(scrname); if(!scr || scr->access != scrPUBLIC) { snprintf(msg, sizeof(msg), "%s: attach failed", scrname); if(!image->getLast(msg)) { image->setValue(msg, "missing"); cmd->errlog("missing", msg); } cmd->leaveMutex(); leaveMutex(); logerror("missing; attach failed", scrname); snprintf(msg, sizeof(msg), "%s: attach failed", scrname); return false; } ++image->refcount; cmd->leaveMutex(); attach(cmd, image, scr); return true;}void ScriptInterp::attach(ScriptCommand *cmdref, ScriptImage *img, Name *scr){ const char *scrname = scr->name; ScriptImage::InitialList *ilist; ScriptBinder *mod; Name *init; Line *line; stack = 0; cmd = cmdref; exiting = initialized = false; session = this; thread = NULL; bool selected = false; Symbol *sym; image = img; frame[stack].local = NULL; for(tempidx = 0; tempidx < SCRIPT_TEMP_SPACE; ++tempidx) temps[tempidx] = (char *)alloc(symsize + 1); tempidx = 0; ilist = image->ilist; while(ilist) { setSymbol(ilist->name, ilist->value, ilist->size); ilist = ilist->next; } sym = mapSymbol("script.authorize", 0); if(sym) sym->type = symTIMER; setSymbol("script.home", scrname); mod = ScriptBinder::first; while(mod) { mod->attach(this); mod = mod->next; } initialize(); init = image->index[SCRIPT_INDEX_SIZE]; leaveMutex(); while(init) { initRuntime(init); while(step()) Thread::yield(); init = init->next; } initialized = true; enterMutex(); initRuntime(scr); mod = ScriptBinder::first; while(mod && !selected) { selected = mod->select(this); mod = mod->next; } if(selected) goto finish; if(fastStart) { image->fastBranch(this); goto finish; } line = getLine(); if(!line) goto finish; if(!stricmp(line->cmd, "options")) execute(line->scr.method);finish: leaveMutex();}void ScriptInterp::detach(void){ ScriptBinder *mod = ScriptBinder::first; char scrname[65]; char *sp; ++sequence; snprintf(scrname, sizeof(scrname), "%s", frame[0].script->name); sp = strchr(scrname, ':'); if(sp) *sp = 0; if(!image) return; if(thread) { delete thread; thread = NULL; } while(mod) { mod->detach(this); mod = mod->next; } enterMutex();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -