Talk:Scheme-like Script Interpreter

From Hack Wars Wiki

Jump to: navigation, search

Optimization suggestions

Just skimmed a little bit over your code. Nice - but long and lacking comments. I only tested my suggestions in challenge scripts. They might not work in your scripts! Thats why I didn't change them in the article.

/*
//old version
boolean isEven(int n) {
	int r=n%2;
	boolean ret=false;
	if(r==0) ret=true;
	return ret;
}
*/
 
//new version
boolean isEven(int n) {
	return n%2==0;
}


That should save 3 ops every time this function is called. But you use it only one time so far so I suggest to get rid of it completely - which if I am right saves you all in all 6 ops. (calling custom functions costs 2 ops and the use of return a third op)

void mainProcess(string script, boolean save) {
	if(calls>0) cStart=calls+1;
	string orScript=script;
	script=replaceAll(replaceAll(script, "	", ""), char(10), " ");
	if(strCount(script, "(")==strCount(script, ")")) {
//		if(isEven(strCount(script, char(34)))) {
		if( strCount(script, char(34))%2==0 ) { //if script has even number of quotation marks
			script=strFind(script);
			script=parameterFind(script, true, 0);
			if(save) {
				string backupData="!~~backupS~~!"+orScript+"!~~backupE~~!"+"!~~paramS~~!"+varData+"!~~paramE~~!"+"!~~callsS~~!"+funcC+"!~~callsE~~!"+"!~~strNameS~~!"+strNames+"!~~strNameE~~!"+"!~~strVarE~~!";
				writeFile(dataFile, backupData);
			}
			evalParams(false);
		}
		else theLog("Error: Missing a quotation mark somewhere?");
	}
	else {
		theLog("Error: Uneven number of brackets.");
	}
}


another function: (nice idea, but why check for negative numbers?)

//orig code
int strCount(string str, string s) {
	int n=strlen(str);
	str=replaceAll(str, s, "");
	int nn=strlen(str);
	int value=0;
	if(n>nn) value=n-nn;
	return value;
}
 
//lesser ops version
int strCount2(string str, string s) {
	return strlen(str) - strlen(replaceAll(str, s, ""));
}
 
// one op less than strCount2 but it only works for up to return values of 79! (max array size is 80)
int strCount3(string str, string s) {
	return length(split(str,s))-1;
}


PS: You use a few functions often closing with "return value;". Often one op could be saved by changing "value=[...];" to "return [...];". return can be used to exit a custom function even from within loops. But test it through-fully. In short scripts it works well - but I don't know if it has bad side effects in complex scripts to return from functions early.

saving one op might not sound much - but if the function is often called then the bonus multiplies. Silverlight 00:17, 10 September 2009 (UTC)

==Returning Early==

After modifying the Eval functions to return early, I ran my "loop test" and it was 10 loops less, which leads me to believe that returning early costs more ops, not less. Surfpup 01:34, 10 September 2009 (UTC) [signature added by Silverlight]

