Initial Import from SVN
This commit is contained in:
30
src/cmd/forth/Makefile
Normal file
30
src/cmd/forth/Makefile
Normal file
@@ -0,0 +1,30 @@
|
||||
TOPSRC = $(shell cd ../../..; pwd)
|
||||
include $(TOPSRC)/target.mk
|
||||
#include $(TOPSRC)/cross.mk
|
||||
|
||||
CFLAGS += -Werror -Wall
|
||||
LIBS += -lm -lc
|
||||
|
||||
OBJS = forth.o func.o
|
||||
|
||||
all: forth
|
||||
|
||||
forth: ${OBJS}
|
||||
${CC} ${LDFLAGS} -o forth.elf ${OBJS} ${LIBS}
|
||||
${OBJDUMP} -S forth.elf > forth.dis
|
||||
${SIZE} forth.elf
|
||||
${ELF2AOUT} forth.elf $@ && rm forth.elf
|
||||
|
||||
clean:
|
||||
rm -f *.o *.elf forth *.dis *~
|
||||
|
||||
func.txt: func.c
|
||||
grep '^ \*+' func.c | expand | sed 's/^ \*+ *$$//' |\
|
||||
sed 's/^ \*+ //' > func.txt
|
||||
|
||||
install: all
|
||||
install forth $(DESTDIR)/bin/
|
||||
|
||||
###
|
||||
forth.o: forth.c io.h forth.h
|
||||
func.o: func.c io.h forth.h
|
||||
23
src/cmd/forth/fact.fth
Normal file
23
src/cmd/forth/fact.fth
Normal file
@@ -0,0 +1,23 @@
|
||||
\ Iterative factorial function.
|
||||
|
||||
." Defining fact function ... "
|
||||
: fact ( n -- n! )
|
||||
dup 2 < if drop 1 else
|
||||
dup begin 1- swap over * swap dup 1 = until
|
||||
drop then
|
||||
; ." done." cr
|
||||
|
||||
." 1! = " 1 fact . cr
|
||||
." 2! = " 2 fact . cr
|
||||
." 3! = " 3 fact . cr
|
||||
." 4! = " 4 fact . cr
|
||||
." 5! = " 5 fact . cr
|
||||
." 6! = " 6 fact . cr
|
||||
." 7! = " 7 fact . cr
|
||||
." 8! = " 8 fact . cr
|
||||
." 9! = " 9 fact . cr
|
||||
." 10! = " 10 fact . cr
|
||||
." 11! = " 11 fact . cr
|
||||
." 12! = " 12 fact . cr
|
||||
|
||||
halt
|
||||
800
src/cmd/forth/forth.c
Normal file
800
src/cmd/forth/forth.c
Normal file
@@ -0,0 +1,800 @@
|
||||
/*
|
||||
* Portable Forth interpreter.
|
||||
* Copyright (C) 1990-2012 Serge Vakulenko, <serge@vak.ru>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software
|
||||
* and its documentation for any purpose and without fee is hereby
|
||||
* granted, provided that the above copyright notice appear in all
|
||||
* copies and that both that the copyright notice and this
|
||||
* permission notice and warranty disclaimer appear in supporting
|
||||
* documentation, and that the name of the author not be used in
|
||||
* advertising or publicity pertaining to distribution of the
|
||||
* software without specific, written prior permission.
|
||||
*
|
||||
* The author disclaim all warranties with regard to this
|
||||
* software, including all implied warranties of merchantability
|
||||
* and fitness. In no event shall the author be liable for any
|
||||
* special, indirect or consequential damages or any damages
|
||||
* whatsoever resulting from loss of use, data or profits, whether
|
||||
* in an action of contract, negligence or other tortious action,
|
||||
* arising out of or in connection with the use or performance of
|
||||
* this software.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdarg.h>
|
||||
#include "io.h"
|
||||
#include "forth.h"
|
||||
|
||||
#define OKPROMPT "Ok\n> "
|
||||
#define ERRPROMPT "> "
|
||||
#define COMPILEPROMPT ": "
|
||||
|
||||
value_t defbuf [DEFSZ];
|
||||
value_t *defptr;
|
||||
|
||||
value_t *execstack [NESTSZ];
|
||||
value_t *execptr;
|
||||
int execcnt;
|
||||
|
||||
struct loop loopstack [LOOPSZ];
|
||||
struct loop *loopptr;
|
||||
|
||||
union memory memory;
|
||||
integer_t here = 0;
|
||||
integer_t lowmem;
|
||||
|
||||
integer_t stack [STACKSZ];
|
||||
integer_t *stackptr;
|
||||
|
||||
jmp_buf errjmp;
|
||||
|
||||
ident_t dict [DICTSZ];
|
||||
ident_t *dictptr;
|
||||
ident_t *lowdictptr;
|
||||
|
||||
int outstack [OUTSZ];
|
||||
int outptr;
|
||||
int instack [INSZ];
|
||||
int inptr;
|
||||
|
||||
integer_t compindex;
|
||||
integer_t baseindex;
|
||||
integer_t spanindex;
|
||||
integer_t hldindex;
|
||||
|
||||
int tty;
|
||||
int debug;
|
||||
int boln;
|
||||
int errorflag;
|
||||
|
||||
value_t _x;
|
||||
|
||||
void forthresume (int clrflag)
|
||||
{
|
||||
errorflag = 1;
|
||||
if (clrflag)
|
||||
stackptr = stack;
|
||||
longjmp (errjmp, 1);
|
||||
}
|
||||
|
||||
void error (char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start (ap, fmt);
|
||||
vprintf (fmt, ap);
|
||||
va_end (ap);
|
||||
printf ("\n");
|
||||
forthresume (1);
|
||||
}
|
||||
|
||||
void usage ()
|
||||
{
|
||||
printf ("Usage: forth [-d] [files...]\n");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
void initdict ()
|
||||
{
|
||||
struct table *t;
|
||||
ident_t *w;
|
||||
|
||||
dictptr = dict;
|
||||
for (t=func_table; t->name; ++t, ++dictptr) {
|
||||
strncpy (dictptr->name, t->name, NAMESZ);
|
||||
dictptr->name [NAMESZ-1] = 0;
|
||||
dictptr->type = t->type;
|
||||
dictptr->val.p = t->func;
|
||||
dictptr->immed = t->immed;
|
||||
}
|
||||
|
||||
w = enter ("bl");
|
||||
++dictptr;
|
||||
w->type = FGENINT;
|
||||
w->val.i = ' ';
|
||||
|
||||
w = enter ("pad");
|
||||
++dictptr;
|
||||
w->type = FGENINT;
|
||||
w->val.i = pad;
|
||||
|
||||
lowmem = here;
|
||||
|
||||
compindex = alloc ((integer_t) 1);
|
||||
w = enter ("state");
|
||||
++dictptr;
|
||||
w->type = FGENINT;
|
||||
w->val.i = compindex;
|
||||
|
||||
baseindex = alloc ((integer_t) 1);
|
||||
w = enter ("base");
|
||||
++dictptr;
|
||||
w->type = FGENINT;
|
||||
w->val.i = baseindex;
|
||||
|
||||
spanindex = alloc ((integer_t) 1);
|
||||
w = enter ("span");
|
||||
++dictptr;
|
||||
w->type = FGENINT;
|
||||
w->val.i = spanindex;
|
||||
|
||||
hldindex = alloc ((integer_t) 1);
|
||||
w = enter ("hld");
|
||||
++dictptr;
|
||||
w->type = FGENINT;
|
||||
w->val.i = hldindex;
|
||||
|
||||
lowdictptr = dictptr;
|
||||
}
|
||||
|
||||
void scompile (ident_t *w)
|
||||
{
|
||||
(defptr++)->i = w->type;
|
||||
switch (w->type) {
|
||||
case FGENINT:
|
||||
case FGENFLT:
|
||||
case FSUBR:
|
||||
case FHARDWARE:
|
||||
*defptr++ = w->val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void sexecute (ident_t *w)
|
||||
{
|
||||
if (w >= dictptr)
|
||||
error ("bad execute");
|
||||
switch (w->type) {
|
||||
case FGENINT:
|
||||
push (w->val.i);
|
||||
break;
|
||||
case FGENFLT:
|
||||
fpush (w->val.r);
|
||||
break;
|
||||
case FSUBR:
|
||||
execute (w->val.v);
|
||||
break;
|
||||
case FHARDWARE:
|
||||
(*w->val.p) ();
|
||||
break;
|
||||
default:
|
||||
error ("%s ?", w->name);
|
||||
}
|
||||
}
|
||||
|
||||
int valsize (value_t *a)
|
||||
{
|
||||
switch (a->i) {
|
||||
default: return (1);
|
||||
case FGENINT:
|
||||
case FGENFLT:
|
||||
case FSUBR:
|
||||
case FHARDWARE: return (2);
|
||||
case FSTRING:
|
||||
case FCSTRING:
|
||||
case FQUOTE: return (3 + a[1].i / sizeof (value_t));
|
||||
}
|
||||
}
|
||||
|
||||
void run ()
|
||||
{
|
||||
int count;
|
||||
integer_t c;
|
||||
char *p;
|
||||
|
||||
while (execptr) {
|
||||
switch ((execptr++)->i) {
|
||||
case FGENINT:
|
||||
push ((execptr++)->i);
|
||||
continue;
|
||||
case FGENFLT:
|
||||
fpush ((execptr++)->r);
|
||||
continue;
|
||||
case FSUBR:
|
||||
execute ((execptr++)->v);
|
||||
continue;
|
||||
case FHARDWARE:
|
||||
(*(execptr++)->p) ();
|
||||
continue;
|
||||
case FSTRING:
|
||||
case FCSTRING:
|
||||
c = (execptr++)->i;
|
||||
p = (char*) execptr++;
|
||||
execptr += c / sizeof (value_t);
|
||||
for (; *p; ++p)
|
||||
putc (*p, stdout);
|
||||
break;
|
||||
case FQUOTE:
|
||||
c = (execptr++)->i;
|
||||
p = (char*) execptr++;
|
||||
execptr += c / sizeof (value_t);
|
||||
push (c = here);
|
||||
while (*p)
|
||||
STOREBYTE (c++, *p++);
|
||||
STOREBYTE (c, 0);
|
||||
break;
|
||||
case FCONDIF:
|
||||
if (pop ())
|
||||
continue;
|
||||
for (count=0; execptr->i; execptr+=valsize(execptr))
|
||||
if (execptr->i == FCONDIF)
|
||||
++count;
|
||||
else if (execptr->i == FCONDTHEN) {
|
||||
if (--count < 0) {
|
||||
++execptr;
|
||||
break;
|
||||
}
|
||||
} else if (execptr->i == FCONDELSE)
|
||||
if (count <= 0) {
|
||||
++execptr;
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
case FCONDELSE:
|
||||
for (count=0; execptr->i; execptr+=valsize(execptr))
|
||||
if (execptr->i == FCONDIF)
|
||||
++count;
|
||||
else if (execptr->i == FCONDTHEN)
|
||||
if (--count < 0) {
|
||||
++execptr;
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
case FUNTIL:
|
||||
if (loopptr <= loopstack)
|
||||
error ("until but no begin");
|
||||
if (loopptr[-1].type != FBEGIN)
|
||||
error ("bad until");
|
||||
if (pop ()) {
|
||||
--loopptr;
|
||||
continue;
|
||||
}
|
||||
execptr = loopptr[-1].ptr;
|
||||
continue;
|
||||
case FREPEAT:
|
||||
if (loopptr <= loopstack)
|
||||
error ("repeat but no begin");
|
||||
if (loopptr[-1].type != FBEGIN)
|
||||
error ("bad repeat");
|
||||
execptr = loopptr[-1].ptr;
|
||||
continue;
|
||||
case FWHILE:
|
||||
if (pop ())
|
||||
continue;
|
||||
for (count=0; execptr->i; execptr+=valsize(execptr))
|
||||
if (execptr->i == FBEGIN)
|
||||
++count;
|
||||
else if (execptr->i==FUNTIL || execptr->i==FREPEAT)
|
||||
if (--count < 0) {
|
||||
++execptr;
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
case FLEAVE:
|
||||
if (loopptr <= loopstack)
|
||||
error ("bad leave");
|
||||
leave: for (count=0; execptr->i; execptr+=valsize (execptr))
|
||||
if (execptr->i==FBEGIN || execptr->i==FDO || execptr->i==FIFDO)
|
||||
++count;
|
||||
else if (execptr->i==FUNTIL || execptr->i==FREPEAT ||
|
||||
execptr->i==FLOOP || execptr->i==FPLOOP)
|
||||
if (--count < 0) {
|
||||
++execptr;
|
||||
break;
|
||||
}
|
||||
--loopptr;
|
||||
continue;
|
||||
case FDO:
|
||||
if (loopptr >= loopstack+LOOPSZ)
|
||||
error ("too deep do nesting");
|
||||
loopptr->cnt = loopptr->low = pop ();
|
||||
loopptr->up = pop ();
|
||||
loopptr->type = FDO;
|
||||
loopptr->ptr = execptr;
|
||||
++loopptr;
|
||||
continue;
|
||||
case FIFDO:
|
||||
if (loopptr >= loopstack+LOOPSZ)
|
||||
error ("too deep ?do nesting");
|
||||
loopptr->cnt = loopptr->low = pop ();
|
||||
loopptr->up = pop ();
|
||||
loopptr->type = FIFDO;
|
||||
loopptr->ptr = execptr;
|
||||
++loopptr;
|
||||
if (loopptr[-1].low == loopptr[-1].up)
|
||||
goto leave;
|
||||
continue;
|
||||
case FLOOP:
|
||||
if (loopptr <= loopstack)
|
||||
error ("bad loop");
|
||||
if (loopptr[-1].type != FDO && loopptr[-1].type != FIFDO)
|
||||
error ("invalid loop");
|
||||
++loopptr[-1].cnt;
|
||||
if (loopptr[-1].cnt >= loopptr[-1].up) {
|
||||
--loopptr;
|
||||
continue;
|
||||
}
|
||||
execptr = loopptr[-1].ptr;
|
||||
continue;
|
||||
case FPLOOP:
|
||||
if (loopptr <= loopstack)
|
||||
error ("bad +loop");
|
||||
if (loopptr[-1].type != FDO && loopptr[-1].type != FIFDO)
|
||||
error ("invalid loop");
|
||||
c = pop ();
|
||||
if ((c>0 && loopptr[-1].cnt<loopptr[-1].up &&
|
||||
loopptr[-1].cnt+c>=loopptr[-1].up) ||
|
||||
(c<0 && loopptr[-1].cnt>=loopptr[-1].up &&
|
||||
loopptr[-1].cnt+c<loopptr[-1].up))
|
||||
{
|
||||
--loopptr;
|
||||
continue;
|
||||
}
|
||||
loopptr[-1].cnt += c;
|
||||
execptr = loopptr[-1].ptr;
|
||||
continue;
|
||||
case FCOUNTI:
|
||||
if (loopptr <= loopstack)
|
||||
error ("bad i");
|
||||
push (loopptr[-1].cnt);
|
||||
continue;
|
||||
case FCOUNTJ:
|
||||
if (loopptr <= loopstack+1)
|
||||
error ("bad j");
|
||||
push (loopptr[-2].cnt);
|
||||
continue;
|
||||
case FCOUNTK:
|
||||
if (loopptr <= loopstack+2)
|
||||
error ("bad k");
|
||||
push (loopptr[-3].cnt);
|
||||
continue;
|
||||
case FBEGIN:
|
||||
if (loopptr >= loopstack+LOOPSZ)
|
||||
error ("too deep begin nesting");
|
||||
loopptr->type = FBEGIN;
|
||||
loopptr->ptr = execptr;
|
||||
++loopptr;
|
||||
continue;
|
||||
case FCONDTHEN:
|
||||
continue;
|
||||
case FEXIT:
|
||||
case 0:
|
||||
doexit: --execcnt;
|
||||
if (execcnt < 0)
|
||||
return;
|
||||
execptr = execstack [execcnt];
|
||||
continue;
|
||||
}
|
||||
}
|
||||
goto doexit;
|
||||
}
|
||||
|
||||
int symdigit (int c)
|
||||
{
|
||||
c &= 0377;
|
||||
switch (base) {
|
||||
case BINARY:
|
||||
switch (c) {
|
||||
case '0': return (0);
|
||||
case '1': return (1);
|
||||
}
|
||||
return (-1);
|
||||
case OCTAL:
|
||||
switch (c) {
|
||||
case '0': case '1': case '2': case '3': case '4': case '5':
|
||||
case '6': case '7':
|
||||
return (c - '0');
|
||||
}
|
||||
return (-1);
|
||||
case DECIMAL:
|
||||
switch (c) {
|
||||
case '0': case '1': case '2': case '3': case '4': case '5':
|
||||
case '6': case '7': case '8': case '9':
|
||||
return (c - '0');
|
||||
}
|
||||
return (-1);
|
||||
case HEX:
|
||||
switch (c) {
|
||||
case '0': case '1': case '2': case '3': case '4': case '5':
|
||||
case '6': case '7': case '8': case '9':
|
||||
return (c - '0');
|
||||
}
|
||||
switch (c) {
|
||||
case 'a': case 'A': return (10);
|
||||
case 'b': case 'B': return (11);
|
||||
case 'c': case 'C': return (12);
|
||||
case 'd': case 'D': return (13);
|
||||
case 'e': case 'E': return (14);
|
||||
case 'f': case 'F': return (15);
|
||||
}
|
||||
return (-1);
|
||||
}
|
||||
return (-1);
|
||||
}
|
||||
|
||||
int integ (char *s, integer_t *i)
|
||||
{
|
||||
integer_t c;
|
||||
int neg, d;
|
||||
|
||||
neg = (*s == '-');
|
||||
if (neg)
|
||||
++s;
|
||||
if (! *s)
|
||||
return (0);
|
||||
c = 0;
|
||||
while ((d = symdigit (*s)) >= 0) {
|
||||
c = c*base + d;
|
||||
++s;
|
||||
}
|
||||
if (*s)
|
||||
return (0);
|
||||
*i = neg ? -c : c;
|
||||
return (1);
|
||||
}
|
||||
|
||||
int realnum (char *s, real_t *r)
|
||||
{
|
||||
int d, e;
|
||||
int neg = 0, eneg = 0, ep = 0;
|
||||
real_t v;
|
||||
|
||||
if (*s == '-') {
|
||||
neg = 1;
|
||||
++s;
|
||||
}
|
||||
if (! *s)
|
||||
return (0);
|
||||
v = 0;
|
||||
while ((d = symdigit (*s)) >= 0) {
|
||||
v = v*base + d;
|
||||
++s;
|
||||
}
|
||||
if (*s=='.' || *s==',') {
|
||||
++s;
|
||||
while ((d = symdigit (*s)) >= 0) {
|
||||
v = v*base + d;
|
||||
++s;
|
||||
++ep;
|
||||
}
|
||||
}
|
||||
if (neg)
|
||||
v = -v;
|
||||
e = 0;
|
||||
if (*s=='e' || *s=='E') {
|
||||
++s;
|
||||
if (*s == '-') {
|
||||
eneg = 1;
|
||||
++s;
|
||||
}
|
||||
while ((d = symdigit (*s)) >= 0) {
|
||||
e = e*base + d;
|
||||
++s;
|
||||
}
|
||||
}
|
||||
if (*s)
|
||||
return (0);
|
||||
if (eneg)
|
||||
e = -e;
|
||||
e -= ep;
|
||||
if (e < 0) {
|
||||
while (++e <= 0)
|
||||
v /= base;
|
||||
} else {
|
||||
while (--e >= 0)
|
||||
v *= base;
|
||||
}
|
||||
*r = v;
|
||||
return (1);
|
||||
}
|
||||
|
||||
void forth ()
|
||||
{
|
||||
char *p;
|
||||
ident_t *w;
|
||||
integer_t i;
|
||||
real_t r;
|
||||
|
||||
tty = isatty (fileno (stdin));
|
||||
boln = 1;
|
||||
compilation = 0;
|
||||
base = DECIMAL;
|
||||
errorflag = 0;
|
||||
stackptr = stack;
|
||||
setjmp (errjmp);
|
||||
loopptr = loopstack;
|
||||
defptr = defbuf;
|
||||
execcnt = -1;
|
||||
if (inptr) {
|
||||
while (--inptr > 0)
|
||||
close (instack [inptr]);
|
||||
fclose (stdin);
|
||||
fdopen (instack [0], "r");
|
||||
}
|
||||
if (outptr) {
|
||||
while (--outptr > 0)
|
||||
close (outstack [inptr]);
|
||||
fclose (stdout);
|
||||
fdopen (outstack [0], "a");
|
||||
}
|
||||
for (;;) {
|
||||
if (! (p = getword (' ', 1)))
|
||||
return;
|
||||
errorflag = 0;
|
||||
w = find (p);
|
||||
if (w) {
|
||||
if (compilation && ! w->immed) {
|
||||
scompile (w);
|
||||
continue;
|
||||
}
|
||||
sexecute (w);
|
||||
if (execcnt >= 0)
|
||||
run ();
|
||||
continue;
|
||||
}
|
||||
if (integ (p, &i)) {
|
||||
if (compilation) {
|
||||
(defptr++)->i = FGENINT;
|
||||
(defptr++)->i = i;
|
||||
continue;
|
||||
}
|
||||
push (i);
|
||||
continue;
|
||||
}
|
||||
if (realnum (p, &r)) {
|
||||
if (compilation) {
|
||||
(defptr++)->i = FGENFLT;
|
||||
(defptr++)->r = r;
|
||||
continue;
|
||||
}
|
||||
fpush (r);
|
||||
continue;
|
||||
}
|
||||
error ("%s ?", p);
|
||||
}
|
||||
}
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
int fdin;
|
||||
|
||||
printf ("Portable Forth, Version 1.4\n");
|
||||
printf ("Copyright (C) 1990-2012 Serge Vakulenko\n\n");
|
||||
for (++argv, --argc; argc>0 && **argv=='-'; ++argv, --argc) {
|
||||
if (! strcmp ("-d", *argv))
|
||||
++debug;
|
||||
else
|
||||
usage ();
|
||||
}
|
||||
initdict ();
|
||||
fdin = dup (fileno (stdin));
|
||||
for (; argc>0; ++argv, --argc) {
|
||||
if (strcmp ("-", *argv) == 0) {
|
||||
fclose (stdin);
|
||||
fdopen (dup (fdin), "r");
|
||||
} else {
|
||||
FILE *fd = fopen (*argv, "r");
|
||||
if (! fd) {
|
||||
fprintf (stderr, "Cannot open %s\n", *argv);
|
||||
exit (1);
|
||||
}
|
||||
fclose (stdin);
|
||||
fdopen (dup (fileno (fd)), "r");
|
||||
fclose (fd);
|
||||
}
|
||||
forth ();
|
||||
}
|
||||
fclose (stdin);
|
||||
fdopen (dup (fdin), "r");
|
||||
close (fdin);
|
||||
forth ();
|
||||
return (0);
|
||||
}
|
||||
|
||||
char *getword (int delim, int contflag)
|
||||
{
|
||||
static char buf [256];
|
||||
char *p;
|
||||
int c;
|
||||
|
||||
if (! contflag && boln)
|
||||
return (0);
|
||||
p = buf;
|
||||
for (;;) {
|
||||
if (boln) {
|
||||
if (tty)
|
||||
printf (errorflag ? ERRPROMPT : compilation ?
|
||||
COMPILEPROMPT : OKPROMPT);
|
||||
boln = 0;
|
||||
}
|
||||
switch (c = getc (stdin)) {
|
||||
case -1:
|
||||
*p = 0;
|
||||
if (p <= buf) {
|
||||
if (inptr <= 0)
|
||||
return (0);
|
||||
fclose (stdin);
|
||||
fdopen (dup (instack [--inptr]), "r");
|
||||
close (instack [inptr]);
|
||||
tty = isatty (fileno (stdin));
|
||||
boln = 1;
|
||||
continue;
|
||||
}
|
||||
return (buf);
|
||||
case '\n':
|
||||
boln = 1;
|
||||
goto seedelim;
|
||||
case 0:
|
||||
c = delim;
|
||||
goto seedelim;
|
||||
case '\t':
|
||||
c = ' ';
|
||||
default:
|
||||
if (c == delim) {
|
||||
seedelim: *p = 0;
|
||||
if (contflag && p<=buf)
|
||||
continue;
|
||||
return (buf);
|
||||
}
|
||||
if (p < buf+sizeof(buf)-1)
|
||||
*p++ = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int stackerr (int i)
|
||||
{
|
||||
error (i ? "stack overflow" : "stack empty");
|
||||
return (0);
|
||||
}
|
||||
|
||||
integer_t alloc (integer_t n)
|
||||
{
|
||||
integer_t p;
|
||||
|
||||
here = (here + sizeof (value_t) - 1) / sizeof (value_t) * sizeof (value_t);
|
||||
n *= sizeof (value_t);
|
||||
if (here+n > MEMSZ)
|
||||
error ("memory overflow");
|
||||
p = here;
|
||||
here += n;
|
||||
return (p);
|
||||
}
|
||||
|
||||
integer_t allot (integer_t n)
|
||||
{
|
||||
integer_t p;
|
||||
|
||||
if (here+n > MEMSZ)
|
||||
error ("memory overflow");
|
||||
p = here;
|
||||
here += n;
|
||||
return (p);
|
||||
}
|
||||
|
||||
void execute (value_t *a)
|
||||
{
|
||||
if (execcnt >= 0) {
|
||||
if (execcnt >= NESTSZ)
|
||||
error ("too deep recursion");
|
||||
execstack [execcnt++] = execptr;
|
||||
execptr = a;
|
||||
} else {
|
||||
execptr = a;
|
||||
execcnt = 0;
|
||||
}
|
||||
}
|
||||
|
||||
ident_t *find (char *name)
|
||||
{
|
||||
ident_t *w;
|
||||
|
||||
for (w=dictptr-1; w>=dict; --w)
|
||||
if (name[0]==w->name[0] && !strcmp (name, w->name))
|
||||
return (w);
|
||||
return (0);
|
||||
}
|
||||
|
||||
ident_t *enter (char *name)
|
||||
{
|
||||
ident_t *w;
|
||||
|
||||
if (dictptr >= dict+DICTSZ)
|
||||
error ("dictionary overflow");
|
||||
w = dictptr;
|
||||
strncpy (w->name, name, NAMESZ);
|
||||
w->name [NAMESZ-1] = 0;
|
||||
w->type = 0;
|
||||
w->immed = 0;
|
||||
return (w);
|
||||
}
|
||||
|
||||
char *funcname (funcptr_t p, int type)
|
||||
{
|
||||
ident_t *w;
|
||||
|
||||
for (w=dictptr-1; w>=dict; --w)
|
||||
if (type==w->type && p==w->val.p)
|
||||
return (w->name);
|
||||
return ("???");
|
||||
}
|
||||
|
||||
void decompile (value_t *a)
|
||||
{
|
||||
char *p;
|
||||
int c;
|
||||
|
||||
for (; a->i; ++a) {
|
||||
switch (a->i) {
|
||||
case FSUBR:
|
||||
printf ("%s ", funcname ((++a)->p, FSUBR));
|
||||
continue;
|
||||
case FHARDWARE:
|
||||
printf ("%s ", funcname ((++a)->p, FHARDWARE));
|
||||
continue;
|
||||
case FQUOTE:
|
||||
printf ("\" ");
|
||||
goto decompstring;
|
||||
case FCSTRING:
|
||||
printf (".( ");
|
||||
c = (++a)->i;
|
||||
p = (char*) ++a;
|
||||
for (; *p; ++p)
|
||||
putc (*p, stdout);
|
||||
a += c / sizeof (value_t);
|
||||
printf (") ");
|
||||
continue;
|
||||
case FSTRING:
|
||||
printf (".\" ");
|
||||
decompstring: c = (++a)->i;
|
||||
p = (char*) ++a;
|
||||
for (; *p; ++p)
|
||||
putc (*p, stdout);
|
||||
a += c / sizeof (value_t);
|
||||
printf ("\" ");
|
||||
continue;
|
||||
case FGENINT: printf ("%ld ", (++a)->i); continue;
|
||||
case FGENFLT: printf ("%g ", (double) (++a)->r); continue;
|
||||
case FCONDIF: printf ("if "); continue;
|
||||
case FCONDELSE: printf ("else "); continue;
|
||||
case FUNTIL: printf ("until "); continue;
|
||||
case FREPEAT: printf ("repeat "); continue;
|
||||
case FWHILE: printf ("while "); continue;
|
||||
case FLEAVE: printf ("leave "); continue;
|
||||
case FDO: printf ("do "); continue;
|
||||
case FIFDO: printf ("?do "); continue;
|
||||
case FLOOP: printf ("loop "); continue;
|
||||
case FPLOOP: printf ("+loop "); continue;
|
||||
case FCOUNTI: printf ("i "); continue;
|
||||
case FCOUNTJ: printf ("j "); continue;
|
||||
case FCOUNTK: printf ("k "); continue;
|
||||
case FBEGIN: printf ("begin "); continue;
|
||||
case FCONDTHEN: printf ("then "); continue;
|
||||
case FEXIT: printf ("exit "); continue;
|
||||
default: printf ("?%ld ", a->i); continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
195
src/cmd/forth/forth.h
Normal file
195
src/cmd/forth/forth.h
Normal file
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Portable Forth interpreter.
|
||||
* Copyright (C) 1990-2012 Serge Vakulenko, <vak@cronyx.ru>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software
|
||||
* and its documentation for any purpose and without fee is hereby
|
||||
* granted, provided that the above copyright notice appear in all
|
||||
* copies and that both that the copyright notice and this
|
||||
* permission notice and warranty disclaimer appear in supporting
|
||||
* documentation, and that the name of the author not be used in
|
||||
* advertising or publicity pertaining to distribution of the
|
||||
* software without specific, written prior permission.
|
||||
*
|
||||
* The author disclaim all warranties with regard to this
|
||||
* software, including all implied warranties of merchantability
|
||||
* and fitness. In no event shall the author be liable for any
|
||||
* special, indirect or consequential damages or any damages
|
||||
* whatsoever resulting from loss of use, data or profits, whether
|
||||
* in an action of contract, negligence or other tortious action,
|
||||
* arising out of or in connection with the use or performance of
|
||||
* this software.
|
||||
*/
|
||||
#include <setjmp.h>
|
||||
|
||||
#define MEMSZ 4096 /* max size of allot'ated memory */
|
||||
#define DEFSZ 512 /* max size of compiled function */
|
||||
#define STACKSZ 256 /* max size of data stack */
|
||||
#define NAMESZ 32 /* max length of ident name */
|
||||
#define DICTSZ 256 /* max size of dictionary */
|
||||
#define NESTSZ 512 /* max depth of function calls nesting */
|
||||
#define LOOPSZ 32 /* max loop nesting */
|
||||
#define OUTSZ 8 /* max output file nesting */
|
||||
#define INSZ 8 /* max input file nesting */
|
||||
|
||||
/* types of idents */
|
||||
|
||||
#define FGENINT 1 /* constant */
|
||||
#define FGENFLT 2 /* float constant */
|
||||
#define FSUBR 3 /* compiled function */
|
||||
#define FHARDWARE 4 /* builtin function */
|
||||
#define FSTRING 5 /* ." */
|
||||
#define FCSTRING 6 /* .( */
|
||||
#define FQUOTE 7 /* " */
|
||||
#define FCQUOTE 8 /* ascii */
|
||||
/* */
|
||||
#define FREPEAT 10 /* repeat */
|
||||
#define FDO 11 /* do */
|
||||
#define FLOOP 12 /* loop */
|
||||
#define FPLOOP 13 /* +loop */
|
||||
#define FCONDIF 14 /* if */
|
||||
#define FCONDELSE 15 /* else */
|
||||
#define FCONDTHEN 16 /* then */
|
||||
#define FBEGIN 17 /* begin */
|
||||
#define FUNTIL 18 /* until */
|
||||
#define FWHILE 19 /* while */
|
||||
#define FCOUNTI 20 /* i */
|
||||
#define FCOUNTJ 21 /* j */
|
||||
#define FCOUNTK 22 /* k */
|
||||
#define FLEAVE 23 /* leave */
|
||||
#define FIFDO 24 /* ?do */
|
||||
#define FEXIT 25 /* exit */
|
||||
|
||||
#define FETCHWORD(a) (memory.v [(a) / sizeof(value_t)])
|
||||
#define STOREWORD(a,w) (memory.v [(a) / sizeof(value_t)] = (w))
|
||||
#define FETCHBYTE(a) ((int) (unsigned char) memory.c [a])
|
||||
#define STOREBYTE(a,w) (memory.c [a] = (w))
|
||||
|
||||
#define compilation FETCHWORD (compindex).i
|
||||
#define base FETCHWORD (baseindex).i
|
||||
#define span FETCHWORD (spanindex).i
|
||||
#define hld FETCHWORD (hldindex).i
|
||||
#define pad (MEMSZ-1)
|
||||
|
||||
#define push(i) ((stackptr < stack+STACKSZ) ? \
|
||||
*stackptr++ = (i) : stackerr (1))
|
||||
#define fpush(f) ((stackptr < stack+STACKSZ) ? \
|
||||
*stackptr++ = ftoi (f) : stackerr (1))
|
||||
|
||||
#define pop() ((stackptr > stack) ? *--stackptr : \
|
||||
(integer_t) stackerr (0))
|
||||
#define fpop() ((stackptr > stack) ? itof (*--stackptr) : \
|
||||
(real_t) stackerr (0))
|
||||
|
||||
/*
|
||||
* Size of integer_t must be equal to size of real_t.
|
||||
* All known machines have longs and floats of the same size,
|
||||
* so we will use these types.
|
||||
*/
|
||||
typedef long integer_t;
|
||||
typedef unsigned long uinteger_t;
|
||||
typedef float real_t;
|
||||
typedef void (*funcptr_t) (void);
|
||||
|
||||
typedef union value {
|
||||
integer_t i;
|
||||
real_t r;
|
||||
union value *v;
|
||||
funcptr_t p;
|
||||
} value_t;
|
||||
|
||||
typedef struct ident {
|
||||
int type;
|
||||
int immed;
|
||||
value_t val;
|
||||
char name [NAMESZ];
|
||||
} ident_t;
|
||||
|
||||
struct table {
|
||||
char *name;
|
||||
funcptr_t func;
|
||||
int type;
|
||||
int immed;
|
||||
};
|
||||
|
||||
struct loop {
|
||||
int type;
|
||||
integer_t cnt;
|
||||
integer_t low;
|
||||
integer_t up;
|
||||
value_t *ptr;
|
||||
};
|
||||
|
||||
union memory {
|
||||
char c [MEMSZ];
|
||||
value_t v [MEMSZ / sizeof(value_t)];
|
||||
};
|
||||
|
||||
enum {
|
||||
BINARY = 2,
|
||||
OCTAL = 8,
|
||||
DECIMAL = 10,
|
||||
HEX = 16,
|
||||
};
|
||||
|
||||
static inline integer_t ftoi (real_t z)
|
||||
{
|
||||
value_t x;
|
||||
|
||||
x.r = z;
|
||||
return x.i;
|
||||
}
|
||||
|
||||
static inline real_t itof (integer_t z)
|
||||
{
|
||||
value_t x;
|
||||
|
||||
x.i = z;
|
||||
return x.r;
|
||||
}
|
||||
|
||||
static inline value_t itov (integer_t z)
|
||||
{
|
||||
value_t x;
|
||||
|
||||
x.i = z;
|
||||
return x;
|
||||
}
|
||||
|
||||
extern ident_t dict [];
|
||||
extern ident_t *dictptr;
|
||||
extern ident_t *lowdictptr;
|
||||
extern jmp_buf errjmp;
|
||||
extern value_t defbuf [];
|
||||
extern value_t *defptr;
|
||||
extern union memory memory;
|
||||
extern integer_t here;
|
||||
extern integer_t lowmem;
|
||||
extern integer_t stack [];
|
||||
extern integer_t *stackptr;
|
||||
extern struct table func_table [];
|
||||
extern integer_t compindex;
|
||||
extern integer_t baseindex;
|
||||
extern integer_t spanindex;
|
||||
extern integer_t hldindex;
|
||||
extern int outstack [];
|
||||
extern int outptr;
|
||||
extern int instack [];
|
||||
extern int inptr;
|
||||
extern int tty;
|
||||
extern int boln;
|
||||
|
||||
extern value_t *execptr;
|
||||
extern int execcnt;
|
||||
|
||||
extern void error (char *fmt, ...);
|
||||
extern ident_t *find (char *name);
|
||||
extern ident_t *enter (char *name);
|
||||
extern char *getword (int delim, int contflag);
|
||||
extern integer_t allot (integer_t n);
|
||||
extern integer_t alloc (integer_t n);
|
||||
extern void sexecute (ident_t *w);
|
||||
extern void execute (value_t *a);
|
||||
extern int stackerr (int i);
|
||||
extern void forthresume (int clrflag);
|
||||
extern void decompile (value_t *a);
|
||||
2001
src/cmd/forth/func.c
Normal file
2001
src/cmd/forth/func.c
Normal file
File diff suppressed because it is too large
Load Diff
302
src/cmd/forth/func.txt
Normal file
302
src/cmd/forth/func.txt
Normal file
@@ -0,0 +1,302 @@
|
||||
Portable Forth interpreter.
|
||||
|
||||
Copyright (C) 1990-2012 Serge Vakulenko, <serge@vak.ru>
|
||||
|
||||
(
|
||||
Start a comment which is ended by a ")" or newline.
|
||||
\
|
||||
Start a comment to end of line.
|
||||
dup ( x -- x x )
|
||||
Duplicate the top item.
|
||||
?dup ( x -- x x )
|
||||
Duplicate the top item if nonzero.
|
||||
2dup ( x y -- x y x y )
|
||||
Duplicate the top two words.
|
||||
drop ( x -- )
|
||||
Drop the top of stack.
|
||||
2drop ( x y -- )
|
||||
Drop the top two items from the stack.
|
||||
over ( x y -- x y x )
|
||||
Copy second to top
|
||||
2over ( x y z w -- x y z w x y )
|
||||
Copy second to top
|
||||
rot ( x y z -- y z x )
|
||||
Move the third element to the top.
|
||||
2rot ( x x y y z z -- y y z z x x )
|
||||
Move the third element to the top.
|
||||
-rot ( y z x -- x y z )
|
||||
Move the top element to the third.
|
||||
swap ( x y -- y x )
|
||||
Exchange the top two items.
|
||||
2swap ( w x y z -- y z w x )
|
||||
Swap the top two words with the second-to-the-top two words.
|
||||
pick ( an, an-1, a0, n -- an, an-1, a0, an )
|
||||
Get the "n"th word on the opstack (zero-based, starting
|
||||
from the word below "n") to the top of stack.
|
||||
roll ( an, an-1, a0, n -- an-1, a0, an )
|
||||
Roll n words on the opstack (zero-based, starting
|
||||
from the word below "n").
|
||||
sempty
|
||||
Empty data stack.
|
||||
/, f/, *, f*, -, f-, +, f+ ( x y -- d )
|
||||
Return the result of the applied binary operation to the
|
||||
two arguments. Dividing by zero is undefined.
|
||||
mod ( x y -- r )
|
||||
Return the remainder of x/y. This is explicitly calculated
|
||||
as x-int(x/y)*x.
|
||||
/mod ( x y -- r d )
|
||||
Return x/y and the remainder of x/y.
|
||||
abs, fabs ( x -- |x| )
|
||||
Change sign of top of stack if it's negative
|
||||
negate, fnegate ( x -- -x )
|
||||
Replace top of stack with its negation.
|
||||
1+, 1-, 2+, 2-, 2*, 2/ ( x -- op(x) )
|
||||
Perform unary op.
|
||||
* / ( x y z -- w )
|
||||
Return x*y/z.
|
||||
* /mod ( x y z -- r w )
|
||||
Return x*y%z, x*y/z.
|
||||
true, false ( -- b )
|
||||
Push the boolean true and false values onto the stack. These
|
||||
values are used uniformly by all of forth.
|
||||
or, and, xor, not
|
||||
Bitwise OR and AND operations. These will work with "true"
|
||||
and "false" to provide logical functionality.
|
||||
=, f= ( x y -- b )
|
||||
Return whether x is equal to y.
|
||||
>, f> ( x y -- b )
|
||||
Return whether x is greater than y.
|
||||
<, f< ( x y -- b )
|
||||
Return whether x is less than y.
|
||||
u< ( x y -- b )
|
||||
Return whether unsigned x is less than unsigned y.
|
||||
max, fmax ( x y -- max(x,y) )
|
||||
Take the greater of the top two elements
|
||||
min, fmin (x y -- min(x,y) )
|
||||
Take the lesser of the top two elements
|
||||
i->f ( i -- f )
|
||||
Convert the integer_t "i" to the equivalent floating format "f".
|
||||
f->i ( f -- i )
|
||||
Convert the floating number "f" to the equivalent integer_t "i".
|
||||
Integer portions of "f" will be truncated; for details, refer to the
|
||||
"cvtfl" instruction in the VAX architecture handbook.
|
||||
f. ( f -- )
|
||||
Print the floating-point number.
|
||||
. ( i -- )
|
||||
Print the integer_t.
|
||||
.s ( -- )
|
||||
Print the stack.
|
||||
halt
|
||||
Exit back to OS.
|
||||
quit
|
||||
Start interpreting from the keyboard again,
|
||||
don't clean the data stack.
|
||||
:
|
||||
Start compilation mode for the next word in the stream.
|
||||
;
|
||||
End compilation mode, unsmudge the entry.
|
||||
immediate
|
||||
Set 'immediate' mode for last compiled word
|
||||
constant
|
||||
fconstant
|
||||
Like variable, but later references to this word return the
|
||||
numerical constant. Thus
|
||||
42 constant ascii_star
|
||||
ascii_star emit
|
||||
will print a star to the current output device.
|
||||
variable
|
||||
Take the next word and add it to the dictionary
|
||||
as a variable. Subsequent references to this name
|
||||
will return an address which is the word allocated
|
||||
to this variable. Uses such as
|
||||
variable foobar 400 allot
|
||||
will make "foobar" return the address of a 404-byte array
|
||||
(the initially allocated longword, 4 bytes, plus
|
||||
the allot'ed 400 bytes).
|
||||
create
|
||||
Take the next word and add it to the dictionary
|
||||
as a variable. Subsequent references to this name
|
||||
will return current value of 'here'.
|
||||
forget
|
||||
Take the next word and forget all words, defined later
|
||||
than given one. Depth is limited by 'freezedict'.
|
||||
empty
|
||||
Forget all words, defined after 'freezedict'.
|
||||
freezedict
|
||||
Update low margin of dictionary.
|
||||
All words, defined up to moment, would not be
|
||||
destroyed by 'forget'.
|
||||
here ( -- a )
|
||||
Push the address of the next open memory location in the
|
||||
dictionary to stack.
|
||||
allot ( d -- )
|
||||
Add "d" to HERE, effectively moving the bottom of the dictionary
|
||||
forward "d" bytes.
|
||||
alloc ( d -- )
|
||||
Alloc d words.
|
||||
align ( -- )
|
||||
Align 'here' on word boundary.
|
||||
@ ( a -- x )
|
||||
Fetch a word at address "a".
|
||||
! ( x a -- )
|
||||
Store a word at address "a".
|
||||
c@ ( a -- d)
|
||||
Fetch the byte quantity "d" from byte address "a".
|
||||
c! ( d a -- )
|
||||
Store the byte quantity "d" at byte address "a".
|
||||
fill ( a n d -- )
|
||||
Fill "n" bytes of memory starting at "a" with the value "d".
|
||||
type ( a n -- )
|
||||
Type string on stdout.
|
||||
expect ( a n -- )
|
||||
Read string from stdin.
|
||||
, ( d -- )
|
||||
Move the word "d" into the next open dictionary word,
|
||||
advancing HERE.
|
||||
c, ( d -- )
|
||||
As ",", but only a byte operation is done.
|
||||
allwords
|
||||
List all user defined words.
|
||||
words
|
||||
List words, defined after 'freezedict'.
|
||||
list
|
||||
Take the next word in the input stream as a name of word.
|
||||
If this word is user defined, print it's definition.
|
||||
fsqrt ( f -- s )
|
||||
Compute square root of f, both f and s are float.
|
||||
flog ( f -- s )
|
||||
Compute logarithm of f.
|
||||
fexp ( f -- s )
|
||||
Compute e to the f power.
|
||||
sin ( i -- s )
|
||||
"i" is a degree measure; "s" is sin(i)*10000.
|
||||
fsin ( f -- s )
|
||||
"f" is the radian measure; "s" is the sin() value.
|
||||
cos, fcos
|
||||
As sin, fsin, but for cos() values.
|
||||
tan, ftan
|
||||
As sin, fsin, but for tan() values.
|
||||
fasin ( s -- f )
|
||||
Compute asin(s) in radians (float).
|
||||
Return value is in range -pi/2..pi/2.
|
||||
facos
|
||||
As fasin, but for acos() values.
|
||||
Return value is in range 0..pi.
|
||||
fatan
|
||||
As fasin, but for atan() values.
|
||||
Return value is in range -pi/2..pi/2.
|
||||
fsinh ( f -- s )
|
||||
Compute hyperbolic sine function.
|
||||
fcosh
|
||||
As fsinh, but for cosh() values.
|
||||
ftanh
|
||||
As fsinh, but for tanh() values.
|
||||
key ( -- c )
|
||||
Read character from input stream.
|
||||
All characters codes are non-negative, -1 means EOF.
|
||||
emit ( c -- )
|
||||
Print the specified character to the current output unit.
|
||||
cr
|
||||
Print a newline sequence to the current output unit.
|
||||
space
|
||||
Print a space to the current output unit.
|
||||
spaces ( n -- )
|
||||
Print n spaces to the current output unit.
|
||||
outpop
|
||||
Close the current output file & start using the previous output
|
||||
file. This is a no-op if this is the first output file.
|
||||
output
|
||||
Take the next word in the input stream & try to open it
|
||||
for writing. If you can't, call "abort". Otherwise, make
|
||||
it the current output file, pushing the current output
|
||||
onto a stack so that a later "outpop" will close
|
||||
this file & continue with the old one.
|
||||
input
|
||||
As output, but open for reading. There is no corresponding
|
||||
"inpop", as EOF status will cause the equivalent action.
|
||||
count ( a -- a n )
|
||||
Count characters in string a.
|
||||
word ( c -- a )
|
||||
Input word to delimiter c, placing it 'here'. Return address
|
||||
of 'here'.
|
||||
<#
|
||||
Begin format processing, set 'hld' to 'pad'.
|
||||
hold ( c -- )
|
||||
Add character to pad.
|
||||
# ( x -- x/base )
|
||||
Add remainder as a character to format string.
|
||||
#s ( x -- 0 )
|
||||
Add ascii representation of unsigned value
|
||||
to format string. If value is zero, add '0'.
|
||||
sign ( x -- )
|
||||
Add minus to format string if value is negative.
|
||||
#> ( x -- a n )
|
||||
Close format processing, return address and length.
|
||||
.(
|
||||
Print the string immediately (in interpretive mode) or compile
|
||||
code which will print the string (in compilation mode).
|
||||
."
|
||||
Print the string immediately (in interpretive mode) or compile
|
||||
code which will print the string (in compilation mode).
|
||||
"
|
||||
Place string in data area. 'Here' will point on it.
|
||||
ascii ( -- c )
|
||||
Get the next word and push in stack the ascii value
|
||||
of the first character.
|
||||
ncompile ( n -- )
|
||||
Get the integer_t value from stack and compile the code
|
||||
generating that value.
|
||||
fcompile ( f -- )
|
||||
Get the float value from stack and compile the code
|
||||
generating that value.
|
||||
compile xxx ( -- )
|
||||
Compile the code for executing given symbol.
|
||||
execute ( i -- )
|
||||
Get the index of symbol from stack and execute it.
|
||||
latest ( -- i )
|
||||
Push in stack the index of current symbol under definition.
|
||||
find ( a -- i )
|
||||
Stack contains the address of string with the name of symbol.
|
||||
Find this symbol in dictionary and return it's index.
|
||||
base
|
||||
A variable which holds the current base.
|
||||
bl
|
||||
A constant which holds the code for blank character.
|
||||
hld
|
||||
A variable which holds the address of pad.
|
||||
pad
|
||||
A constant which holds the end address of memory.
|
||||
state
|
||||
A variable which holds the current state; 0 = interpreting,
|
||||
non-0 means compiling.
|
||||
if ... [ else ] ... endif
|
||||
The conditional structure. Note "endif", not "then".
|
||||
'endif' is equivalent to 'then'.
|
||||
begin ... again
|
||||
Unconditional looping structure.
|
||||
'again' is equivalent to 'repeat'.
|
||||
begin ... until
|
||||
Conditional looping--will loop until the "until" receives a
|
||||
boolean "true" on the stack.
|
||||
begin ... while ... repeat
|
||||
Looping structure where the test is at the "while" word.
|
||||
do ... loop
|
||||
Counting loop.
|
||||
do ... +loop
|
||||
As do...loop, but +loop takes the amount to increment by.
|
||||
?do
|
||||
The same as do, but does not execute loop if upper and lower
|
||||
bounds are aqual.
|
||||
leave
|
||||
Causes the innermost loop to reach its exit condition. The
|
||||
next execution of "loop" or "+loop" will fall through.
|
||||
i, j, k
|
||||
The loop indices of (respectively) the innermost, second, and
|
||||
third loops.
|
||||
myself
|
||||
recurse
|
||||
Compile address of function under definition.
|
||||
Results in calling function by itself.
|
||||
For example,
|
||||
: hihi ." Hi! " recurse ;
|
||||
calls itself indefinitely.
|
||||
114
src/cmd/forth/io.h
Normal file
114
src/cmd/forth/io.h
Normal file
@@ -0,0 +1,114 @@
|
||||
#if 0
|
||||
/*
|
||||
* Use standard I/O library.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#else
|
||||
/*
|
||||
* Use internal I/O library.
|
||||
*/
|
||||
#include <stdarg.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
typedef int FILE;
|
||||
|
||||
#define stdin ((FILE*) 0)
|
||||
#define stdout ((FILE*) 1)
|
||||
#define stderr ((FILE*) 2)
|
||||
|
||||
static inline int fileno (FILE *stream)
|
||||
{
|
||||
return (int) stream;
|
||||
}
|
||||
|
||||
static inline FILE *fopen (const char *path, const char *mode)
|
||||
{
|
||||
int fd, flags;
|
||||
|
||||
if (mode[0] == 'w')
|
||||
flags = O_WRONLY;
|
||||
else if (mode[0] == 'a')
|
||||
flags = O_WRONLY | O_APPEND | O_CREAT;
|
||||
else if (mode[0] == 'r' && mode[1] == '+')
|
||||
flags = O_RDWR | O_CREAT;
|
||||
else
|
||||
flags = O_RDONLY;
|
||||
|
||||
fd = open (path, flags, 0664);
|
||||
if (fd < 0)
|
||||
return 0;
|
||||
return (FILE*) fd;
|
||||
}
|
||||
|
||||
static inline FILE *fdopen (int fildes, const char *mode)
|
||||
{
|
||||
if (fildes < 0)
|
||||
return 0;
|
||||
return (FILE*) fildes;
|
||||
}
|
||||
|
||||
static inline int fclose (FILE *stream)
|
||||
{
|
||||
return close ((int) stream);
|
||||
}
|
||||
|
||||
extern int vsprintf (char *s, const char *format, va_list ap);
|
||||
|
||||
static inline int vfprintf (FILE *stream, const char *format, va_list ap)
|
||||
{
|
||||
int len;
|
||||
char str[160];
|
||||
|
||||
vsprintf (str, format, ap);
|
||||
len = strlen (str);
|
||||
if (len > 0) {
|
||||
write ((int) stream, str, len);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
static inline int vprintf (const char *format, va_list ap)
|
||||
{
|
||||
return vfprintf (stdout, format, ap);
|
||||
}
|
||||
|
||||
static inline int fprintf (FILE *stream, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int ret;
|
||||
|
||||
va_start (ap, format);
|
||||
ret = vfprintf (stream, format, ap);
|
||||
va_end (ap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int printf (const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int ret;
|
||||
|
||||
va_start (ap, format);
|
||||
ret = vfprintf (stdout, format, ap);
|
||||
va_end (ap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int putc (int c, FILE *stream)
|
||||
{
|
||||
unsigned char sym = c;
|
||||
|
||||
if (write ((int) stream, &sym, 1) < 0)
|
||||
return -1;
|
||||
return c;
|
||||
}
|
||||
|
||||
static inline int getc (FILE *stream)
|
||||
{
|
||||
unsigned char sym;
|
||||
|
||||
if (read ((int) stream, &sym, 1) != 1)
|
||||
return -1;
|
||||
return sym;
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user