Currently, we are using the Whitespace 0.3 interpreter on SPOJ.
Below, you will find a simple asm2ws compiler in C++, which is nowhere near as good as the one used by the developers of Whitespace, but it works for me.
The interpreter:
//Simple assembler to whitespace 0.2.1 interpreter
//(c) Adrian Kosowski, 2004
//public domain, no warranty, lots of bugs, change whatever you like, etc., etc.
//usage: asm2ws < program.wsa > program.ws
//error codes:
//1. line too long (all wsa files must end with an empty line! :)
//2. unknown command
//remove the ! OUTPUT COMMENT lines to get rid of comments in the output file
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#define LL 256
char buf[LL], word[LL], argenc[LL];
int argument;
char* encode (int arg)
{
int pos, i;
sprintf(argenc, "%d", arg);//! OUTPUT COMMENT
pos=strlen(argenc);
if (arg>=0) argenc[pos]=' ';
else argenc[pos]='\t';
pos++;
for (i=31; i>=0; i--) if (arg & (1<<i)) break;
for (;i>=0; i--, pos++)
if (arg & (1<<i)) argenc[pos]='\t';
else argenc[pos]=' ';
argenc[pos]='\n';
pos++;
argenc[pos]=0;
return argenc;
}
int main ()
{
int ln=0;
while (fgets(buf, LL, stdin)!=NULL)
{
ln++;
int l = strlen(buf);
//Checking line length
if (buf[l-1]!='\n')
{
fprintf (stderr, "line %d, error 1: line of excessive length found on input\n", ln);
return 1;
}
l--;
buf[l]=0;
sscanf (buf, "%s%d", word, &argument);
// Processing of comments
if (!isalnum(word[0])) continue;
// Printing additional comments :)
printf ("%s", word);//! OUTPUT COMMENT
//Processing of commands - stack ops
if (!strcasecmp(word, "push" )) {printf (" %s", encode(argument)); continue;}
if (!strcasecmp(word, "dup" )) {printf (" \n "); continue;}
if (!strcasecmp(word, "swap" )) {printf (" \n\t"); continue;}
if (!strcasecmp(word, "pop" )) {printf (" \n\n"); continue;}
//Processing of commands - arithmetic
if (!strcasecmp(word, "add" )) {printf ("\t "); continue;}
if (!strcasecmp(word, "sub" )) {printf ("\t \t"); continue;}
if (!strcasecmp(word, "mul" )) {printf ("\t \n"); continue;}
if (!strcasecmp(word, "div" )) {printf ("\t \t "); continue;}
if (!strcasecmp(word, "mod" )) {printf ("\t \t\t"); continue;}
//Processing of commands - heap ops
if (!strcasecmp(word, "store" )) {printf ("\t\t "); continue;}
if (!strcasecmp(word, "retrieve")) {printf ("\t\t\t"); continue;}
//Processing of commands - flow ctrl
if (!strcasecmp(word, "label" )) {printf ("\n %s", encode(argument)); continue;}
if (!strcasecmp(word, "call" )) {printf ("\n \t%s", encode(argument)); continue;}
if (!strcasecmp(word, "jmp" )) {printf ("\n \n%s", encode(argument)); continue;}
if (!strcasecmp(word, "jz" )) {printf ("\n\t %s", encode(argument)); continue;}
if (!strcasecmp(word, "jlz" )) {printf ("\n\t\t%s", encode(argument)); continue;}
if (!strcasecmp(word, "return" )) {printf ("\n\t\n"); continue;}
if (!strcasecmp(word, "stop." )) {printf ("\n\n\n"); continue;}
//Processing of commands - io
if (!strcasecmp(word, "putchar" )) {printf ("\t\n "); continue;}
if (!strcasecmp(word, "print" )) {printf ("\t\n \t"); continue;}
if (!strcasecmp(word, "getchar" )) {printf ("\t\n\t "); continue;}
if (!strcasecmp(word, "read" )) {printf ("\t\n\t\t"); continue;}
//Unknown command
fprintf (stderr, "line %d, error 2: unknown command `%s'\n", ln, word);
return 2;
}
return 0;
}
A sample input file (test.wsa
)
[Solution to the SPOJ TEST program]
[@author A. Kosowski, 2004]
;starts here:
label 2
push 0
read
push 0
retrieve
push 42
sub
dup
jz 1 ;jump if number read was 42
push 42
add
print
push 10
putchar
jmp 2
label 1
stop.