1 /* @(#) pf_save.c 98/01/26 1.3 */
2 /***************************************************************
3 ** Save and Load Dictionary
4 ** for PForth based on 'C'
6 ** Compile file based version or static data based version
7 ** depending on PF_NO_FILEIO switch.
10 ** Copyright 1994 3DO, Phil Burk, Larry Polansky, David Rosenboom
12 ** Permission to use, copy, modify, and/or distribute this
13 ** software for any purpose with or without fee is hereby granted.
15 ** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
16 ** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
17 ** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
18 ** THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
19 ** CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
20 ** FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
21 ** CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
22 ** OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24 ****************************************************************
25 ** 940225 PLB Fixed CodePtr save, was using NAMEREL instead of CODEREL
26 ** This would only work if the relative location
27 ** of names and code was the same when saved and reloaded.
28 ** 940228 PLB Added PF_NO_FILEIO version
29 ** 961204 PLB Added PF_STATIC_DIC
30 ** 000623 PLB Cast chars as ucell_t before shifting for 16 bit systems.
31 ***************************************************************/
37 /* If no File I/O, then force static dictionary. */
49 Dictionary File Format based on IFF standard.
50 The chunk IDs, sizes, and data values are all Big Endian in conformance with the IFF standard.
51 The dictionaries may be big or little endian.
54 'P4TH' - Form Identifier
59 struct DictionaryInfoChunk
63 Name and Header portion of dictionary. (Big or Little Endian) (Optional)
67 Code portion of dictionary. (Big or Little Endian)
71 /***************************************************************/
72 /* Endian-ness tools. */
73 ucell_t ReadCellBigEndian( const uint8_t *addr )
75 ucell_t temp = (ucell_t)addr[0];
76 temp = (temp << 8) | ((ucell_t)addr[1]);
77 temp = (temp << 8) | ((ucell_t)addr[2]);
78 temp = (temp << 8) | ((ucell_t)addr[3]);
79 if( sizeof(ucell_t) == 8 )
81 temp = (temp << 8) | ((ucell_t)addr[4]);
82 temp = (temp << 8) | ((ucell_t)addr[5]);
83 temp = (temp << 8) | ((ucell_t)addr[6]);
84 temp = (temp << 8) | ((ucell_t)addr[7]);
89 /***************************************************************/
90 /* Endian-ness tools. */
91 uint32_t Read32BigEndian( const uint8_t *addr )
93 uint32_t temp = (uint32_t)addr[0];
94 temp = (temp << 8) | ((uint32_t)addr[1]);
95 temp = (temp << 8) | ((uint32_t)addr[2]);
96 temp = (temp << 8) | ((uint32_t)addr[3]);
100 /***************************************************************/
101 uint16_t Read16BigEndian( const uint8_t *addr )
103 return (uint16_t) ((addr[0]<<8) | addr[1]);
106 /***************************************************************/
107 ucell_t ReadCellLittleEndian( const uint8_t *addr )
110 if( sizeof(ucell_t) == 8 )
112 temp = (temp << 8) | ((uint32_t)addr[7]);
113 temp = (temp << 8) | ((uint32_t)addr[6]);
114 temp = (temp << 8) | ((uint32_t)addr[5]);
115 temp = (temp << 8) | ((uint32_t)addr[4]);
117 temp = (temp << 8) | ((uint32_t)addr[3]);
118 temp = (temp << 8) | ((uint32_t)addr[2]);
119 temp = (temp << 8) | ((uint32_t)addr[1]);
120 temp = (temp << 8) | ((uint32_t)addr[0]);
124 /***************************************************************/
125 uint32_t Read32LittleEndian( const uint8_t *addr )
127 uint32_t temp = (uint32_t)addr[3];
128 temp = (temp << 8) | ((uint32_t)addr[2]);
129 temp = (temp << 8) | ((uint32_t)addr[1]);
130 temp = (temp << 8) | ((uint32_t)addr[0]);
134 /***************************************************************/
135 uint16_t Read16LittleEndian( const uint8_t *addr )
137 const unsigned char *bp = (const unsigned char *) addr;
138 return (uint16_t) ((bp[1]<<8) | bp[0]);
143 /***************************************************************/
144 static void ReverseCopyFloat( const PF_FLOAT *src, PF_FLOAT *dst );
146 static void ReverseCopyFloat( const PF_FLOAT *src, PF_FLOAT *dst )
149 unsigned char *d = (unsigned char *) dst;
150 const unsigned char *s = (const unsigned char *) src;
152 for( i=0; i<sizeof(PF_FLOAT); i++ )
154 d[i] = s[sizeof(PF_FLOAT) - 1 - i];
158 /***************************************************************/
159 void WriteFloatBigEndian( PF_FLOAT *addr, PF_FLOAT data )
161 if( IsHostLittleEndian() )
163 ReverseCopyFloat( &data, addr );
171 /***************************************************************/
172 PF_FLOAT ReadFloatBigEndian( const PF_FLOAT *addr )
175 if( IsHostLittleEndian() )
177 ReverseCopyFloat( addr, &data );
186 /***************************************************************/
187 void WriteFloatLittleEndian( PF_FLOAT *addr, PF_FLOAT data )
189 if( IsHostLittleEndian() )
195 ReverseCopyFloat( &data, addr );
199 /***************************************************************/
200 PF_FLOAT ReadFloatLittleEndian( const PF_FLOAT *addr )
203 if( IsHostLittleEndian() )
209 ReverseCopyFloat( addr, &data );
214 #endif /* PF_SUPPORT_FP */
216 /***************************************************************/
217 void WriteCellBigEndian( uint8_t *addr, ucell_t data )
219 /* Write should be in order of increasing address
220 * to optimize for burst writes to DRAM. */
221 if( sizeof(ucell_t) == 8 )
223 *addr++ = (uint8_t) (data>>56);
224 *addr++ = (uint8_t) (data>>48);
225 *addr++ = (uint8_t) (data>>40);
226 *addr++ = (uint8_t) (data>>32);
228 *addr++ = (uint8_t) (data>>24);
229 *addr++ = (uint8_t) (data>>16);
230 *addr++ = (uint8_t) (data>>8);
231 *addr = (uint8_t) (data);
234 /***************************************************************/
235 void Write32BigEndian( uint8_t *addr, uint32_t data )
237 *addr++ = (uint8_t) (data>>24);
238 *addr++ = (uint8_t) (data>>16);
239 *addr++ = (uint8_t) (data>>8);
240 *addr = (uint8_t) (data);
243 /***************************************************************/
244 void Write16BigEndian( uint8_t *addr, uint16_t data )
246 *addr++ = (uint8_t) (data>>8);
247 *addr = (uint8_t) (data);
250 /***************************************************************/
251 void WriteCellLittleEndian( uint8_t *addr, ucell_t data )
253 /* Write should be in order of increasing address
254 * to optimize for burst writes to DRAM. */
255 if( sizeof(ucell_t) == 8 )
257 *addr++ = (uint8_t) data; /* LSB at near end */
259 *addr++ = (uint8_t) data;
261 *addr++ = (uint8_t) data;
263 *addr++ = (uint8_t) data;
266 *addr++ = (uint8_t) data;
268 *addr++ = (uint8_t) data;
270 *addr++ = (uint8_t) data;
272 *addr = (uint8_t) data;
274 /***************************************************************/
275 void Write32LittleEndian( uint8_t *addr, uint32_t data )
277 *addr++ = (uint8_t) data;
279 *addr++ = (uint8_t) data;
281 *addr++ = (uint8_t) data;
283 *addr = (uint8_t) data;
286 /***************************************************************/
287 void Write16LittleEndian( uint8_t *addr, uint16_t data )
289 *addr++ = (uint8_t) data;
291 *addr = (uint8_t) data;
294 /***************************************************************/
295 /* Return 1 if host CPU is Little Endian */
296 int IsHostLittleEndian( void )
298 static int gEndianCheck = 1;
299 unsigned char *bp = (unsigned char *) &gEndianCheck;
300 return (int) (*bp); /* Return byte pointed to by address. If LSB then == 1 */
303 #if defined(PF_NO_FILEIO) || defined(PF_NO_SHELL)
305 cell_t ffSaveForth( const char *FileName, ExecToken EntryPoint, cell_t NameSize, cell_t CodeSize)
312 pfReportError("ffSaveForth", PF_ERR_NOT_SUPPORTED);
316 #else /* PF_NO_FILEIO or PF_NO_SHELL */
318 /***************************************************************/
319 static int Write32ToFile( FileStream *fid, uint32_t Val )
324 Write32BigEndian(pad,Val);
325 numw = sdWriteFile( pad, 1, sizeof(pad), fid );
326 if( numw != sizeof(pad) ) return -1;
330 /***************************************************************/
331 static cell_t WriteChunkToFile( FileStream *fid, cell_t ID, char *Data, int32_t NumBytes )
336 EvenNumW = EVENUP(NumBytes);
338 assert(ID <= UINT32_MAX);
339 if( Write32ToFile( fid, (uint32_t)ID ) < 0 ) goto error;
340 assert(EvenNumW <= UINT32_MAX);
341 if( Write32ToFile( fid, (uint32_t)EvenNumW ) < 0 ) goto error;
343 numw = sdWriteFile( Data, 1, EvenNumW, fid );
344 if( numw != EvenNumW ) goto error;
347 pfReportError("WriteChunkToFile", PF_ERR_WRITE_FILE);
351 /* Convert dictionary info chunk between native and on-disk (big-endian). */
353 convertDictionaryInfoWrite (DictionaryInfoChunk *sd)
355 /* Convert all fields in DictionaryInfoChunk from Native to BigEndian.
356 * This assumes they are all 32-bit integers.
359 uint32_t *p = (uint32_t *) sd;
360 for (i=0; i<((int)(sizeof(*sd)/sizeof(uint32_t))); i++)
362 Write32BigEndian( (uint8_t *)&p[i], p[i] );
367 convertDictionaryInfoRead (DictionaryInfoChunk *sd)
369 /* Convert all fields in structure from BigEndian to Native. */
371 uint32_t *p = (uint32_t *) sd;
372 for (i=0; i<((int)(sizeof(*sd)/sizeof(uint32_t))); i++)
374 p[i] = Read32BigEndian( (uint8_t *)&p[i] );
378 /****************************************************************
379 ** Save Dictionary in File.
380 ** If EntryPoint is NULL, save as development environment.
381 ** If EntryPoint is non-NULL, save as turnKey environment with no names.
383 cell_t ffSaveForth( const char *FileName, ExecToken EntryPoint, cell_t NameSize, cell_t CodeSize)
386 DictionaryInfoChunk SD;
388 uint32_t NameChunkSize = 0;
389 uint32_t CodeChunkSize;
390 uint32_t relativeCodePtr;
392 fid = sdOpenFile( FileName, "wb" );
395 pfReportError("pfSaveDictionary", PF_ERR_OPEN_FILE);
399 /* Save in uninitialized form. */
400 pfExecIfDefined("AUTO.TERM");
402 /* Write FORM Header ---------------------------- */
403 if( Write32ToFile( fid, ID_FORM ) < 0 ) goto error;
404 if( Write32ToFile( fid, 0 ) < 0 ) goto error;
405 if( Write32ToFile( fid, ID_P4TH ) < 0 ) goto error;
407 /* Write P4DI Dictionary Info ------------------ */
408 SD.sd_Version = PF_FILE_VERSION;
410 relativeCodePtr = ABS_TO_CODEREL(gCurrentDictionary->dic_CodePtr.Byte); /* 940225 */
411 SD.sd_RelCodePtr = relativeCodePtr;
412 SD.sd_UserStackSize = sizeof(cell_t) * (gCurrentTask->td_StackBase - gCurrentTask->td_StackLimit);
413 SD.sd_ReturnStackSize = sizeof(cell_t) * (gCurrentTask->td_ReturnBase - gCurrentTask->td_ReturnLimit);
414 SD.sd_NumPrimitives = gNumPrimitives; /* Must match compiled dictionary. */
417 SD.sd_FloatSize = sizeof(PF_FLOAT); /* Must match compiled dictionary. */
422 SD.sd_CellSize = sizeof(cell_t);
424 /* Set bit that specifies whether dictionary is BIG or LITTLE Endian. */
426 #if defined(PF_BIG_ENDIAN_DIC)
427 int eflag = SD_F_BIG_ENDIAN_DIC;
428 #elif defined(PF_LITTLE_ENDIAN_DIC)
431 int eflag = IsHostLittleEndian() ? 0 : SD_F_BIG_ENDIAN_DIC;
438 SD.sd_EntryPoint = EntryPoint; /* Turnkey! */
442 SD.sd_EntryPoint = 0;
445 /* Do we save names? */
448 SD.sd_RelContext = 0;
449 SD.sd_RelHeaderPtr = 0;
454 uint32_t relativeHeaderPtr;
455 /* Development mode. */
456 SD.sd_RelContext = ABS_TO_NAMEREL(gVarContext);
457 relativeHeaderPtr = ABS_TO_NAMEREL(gCurrentDictionary->dic_HeaderPtr);
458 SD.sd_RelHeaderPtr = relativeHeaderPtr;
460 /* How much real name space is there? */
461 NameChunkSize = QUADUP(relativeHeaderPtr); /* Align */
463 /* NameSize must be 0 or greater than NameChunkSize + 1K */
464 NameSize = QUADUP(NameSize); /* Align */
467 NameSize = MAX( (ucell_t)NameSize, (NameChunkSize + 1024) );
469 SD.sd_NameSize = NameSize;
472 /* How much real code is there? */
473 CodeChunkSize = QUADUP(relativeCodePtr);
474 CodeSize = QUADUP(CodeSize); /* Align */
475 CodeSize = MAX( (ucell_t)CodeSize, (CodeChunkSize + 2048) );
476 SD.sd_CodeSize = CodeSize;
479 convertDictionaryInfoWrite (&SD);
481 if( WriteChunkToFile( fid, ID_P4DI, (char *) &SD, sizeof(DictionaryInfoChunk) ) < 0 ) goto error;
483 /* Write Name Fields if NameSize non-zero ------- */
486 if( WriteChunkToFile( fid, ID_P4NM, (char *) NAME_BASE,
487 NameChunkSize ) < 0 ) goto error;
490 /* Write Code Fields ---------------------------- */
491 if( WriteChunkToFile( fid, ID_P4CD, (char *) CODE_BASE,
492 CodeChunkSize ) < 0 ) goto error;
494 FormSize = (uint32_t) sdTellFile( fid ) - 8;
495 sdSeekFile( fid, 4, PF_SEEK_SET );
496 if( Write32ToFile( fid, FormSize ) < 0 ) goto error;
500 /* Restore initialization. */
501 pfExecIfDefined("AUTO.INIT");
505 sdSeekFile( fid, 0, PF_SEEK_SET );
506 Write32ToFile( fid, ID_BADF ); /* Mark file as bad. */
509 /* Restore initialization. */
510 pfExecIfDefined("AUTO.INIT");
515 #endif /* !PF_NO_FILEIO and !PF_NO_SHELL */
520 /***************************************************************/
521 static int32_t Read32FromFile( FileStream *fid, uint32_t *ValPtr )
525 numr = sdReadFile( pad, 1, sizeof(pad), fid );
526 if( numr != sizeof(pad) ) return -1;
527 *ValPtr = Read32BigEndian( pad );
531 /***************************************************************/
532 PForthDictionary pfLoadDictionary( const char *FileName, ExecToken *EntryPointPtr )
534 pfDictionary_t *dic = NULL;
536 DictionaryInfoChunk *sd;
544 DBUG(("pfLoadDictionary( %s )\n", FileName ));
547 fid = sdOpenFile( FileName, "rb" );
550 pfReportError("pfLoadDictionary", PF_ERR_OPEN_FILE);
554 /* Read FORM, Size, ID */
555 if (Read32FromFile( fid, &ChunkID ) < 0) goto read_error;
556 if( ChunkID != ID_FORM )
558 pfReportError("pfLoadDictionary", PF_ERR_WRONG_FILE);
562 if (Read32FromFile( fid, &FormSize ) < 0) goto read_error;
563 BytesLeft = FormSize;
565 if (Read32FromFile( fid, &ChunkID ) < 0) goto read_error;
567 if( ChunkID != ID_P4TH )
569 pfReportError("pfLoadDictionary", PF_ERR_BAD_FILE);
573 /* Scan and parse all chunks in file. */
574 while( BytesLeft > 0 )
576 if (Read32FromFile( fid, &ChunkID ) < 0) goto read_error;
577 if (Read32FromFile( fid, &ChunkSize ) < 0) goto read_error;
580 DBUG(("ChunkID = %4s, Size = %d\n", (char *)&ChunkID, ChunkSize ));
585 sd = (DictionaryInfoChunk *) pfAllocMem( ChunkSize );
586 if( sd == NULL ) goto nomem_error;
588 numr = sdReadFile( sd, 1, ChunkSize, fid );
589 if( numr != ChunkSize ) goto read_error;
590 BytesLeft -= ChunkSize;
592 convertDictionaryInfoRead (sd);
594 isDicBigEndian = sd->sd_Flags & SD_F_BIG_ENDIAN_DIC;
598 MSG("pForth loading dictionary from file "); MSG(FileName);
600 MSG_NUM_D(" File format version is ", sd->sd_Version );
601 MSG_NUM_D(" Name space size = ", sd->sd_NameSize );
602 MSG_NUM_D(" Code space size = ", sd->sd_CodeSize );
603 MSG_NUM_D(" Entry Point = ", sd->sd_EntryPoint );
604 MSG_NUM_D(" Cell Size = ", sd->sd_CellSize );
605 MSG( (isDicBigEndian ? " Big Endian Dictionary" :
606 " Little Endian Dictionary") );
607 if( isDicBigEndian == IsHostLittleEndian() ) MSG(" !!!!");
611 if( sd->sd_Version > PF_FILE_VERSION )
613 pfReportError("pfLoadDictionary", PF_ERR_VERSION_FUTURE );
616 if( sd->sd_Version < PF_EARLIEST_FILE_VERSION )
618 pfReportError("pfLoadDictionary", PF_ERR_VERSION_PAST );
621 if( sd->sd_CellSize != sizeof(cell_t) )
623 pfReportError("pfLoadDictionary", PF_ERR_CELL_SIZE_CONFLICT );
626 if( sd->sd_NumPrimitives > NUM_PRIMITIVES )
628 pfReportError("pfLoadDictionary", PF_ERR_NOT_SUPPORTED );
632 /* Check to make sure that EndianNess of dictionary matches mode of pForth. */
633 #if defined(PF_BIG_ENDIAN_DIC)
634 if(isDicBigEndian == 0)
635 #elif defined(PF_LITTLE_ENDIAN_DIC)
636 if(isDicBigEndian == 1)
638 if( isDicBigEndian == IsHostLittleEndian() )
641 pfReportError("pfLoadDictionary", PF_ERR_ENDIAN_CONFLICT );
645 /* Check for compatible float size. */
647 if( sd->sd_FloatSize != sizeof(PF_FLOAT) )
649 if( sd->sd_FloatSize != 0 )
652 pfReportError("pfLoadDictionary", PF_ERR_FLOAT_CONFLICT );
656 dic = pfCreateDictionary( sd->sd_NameSize, sd->sd_CodeSize );
657 if( dic == NULL ) goto nomem_error;
658 gCurrentDictionary = dic;
659 if( sd->sd_NameSize > 0 )
661 gVarContext = NAMEREL_TO_ABS(sd->sd_RelContext); /* Restore context. */
662 gCurrentDictionary->dic_HeaderPtr = (ucell_t)(uint8_t *)
663 NAMEREL_TO_ABS(sd->sd_RelHeaderPtr);
668 gCurrentDictionary->dic_HeaderPtr = (ucell_t)NULL;
670 gCurrentDictionary->dic_CodePtr.Byte = (uint8_t *) CODEREL_TO_ABS(sd->sd_RelCodePtr);
671 gNumPrimitives = sd->sd_NumPrimitives; /* Must match compiled dictionary. */
672 /* Pass EntryPoint back to caller. */
673 if( EntryPointPtr != NULL ) *EntryPointPtr = sd->sd_EntryPoint;
679 pfReportError("pfLoadDictionary", PF_ERR_NO_SHELL );
684 pfReportError("pfLoadDictionary", PF_ERR_NO_NAMES );
687 if( gCurrentDictionary == NULL )
689 pfReportError("pfLoadDictionary", PF_ERR_BAD_FILE );
692 if( ChunkSize > NAME_SIZE )
694 pfReportError("pfLoadDictionary", PF_ERR_TOO_BIG);
697 numr = sdReadFile( (char *) NAME_BASE, 1, ChunkSize, fid );
698 if( numr != ChunkSize ) goto read_error;
699 BytesLeft -= ChunkSize;
700 #endif /* PF_NO_SHELL */
704 if( gCurrentDictionary == NULL )
706 pfReportError("pfLoadDictionary", PF_ERR_BAD_FILE );
709 if( ChunkSize > CODE_SIZE )
711 pfReportError("pfLoadDictionary", PF_ERR_TOO_BIG);
714 numr = sdReadFile( (uint8_t *) CODE_BASE, 1, ChunkSize, fid );
715 if( numr != ChunkSize ) goto read_error;
716 BytesLeft -= ChunkSize;
720 pfReportError("pfLoadDictionary", PF_ERR_BAD_FILE );
721 sdSeekFile( fid, ChunkSize, PF_SEEK_CUR );
731 /* Find special words in dictionary for global XTs. */
732 if( (Result = FindSpecialXTs()) < 0 )
734 pfReportError("pfLoadDictionary: FindSpecialXTs", (Err)Result);
739 DBUG(("pfLoadDictionary: return %p\n", dic));
740 return (PForthDictionary) dic;
743 pfReportError("pfLoadDictionary", PF_ERR_NO_MEM);
748 pfReportError("pfLoadDictionary", PF_ERR_READ_FILE);
757 PForthDictionary pfLoadDictionary( const char *FileName, ExecToken *EntryPointPtr )
760 (void) EntryPointPtr;
763 #endif /* !PF_NO_FILEIO */
767 /***************************************************************/
768 PForthDictionary pfLoadStaticDictionary( void )
773 cell_t NewNameSize, NewCodeSize;
775 if( IF_LITTLE_ENDIAN != IsHostLittleEndian() )
777 MSG( (IF_LITTLE_ENDIAN ?
778 "Little Endian Dictionary on " :
779 "Big Endian Dictionary on ") );
780 MSG( (IsHostLittleEndian() ?
781 "Little Endian CPU" :
786 /* Check to make sure that EndianNess of dictionary matches mode of pForth. */
787 #if defined(PF_BIG_ENDIAN_DIC)
788 if(IF_LITTLE_ENDIAN == 1)
789 #elif defined(PF_LITTLE_ENDIAN_DIC)
790 if(IF_LITTLE_ENDIAN == 0)
791 #else /* Code is native endian! */
792 if( IF_LITTLE_ENDIAN != IsHostLittleEndian() )
795 pfReportError("pfLoadStaticDictionary", PF_ERR_ENDIAN_CONFLICT );
800 #ifndef PF_EXTRA_HEADERS
801 #define PF_EXTRA_HEADERS (20000)
803 #ifndef PF_EXTRA_CODE
804 #define PF_EXTRA_CODE (40000)
807 /* Copy static const data to allocated dictionaries. */
808 NewNameSize = sizeof(MinDicNames) + PF_EXTRA_HEADERS;
809 NewCodeSize = sizeof(MinDicCode) + PF_EXTRA_CODE;
811 DBUG_NUM_D( "static dic name size = ", NewNameSize );
812 DBUG_NUM_D( "static dic code size = ", NewCodeSize );
814 gCurrentDictionary = dic = pfCreateDictionary( NewNameSize, NewCodeSize );
815 if( !dic ) goto nomem_error;
817 pfCopyMemory( (uint8_t *) dic->dic_HeaderBase, MinDicNames, sizeof(MinDicNames) );
818 pfCopyMemory( (uint8_t *) dic->dic_CodeBase, MinDicCode, sizeof(MinDicCode) );
819 DBUG(("Static data copied to newly allocated dictionaries.\n"));
821 dic->dic_CodePtr.Byte = (uint8_t *) CODEREL_TO_ABS(CODEPTR);
822 gNumPrimitives = NUM_PRIMITIVES;
826 /* Setup name space. */
827 dic->dic_HeaderPtr = (ucell_t)(uint8_t *) NAMEREL_TO_ABS(HEADERPTR);
828 gVarContext = NAMEREL_TO_ABS(RELCONTEXT); /* Restore context. */
830 /* Find special words in dictionary for global XTs. */
831 if( (Result = FindSpecialXTs()) < 0 )
833 pfReportError("pfLoadStaticDictionary: FindSpecialXTs", Result);
838 return (PForthDictionary) dic;
844 pfReportError("pfLoadStaticDictionary", PF_ERR_NO_MEM);
845 #endif /* PF_STATIC_DIC */