Commit | Line | Data |
---|---|---|
8e9db35f PB |
1 | /* @(#) pf_core.c 98/01/28 1.5 */ |
2 | /*************************************************************** | |
3 | ** Forth based on 'C' | |
4 | ** | |
5 | ** This file has the main entry points to the pForth library. | |
6 | ** | |
7 | ** Author: Phil Burk | |
8 | ** Copyright 1994 3DO, Phil Burk, Larry Polansky, David Rosenboom | |
9 | ** | |
1f99f95d S |
10 | ** Permission to use, copy, modify, and/or distribute this |
11 | ** software for any purpose with or without fee is hereby granted. | |
12 | ** | |
13 | ** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL | |
14 | ** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED | |
15 | ** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL | |
16 | ** THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR | |
17 | ** CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING | |
18 | ** FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF | |
19 | ** CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
20 | ** OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
8e9db35f PB |
21 | ** |
22 | **************************************************************** | |
23 | ** 940502 PLB Creation. | |
24 | ** 940505 PLB More macros. | |
25 | ** 940509 PLB Moved all stack handling into inner interpreter. | |
26 | ** Added Create, Colon, Semicolon, HNumberQ, etc. | |
27 | ** 940510 PLB Got inner interpreter working with secondaries. | |
28 | ** Added (LITERAL). Compiles colon definitions. | |
29 | ** 940511 PLB Added conditionals, LITERAL, CREATE DOES> | |
30 | ** 940512 PLB Added DO LOOP DEFER, fixed R> | |
31 | ** 940520 PLB Added INCLUDE | |
32 | ** 940521 PLB Added NUMBER? | |
33 | ** 940930 PLB Outer Interpreter now uses deferred NUMBER? | |
34 | ** 941005 PLB Added ANSI locals, LEAVE, modularised | |
35 | ** 950320 RDG Added underflow checking for FP stack | |
36 | ** 970702 PLB Added STACK_SAFETY to FP stack size. | |
37 | ***************************************************************/ | |
38 | ||
39 | #include "pf_all.h" | |
40 | ||
41 | /*************************************************************** | |
42 | ** Global Data | |
43 | ***************************************************************/ | |
44 | ||
2d8c3ec4 | 45 | char gScratch[TIB_SIZE]; |
8e9db35f PB |
46 | pfTaskData_t *gCurrentTask = NULL; |
47 | pfDictionary_t *gCurrentDictionary; | |
2d8c3ec4 | 48 | cell_t gNumPrimitives; |
8e9db35f | 49 | |
2d8c3ec4 PB |
50 | ExecToken gLocalCompiler_XT; /* custom compiler for local variables */ |
51 | ExecToken gNumberQ_XT; /* XT of NUMBER? */ | |
52 | ExecToken gQuitP_XT; /* XT of (QUIT) */ | |
53 | ExecToken gAcceptP_XT; /* XT of ACCEPT */ | |
8e9db35f PB |
54 | |
55 | /* Depth of data stack when colon called. */ | |
2d8c3ec4 | 56 | cell_t gDepthAtColon; |
8e9db35f PB |
57 | |
58 | /* Global Forth variables. */ | |
59 | cell_t gVarContext; /* Points to last name field. */ | |
60 | cell_t gVarState; /* 1 if compiling. */ | |
61 | cell_t gVarBase; /* Numeric Base. */ | |
62 | cell_t gVarEcho; /* Echo input. */ | |
63 | cell_t gVarTraceLevel; /* Trace Level for Inner Interpreter. */ | |
64 | cell_t gVarTraceStack; /* Dump Stack each time if true. */ | |
65 | cell_t gVarTraceFlags; /* Enable various internal debug messages. */ | |
66 | cell_t gVarQuiet; /* Suppress unnecessary messages, OK, etc. */ | |
67 | cell_t gVarReturnCode; /* Returned to caller of Forth, eg. UNIX shell. */ | |
68 | ||
69 | /* data for INCLUDE that allows multiple nested files. */ | |
2d8c3ec4 PB |
70 | IncludeFrame gIncludeStack[MAX_INCLUDE_DEPTH]; |
71 | cell_t gIncludeIndex; | |
8e9db35f PB |
72 | |
73 | static void pfResetForthTask( void ); | |
74 | static void pfInit( void ); | |
75 | static void pfTerm( void ); | |
76 | ||
8e9db35f PB |
77 | #define DEFAULT_RETURN_DEPTH (512) |
78 | #define DEFAULT_USER_DEPTH (512) | |
28475a0f PB |
79 | |
80 | #ifndef PF_DEFAULT_HEADER_SIZE | |
1981b813 | 81 | #define PF_DEFAULT_HEADER_SIZE (120000) |
28475a0f PB |
82 | #endif |
83 | ||
84 | #ifndef PF_DEFAULT_CODE_SIZE | |
85 | #define PF_DEFAULT_CODE_SIZE (300000) | |
86 | #endif | |
8e9db35f PB |
87 | |
88 | /* Initialize globals in a function to simplify loading on | |
89 | * embedded systems which may not support initialization of data section. | |
90 | */ | |
91 | static void pfInit( void ) | |
92 | { | |
93 | /* all zero */ | |
94 | gCurrentTask = NULL; | |
95 | gCurrentDictionary = NULL; | |
96 | gNumPrimitives = 0; | |
97 | gLocalCompiler_XT = 0; | |
98 | gVarContext = (cell_t)NULL; /* Points to last name field. */ | |
99 | gVarState = 0; /* 1 if compiling. */ | |
100 | gVarEcho = 0; /* Echo input. */ | |
101 | gVarTraceLevel = 0; /* Trace Level for Inner Interpreter. */ | |
102 | gVarTraceFlags = 0; /* Enable various internal debug messages. */ | |
103 | gVarReturnCode = 0; /* Returned to caller of Forth, eg. UNIX shell. */ | |
104 | gIncludeIndex = 0; | |
105 | ||
106 | /* non-zero */ | |
107 | gVarBase = 10; /* Numeric Base. */ | |
108 | gDepthAtColon = DEPTH_AT_COLON_INVALID; | |
109 | gVarTraceStack = 1; | |
110 | ||
111 | pfInitMemoryAllocator(); | |
112 | ioInit(); | |
113 | } | |
114 | static void pfTerm( void ) | |
115 | { | |
116 | ioTerm(); | |
117 | } | |
118 | ||
119 | /*************************************************************** | |
120 | ** Task Management | |
121 | ***************************************************************/ | |
122 | ||
123 | void pfDeleteTask( PForthTask task ) | |
124 | { | |
125 | pfTaskData_t *cftd = (pfTaskData_t *)task; | |
126 | FREE_VAR( cftd->td_ReturnLimit ); | |
127 | FREE_VAR( cftd->td_StackLimit ); | |
128 | pfFreeMem( cftd ); | |
129 | } | |
130 | ||
131 | /* Allocate some extra cells to protect against mild stack underflows. */ | |
132 | #define STACK_SAFETY (8) | |
133 | PForthTask pfCreateTask( cell_t UserStackDepth, cell_t ReturnStackDepth ) | |
134 | { | |
135 | pfTaskData_t *cftd; | |
136 | ||
137 | cftd = ( pfTaskData_t * ) pfAllocMem( sizeof( pfTaskData_t ) ); | |
138 | if( !cftd ) goto nomem; | |
139 | pfSetMemory( cftd, 0, sizeof( pfTaskData_t )); | |
140 | ||
141 | /* Allocate User Stack */ | |
142 | cftd->td_StackLimit = (cell_t *) pfAllocMem((ucell_t)(sizeof(cell_t) * | |
143 | (UserStackDepth + STACK_SAFETY))); | |
144 | if( !cftd->td_StackLimit ) goto nomem; | |
145 | cftd->td_StackBase = cftd->td_StackLimit + UserStackDepth; | |
146 | cftd->td_StackPtr = cftd->td_StackBase; | |
147 | ||
148 | /* Allocate Return Stack */ | |
149 | cftd->td_ReturnLimit = (cell_t *) pfAllocMem((ucell_t)(sizeof(cell_t) * ReturnStackDepth) ); | |
150 | if( !cftd->td_ReturnLimit ) goto nomem; | |
151 | cftd->td_ReturnBase = cftd->td_ReturnLimit + ReturnStackDepth; | |
152 | cftd->td_ReturnPtr = cftd->td_ReturnBase; | |
153 | ||
154 | /* Allocate Float Stack */ | |
155 | #ifdef PF_SUPPORT_FP | |
156 | /* Allocate room for as many Floats as we do regular data. */ | |
157 | cftd->td_FloatStackLimit = (PF_FLOAT *) pfAllocMem((ucell_t)(sizeof(PF_FLOAT) * | |
158 | (UserStackDepth + STACK_SAFETY))); | |
159 | if( !cftd->td_FloatStackLimit ) goto nomem; | |
160 | cftd->td_FloatStackBase = cftd->td_FloatStackLimit + UserStackDepth; | |
161 | cftd->td_FloatStackPtr = cftd->td_FloatStackBase; | |
162 | #endif | |
163 | ||
164 | cftd->td_InputStream = PF_STDIN; | |
165 | ||
166 | cftd->td_SourcePtr = &cftd->td_TIB[0]; | |
167 | cftd->td_SourceNum = 0; | |
168 | ||
169 | return (PForthTask) cftd; | |
170 | ||
171 | nomem: | |
172 | ERR("CreateTaskContext: insufficient memory.\n"); | |
173 | if( cftd ) pfDeleteTask( (PForthTask) cftd ); | |
174 | return NULL; | |
175 | } | |
176 | ||
177 | /*************************************************************** | |
178 | ** Dictionary Management | |
179 | ***************************************************************/ | |
180 | ||
529bb4e2 | 181 | ThrowCode pfExecIfDefined( const char *CString ) |
8e9db35f | 182 | { |
529bb4e2 | 183 | ThrowCode result = 0; |
8e9db35f PB |
184 | if( NAME_BASE != (cell_t)NULL) |
185 | { | |
186 | ExecToken XT; | |
187 | if( ffFindC( CString, &XT ) ) | |
188 | { | |
189 | result = pfCatch( XT ); | |
190 | } | |
191 | } | |
192 | return result; | |
193 | } | |
194 | ||
195 | /*************************************************************** | |
196 | ** Delete a dictionary created by pfCreateDictionary() | |
197 | */ | |
198 | void pfDeleteDictionary( PForthDictionary dictionary ) | |
199 | { | |
200 | pfDictionary_t *dic = (pfDictionary_t *) dictionary; | |
201 | if( !dic ) return; | |
202 | ||
203 | if( dic->dic_Flags & PF_DICF_ALLOCATED_SEGMENTS ) | |
204 | { | |
205 | FREE_VAR( dic->dic_HeaderBaseUnaligned ); | |
206 | FREE_VAR( dic->dic_CodeBaseUnaligned ); | |
207 | } | |
208 | pfFreeMem( dic ); | |
209 | } | |
210 | ||
211 | /*************************************************************** | |
212 | ** Create a complete dictionary. | |
213 | ** The dictionary consists of two parts, the header with the names, | |
214 | ** and the code portion. | |
215 | ** Delete using pfDeleteDictionary(). | |
216 | ** Return pointer to dictionary management structure. | |
217 | */ | |
218 | PForthDictionary pfCreateDictionary( cell_t HeaderSize, cell_t CodeSize ) | |
219 | { | |
220 | /* Allocate memory for initial dictionary. */ | |
221 | pfDictionary_t *dic; | |
222 | ||
223 | dic = ( pfDictionary_t * ) pfAllocMem( sizeof( pfDictionary_t ) ); | |
224 | if( !dic ) goto nomem; | |
225 | pfSetMemory( dic, 0, sizeof( pfDictionary_t )); | |
226 | ||
227 | dic->dic_Flags |= PF_DICF_ALLOCATED_SEGMENTS; | |
228 | ||
229 | /* Align dictionary segments to preserve alignment of floats across hosts. | |
230 | * Thank you Helmut Proelss for pointing out that this needs to be cast | |
231 | * to (ucell_t) on 16 bit systems. | |
232 | */ | |
233 | #define DIC_ALIGNMENT_SIZE ((ucell_t)(0x10)) | |
234 | #define DIC_ALIGN(addr) ((((ucell_t)(addr)) + DIC_ALIGNMENT_SIZE - 1) & ~(DIC_ALIGNMENT_SIZE - 1)) | |
235 | ||
236 | /* Allocate memory for header. */ | |
237 | if( HeaderSize > 0 ) | |
238 | { | |
239 | dic->dic_HeaderBaseUnaligned = (ucell_t) pfAllocMem( (ucell_t) HeaderSize + DIC_ALIGNMENT_SIZE ); | |
240 | if( !dic->dic_HeaderBaseUnaligned ) goto nomem; | |
241 | /* Align header base. */ | |
242 | dic->dic_HeaderBase = DIC_ALIGN(dic->dic_HeaderBaseUnaligned); | |
243 | pfSetMemory( (char *) dic->dic_HeaderBase, 0xA5, (ucell_t) HeaderSize); | |
244 | dic->dic_HeaderLimit = dic->dic_HeaderBase + HeaderSize; | |
245 | dic->dic_HeaderPtr = dic->dic_HeaderBase; | |
246 | } | |
247 | else | |
248 | { | |
249 | dic->dic_HeaderBase = 0; | |
250 | } | |
251 | ||
252 | /* Allocate memory for code. */ | |
253 | dic->dic_CodeBaseUnaligned = (ucell_t) pfAllocMem( (ucell_t) CodeSize + DIC_ALIGNMENT_SIZE ); | |
254 | if( !dic->dic_CodeBaseUnaligned ) goto nomem; | |
255 | dic->dic_CodeBase = DIC_ALIGN(dic->dic_CodeBaseUnaligned); | |
256 | pfSetMemory( (char *) dic->dic_CodeBase, 0x5A, (ucell_t) CodeSize); | |
257 | ||
258 | dic->dic_CodeLimit = dic->dic_CodeBase + CodeSize; | |
259 | dic->dic_CodePtr.Byte = ((uint8_t *) (dic->dic_CodeBase + QUADUP(NUM_PRIMITIVES))); | |
260 | ||
261 | return (PForthDictionary) dic; | |
262 | nomem: | |
263 | pfDeleteDictionary( dic ); | |
264 | return NULL; | |
265 | } | |
266 | ||
267 | /*************************************************************** | |
268 | ** Used by Quit and other routines to restore system. | |
269 | ***************************************************************/ | |
270 | ||
271 | static void pfResetForthTask( void ) | |
272 | { | |
273 | /* Go back to terminal input. */ | |
274 | gCurrentTask->td_InputStream = PF_STDIN; | |
275 | ||
276 | /* Reset stacks. */ | |
277 | gCurrentTask->td_StackPtr = gCurrentTask->td_StackBase; | |
278 | gCurrentTask->td_ReturnPtr = gCurrentTask->td_ReturnBase; | |
279 | #ifdef PF_SUPPORT_FP /* Reset Floating Point stack too! */ | |
280 | gCurrentTask->td_FloatStackPtr = gCurrentTask->td_FloatStackBase; | |
281 | #endif | |
282 | ||
283 | /* Advance >IN to end of input. */ | |
284 | gCurrentTask->td_IN = gCurrentTask->td_SourceNum; | |
285 | gVarState = 0; | |
286 | } | |
287 | ||
288 | /*************************************************************** | |
289 | ** Set current task context. | |
290 | ***************************************************************/ | |
291 | ||
292 | void pfSetCurrentTask( PForthTask task ) | |
293 | { | |
294 | gCurrentTask = (pfTaskData_t *) task; | |
295 | } | |
296 | ||
297 | /*************************************************************** | |
298 | ** Set Quiet Flag. | |
299 | ***************************************************************/ | |
300 | ||
301 | void pfSetQuiet( cell_t IfQuiet ) | |
302 | { | |
303 | gVarQuiet = (cell_t) IfQuiet; | |
304 | } | |
305 | ||
306 | /*************************************************************** | |
307 | ** Query message status. | |
308 | ***************************************************************/ | |
309 | ||
310 | cell_t pfQueryQuiet( void ) | |
311 | { | |
312 | return gVarQuiet; | |
313 | } | |
314 | ||
315 | /*************************************************************** | |
316 | ** Top level interpreter. | |
317 | ***************************************************************/ | |
318 | ThrowCode pfQuit( void ) | |
319 | { | |
320 | ThrowCode exception; | |
321 | int go = 1; | |
322 | ||
323 | while(go) | |
324 | { | |
325 | exception = ffOuterInterpreterLoop(); | |
326 | if( exception == 0 ) | |
327 | { | |
328 | exception = ffOK(); | |
329 | } | |
330 | ||
331 | switch( exception ) | |
332 | { | |
333 | case 0: | |
334 | break; | |
335 | ||
336 | case THROW_BYE: | |
337 | go = 0; | |
338 | break; | |
339 | ||
340 | case THROW_ABORT: | |
341 | default: | |
342 | ffDotS(); | |
343 | pfReportThrow( exception ); | |
344 | pfHandleIncludeError(); | |
345 | pfResetForthTask(); | |
346 | break; | |
347 | } | |
348 | } | |
349 | ||
350 | return gVarReturnCode; | |
351 | } | |
352 | ||
353 | /*************************************************************** | |
354 | ** Include file based on 'C' name. | |
355 | ***************************************************************/ | |
356 | ||
357 | cell_t pfIncludeFile( const char *FileName ) | |
358 | { | |
359 | FileStream *fid; | |
360 | cell_t Result; | |
361 | char buffer[32]; | |
362 | cell_t numChars, len; | |
363 | ||
364 | /* Open file. */ | |
365 | fid = sdOpenFile( FileName, "r" ); | |
366 | if( fid == NULL ) | |
367 | { | |
368 | ERR("pfIncludeFile could not open "); | |
369 | ERR(FileName); | |
370 | EMIT_CR; | |
371 | return -1; | |
372 | } | |
373 | ||
374 | /* Create a dictionary word named ::::FileName for FILE? */ | |
375 | pfCopyMemory( &buffer[0], "::::", 4); | |
376 | len = (cell_t) pfCStringLength(FileName); | |
377 | numChars = ( len > (32-4-1) ) ? (32-4-1) : len; | |
378 | pfCopyMemory( &buffer[4], &FileName[len-numChars], numChars+1 ); | |
379 | CreateDicEntryC( ID_NOOP, buffer, 0 ); | |
380 | ||
381 | Result = ffIncludeFile( fid ); /* Also close the file. */ | |
382 | ||
383 | /* Create a dictionary word named ;;;; for FILE? */ | |
384 | CreateDicEntryC( ID_NOOP, ";;;;", 0 ); | |
385 | ||
386 | return Result; | |
387 | } | |
388 | ||
389 | /*************************************************************** | |
390 | ** Output 'C' string message. | |
391 | ** Use sdTerminalOut which works before initializing gCurrentTask. | |
392 | ***************************************************************/ | |
393 | void pfDebugMessage( const char *CString ) | |
394 | { | |
395 | #if 0 | |
396 | while( *CString ) | |
397 | { | |
398 | char c = *CString++; | |
399 | if( c == '\n' ) | |
400 | { | |
401 | sdTerminalOut( 0x0D ); | |
402 | sdTerminalOut( 0x0A ); | |
403 | pfDebugMessage( "DBG: " ); | |
404 | } | |
405 | else | |
406 | { | |
407 | sdTerminalOut( c ); | |
408 | } | |
409 | } | |
410 | #else | |
411 | (void)CString; | |
412 | #endif | |
413 | } | |
414 | ||
415 | /*************************************************************** | |
416 | ** Print a decimal number to debug output. | |
417 | */ | |
418 | void pfDebugPrintDecimalNumber( int n ) | |
419 | { | |
420 | pfDebugMessage( ConvertNumberToText( n, 10, TRUE, 1 ) ); | |
421 | } | |
422 | ||
423 | ||
424 | /*************************************************************** | |
425 | ** Output 'C' string message. | |
426 | ** This is provided to help avoid the use of printf() and other I/O | |
427 | ** which may not be present on a small embedded system. | |
428 | ** Uses ioType & ioEmit so requires that gCurrentTask has been initialized. | |
429 | ***************************************************************/ | |
430 | void pfMessage( const char *CString ) | |
431 | { | |
432 | ioType( CString, (cell_t) pfCStringLength(CString) ); | |
433 | } | |
434 | ||
435 | /************************************************************************** | |
436 | ** Main entry point for pForth. | |
437 | */ | |
529bb4e2 | 438 | ThrowCode pfDoForth( const char *DicFileName, const char *SourceName, cell_t IfInit ) |
8e9db35f PB |
439 | { |
440 | pfTaskData_t *cftd; | |
441 | pfDictionary_t *dic = NULL; | |
529bb4e2 | 442 | ThrowCode Result = 0; |
8e9db35f PB |
443 | ExecToken EntryPoint = 0; |
444 | ||
445 | #ifdef PF_USER_INIT | |
446 | Result = PF_USER_INIT; | |
447 | if( Result < 0 ) goto error1; | |
448 | #endif | |
449 | ||
450 | pfInit(); | |
451 | ||
452 | /* Allocate Task structure. */ | |
453 | pfDebugMessage("pfDoForth: call pfCreateTask()\n"); | |
454 | cftd = pfCreateTask( DEFAULT_USER_DEPTH, DEFAULT_RETURN_DEPTH ); | |
455 | ||
456 | if( cftd ) | |
457 | { | |
458 | pfSetCurrentTask( cftd ); | |
459 | ||
460 | if( !gVarQuiet ) | |
461 | { | |
462 | MSG( "PForth V"PFORTH_VERSION ); | |
463 | if( IsHostLittleEndian() ) MSG("-LE"); | |
464 | else MSG("-BE"); | |
465 | #if PF_BIG_ENDIAN_DIC | |
466 | MSG("/BE"); | |
467 | #elif PF_LITTLE_ENDIAN_DIC | |
468 | MSG("/LE"); | |
469 | #endif | |
470 | if (sizeof(cell_t) == 8) | |
471 | { | |
472 | MSG("/64"); | |
473 | } | |
474 | else if (sizeof(cell_t) == 4) | |
475 | { | |
476 | MSG("/32"); | |
477 | } | |
478 | ||
479 | MSG( ", built "__DATE__" "__TIME__ ); | |
480 | } | |
481 | ||
482 | /* Don't use MSG before task set. */ | |
483 | if( SourceName ) | |
484 | { | |
485 | pfDebugMessage("SourceName = "); pfDebugMessage(SourceName); pfDebugMessage("\n"); | |
486 | } | |
487 | ||
488 | ||
489 | #ifdef PF_NO_GLOBAL_INIT | |
490 | if( LoadCustomFunctionTable() < 0 ) goto error2; /* Init custom 'C' call array. */ | |
491 | #endif | |
492 | ||
493 | #if (!defined(PF_NO_INIT)) && (!defined(PF_NO_SHELL)) | |
494 | if( IfInit ) | |
495 | { | |
496 | pfDebugMessage("Build dictionary from scratch.\n"); | |
28475a0f | 497 | dic = pfBuildDictionary( PF_DEFAULT_HEADER_SIZE, PF_DEFAULT_CODE_SIZE ); |
8e9db35f PB |
498 | } |
499 | else | |
500 | #else | |
501 | TOUCH(IfInit); | |
502 | #endif /* !PF_NO_INIT && !PF_NO_SHELL*/ | |
503 | { | |
504 | if( DicFileName ) | |
505 | { | |
506 | pfDebugMessage("DicFileName = "); pfDebugMessage(DicFileName); pfDebugMessage("\n"); | |
507 | if( !gVarQuiet ) | |
508 | { | |
509 | EMIT_CR; | |
510 | } | |
511 | dic = pfLoadDictionary( DicFileName, &EntryPoint ); | |
512 | } | |
513 | else | |
514 | { | |
515 | if( !gVarQuiet ) | |
516 | { | |
517 | MSG(" (static)"); | |
518 | EMIT_CR; | |
519 | } | |
520 | dic = pfLoadStaticDictionary(); | |
521 | } | |
522 | } | |
523 | if( dic == NULL ) goto error2; | |
524 | ||
525 | if( !gVarQuiet ) | |
526 | { | |
527 | EMIT_CR; | |
528 | } | |
529 | ||
530 | pfDebugMessage("pfDoForth: try AUTO.INIT\n"); | |
531 | Result = pfExecIfDefined("AUTO.INIT"); | |
532 | if( Result != 0 ) | |
533 | { | |
534 | MSG("Error in AUTO.INIT"); | |
535 | goto error2; | |
536 | } | |
537 | ||
538 | if( EntryPoint != 0 ) | |
539 | { | |
540 | Result = pfCatch( EntryPoint ); | |
541 | } | |
542 | #ifndef PF_NO_SHELL | |
543 | else | |
544 | { | |
545 | if( SourceName == NULL ) | |
546 | { | |
547 | pfDebugMessage("pfDoForth: pfQuit\n"); | |
548 | Result = pfQuit(); | |
549 | } | |
550 | else | |
551 | { | |
552 | if( !gVarQuiet ) | |
553 | { | |
554 | MSG("Including: "); | |
555 | MSG(SourceName); | |
556 | MSG("\n"); | |
557 | } | |
558 | Result = pfIncludeFile( SourceName ); | |
559 | } | |
560 | } | |
561 | #endif /* PF_NO_SHELL */ | |
562 | ||
563 | /* Clean up after running Forth. */ | |
564 | pfExecIfDefined("AUTO.TERM"); | |
565 | pfDeleteDictionary( dic ); | |
566 | pfDeleteTask( cftd ); | |
567 | } | |
568 | ||
569 | pfTerm(); | |
570 | ||
571 | #ifdef PF_USER_TERM | |
572 | PF_USER_TERM; | |
573 | #endif | |
574 | ||
575 | return Result; | |
576 | ||
577 | error2: | |
578 | MSG("pfDoForth: Error occured.\n"); | |
579 | pfDeleteTask( cftd ); | |
580 | /* Terminate so we restore normal shell tty mode. */ | |
581 | pfTerm(); | |
582 | ||
583 | #ifdef PF_USER_INIT | |
584 | error1: | |
585 | #endif | |
586 | ||
587 | return -1; | |
588 | } | |
589 | ||
590 | ||
591 | #ifdef PF_UNIT_TEST | |
592 | cell_t pfUnitTest( void ) | |
593 | { | |
594 | cell_t numErrors = 0; | |
595 | numErrors += pfUnitTestText(); | |
596 | return numErrors; | |
597 | } | |
598 | #endif |