Hacktendo:ScriptInterpreter
From Hack Wars Wiki
Map-Initialize
//setGlobal("script", "(debug 'bla)"); int pCount=0; void main() { setGlobal("log?", true); setGlobal("numbers", "123456789"); setGlobal("n1", "3"); string quote=char(34); string newline=char(10); setGlobal("runCall", 0); //Link to Function Scripts setGlobal("eval", createSprite(0,1,-1000,-1000,-1000)); setGlobal("function:echo", 3); setGlobal("function:replaceAll", 4); setGlobal("function:getGlobal", 5); setGlobal("function:substr", 6); setGlobal("function:and", 8); setGlobal("function:=", 9); setGlobal("function:booleanToStr", 10); setGlobal("function:add", 11); setGlobal("function:define", 12); setGlobal("type:string", "replaceAll\getGlobal\substr\booleanToStr\\"); setGlobal("type:int", "add\\"); setGlobal("type:boolean", "and\=\\"); setGlobal("type:void", "echo\define\\"); int calls=0; int pCount=0; string script="(define int four 4) (echo (booleanToStr (= four 4))))"; //save("script", script); //string script="(debug (replaceAll (getGlobal 'numbers) (getGlobal 'n1) '2))"; //debug("0:"+script); //if(strCount(script, "(")==strCount(script, ")")) { //if( strCount(script, quote)%2==0) { //if script has even number of quotation marks if(indexOf(script, quote+"", 0)>-1) { script=strFind(script); } setGlobal("boolean:false", false); setGlobal("boolean:true", true); // debug("1:"+script); script=parameterFind(script, true, 0); setGlobal("script", script); //debug("2:"+getGlobal("$PARAM_0")); //debug("3:"+calls); setGlobal("calls", calls); messageSprite(getGlobal("eval"), "initialize", ""); /* } else theLog("Error: Missing a quotation mark somewhere?"); } else { theLog("Error: Uneven number of brackets."); }*/ } string parameterFind(string text, boolean countIt, int type) { //text=replaceAll(text, "\(", "<"); //text=replaceAll(text, "\)", ">"); //string checkingS=replaceAll(text, "{}", ""); //debug("Text:"+text); string newText=""; newText=text+""; string openB="("; string closeB=")"; //string openB="!?BLARGHO!?"; //string closeB="!?BLARGHC!?"; if(indexOf(text, openB, 0)>-1) { //if(type==1) { openB="{"; closeB="}"; } int Open=0; int Close=0; int x=indexOf(text, openB, 0); int closeQ=0; int p1=x; int endParam=0; while(p1>-1) { int pos1=indexOf(text,openB,x); int pos2=indexOf(text, closeB, x); int q=indexOf(text, quote, x); int bx=x; boolean go=true; int pos2a=indexOf(text,closeB,p1); if(go) { if (pos1!=-1 && pos2!=-1 && pos1<pos2) { Open++; x=pos1+1; } if (pos1!=-1 && pos2!=-1 && pos1>pos2) { Close++; x=pos2+1; } if (pos1==-1 && pos2!=-1) { Close++; x=pos2+1; } //} if(q>-1) { int y=indexOf(text, quote, q+1); if(y>x && (y<pos1 || pos1==-1) && (y<pos2 || pos2==-1)) { x=y+1;} } if (pos2!=-1 && Open==Close) { endParam=pos2; string wholeStr=""; if(p1+1<pos2) wholeStr=substr(text, p1, pos2+1); string theStr=""; if(p1<pos2) theStr=substr(text, p1+1, pos2); //debug("str:"+theStr+","+wholeStr); if(indexOf(theStr, openB, 0)>-1) { //debug("It is "+theStr); theStr=parameterFind(theStr, false, type); //debug("Updated to "+theStr); } if(theStr=="") theStr="NULL"; //debug("2str:"+theStr+","+wholeStr); if(wholeStr!="") { string paramThing="PARAM_"+pCount+""; //debug("setting $PARAM_"+pCount+" as: "+theStr); //debug("wholestr:"+wholeStr); //debug("Replacing "+wholeStr+" with "+paramThing); setGlobal("PARAM_"+pCount, theStr); string bla=replaceAll(newText+"", addSlashes(wholeStr), addSlashes(paramThing)); newText=bla+""; //debug("newtext:"+newText); if(countIt) { setGlobal("call:"+calls, pCount); calls++; } pCount++; } x=pos2+1; p1=indexOf(text, openB, x); } } } } return newText; } string strFind(string text) { int sPos=indexOf(text, quote, 0); string theStr=""; string wholeStr=""; string currentSection=""; while(sPos>-1) { int s2Pos=indexOf(text, quote, sPos+1); if(s2Pos>-1) { wholeStr=substr(text, sPos, s2Pos+1); theStr=substr(text, sPos+1, s2Pos); //if(theStr=="") theStr="NULL"; //theStr=replaceAll(theStr,"//","??/??"); setGlobal("string:STR_"+strCount, theStr); text=replaceAll(text, addSlashes(wholeStr), "STR_"+strCount); //strCount++; sPos=indexOf(text, quote, 0); } else { int lineNumber=strCount(substr(text,0,sPos),newLine)+1; theLog("Error: Quotation mark at line "+lineNumber+" has no corresponding closing quotation mark."); break; } } return text; } int strCount(string str, string s) { return (strlen(str) - strlen(replaceAll(str, addSlashes(s), ""))); } void theLog(string s) { debug(s); } string addSlashes(string str) { str=replaceAll(str, "\(", "\\("); str=replaceAll(str, "\)", "\\)"); return str; } |
Main Sprite (Script #1)
string slash="\";/*"\*///this is used to prevent red text in the code in the wiki int main() { if(getMessageCount()>0) { if(getFlag()=="initialize") { setLocal("runCall", 0); } int calls=getGlobal("calls"); int i=getLocal("runCall"); if(i<calls) { int p=getGlobal("call:"+i); //debug("i:"+i+",P:"+getGlobal("call:"+i)); //debug("Evaluating:"+getGlobal("PARAM_"+p)); eval(getGlobal("PARAM_"+p)); setLocal("runCall", i+1); } } } void eval(string script) { int n=indexOf(script, char(32)+"", 0); string fName=substr(script, 0, n); if(indexOf(getGlobal("type:void"), fName+slash, 0)>-1) { string rest=substr(script, n+1, strlen(script)); //debug("Contacting "+fName+" with "+rest); //debug("SpriteN:"+getGlobal("function:"+fName)); messageSprite(createSprite(0, getGlobal("function:"+fName), -1000, -1000, 1000), getID()+"", rest); } else { debug("Fatal Error: Only void functions may be run at the top level; "+fName+" is not a void function."); destroySprite(); } } |
Function Sprite Template
This is a template which will allow you to implement whatever functions you want to. I tried to make it as simple as possible. For some functions you may have to change the code, but for most you will hopefully only have to modify the title string, the varType[] array, and the parameters integer. You will also certainly have to modify the Return function, which is where the function itself is actually executed. Here, you can see substr() being used, as an example.
string slash="\";/*"\*///this is used to prevent red text in the code in the wiki void Return(string prefix) { setLocal("return", substr(getLocal(prefix+"-varValue0"), getLocal(prefix+"-varValue1"), getLocal(prefix+"-varValue2"))+""); //Execute the function, store it in a local as a string (if it's not void). } int main() { //logs are for debugging purposes. set global "log?" to true on the map if you want to see the sprites chatting with each other, and such. string title=""; //The function we are handling goes in here. boolean saveVar=true; //Should we remember the calculations, after passing off data to another sprite? (always true, so might be kind of pointless to ask..) boolean wait?=false; //This becomes true if one of the parameters contain another function or calculation that we must pass off to another sprite (and therefore, we must wait for their response). string varType[]={"string", "int", "int"}; //This is an array of all the variable types for the input parameters of this function. boolean arbitraryValues?=false; int parameters=0; //How many input parameters does this function take? if(isLocalSet("parameters")) parameters=getLocal("parameters"); while(getMessageCount()>0) { int fromSprite=parseInt(getFlag()); //The flag will always be a sort of "return address" to know who to respond to or who is responding to us. string stuff=getMessage(); //This is where all the parameters are, separated by spaces (hopefully). string params[]={""}; //Used to contain all the parameters. split() has not been implemented in Hacktendo, so we have to do it manually. log("received from "+fromSprite+": "+stuff); if(indexOf(stuff, "RESPONSE"+slash, 0)==0) { //Now we will remove the "RESPONSE"+slash from the data. int i1=indexOf(stuff, slash, 0); if(true) { if(strlen(stuff)>i1) stuff=substr(stuff, i1+1, strlen(stuff)); else stuff=""; } int sendTo=getLocal("waiting"+fromSprite); //The sprite we respond to (which is associated with the sprite we asked) int varN=getLocal("waiting-var"+fromSprite); //The parameter number that we have associated with the sprite that we asked to do this calculation. //Now we check the variable type, and use setLocal() accordingly. //We use setLocal() to remember which parameter it is and what its value is. string theType=varType[varN]; if(arbitraryValues?) theType=varType[0]; if(theType=="int") setLocal("waiting-varValue"+varN, parseInt(stuff)); if(theType=="string") setLocal("waiting-varValue"+varN, stuff); if(theType=="float") setLocal("waiting-varValue"+varN, parseFloat(stuff)); if(theType=="boolean") setLocal("waiting-varValue"+varN, getGlobal("boolean:"+stuff)); //globals "boolean:false" and "boolean:true" should be defined. log("sendTo:"+sendTo+",varN:"+varN+",stuff:"+stuff); boolean ready?=true; for(int z=0;z<parameters;z++) { if(isLocalSet("waiting-varValue"+z+"")==false) { ready?=false; break; } } if(ready?) { //Do we have all the parameter values yet? Return("waiting"); string theValue=""; if(isLocalSet("return")==true) theValue=getLocal("return"); log("response to "+sendTo+": "+theValue); messageSprite(sendTo, getID()+"", "RESPONSE"+slash+theValue); //We finally respond to the sprite that asked us to do this... //For functions that have no return value (void functions), we need only supply the message "RESPONSE\". destroySprite(); //Our job is done, let's die now. } } else {//We know that a sprite is asking us to perform a calculation. int i=0; int count=strCount(stuff, " "); //How many spaces are there? int p1=0; while(i<=count) { //This will do essentially what split() does, by spaces. int p2=indexOf(stuff, " ", p1+1); if(p2==-1) p2=strlen(stuff); params[i]=substr(stuff, p1, p2); string theType=varType[i]; if(arbitraryValues?) theType=varType[0]; if(true) { //Here we will define values, depending on what type each parameter is. These values are only used if there is no dependency upon another sprite's calculation, thus "temporary" if(theType=="string") setLocal("temp-varValue"+i, processStr(params[i], true, i)); else if(theType=="int") setLocal("temp-varValue"+i, processInt(params[i], true, i)); else if(theType=="boolean") setLocal("temp-varValue"+i, processBoolean(params[i], true, i)); else if(theType=="float") setLocal("temp-varValue"+i, processFloat(params[i], true, i)); } p1=p2+1; i++; } if(arbitraryValues?) setLocal("parameters", i); if(!wait?) { //If we don't need to wait on another sprite to do something for us... Return("temp"); string theValue=""; if(isLocalSet("return")) theValue=getLocal("return"); log("response to "+fromSprite+":"+getLocal("return")); messageSprite(fromSprite, getID()+"", "RESPONSE"+slash+theValue); //Respond with our answer. destroySprite(); //Suicide! } } nextMessage(); } } string booleanToStr(boolean b) { string r=""; if(b) r="true"; else r="false"; return r; } int strCount(string str, string s) { return (strlen(str) - strlen(replaceAll(str, s, ""))); } boolean processBoolean(string name, boolean eval, int var) { boolean value=false; boolean saveThisVar=saveVar; if(indexOf(name, "PARAM_", 0)==0) { if(eval==true) { eval(getGlobal(name)); saveThisVar=false; } } else { if(isGlobalSet("boolean:"+name)) value=getGlobal("boolean:"+name); else { log("Warning: Arg "+var+", boolean "+name+" is null"); } } if(saveThisVar) setLocal("waiting-varValue"+var, value); return value; } int processFloat(string name, boolean eval, int var) { float value=0; boolean saveThisVar=saveVar; string c1=substr(name, 0, 1); if(indexOf(getGlobal("numbers"), c1, 0)>-1 || c1=="-") {//it's a number value=parseFloat(name); } else { if(indexOf(name, "PARAM_", 0)==0) { if(eval==true) { eval(getGlobal(name)); saveThisVar=false; } } else { if(isGlobalSet("float:"+name)) value=getGlobal("float:"+name); else { log("Warning: Arg "+var+", float "+name+" is null"); } } } if(saveThisVar) setLocal("waiting-varValue"+var, value); return value; } int processInt(string name, boolean eval, int var) { int value=0; boolean saveThisVar=saveVar; string c1=substr(name, 0, 1); if(indexOf(getGlobal("numbers"), c1, 0)>-1 || c1=="-") {//it's a number value=parseInt(name); } else { if(indexOf(name, "PARAM_", 0)==0) { if(eval==true) { eval(getGlobal(name)); saveThisVar=false; } } else { if(isGlobalSet("int:"+name)) value=getGlobal("int:"+name); else { log("Warning: Arg "+var+", int "+name+" is null"); } } } if(saveThisVar) setLocal("waiting-varValue"+var, value); return value; } string processStr(string name, boolean eval, int var) { string value=""; boolean saveThisVar=saveVar; if(substr(name+"", 0, 1)=="'") { if(strlen(name)>1) value=substr(name+"", 1, strlen(name)); //it's a symbol } else { if(indexOf(name, "PARAM_", 0)==0) { value=getGlobal(name); if(eval) { eval(value, var); saveThisVar=false; } } else { if(isGlobalSet("string:"+name)) value=getGlobal("string:"+name); else { log("Warning: string "+name+" is null"); } } } if(saveThisVar) setLocal("waiting-varValue"+var, value+""); return value; } void eval(string script, int var) { int n=indexOf(script, char(32)+"", 0); string fName=substr(script, 0, n); string theType=varType[var]; if(arbitraryValues?) theType=varType[0]; if(indexOf(getGlobal("type:"+theType), fName+slash, 0)>-1) { string rest=substr(script, n+1, strlen(script)); int s=createSprite(0, getGlobal("function:"+fName), -1000, -1000, 1000); messageSprite(s, getID()+"", rest); log("asked "+fName+"("+s+"): "+rest); setLocal("waiting"+s, fromSprite); setLocal("waiting-var"+s, var); wait?=true; } else { log("Fatal Error: "+title+" requires "+theType+" for arg"+var+"; "+fName+" does not return "+theType+"."); destroySprite(); } } void log(string m) { if(getGlobal("log?")) debug(title+"("+getID()+") "+m); } |
