1: /* Gforth virtual machine (aka inner interpreter)
2:
3: Copyright (C) 1995 Free Software Foundation, Inc.
4:
5: This file is part of Gforth.
6:
7: Gforth is free software; you can redistribute it and/or
8: modify it under the terms of the GNU General Public License
9: as published by the Free Software Foundation; either version 2
10: of the License, or (at your option) any later version.
11:
12: This program is distributed in the hope that it will be useful,
13: but WITHOUT ANY WARRANTY; without even the implied warranty of
14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15: GNU General Public License for more details.
16:
17: You should have received a copy of the GNU General Public License
18: along with this program; if not, write to the Free Software
19: Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20: */
21:
22: #include "config.h"
23: #include <ctype.h>
24: #include <stdio.h>
25: #include <string.h>
26: #include <math.h>
27: #include <sys/types.h>
28: #include <sys/stat.h>
29: #include <fcntl.h>
30: #include <assert.h>
31: #include <stdlib.h>
32: #include <time.h>
33: #include <sys/time.h>
34: #include <unistd.h>
35: #include <errno.h>
36: #include <pwd.h>
37: #include "forth.h"
38: #include "io.h"
39: #include "threading.h"
40:
41: #ifndef SEEK_SET
42: /* should be defined in stdio.h, but some systems don't have it */
43: #define SEEK_SET 0
44: #endif
45:
46: #define IOR(flag) ((flag)? -512-errno : 0)
47:
48: typedef struct F83Name {
49: struct F83Name *next; /* the link field for old hands */
50: char countetc;
51: Char name[0];
52: } F83Name;
53:
54: /* are macros for setting necessary? */
55: #define F83NAME_COUNT(np) ((np)->countetc & 0x1f)
56: #define F83NAME_SMUDGE(np) (((np)->countetc & 0x40) != 0)
57: #define F83NAME_IMMEDIATE(np) (((np)->countetc & 0x20) != 0)
58:
59: Cell *SP;
60: Float *FP;
61: #if 0
62: /* not used currently */
63: int emitcounter;
64: #endif
65: #define NULLC '\0'
66:
67: char *cstr(Char *from, UCell size, int clear)
68: /* return a C-string corresponding to the Forth string ( FROM SIZE ).
69: the C-string lives until the next call of cstr with CLEAR being true */
70: {
71: static struct cstr_buffer {
72: char *buffer;
73: size_t size;
74: } *buffers=NULL;
75: static int nbuffers=0;
76: static int used=0;
77: struct cstr_buffer *b;
78:
79: if (buffers==NULL)
80: buffers=malloc(0);
81: if (clear)
82: used=0;
83: if (used>=nbuffers) {
84: buffers=realloc(buffers,sizeof(struct cstr_buffer)*(used+1));
85: buffers[used]=(struct cstr_buffer){malloc(0),0};
86: nbuffers=used+1;
87: }
88: b=&buffers[used];
89: if (size+1 > b->size) {
90: b->buffer = realloc(b->buffer,size+1);
91: b->size = size+1;
92: }
93: memcpy(b->buffer,from,size);
94: b->buffer[size]='\0';
95: used++;
96: return b->buffer;
97: }
98:
99: char *tilde_cstr(Char *from, UCell size, int clear)
100: /* like cstr(), but perform tilde expansion on the string */
101: {
102: char *s1,*s2;
103: int s1_len, s2_len;
104: struct passwd *getpwnam (), *user_entry;
105:
106: if (size<1 || from[0]!='~')
107: return cstr(from, size, clear);
108: if (size<2 || from[1]=='/') {
109: s1 = (char *)getenv ("HOME");
110: s2 = from+1;
111: s2_len = size-1;
112: } else {
113: UCell i;
114: for (i=1; i<size && from[i]!='/'; i++)
115: ;
116: {
117: char user[i];
118: memcpy(user,from+1,i-1);
119: user[i-1]='\0';
120: user_entry=getpwnam(user);
121: }
122: if (user_entry==NULL)
123: return cstr(from, size, clear);
124: s1 = user_entry->pw_dir;
125: s2 = from+i;
126: s2_len = size-i;
127: }
128: s1_len = strlen(s1);
129: if (s1_len>1 && s1[s1_len-1]=='/')
130: s1_len--;
131: {
132: char path[s1_len+s2_len];
133: memcpy(path,s1,s1_len);
134: memcpy(path+s1_len,s2,s2_len);
135: return cstr(path,s1_len+s2_len,clear);
136: }
137: }
138:
139:
140: #define NEWLINE '\n'
141:
142: #ifndef HAVE_RINT
143: #define rint(x) floor((x)+0.5)
144: #endif
145:
146: static char* fileattr[6]={"r","rb","r+","r+b","w","wb"};
147:
148: static Address up0=NULL;
149:
150: /* if machine.h has not defined explicit registers, define them as implicit */
151: #ifndef IPREG
152: #define IPREG
153: #endif
154: #ifndef SPREG
155: #define SPREG
156: #endif
157: #ifndef RPREG
158: #define RPREG
159: #endif
160: #ifndef FPREG
161: #define FPREG
162: #endif
163: #ifndef LPREG
164: #define LPREG
165: #endif
166: #ifndef CFAREG
167: #define CFAREG
168: #endif
169: #ifndef UPREG
170: #define UPREG
171: #endif
172: #ifndef TOSREG
173: #define TOSREG
174: #endif
175: #ifndef FTOSREG
176: #define FTOSREG
177: #endif
178:
179: /* declare and compute cfa for certain threading variants */
180: /* warning: this is nonsyntactical; it will not work in place of a statement */
181: #ifdef CFA_NEXT
182: #define DOCFA
183: #else
184: #define DOCFA Xt cfa; GETCFA(cfa)
185: #endif
186:
187: Label *engine(Xt *ip0, Cell *sp0, Cell *rp0, Float *fp0, Address lp0)
188: /* executes code at ip, if ip!=NULL
189: returns array of machine code labels (for use in a loader), if ip==NULL
190: */
191: {
192: register Xt *ip IPREG = ip0;
193: register Cell *sp SPREG = sp0;
194: register Cell *rp RPREG = rp0;
195: register Float *fp FPREG = fp0;
196: register Address lp LPREG = lp0;
197: #ifdef CFA_NEXT
198: register Xt cfa CFAREG;
199: #endif
200: register Address up UPREG = up0;
201: IF_TOS(register Cell TOS TOSREG;)
202: IF_FTOS(register Float FTOS FTOSREG;)
203: static Label symbols[]= {
204: &&docol,
205: &&docon,
206: &&dovar,
207: &&douser,
208: &&dodefer,
209: &&dofield,
210: &&dodoes,
211: /* the following entry is normally unused;
212: it's there because its index indicates a does-handler */
213: #ifdef CPU_DEP1
214: CPU_DEP1,
215: #else
216: (Label)0,
217: #endif
218: #include "prim_labels.i"
219: (Label)0
220: };
221: #ifdef CPU_DEP2
222: CPU_DEP2
223: #endif
224:
225: #ifdef DEBUG
226: fprintf(stderr,"ip=%x, sp=%x, rp=%x, fp=%x, lp=%x, up=%x\n",
227: (unsigned)ip,(unsigned)sp,(unsigned)rp,
228: (unsigned)fp,(unsigned)lp,(unsigned)up);
229: #endif
230:
231: if (ip == NULL)
232: return symbols;
233:
234: IF_TOS(TOS = sp[0]);
235: IF_FTOS(FTOS = fp[0]);
236: /* prep_terminal(); */
237: NEXT_P0;
238: NEXT;
239:
240: #ifdef CPU_DEP3
241: CPU_DEP3
242: #endif
243:
244: docol:
245: {
246: DOCFA;
247: #ifdef DEBUG
248: fprintf(stderr,"%08lx: col: %08lx\n",(Cell)ip,(Cell)PFA1(cfa));
249: #endif
250: #ifdef CISC_NEXT
251: /* this is the simple version */
252: *--rp = (Cell)ip;
253: ip = (Xt *)PFA1(cfa);
254: NEXT_P0;
255: NEXT;
256: #else
257: /* this one is important, so we help the compiler optimizing
258: The following version may be better (for scheduling), but probably has
259: problems with code fields employing calls and delay slots
260: */
261: {
262: DEF_CA
263: Xt *current_ip = (Xt *)PFA1(cfa);
264: cfa = *current_ip;
265: NEXT1_P1;
266: *--rp = (Cell)ip;
267: ip = current_ip+1;
268: NEXT1_P2;
269: }
270: #endif
271: }
272:
273: docon:
274: {
275: DOCFA;
276: #ifdef DEBUG
277: fprintf(stderr,"%08lx: con: %08lx\n",(Cell)ip,*(Cell*)PFA1(cfa));
278: #endif
279: #ifdef USE_TOS
280: *sp-- = TOS;
281: TOS = *(Cell *)PFA1(cfa);
282: #else
283: *--sp = *(Cell *)PFA1(cfa);
284: #endif
285: }
286: NEXT_P0;
287: NEXT;
288:
289: dovar:
290: {
291: DOCFA;
292: #ifdef DEBUG
293: fprintf(stderr,"%08lx: var: %08lx\n",(Cell)ip,(Cell)PFA1(cfa));
294: #endif
295: #ifdef USE_TOS
296: *sp-- = TOS;
297: TOS = (Cell)PFA1(cfa);
298: #else
299: *--sp = (Cell)PFA1(cfa);
300: #endif
301: }
302: NEXT_P0;
303: NEXT;
304:
305: douser:
306: {
307: DOCFA;
308: #ifdef DEBUG
309: fprintf(stderr,"%08lx: user: %08lx\n",(Cell)ip,(Cell)PFA1(cfa));
310: #endif
311: #ifdef USE_TOS
312: *sp-- = TOS;
313: TOS = (Cell)(up+*(Cell*)PFA1(cfa));
314: #else
315: *--sp = (Cell)(up+*(Cell*)PFA1(cfa));
316: #endif
317: }
318: NEXT_P0;
319: NEXT;
320:
321: dodefer:
322: {
323: DOCFA;
324: #ifdef DEBUG
325: fprintf(stderr,"%08lx: defer: %08lx\n",(Cell)ip,*(Cell*)PFA1(cfa));
326: #endif
327: EXEC(*(Xt *)PFA1(cfa));
328: }
329:
330: dofield:
331: {
332: DOCFA;
333: #ifdef DEBUG
334: fprintf(stderr,"%08lx: field: %08lx\n",(Cell)ip,(Cell)PFA1(cfa));
335: #endif
336: TOS += *(Cell*)PFA1(cfa);
337: }
338: NEXT_P0;
339: NEXT;
340:
341: dodoes:
342: /* this assumes the following structure:
343: defining-word:
344:
345: ...
346: DOES>
347: (possible padding)
348: possibly handler: jmp dodoes
349: (possible branch delay slot(s))
350: Forth code after DOES>
351:
352: defined word:
353:
354: cfa: address of or jump to handler OR
355: address of or jump to dodoes, address of DOES-code
356: pfa:
357:
358: */
359: {
360: DOCFA;
361:
362: /* fprintf(stderr, "Got CFA %08lx at doescode %08lx/%08lx: does: %08lx\n",cfa,(Cell)ip,(Cell)PFA(cfa),(Cell)DOES_CODE1(cfa));*/
363: #ifdef DEBUG
364: fprintf(stderr,"%08lx/%08lx: does: %08lx\n",(Cell)ip,(Cell)PFA(cfa),(Cell)DOES_CODE1(cfa));
365: fflush(stderr);
366: #endif
367: *--rp = (Cell)ip;
368: /* PFA1 might collide with DOES_CODE1 here, so we use PFA */
369: ip = DOES_CODE1(cfa);
370: #ifdef USE_TOS
371: *sp-- = TOS;
372: TOS = (Cell)PFA(cfa);
373: #else
374: *--sp = (Cell)PFA(cfa);
375: #endif
376: /* fprintf(stderr,"TOS = %08lx, IP=%08lx\n", TOS, IP);*/
377: }
378: NEXT_P0;
379: NEXT;
380:
381: #include "primitives.i"
382: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>