don't forget to sign your comments here.
That surprises me. Try this:
WARNING Code not tested (even lacking a compilation check! feel free to correct such mistakes)
legend:
//* changed line
//+ new line
//- removed line
//?2 removal of one line.
//?3 additional changes
for a benchmark don't use the //?2 and //?3 changes to avoid having them influencing the test of early returning.
int intEval(string script, boolean log) {
	string stuff[]=split(script, " ");
//-3	int length=length(stuff);
//-2	int value="";
	//Math
//*	if(stuff[0]=="+") value=processInt(stuff[1], true)+processInt(stuff[2], true);
	if(stuff[0]=="+") return processInt(stuff[1], true)+processInt(stuff[2], true);
//*	else if(stuff[0]=="-") value=processInt(stuff[1], true)-processInt(stuff[2], true);
	else if(stuff[0]=="-") return processInt(stuff[1], true)-processInt(stuff[2], true);
//*	else if(stuff[0]=="/") value=processInt(stuff[1], true)/processInt(stuff[2], true);
	else if(stuff[0]=="/") return processInt(stuff[1], true)/processInt(stuff[2], true);
//*	else if(stuff[0]=="*") value=processInt(stuff[1], true)*processInt(stuff[2], true);
	else if(stuff[0]=="*") return processInt(stuff[1], true)*processInt(stuff[2], true);
	//else if(stuff[0]=="sqrt") value=sqrt(processInt(stuff[1], true));
	//General
//*	else if(stuff[0]=="indexOf") value=indexOf(processStr(stuff[1], true), processStr(stuff[2], true), processInt(stuff[3], true));
	else if(stuff[0]=="indexOf") return indexOf(processStr(stuff[1], true), processStr(stuff[2], true), processInt(stuff[3], true));
	else if(stuff[0]=="strlen") {
//*		value=strlen(processStr(stuff[1], true));
		return strlen(processStr(stuff[1], true));
	}
	else if(stuff[0]=="strToInt") {
//*		value=parseInt(processStr(stuff[1], true));
		return parseInt(processStr(stuff[1], true));
	}
 
	//File I/O
	else if(stuff[0]=="countLines") {
//*		value=countLines(processStr(stuff[1], true));
		return countLines(processStr(stuff[1], true));
	}
	else if(stuff[0]=="cond") {
//+3	AFAIK putting length() into the for condition will hurt ops if there are more than 2 loops
		int length=length(stuff);
		for(int z=1;z<length;z+=2) {
//-3			boolean outcome=false;
//*3			if(stuff[z]=="else") outcome=true;
			if(stuff[z]=="else") return intEval(processParam(stuff[z+1]), true);
//*3			if(stuff[z]!="else") outcome=boolEval(processParam(stuff[z]), true);
			else if (boolEval(processParam(stuff[z]), true)) return intEval(processParam(stuff[z+1]), true);
//-3			if(outcome==true) { value=intEval(processParam(stuff[z+1]), true); break; }
		}
	}
	else if(indexOf(intFuncData, "////"+stuff[0]+"/", 0)>-1) { //it's a custom function!
		int f=indexOf(intFuncData, "////"+stuff[0]+"/", 0);
		int f2=indexOf(intFuncData, "//", f+5);
		int f3=indexOf(intFuncData, "///", f2+1);
		int f4=indexOf(intFuncData, "////", f3+1);
 
		string parameters=substr(intFuncData, f+strlen(stuff[0])+5, f2);
		string inputTypes=substr(intFuncData, f2+2, f3);
		string code=substr(intFuncData, f3+3, f4);
		string params[]=split(parameters, " ");
		string types[]=split(inputTypes, " ");
/* the following two changes are argutable. The old version costs x ops , with x being the number of params. If there are no params it will still cost one op. The "optimazation" costs  ALWAYS two ops. 
Conclusion: 
one or no param: the old version costs one op less
two params: both cost the same
three params upwards: the new version costs params-2 ops less
Suggestion: Don't include the new version because I guess you will have more one or no param functions USED BY SCRIPTS than those with three or more ops.
 
This is an example where code changes can or are not better on average depending on the average use case.
*/
//+3	AFAIK putting length() into the for condition will hurt ops if there are more than 2 loops
		int lengthParams=length(params);
//*3		for(int z=0;z<length(params); z++) {
		for(int z=0;z<lengthParams; z++) {
			if(types[z]=="string") defineStr(params[z], processStr(stuff[z+1], true));
//*3			if(types[z]=="int") defineInt(params[z], processInt(stuff[z+1], true));
			else if(types[z]=="int") defineInt(params[z], processInt(stuff[z+1], true));
//*3			if(types[z]=="boolean") defineBool(params[z], processBool(stuff[z+1], true));
			else if(types[z]=="boolean") defineBool(params[z], processBool(stuff[z+1], true));
		}
		//theLog(newLine+"Evaluating "+stuff[0]);
//*		value=intEval(processParam(code), true);
		return intEval(processParam(code), true);
	}
	else theLog(newLine+"Error: intEval of "+script+" failed to execute.");
//*	return value;
	return 0;
}
Silverlight 11:06, 10 September 2009 (UTC)


Well Silverlight, I believe the changes you made to the "cond" part completely screw up that function. It's odd really, there doesn't seem to be anything wrong with the code... --Surfpup 19:40, 10 September 2009 (UTC)

Personal tools