/* NovaSquirrel's FALSE interpreter - second release? ------------------------------------------------------------------------------ It's different from PortableFalse in that: - It's NOT strongly typed. You can push an integer to the stack and ! it - Less macro-heavy - < is 'less than' - ; and : work on both numeric addresses and variables - I'm using ` as an escape code for more extensions - `? is like ? except it takes an "else" block too (["true"]["false"]`?) - `/ is modulo - ^ is now XOR, and there is no "read char" command - `! jumps - `O is like pick but removes the picked value from the stack - W,X,Y, and Z push the values of variables w,x,y, and z respectively - Uses some GNU C stuff - Programs have a time limit of two seconds (but it doesn't seem to work?) - Everything's still all in one function but it's not main() - Doesn't put additional main() arguments into variables - Probably more stuff I forgot Some ideas taken from Ian Osgood's DUP and other FALSE-like stuff. */ #include #include #include #include #include #define DEBUG 0 #define LOAD_FROM_FILE 1 typedef unsigned long u32; typedef signed long s32; u32 PC = 0; // Program counter // Index 0 is the stack pointer s32 DST[50]={1}; // Data stack u32 RST[50]={1}; // Return stack s32 Mem[256]={[0 ... 255] = 0}; // Memory for variables u32 PrgEnd; // Ending that we can check against char TempText[60]; // a little text buffer char *ErrMsg; // what error message to show char *Program = NULL; unsigned int TimeStarted; int Ticks = 0; void Err() { printf("\nError at %i: %s \n", PC,ErrMsg); exit(0); } #define ErrWithMsg(Msg) {ErrMsg = Msg; Err();} #define Pop(Var, Stack) { \ Stack[0]--; \ if((Stack[0] < 1) || (Stack[0] > 100)) { \ ErrMsg = "Stack underflow"; Err(); \ } \ *Var = Stack[Stack[0]]; \ } #define Push(Var, Stack) { \ Stack[Stack[0]]=Var; \ Stack[0]++; \ if((Stack[0] < 1) || (Stack[0] > 100)) { \ ErrMsg = "Stack overflow"; Err(); \ } \ } void CheckIndex(int Index, int Min, int Max) { if(Index > Max || Index < Min) { ErrMsg = "CheckIndex() failed somewhere"; Err(); } } void Run(int StartingAt) { s32 a,b,c; // Scratch registers char ext; #if DEBUG printf("\n-- %i to %i\n", PC, StartingAt); #endif Push(PC,RST); PC = StartingAt; if(!(PC>=0 && PC=0 && PC3000) ErrWithMsg("Took too many ticks to finish program"); #if DEBUG putchar('\n'); for(a=0;a':Pop(&b,DST);Pop(&a,DST);Push(-(b>a),DST);break; case '_':Pop(&a,DST);Push(-a,DST);break; case '~':Pop(&a,DST);Push(~a,DST);break; case '%':Pop(&a,DST);break; case 'W':Push(Mem['w'-'a'],DST);break; case 'X':Push(Mem['x'-'a'],DST);break; case 'Y':Push(Mem['y'-'a'],DST);break; case 'Z':Push(Mem['z'-'a'],DST);break; case '$':Pop(&a,DST);Push(a,DST);Push(a,DST);break; case '\\':Pop(&a,DST);Pop(&b,DST);Push(a,DST);Push(b,DST);break; case '@':Pop(&a,DST);Pop(&b,DST);Pop(&c,DST);Push(b,DST);Push(a,DST);Push(c,DST);break; case 'O':Pop(&a,DST);CheckIndex(DST[0]-a,1,49);Push(DST[DST[0]-a],DST);break; // ? case ':':Pop(&a,DST);CheckIndex(a,0,255);Pop(&b,DST);Mem[a]=b;break; case ';':Pop(&a,DST);CheckIndex(a,0,255);Push(Mem[a],DST);break; case '.':Pop(&a,DST);printf("%i",(int)a);break; case ',':Pop(&a,DST);putchar(a);break; case 'B':fflush(stdout);fflush(stdin);break; case '\"':while(Program[++PC]!='\"' && PCPrgEnd){ ErrMsg="[ not closed"; Err();} if(Program[PC++]=='[') Level++; if(Program[PC] ==']') Level--; } break; case ']':Pop(&PC,RST);return; case '!':Pop(&a,DST);Run(a);break; case '?':Pop(&a,DST);Pop(&b,DST);if(b)Run(a);break; case '#': Pop(&a,DST); // pop the 'do' block Pop(&b,DST); // 'condition' block while(1) { Run(b); Pop(&c,DST); if(!c) break; Run(a); } break; case '`': // ` doesn't serve a purpose in FALSE anymore, so I'll make // it my escape code for stupid extensions to FALSE ext = Program[++PC]; if(ext=='/'){ Pop(&b,DST); Pop(&a,DST); if(!b) ErrWithMsg("Division by zero"); Push(a%b,DST); } else if(ext=='?'){ // extended 'if' with an 'else' Pop(&a,DST); Pop(&b,DST); Pop(&c,DST); if(c) Run(b); else Run(a); } else if(ext=='!'){ // jump Pop(&a,DST); if(!(a>=0 && a='a'&&Program[PC]<='z') { Push(Program[PC]-'a',DST); } else { sprintf(TempText,"Unrecognized symbol (%c)",Program[PC]); ErrMsg = TempText; Err(); } break; } PC++; } Pop(&PC,RST); } int NSFalse(char *Program2) { int i; DST[0]=1; RST[0]=1; Program = Program2; PrgEnd = strlen(Program); TimeStarted = (unsigned)time(NULL); for(i=0;i<255;i++) Mem[i]=0; #if !LOAD_FROM_FILE printf("%s \n", Program); #endif Run(0); s32 a; printf("\n"); while(DST[0] != 1) { Pop(&a, DST) printf("%i ", a); } printf("\n"); return(-1); } int main(int argc, char **argv) { char Program[8192]; int i=0; #if LOAD_FROM_FILE if(argc < 2) { printf("Syntax: %s file.f\n", argv[0]); return -1; } FILE *MyFile = fopen(argv[1],"r"); if(MyFile == NULL) { printf("Wasn't able to open %s\n",argv[1]); return -2; } while(!feof(MyFile)) { int j = fgetc(MyFile); Program[i++]=j; } Program[i]=0; fclose(MyFile); return NSFalse(Program); #else // just do sample programs then /* NSFalse("5."); printf("\n\n"); NSFalse("1 2 3 4 5 5 `O"); printf("\n\n"); NSFalse("\"hello!\""); printf("\n\n"); NSFalse("[\"hello!\" ]w:W!"); printf("\n\n"); NSFalse("0[\"hello!\"]?"); printf("\n\n"); NSFalse("1[\"hello!\"]?"); printf("\n\n"); NSFalse("0[\"true\"][\"false\"]`?"); printf("\n\n"); NSFalse("1[\"true\"][\"false\"]`?"); printf("\n\n"); NSFalse("5w:W."); printf("\n\n"); NSFalse("1[$10<][$.1+' ,]#%"); printf("\n\n"); NSFalse("1i:[10i;<][i;$.1+i:' ,]#"); printf("\n\n"); NSFalse("8.1a:[10a;<][a;1+a:'=,]#'D,"); printf("\n\n"); NSFalse("0a:1b:1n:[17n;<][n;1+n:a;$.' ,b;+c:b;a:c;b:]#"); printf("\n"); */ return 1; #endif }