/*
file simple-forth-0.0.2.c
author Dr. Ernesto P. Adorio
UPDEPP (University of the Philippines,
Extension Program in Pampanga
Clarkfield, Pampanga
email ernesto.adorio@gmail.com
version 0.0.1 January 14, 2012 basic interpreter.
0.0.2 January 16, 2012 interactivity added.
*/
#include
#include
#include
#include
enum {E_STACKUNDERFLOW} ERRCODES;
enum {L_EMIT, L_DOT,L_DOTT, L_SPACE, L_ADD, L_SUB, L_MUL, L_DIV, L_DROP, L_INT32, L_CR, L_BYE, L_EOS,L_ERROR} OPCODES;
const char *stdwords[] = {
"emit",
".",
".t",
"space",
"+",
"-",
"*",
"/",
"drop",
"int32",
"cr",
"bye",
"\n",
};
#define MAXSTKLEN 32
#define MAXFSTKLEN 32
#define MAXTOKENLEN 128
int LENSTDWORDS = sizeof(stdwords)/sizeof(stdwords[0]);
char LINEBUFFER[256];
char *goodbye= "bye";
int ERRCODE = 0;
int SP = -1; /* stack pointer index */
int stack[MAXSTKLEN];
double fstack[MAXFSTKLEN];
int opcode;
char *tokstart;
char *tokend;
int eval(int opcode)
{
/* Evaluate opcode */
switch (opcode){
case L_EMIT:
//@@printf("opcode L_EMIT %s %d\n", tokstart, SP);
if (SP < 0) {
ERRCODE = E_STACKUNDERFLOW;
} else {
printf ("%c", stack[SP--]);
}
break;
case L_DOT:
//@@printf("opcode L_EMIT %s %d\n", tokstart, SP);
if (SP < 0) {
ERRCODE = E_STACKUNDERFLOW;
printf("%s", "underflow!");
} else {
printf ("%d", stack[SP--]);
}
break;
case L_DOTT:
//@@printf("opcode L_EMIT %s %d\n", tokstart, SP);
if (SP < 0) {
ERRCODE = E_STACKUNDERFLOW;
printf("%s", "underflow!");
} else {
printf ("%d", stack[SP]);
}
break;
case L_SPACE:
printf ("%c", 32);
break;
case L_ADD:
//printf("opcode L_ADD %s\n", tokstart);
if (SP <= 0) {
ERRCODE = E_STACKUNDERFLOW;
printf("%s", "underflow!");
break;
}
stack[SP-1] += stack[SP];
SP--;
break;
case L_SUB:
//printf("opcode L_SUB %s\n", tokstart);
if (SP <= 0) {
ERRCODE = E_STACKUNDERFLOW;
printf("%s", "underflow!");
break;
}
stack[SP-1] -= stack[SP];
SP--;
break;
case L_MUL:
//printf("opcode L_MUL %s\n", tokstart);
if (SP <= 0) {
ERRCODE = E_STACKUNDERFLOW;
printf("%s", "underflow!");
break;
}
stack[SP-1] *= stack[SP];
SP--;
break;
case L_DIV:
//printf("opcode L_DIV %s\n", tokstart);
if (SP <= 0) {
ERRCODE = E_STACKUNDERFLOW;
printf("%s", "underflow!");
break;
}
stack[SP-1] /= stack[SP];
SP--;
break;
case L_INT32:
//printf("opcode L_INT32 %s\n",tokstart);
stack[++SP]= atoi(tokstart);
break;
case L_DROP:
//printf("opcode L_DROP %s \n", tokstart);
SP=SP -1;
break;
case L_CR:
// printf("opcode L_CR %s \n", tokstart);
printf("\n");
break;
default:
;
break;
}
}
void nexttoken()
{
tokstart = tokend;
//@ printf("inside nexttoken [%s]", tokstart);
/* ignore leading white spaces */
while (isspace(*tokstart)) tokstart++;
/* find terminating space of end of string */
tokend = tokstart;
while (!isspace(*tokend) && *tokend != '\0') tokend++;
/* string terminator */
if (*tokend != '\0') {
*tokend = '\0';
tokend ++;
}
/* get opcode */
opcode = -1;
if (tokend == tokstart) {
opcode = L_EOS;
return;
}
/*@@@ printf("token [%s]\n", tokstart); */
for (int i =0; i < LENSTDWORDS; i++) {
if (strcmp(stdwords[i], tokstart) == 0){
opcode = i;
//@ printf("opcde [%d]", opcode);
break;
}
}
if (opcode == -1){
opcode = L_INT32;
}
}
int main(){
while (1) {
// read string.
printf("> ");
if (fgets(LINEBUFFER, 250, stdin)!= NULL) {
tokend=LINEBUFFER;
// @@@ printf("input string [%s]", LINEBUFFER);
} else {
tokend= goodbye;
}
// eval
// printf ("Entering evaluation loop.\n");
while (1) {
nexttoken();
//@ printf ("[%d] %s", opcode, tokstart);
eval(opcode);
if (opcode== L_BYE) {
//printf ("%% opcode is L_BYE");
return 0;
}
if (opcode ==L_EOS) {
break;
}
if (ERRCODE != 0) {
printf("ERRORCODE [%d]", ERRCODE);
break;
};
}
// loop back unless BYE!
}
printf("\n");
return 0;
}
Save file to simple-forth-0.0.2.c, then compile it using the following command:
: gcc simple-forth.c -std=c99 -o simple-forth-0.0.2
Then run it by issuing ./simple-forth00.0.2 Here is an uninspired terminal run:
> 2 3 - 1 + . 0> 56 emit 8> 97 emit a> 64 emit @> > > bye
Next, we will add add a floating point computation capabilities using a separate stack.
No comments:
Post a Comment