/* Gforth virtual machine (aka inner interpreter) Copyright (C) 1995,1996,1997,1998,2000 Free Software Foundation, Inc. This file is part of Gforth. Gforth is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. */ #include "config.h" #include #include #include #include #include #include #include #include "forth.h" #include "io.h" #include "threaded.h" #ifndef STANDALONE #include #include #include #include #include #include #include #include #include #ifdef HAVE_FNMATCH_H #include #else #include "fnmatch.h" #endif #else #include "systypes.h" #endif #if defined(HAVE_LIBDL) || defined(HAVE_DLOPEN) /* what else? */ #include #endif #if defined(_WIN32) #include #endif #ifdef hpux #include #endif #ifndef SEEK_SET /* should be defined in stdio.h, but some systems don't have it */ #define SEEK_SET 0 #endif #define IOR(flag) ((flag)? -512-errno : 0) struct F83Name { struct F83Name *next; /* the link field for old hands */ char countetc; char name[0]; }; #define F83NAME_COUNT(np) ((np)->countetc & 0x1f) struct Longname { struct Longname *next; /* the link field for old hands */ Cell countetc; char name[0]; }; #define LONGNAME_COUNT(np) ((np)->countetc & (((~((UCell)0))<<3)>>3)) Cell *SP; Float *FP; Address UP=NULL; #if 0 /* not used currently */ int emitcounter; #endif #define NULLC '\0' #ifdef MEMCMP_AS_SUBROUTINE extern int gforth_memcmp(const char * s1, const char * s2, size_t n); #define memcmp(s1,s2,n) gforth_memcmp(s1,s2,n) #endif #ifdef HAS_FILE char *cstr(Char *from, UCell size, int clear) /* return a C-string corresponding to the Forth string ( FROM SIZE ). the C-string lives until the next call of cstr with CLEAR being true */ { static struct cstr_buffer { char *buffer; size_t size; } *buffers=NULL; static int nbuffers=0; static int used=0; struct cstr_buffer *b; if (buffers==NULL) buffers=malloc(0); if (clear) used=0; if (used>=nbuffers) { buffers=realloc(buffers,sizeof(struct cstr_buffer)*(used+1)); buffers[used]=(struct cstr_buffer){malloc(0),0}; nbuffers=used+1; } b=&buffers[used]; if (size+1 > b->size) { b->buffer = realloc(b->buffer,size+1); b->size = size+1; } memcpy(b->buffer,from,size); b->buffer[size]='\0'; used++; return b->buffer; } char *tilde_cstr(Char *from, UCell size, int clear) /* like cstr(), but perform tilde expansion on the string */ { char *s1,*s2; int s1_len, s2_len; struct passwd *getpwnam (), *user_entry; if (size<1 || from[0]!='~') return cstr(from, size, clear); if (size<2 || from[1]=='/') { s1 = (char *)getenv ("HOME"); if(s1 == NULL) s1 = ""; s2 = from+1; s2_len = size-1; } else { UCell i; for (i=1; ipw_dir; s2 = from+i; s2_len = size-i; } s1_len = strlen(s1); if (s1_len>1 && s1[s1_len-1]=='/') s1_len--; { char path[s1_len+s2_len]; memcpy(path,s1,s1_len); memcpy(path+s1_len,s2,s2_len); return cstr(path,s1_len+s2_len,clear); } } #endif DCell timeval2us(struct timeval *tvp) { #ifndef BUGGY_LONG_LONG return (tvp->tv_sec*(DCell)1000000)+tvp->tv_usec; #else DCell d2; DCell d1=mmul(tvp->tv_sec,1000000); d2.lo = d1.lo+tvp->tv_usec; d2.hi = d1.hi + (d2.lo=MAX_SYMBOLS) { fprintf(stderr,"gforth-ditc: more than %d primitives\n",MAX_SYMBOLS); exit(1); } symbols[i] = &routines[i]; } #endif /* defined(DOUBLY_INDIRECT) */ return symbols; } IF_spTOS(spTOS = sp[0]); IF_fpTOS(fpTOS = fp[0]); /* prep_terminal(); */ SET_IP(ip); NEXT; #ifdef CPU_DEP3 CPU_DEP3 #endif docol: { DOCFA; #ifdef DEBUG fprintf(stderr,"%08lx: col: %08lx\n",(Cell)ip,(Cell)PFA1(cfa)); #endif #ifdef CISC_NEXT /* this is the simple version */ *--rp = (Cell)ip; SET_IP((Xt *)PFA1(cfa)); NEXT; #else /* this one is important, so we help the compiler optimizing */ { DEF_CA rp[-1] = (Cell)ip; SET_IP((Xt *)PFA1(cfa)); NEXT_P1; rp--; NEXT_P2; } #endif } docon: { DOCFA; #ifdef DEBUG fprintf(stderr,"%08lx: con: %08lx\n",(Cell)ip,*(Cell*)PFA1(cfa)); #endif #ifdef USE_TOS *sp-- = spTOS; spTOS = *(Cell *)PFA1(cfa); #else *--sp = *(Cell *)PFA1(cfa); #endif } NEXT_P0; NEXT; dovar: { DOCFA; #ifdef DEBUG fprintf(stderr,"%08lx: var: %08lx\n",(Cell)ip,(Cell)PFA1(cfa)); #endif #ifdef USE_TOS *sp-- = spTOS; spTOS = (Cell)PFA1(cfa); #else *--sp = (Cell)PFA1(cfa); #endif } NEXT_P0; NEXT; douser: { DOCFA; #ifdef DEBUG fprintf(stderr,"%08lx: user: %08lx\n",(Cell)ip,(Cell)PFA1(cfa)); #endif #ifdef USE_TOS *sp-- = spTOS; spTOS = (Cell)(up+*(Cell*)PFA1(cfa)); #else *--sp = (Cell)(up+*(Cell*)PFA1(cfa)); #endif } NEXT_P0; NEXT; dodefer: { DOCFA; #ifdef DEBUG fprintf(stderr,"%08lx: defer: %08lx\n",(Cell)ip,*(Cell*)PFA1(cfa)); #endif EXEC(*(Xt *)PFA1(cfa)); } dofield: { DOCFA; #ifdef DEBUG fprintf(stderr,"%08lx: field: %08lx\n",(Cell)ip,(Cell)PFA1(cfa)); #endif spTOS += *(Cell*)PFA1(cfa); } NEXT_P0; NEXT; dodoes: /* this assumes the following structure: defining-word: ... DOES> (possible padding) possibly handler: jmp dodoes (possible branch delay slot(s)) Forth code after DOES> defined word: cfa: address of or jump to handler OR address of or jump to dodoes, address of DOES-code pfa: */ { DOCFA; /* fprintf(stderr, "Got CFA %08lx at doescode %08lx/%08lx: does: %08lx\n",cfa,(Cell)ip,(Cell)PFA(cfa),(Cell)DOES_CODE1(cfa));*/ #ifdef DEBUG fprintf(stderr,"%08lx/%08lx: does: %08lx\n",(Cell)ip,(Cell)PFA(cfa),(Cell)DOES_CODE1(cfa)); fflush(stderr); #endif *--rp = (Cell)ip; /* PFA1 might collide with DOES_CODE1 here, so we use PFA */ #ifdef USE_TOS *sp-- = spTOS; spTOS = (Cell)PFA(cfa); #else *--sp = (Cell)PFA(cfa); #endif SET_IP(DOES_CODE1(cfa)); /* fprintf(stderr,"TOS = %08lx, IP=%08lx\n", spTOS, IP);*/ } NEXT; #include "prim.i" }