/ /* File forth-and-c.c Author Ernesto P. Adorio ernesto.adorio@gmail.com Desc This simple forth interpreter reads from the command line based on the following prescription. loop: read eval print This version uses double floating point numbers for ease in applications. Version 0.0.1 march 12, 2014 Compile gcc -std=gnu99 forth-and-c.c */ #include#include #include #include /* Constants */ char* ByeMessage = "Thanks for trying out forth-and-c.\n"; char* WelcomeMessage="Welcome to Forth-and-C Version 0.0.1, March 12, 2014.\n"; /* Global interpreter variables. */ #define BUFFMAXLEN 1024 #define EOI '\0' char BUFF[BUFFMAXLEN]; char * tokenstart, *tokenend = BUFF; #define MAXSTACKDEPTH 10 union { double f; long int i; }OPSTACK[MAXSTACKDEPTH]; int opindex = -1; char PROMPT[32]= ">> "; /* token system */ double fnum; /* number read */ enum tokentype { FPLUS, FMINUS, FDIV, FMUL, DOT, BYE, EMIT, CR, EOL, FNUM, UNDEFINED}; char* symbols[] ={ "+", "-", "/", "*", ".", "bye","emit", "cr" }; int NSYMBOLS=8; char* errmssgs[] = {"NOERROR", "OVERFLOW", "UNDERFLOW"}; enum errorcodes {NOERROR, OVERFLOW, UNDERFLOW}; int error = NOERROR; int lex(void) { /* process token pointed to by token start */ if (*tokenstart==EOI) { return EOL; } for (int i = 0; i < NSYMBOLS; i++){ if (strcmp(tokenstart, symbols[i]) == 0){ return i; } } /* Pure Forth assumes a number only after trying other token types */ fnum = strtod(tokenstart,NULL); return FNUM; /* Error at this stage! */ return UNDEFINED; }p int parse(void) /* Parsing system, splits input line into tokens */ { tokenstart = tokenend; /* Find location of next space character. */ while (! isspace(*tokenend) && *tokenend !=EOI)tokenend++; if (*tokenend != EOI){ *tokenend++='\0'; return 1; } else { /* reset tokenend */ return EOL; } } int execute(int toktype) { switch(toktype) { case FNUM:if (opindex < MAXSTACKDEPTH) { OPSTACK[++opindex].f = fnum; } break; case DOT: if (opindex >= 0){ printf("%f ", OPSTACK[opindex--].f); } else { error= UNDERFLOW; }; break; case FPLUS: OPSTACK[--opindex].f += OPSTACK[opindex + 1].f; break; case FMINUS: OPSTACK[--opindex].f -= OPSTACK[opindex + 1].f; break; case FMUL: OPSTACK[--opindex].f *= OPSTACK[opindex + 1].f; break; case FDIV: OPSTACK[--opindex].f /= OPSTACK[opindex + 1].f; break; case EMIT:putchar( (int) (OPSTACK[opindex--].f)); break; case CR: /* carriage return */ putchar(10); putchar(13); break; default: break; }; }; int main() { int ntokens = 0; /* print welcome.*/ printf("%s", WelcomeMessage); while (1) { /* read input */ printf("%s", PROMPT); fgets(BUFF, BUFFMAXLEN, stdin); /*reset tokenizer */ tokenend=BUFF; while (parse()!= EOL) { ntokens ++; int tokentype = lex(); // printf("%d: %s %d\n",ntokens, tokenstart, tokentype); execute(tokentype); if (tokentype == BYE) { printf("%s", ByeMessage); return (0); } if (error) { printf("%s", errmssgs[error]); switch(error){ case UNDERFLOW:opindex= -1; break ; case OVERFLOW: opindex= MAXSTACKDEPTH - 1; break; default: break; } error = 0; } } } }
We have decided to rewrite our Forth interpreter written in C. Default data type are double floating point numbers and this allows you to use it for processing simple arithmetic problems.
Compile the above using the command line invocation
gcc -std=gnu99 forth-and-c.cThen run the program by typing ./a.out Type the expression 4 3 * 1 - . You should get the answer 11.
No comments:
Post a Comment