summaryrefslogtreecommitdiff
path: root/stand/ficl/ficl.h
blob: 97cf00b0dff39d38bf7b168f80a1a5d073fdb7b6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
/*******************************************************************
** f i c l . h
** Forth Inspired Command Language
** Author: John Sadler (john_sadler@alum.mit.edu)
** Created: 19 July 1997
** Dedicated to RHS, in loving memory
** $Id: ficl.h,v 1.18 2001/12/05 07:21:34 jsadler Exp $
*******************************************************************/
/*
** Copyright (c) 1997-2001 John Sadler (john_sadler@alum.mit.edu)
** All rights reserved.
**
** Get the latest Ficl release at http://ficl.sourceforge.net
**
** I am interested in hearing from anyone who uses ficl. If you have
** a problem, a success story, a defect, an enhancement request, or
** if you would like to contribute to the ficl release, please
** contact me by email at the address above.
**
** L I C E N S E  and  D I S C L A I M E R
** 
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
** 1. Redistributions of source code must retain the above copyright
**    notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
**    notice, this list of conditions and the following disclaimer in the
**    documentation and/or other materials provided with the distribution.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
** ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
** SUCH DAMAGE.
*/

/* $FreeBSD$ */

#if !defined (__FICL_H__)
#define __FICL_H__
/*
** Ficl (Forth-inspired command language) is an ANS Forth
** interpreter written in C. Unlike traditional Forths, this
** interpreter is designed to be embedded into other systems
** as a command/macro/development prototype language. 
**
** Where Forths usually view themselves as the center of the system
** and expect the rest of the system to be coded in Forth, Ficl
** acts as a component of the system. It is easy to export 
** code written in C or ASM to Ficl in the style of TCL, or to invoke
** Ficl code from a compiled module. This allows you to do incremental
** development in a way that combines the best features of threaded 
** languages (rapid development, quick code/test/debug cycle,
** reasonably fast) with the best features of C (everyone knows it,
** easier to support large blocks of code, efficient, type checking).
**
** Ficl provides facilities for interoperating
** with programs written in C: C functions can be exported to Ficl,
** and Ficl commands can be executed via a C calling interface. The
** interpreter is re-entrant, so it can be used in multiple instances
** in a multitasking system. Unlike Forth, Ficl's outer interpreter
** expects a text block as input, and returns to the caller after each
** text block, so the "data pump" is somewhere in external code. This
** is more like TCL than Forth, which usually expcets to be at the center
** of the system, requesting input at its convenience. Each Ficl virtual 
** machine can be bound to a different I/O channel, and is independent
** of all others in in the same address space except that all virtual
** machines share a common dictionary (a sort or open symbol table that
** defines all of the elements of the language).
**
** Code is written in ANSI C for portability. 
**
** Summary of Ficl features and constraints:
** - Standard: Implements the ANSI Forth CORE word set and part 
**   of the CORE EXT word-set, SEARCH and SEARCH EXT, TOOLS and
**   TOOLS EXT, LOCAL and LOCAL ext and various extras.
** - Extensible: you can export code written in Forth, C, 
**   or asm in a straightforward way. Ficl provides open
**   facilities for extending the language in an application
**   specific way. You can even add new control structures!
** - Ficl and C can interact in two ways: Ficl can encapsulate
**   C code, or C code can invoke Ficl code.
** - Thread-safe, re-entrant: The shared system dictionary 
**   uses a locking mechanism that you can either supply
**   or stub out to provide exclusive access. Each Ficl
**   virtual machine has an otherwise complete state, and
**   each can be bound to a separate I/O channel (or none at all).
** - Simple encapsulation into existing systems: a basic implementation
**   requires three function calls (see the example program in testmain.c).
** - ROMable: Ficl is designed to work in RAM-based and ROM code / RAM data
**   environments. It does require somewhat more memory than a pure
**   ROM implementation because it builds its system dictionary in 
**   RAM at startup time.
** - Written an ANSI C to be as simple as I can make it to understand,
**   support, debug, and port. Compiles without complaint at /Az /W4 
**   (require ANSI C, max warnings) under Microsoft VC++ 5.
** - Does full 32 bit math (but you need to implement
**   two mixed precision math primitives (see sysdep.c))
** - Indirect threaded interpreter is not the fastest kind of
**   Forth there is (see pForth 68K for a really fast subroutine
**   threaded interpreter), but it's the cleanest match to a
**   pure C implementation.
**
** P O R T I N G   F i c l
**
** To install Ficl on your target system, you need an ANSI C compiler
** and its runtime library. Inspect the system dependent macros and
** functions in sysdep.h and sysdep.c and edit them to suit your
** system. For example, INT16 is a short on some compilers and an
** int on others. Check the default CELL alignment controlled by
** FICL_ALIGN. If necessary, add new definitions of ficlMalloc, ficlFree,
** ficlLockDictionary, and ficlTextOut to work with your operating system.
** Finally, use testmain.c as a guide to installing the Ficl system and 
** one or more virtual machines into your code. You do not need to include
** testmain.c in your build.
**
** T o   D o   L i s t
**
** 1. Unimplemented system dependent CORE word: key
** 2. Ficl uses the PAD in some CORE words - this violates the standard,
**    but it's cleaner for a multithreaded system. I'll have to make a
**    second pad for reference by the word PAD to fix this.
**
** F o r   M o r e   I n f o r m a t i o n
**
** Web home of ficl
**   http://ficl.sourceforge.net
** Check this website for Forth literature (including the ANSI standard)
**   http://www.taygeta.com/forthlit.html
** and here for software and more links
**   http://www.taygeta.com/forth.html
**
** Obvious Performance enhancement opportunities
** Compile speed
** - work on interpret speed
** - turn off locals (FICL_WANT_LOCALS)
** Interpret speed 
** - Change inner interpreter (and everything else)
**   so that a definition is a list of pointers to functions
**   and inline data rather than pointers to words. This gets
**   rid of vm->runningWord and a level of indirection in the
**   inner loop. I'll look at it for ficl 3.0
** - Make the main hash table a bigger prime (HASHSIZE)
** - FORGET about twiddling the hash function - my experience is
**   that that is a waste of time.
** - Eliminate the need to pass the pVM parameter on the stack
**   by dedicating a register to it. Most words need access to the
**   vm, but the parameter passing overhead can be reduced. One way
**   requires that the host OS have a task switch callout. Create
**   a global variable for the running VM and refer to it in words
**   that need VM access. Alternative: use thread local storage. 
**   For single threaded implementations, you can just use a global.
**   The first two solutions create portability problems, so I
**   haven't considered doing them. Another possibility is to
**   declare the pVm parameter to be "register", and hope the compiler
**   pays attention.
**
*/

/*
** Revision History:
** 
** 15 Apr 1999 (sadler) Merged FreeBSD changes for exception wordset and
** counted strings in ficlExec. 
** 12 Jan 1999 (sobral) Corrected EVALUATE behavior. Now TIB has an
** "end" field, and all words respect this. ficlExec is passed a "size"
** of TIB, as well as vmPushTib. This size is used to calculate the "end"
** of the string, ie, base+size. If the size is not known, pass -1.
**
** 10 Jan 1999 (sobral) EXCEPTION word set has been added, and existing
** words has been modified to conform to EXCEPTION EXT word set. 
**
** 27 Aug 1998 (sadler) testing and corrections for LOCALS, LOCALS EXT,
**  SEARCH / SEARCH EXT, TOOLS / TOOLS EXT. 
**  Added .X to display in hex, PARSE and PARSE-WORD to supplement WORD,
**  EMPTY to clear stack.
**
** 29 jun 1998 (sadler) added variable sized hash table support
**  and ANS Forth optional SEARCH & SEARCH EXT word set.
** 26 May 1998 (sadler) 
**  FICL_PROMPT macro
** 14 April 1998 (sadler) V1.04
**  Ficlwin: Windows version, Skip Carter's Linux port
** 5 March 1998 (sadler) V1.03
**  Bug fixes -- passes John Ryan's ANS test suite "core.fr"
**
** 24 February 1998 (sadler) V1.02
** -Fixed bugs in <# # #>
** -Changed FICL_WORD so that storage for the name characters
**  can be allocated from the dictionary as needed rather than 
**  reserving 32 bytes in each word whether needed or not - 
**  this saved 50% of the dictionary storage requirement.
** -Added words in testmain for Win32 functions system,chdir,cwd,
**  also added a word that loads and evaluates a file.
**
** December 1997 (sadler)
** -Added VM_RESTART exception handling in ficlExec -- this lets words
**  that require additional text to succeed (like :, create, variable...)
**  recover gracefully from an empty input buffer rather than emitting
**  an error message. Definitions can span multiple input blocks with
**  no restrictions.
** -Changed #include order so that <assert.h> is included in sysdep.h,
**  and sysdep is included in all other files. This lets you define
**  NDEBUG in sysdep.h to disable assertions if you want to.
** -Make PC specific system dependent code conditional on _M_IX86
**  defined so that ports can coexist in sysdep.h/sysdep.c
*/

#ifdef __cplusplus
extern "C" {
#endif

#include "sysdep.h"
#include <limits.h> /* UCHAR_MAX */

/*
** Forward declarations... read on.
*/
struct ficl_word;
typedef struct ficl_word FICL_WORD;
struct vm;
typedef struct vm FICL_VM;
struct ficl_dict;
typedef struct ficl_dict FICL_DICT;
struct ficl_system;
typedef struct ficl_system FICL_SYSTEM;
struct ficl_system_info;
typedef struct ficl_system_info FICL_SYSTEM_INFO;

/* 
** the Good Stuff starts here...
*/
#define FICL_VER        "3.03"
#define FICL_VER_MAJOR  3
#define FICL_VER_MINOR  3
#if !defined (FICL_PROMPT)
#define FICL_PROMPT "ok> "
#endif

/*
** ANS Forth requires false to be zero, and true to be the ones
** complement of false... that unifies logical and bitwise operations
** nicely.
*/
#define FICL_TRUE  (~(FICL_UNS)0)
#define FICL_FALSE (0)
#define FICL_BOOL(x) ((x) ? FICL_TRUE : FICL_FALSE)


/*
** A CELL is the main storage type. It must be large enough
** to contain a pointer or a scalar. In order to accommodate 
** 32 bit and 64 bit processors, use abstract types for int, 
** unsigned, and float.
*/
typedef union _cell
{
    FICL_INT i;
    FICL_UNS u;
#if (FICL_WANT_FLOAT)
    FICL_FLOAT f;
#endif
    void *p;
    void (*fn)(void);
} CELL;

/*
** LVALUEtoCELL does a little pointer trickery to cast any CELL sized
** lvalue (informal definition: an expression whose result has an
** address) to CELL. Remember that constants and casts are NOT
** themselves lvalues!
*/
#define LVALUEtoCELL(v) (*(CELL *)&v)

/*
** PTRtoCELL is a cast through void * intended to satisfy the
** most outrageously pedantic compiler... (I won't mention 
** its name)
*/
#define PTRtoCELL (CELL *)(void *)
#define PTRtoSTRING (FICL_STRING *)(void *)

/*
** Strings in FICL are stored in Pascal style - with a count
** preceding the text. We'll also NULL-terminate them so that 
** they work with the usual C lib string functions. (Belt &
** suspenders? You decide.)
** STRINGINFO hides the implementation with a couple of
** macros for use in internal routines.
*/

typedef unsigned char FICL_COUNT;
#define FICL_STRING_MAX UCHAR_MAX
typedef struct _ficl_string
{
    FICL_COUNT count;
    char text[1];
} FICL_STRING;

typedef struct 
{
    FICL_UNS count;
    char *cp;
} STRINGINFO;

#define SI_COUNT(si) (si.count)
#define SI_PTR(si)   (si.cp)
#define SI_SETLEN(si, len) (si.count = (FICL_UNS)(len))
#define SI_SETPTR(si, ptr) (si.cp = (char *)(ptr))
/* 
** Init a STRINGINFO from a pointer to NULL-terminated string
*/
#define SI_PSZ(si, psz) \
            {si.cp = psz; si.count = (FICL_COUNT)strlen(psz);}
/* 
** Init a STRINGINFO from a pointer to FICL_STRING
*/
#define SI_PFS(si, pfs) \
            {si.cp = pfs->text; si.count = pfs->count;}

/*
** Ficl uses this little structure to hold the address of 
** the block of text it's working on and an index to the next
** unconsumed character in the string. Traditionally, this is
** done by a Text Input Buffer, so I've called this struct TIB.
**
** Since this structure also holds the size of the input buffer,
** and since evaluate requires that, let's put the size here.
** The size is stored as an end-pointer because that is what the
** null-terminated string aware functions find most easy to deal
** with.
** Notice, though, that nobody really uses this except evaluate,
** so it might just be moved to FICL_VM instead. (sobral)
*/
typedef struct
{
    FICL_INT index;
    char *end;
    char *cp;
} TIB;


/*
** Stacks get heavy use in Ficl and Forth...
** Each virtual machine implements two of them:
** one holds parameters (data), and the other holds return
** addresses and control flow information for the virtual
** machine. (Note: C's automatic stack is implicitly used,
** but not modeled because it doesn't need to be...)
** Here's an abstract type for a stack
*/
typedef struct _ficlStack
{
    FICL_UNS nCells;    /* size of the stack */
    CELL *pFrame;       /* link reg for stack frame */
    CELL *sp;           /* stack pointer */
    CELL base[1];       /* Top of stack */
} FICL_STACK;

/*
** Stack methods... many map closely to required Forth words.
*/
FICL_STACK *stackCreate   (unsigned nCells);
void        stackDelete   (FICL_STACK *pStack);
int         stackDepth    (FICL_STACK *pStack);
void        stackDrop     (FICL_STACK *pStack, int n);
CELL        stackFetch    (FICL_STACK *pStack, int n);
CELL        stackGetTop   (FICL_STACK *pStack);
void        stackLink     (FICL_STACK *pStack, int nCells);
void        stackPick     (FICL_STACK *pStack, int n);
CELL        stackPop      (FICL_STACK *pStack);
void       *stackPopPtr   (FICL_STACK *pStack);
FICL_UNS    stackPopUNS   (FICL_STACK *pStack);
FICL_INT    stackPopINT   (FICL_STACK *pStack);
void        stackPush     (FICL_STACK *pStack, CELL c);
void        stackPushPtr  (FICL_STACK *pStack, void *ptr);
void        stackPushUNS  (FICL_STACK *pStack, FICL_UNS u);
void        stackPushINT  (FICL_STACK *pStack, FICL_INT i);
void        stackReset    (FICL_STACK *pStack);
void        stackRoll     (FICL_STACK *pStack, int n);
void        stackSetTop   (FICL_STACK *pStack, CELL c);
void        stackStore    (FICL_STACK *pStack, int n, CELL c);
void        stackUnlink   (FICL_STACK *pStack);

#if (FICL_WANT_FLOAT)
float       stackPopFloat (FICL_STACK *pStack);
void        stackPushFloat(FICL_STACK *pStack, FICL_FLOAT f);
#endif

/*
** Shortcuts (Guy Carver)
*/
#define PUSHPTR(p)   stackPushPtr(pVM->pStack,p)
#define PUSHUNS(u)   stackPushUNS(pVM->pStack,u)
#define PUSHINT(i)   stackPushINT(pVM->pStack,i)
#define PUSHFLOAT(f) stackPushFloat(pVM->fStack,f)
#define PUSH(c)      stackPush(pVM->pStack,c)
#define POPPTR()     stackPopPtr(pVM->pStack)
#define POPUNS()     stackPopUNS(pVM->pStack)
#define POPINT()     stackPopINT(pVM->pStack)
#define POPFLOAT()   stackPopFloat(pVM->fStack)
#define POP()        stackPop(pVM->pStack)
#define GETTOP()     stackGetTop(pVM->pStack)
#define SETTOP(c)    stackSetTop(pVM->pStack,LVALUEtoCELL(c))
#define GETTOPF()    stackGetTop(pVM->fStack)
#define SETTOPF(c)   stackSetTop(pVM->fStack,LVALUEtoCELL(c))
#define STORE(n,c)   stackStore(pVM->pStack,n,LVALUEtoCELL(c))
#define DEPTH()      stackDepth(pVM->pStack)
#define DROP(n)      stackDrop(pVM->pStack,n)
#define DROPF(n)     stackDrop(pVM->fStack,n)
#define FETCH(n)     stackFetch(pVM->pStack,n)
#define PICK(n)      stackPick(pVM->pStack,n)
#define PICKF(n)     stackPick(pVM->fStack,n)
#define ROLL(n)      stackRoll(pVM->pStack,n)
#define ROLLF(n)     stackRoll(pVM->fStack,n)

/* 
** The virtual machine (VM) contains the state for one interpreter.
** Defined operations include:
** Create & initialize
** Delete
** Execute a block of text
** Parse a word out of the input stream
** Call return, and branch 
** Text output
** Throw an exception
*/

typedef FICL_WORD ** IPTYPE; /* the VM's instruction pointer */

/*
** Each VM has a placeholder for an output function -
** this makes it possible to have each VM do I/O
** through a different device. If you specify no
** OUTFUNC, it defaults to ficlTextOut.
*/
typedef void (*OUTFUNC)(FICL_VM *pVM, char *text, int fNewline);

/*
** Each VM operates in one of two non-error states: interpreting
** or compiling. When interpreting, words are simply executed.
** When compiling, most words in the input stream have their
** addresses inserted into the word under construction. Some words
** (known as IMMEDIATE) are executed in the compile state, too.
*/
/* values of STATE */
#define INTERPRET 0
#define COMPILE   1

/*
** The pad is a small scratch area for text manipulation. ANS Forth
** requires it to hold at least 84 characters.
*/
#if !defined nPAD
#define nPAD 256
#endif

/* 
** ANS Forth requires that a word's name contain {1..31} characters.
*/
#if !defined nFICLNAME
#define nFICLNAME       31
#endif

/*
** OK - now we can really define the VM...
*/
struct vm
{
    FICL_SYSTEM    *pSys;       /* Which system this VM belongs to  */
    FICL_VM        *link;       /* Ficl keeps a VM list for simple teardown */
    jmp_buf        *pState;     /* crude exception mechanism...     */
    OUTFUNC         textOut;    /* Output callback - see sysdep.c   */
    void *          pExtend;    /* vm extension pointer for app use - initialized from FICL_SYSTEM */
    short           fRestart;   /* Set TRUE to restart runningWord  */
    IPTYPE          ip;         /* instruction pointer              */
    FICL_WORD      *runningWord;/* address of currently running word (often just *(ip-1) ) */
    FICL_UNS        state;      /* compiling or interpreting        */
    FICL_UNS        base;       /* number conversion base           */
    FICL_STACK     *pStack;     /* param stack                      */
    FICL_STACK     *rStack;     /* return stack                     */
#if FICL_WANT_FLOAT
    FICL_STACK     *fStack;     /* float stack (optional)           */
#endif
    CELL            sourceID;   /* -1 if EVALUATE, 0 if normal input */
    TIB             tib;        /* address of incoming text string  */
#if FICL_WANT_USER
    CELL            user[FICL_USER_CELLS];
#endif
    char            pad[nPAD];  /* the scratch area (see above)     */
};

/*
** A FICL_CODE points to a function that gets called to help execute
** a word in the dictionary. It always gets passed a pointer to the
** running virtual machine, and from there it can get the address
** of the parameter area of the word it's supposed to operate on.
** For precompiled words, the code is all there is. For user defined
** words, the code assumes that the word's parameter area is a list
** of pointers to the code fields of other words to execute, and
** may also contain inline data. The first parameter is always
** a pointer to a code field.
*/
typedef void (*FICL_CODE)(FICL_VM *pVm);

#if 0
#define VM_ASSERT(pVM) assert((*(pVM->ip - 1)) == pVM->runningWord)
#else
#define VM_ASSERT(pVM) 
#endif

/* 
** Ficl models memory as a contiguous space divided into
** words in a linked list called the dictionary.
** A FICL_WORD starts each entry in the list.
** Version 1.02: space for the name characters is allotted from
** the dictionary ahead of the word struct, rather than using
** a fixed size array for each name.
*/
struct ficl_word
{
    struct ficl_word *link;     /* Previous word in the dictionary      */
    UNS16 hash;
    UNS8 flags;                 /* Immediate, Smudge, Compile-only      */
    FICL_COUNT nName;           /* Number of chars in word name         */
    char *name;                 /* First nFICLNAME chars of word name   */
    FICL_CODE code;             /* Native code to execute the word      */
    CELL param[1];              /* First data cell of the word          */
};

/*
** Worst-case size of a word header: nFICLNAME chars in name
*/
#define CELLS_PER_WORD  \
    ( (sizeof (FICL_WORD) + nFICLNAME + sizeof (CELL)) \
                          / (sizeof (CELL)) )

int wordIsImmediate(FICL_WORD *pFW);
int wordIsCompileOnly(FICL_WORD *pFW);

/* flag values for word header */
#define FW_IMMEDIATE    1   /* execute me even if compiling */
#define FW_COMPILE      2   /* error if executed when not compiling */
#define FW_SMUDGE       4   /* definition in progress - hide me */
#define FW_ISOBJECT     8   /* word is an object or object member variable */

#define FW_COMPIMMED    (FW_IMMEDIATE | FW_COMPILE)
#define FW_DEFAULT      0


/*
** Exit codes for vmThrow
*/
#define VM_INNEREXIT -256   /* tell ficlExecXT to exit inner loop */
#define VM_OUTOFTEXT -257   /* hungry - normal exit */
#define VM_RESTART   -258   /* word needs more text to succeed - re-run it */
#define VM_USEREXIT  -259   /* user wants to quit */
#define VM_ERREXIT   -260   /* interp found an error */
#define VM_BREAK     -261   /* debugger breakpoint */
#define VM_ABORT       -1   /* like errexit -- abort */
#define VM_ABORTQ      -2   /* like errexit -- abort" */
#define VM_QUIT       -56   /* like errexit, but leave pStack & base alone */


void        vmBranchRelative(FICL_VM *pVM, int offset);
FICL_VM *   vmCreate       (FICL_VM *pVM, unsigned nPStack, unsigned nRStack);
void        vmDelete       (FICL_VM *pVM);
void        vmExecute      (FICL_VM *pVM, FICL_WORD *pWord);
FICL_DICT  *vmGetDict      (FICL_VM *pVM);
char *      vmGetString    (FICL_VM *pVM, FICL_STRING *spDest, char delimiter);
STRINGINFO  vmGetWord      (FICL_VM *pVM);
STRINGINFO  vmGetWord0     (FICL_VM *pVM);
int         vmGetWordToPad (FICL_VM *pVM);
STRINGINFO  vmParseString  (FICL_VM *pVM, char delimiter);
STRINGINFO  vmParseStringEx(FICL_VM *pVM, char delimiter, char fSkipLeading);
CELL        vmPop          (FICL_VM *pVM);
void        vmPush         (FICL_VM *pVM, CELL c);
void        vmPopIP        (FICL_VM *pVM);
void        vmPushIP       (FICL_VM *pVM, IPTYPE newIP);
void        vmQuit         (FICL_VM *pVM);
void        vmReset        (FICL_VM *pVM);
void        vmSetTextOut   (FICL_VM *pVM, OUTFUNC textOut);
void        vmTextOut      (FICL_VM *pVM, char *text, int fNewline);
void        vmTextOut      (FICL_VM *pVM, char *text, int fNewline);
void        vmThrow        (FICL_VM *pVM, int except);
void        vmThrowErr     (FICL_VM *pVM, char *fmt, ...);

#define vmGetRunningWord(pVM) ((pVM)->runningWord)


/*
** The inner interpreter - coded as a macro (see note for 
** INLINE_INNER_LOOP in sysdep.h for complaints about VC++ 5
*/
#define M_VM_STEP(pVM) \
        FICL_WORD *tempFW = *(pVM)->ip++; \
        (pVM)->runningWord = tempFW; \
        tempFW->code(pVM); 

#define M_INNER_LOOP(pVM) \
    for (;;)  { M_VM_STEP(pVM) }


#if INLINE_INNER_LOOP != 0
#define     vmInnerLoop(pVM) M_INNER_LOOP(pVM)
#else
void        vmInnerLoop(FICL_VM *pVM);
#endif

/*
** vmCheckStack needs a vm pointer because it might have to say
** something if it finds a problem. Parms popCells and pushCells
** correspond to the number of parameters on the left and right of 
** a word's stack effect comment.
*/
void        vmCheckStack(FICL_VM *pVM, int popCells, int pushCells);
#if FICL_WANT_FLOAT
void        vmCheckFStack(FICL_VM *pVM, int popCells, int pushCells);
#endif

/*
** TIB access routines...
** ANS forth seems to require the input buffer to be represented 
** as a pointer to the start of the buffer, and an index to the
** next character to read.
** PushTib points the VM to a new input string and optionally
**  returns a copy of the current state
** PopTib restores the TIB state given a saved TIB from PushTib
** GetInBuf returns a pointer to the next unused char of the TIB
*/
void        vmPushTib  (FICL_VM *pVM, char *text, FICL_INT nChars, TIB *pSaveTib);
void        vmPopTib   (FICL_VM *pVM, TIB *pTib);
#define     vmGetInBuf(pVM)      ((pVM)->tib.cp + (pVM)->tib.index)
#define     vmGetInBufLen(pVM)   ((pVM)->tib.end - (pVM)->tib.cp)
#define     vmGetInBufEnd(pVM)   ((pVM)->tib.end)
#define     vmGetTibIndex(pVM)    (pVM)->tib.index
#define     vmSetTibIndex(pVM, i) (pVM)->tib.index = i
#define     vmUpdateTib(pVM, str) (pVM)->tib.index = (str) - (pVM)->tib.cp

/*
** Generally useful string manipulators omitted by ANSI C...
** ltoa complements strtol
*/
#if defined(_WIN32) && !FICL_MAIN
/* #SHEESH
** Why do Microsoft Meatballs insist on contaminating
** my namespace with their string functions???
*/
#pragma warning(disable: 4273)
#endif

int        isPowerOfTwo(FICL_UNS u);

char       *ltoa( FICL_INT value, char *string, int radix );
char       *ultoa(FICL_UNS value, char *string, int radix );
char        digit_to_char(int value);
char       *strrev( char *string );
char       *skipSpace(char *cp, char *end);
char       *caseFold(char *cp);
int         strincmp(char *cp1, char *cp2, FICL_UNS count);

#if defined(_WIN32) && !FICL_MAIN
#pragma warning(default: 4273)
#endif

/*
** Ficl hash table - variable size.
** assert(size > 0)
** If size is 1, the table degenerates into a linked list.
** A WORDLIST (see the search order word set in DPANS) is
** just a pointer to a FICL_HASH in this implementation.
*/
#if !defined HASHSIZE /* Default size of hash table. For most uniform */
#define HASHSIZE 241  /*   performance, use a prime number!   */
#endif

typedef struct ficl_hash 
{
    struct ficl_hash *link;  /* link to parent class wordlist for OO */
    char      *name;         /* optional pointer to \0 terminated wordlist name */
    unsigned   size;         /* number of buckets in the hash */
    FICL_WORD *table[1];
} FICL_HASH;

void        hashForget    (FICL_HASH *pHash, void *where);
UNS16       hashHashCode  (STRINGINFO si);
void        hashInsertWord(FICL_HASH *pHash, FICL_WORD *pFW);
FICL_WORD  *hashLookup    (FICL_HASH *pHash, STRINGINFO si, UNS16 hashCode);
void        hashReset     (FICL_HASH *pHash);

/*
** A Dictionary is a linked list of FICL_WORDs. It is also Ficl's
** memory model. Description of fields:
**
** here -- points to the next free byte in the dictionary. This
**      pointer is forced to be CELL-aligned before a definition is added.
**      Do not assume any specific alignment otherwise - Use dictAlign().
**
** smudge -- pointer to word currently being defined (or last defined word)
**      If the definition completes successfully, the word will be
**      linked into the hash table. If unsuccessful, dictUnsmudge
**      uses this pointer to restore the previous state of the dictionary.
**      Smudge prevents unintentional recursion as a side-effect: the
**      dictionary search algo examines only completed definitions, so a 
**      word cannot invoke itself by name. See the ficl word "recurse".
**      NOTE: smudge always points to the last word defined. IMMEDIATE
**      makes use of this fact. Smudge is initially NULL.
**
** pForthWords -- pointer to the default wordlist (FICL_HASH).
**      This is the initial compilation list, and contains all
**      ficl's precompiled words.
**
** pCompile -- compilation wordlist - initially equal to pForthWords
** pSearch  -- array of pointers to wordlists. Managed as a stack.
**      Highest index is the first list in the search order.
** nLists   -- number of lists in pSearch. nLists-1 is the highest 
**      filled slot in pSearch, and points to the first wordlist
**      in the search order
** size -- number of cells in the dictionary (total)
** dict -- start of data area. Must be at the end of the struct.
*/
struct ficl_dict
{
    CELL *here;
    FICL_WORD *smudge;
    FICL_HASH *pForthWords;
    FICL_HASH *pCompile;
    FICL_HASH *pSearch[FICL_DEFAULT_VOCS];
    int        nLists;
    unsigned   size;    /* Number of cells in dict (total)*/
    CELL       *dict;   /* Base of dictionary memory      */
};

void       *alignPtr(void *ptr);
void        dictAbortDefinition(FICL_DICT *pDict);
void        dictAlign      (FICL_DICT *pDict);
int         dictAllot      (FICL_DICT *pDict, int n);
int         dictAllotCells (FICL_DICT *pDict, int nCells);
void        dictAppendCell (FICL_DICT *pDict, CELL c);
void        dictAppendChar (FICL_DICT *pDict, char c);
FICL_WORD  *dictAppendWord (FICL_DICT *pDict, 
                           char *name, 
                           FICL_CODE pCode, 
                           UNS8 flags);
FICL_WORD  *dictAppendWord2(FICL_DICT *pDict, 
                           STRINGINFO si, 
                           FICL_CODE pCode, 
                           UNS8 flags);
void        dictAppendUNS  (FICL_DICT *pDict, FICL_UNS u);
int         dictCellsAvail (FICL_DICT *pDict);
int         dictCellsUsed  (FICL_DICT *pDict);
void        dictCheck      (FICL_DICT *pDict, FICL_VM *pVM, int n);
void        dictCheckThreshold(FICL_DICT* dp);
FICL_DICT  *dictCreate(unsigned nCELLS);
FICL_DICT  *dictCreateHashed(unsigned nCells, unsigned nHash);
FICL_HASH  *dictCreateWordlist(FICL_DICT *dp, int nBuckets);
void        dictDelete     (FICL_DICT *pDict);
void        dictEmpty      (FICL_DICT *pDict, unsigned nHash);
#if FICL_WANT_FLOAT
void        dictHashSummary(FICL_VM *pVM);
#endif
int         dictIncludes   (FICL_DICT *pDict, void *p);
FICL_WORD  *dictLookup     (FICL_DICT *pDict, STRINGINFO si);
#if FICL_WANT_LOCALS
FICL_WORD  *ficlLookupLoc  (FICL_SYSTEM *pSys, STRINGINFO si);
#endif
void        dictResetSearchOrder(FICL_DICT *pDict);
void        dictSetFlags   (FICL_DICT *pDict, UNS8 set, UNS8 clr);
void        dictSetImmediate(FICL_DICT *pDict);
void        dictUnsmudge   (FICL_DICT *pDict);
CELL       *dictWhere      (FICL_DICT *pDict);


/* 
** P A R S E   S T E P
** (New for 2.05)
** See words.c: interpWord
** By default, ficl goes through two attempts to parse each token from its input
** stream: it first attempts to match it with a word in the dictionary, and
** if that fails, it attempts to convert it into a number. This mechanism is now
** extensible by additional steps. This allows extensions like floating point and 
** double number support to be factored cleanly.
**
** Each parse step is a function that receives the next input token as a STRINGINFO.
** If the parse step matches the token, it must apply semantics to the token appropriate
** to the present value of VM.state (compiling or interpreting), and return FICL_TRUE.
** Otherwise it returns FICL_FALSE. See words.c: isNumber for an example
**
** Note: for the sake of efficiency, it's a good idea both to limit the number
** of parse steps and to code each parse step so that it rejects tokens that
** do not match as quickly as possible.
*/

typedef int (*FICL_PARSE_STEP)(FICL_VM *pVM, STRINGINFO si);

/*
** Appends a parse step function to the end of the parse list (see 
** FICL_PARSE_STEP notes in ficl.h for details). Returns 0 if successful,
** nonzero if there's no more room in the list. Each parse step is a word in 
** the dictionary. Precompiled parse steps can use (PARSE-STEP) as their 
** CFA - see parenParseStep in words.c.
*/
int  ficlAddParseStep(FICL_SYSTEM *pSys, FICL_WORD *pFW); /* ficl.c */
void ficlAddPrecompiledParseStep(FICL_SYSTEM *pSys, char *name, FICL_PARSE_STEP pStep);
void ficlListParseSteps(FICL_VM *pVM);

/*
** FICL_BREAKPOINT record.
** origXT - if NULL, this breakpoint is unused. Otherwise it stores the xt 
** that the breakpoint overwrote. This is restored to the dictionary when the
** BP executes or gets cleared
** address - the location of the breakpoint (address of the instruction that
**           has been replaced with the breakpoint trap
** origXT  - The original contents of the location with the breakpoint
** Note: address is NULL when this breakpoint is empty
*/
typedef struct FICL_BREAKPOINT
{
    void      *address;
    FICL_WORD *origXT;
} FICL_BREAKPOINT;


/*
** F I C L _ S Y S T E M
** The top level data structure of the system - ficl_system ties a list of
** virtual machines with their corresponding dictionaries. Ficl 3.0 will
** support multiple Ficl systems, allowing multiple concurrent sessions 
** to separate dictionaries with some constraints. 
** The present model allows multiple sessions to one dictionary provided
** you implement ficlLockDictionary() as specified in sysdep.h
** Note: the pExtend pointer is there to provide context for applications. It is copied
** to each VM's pExtend field as that VM is created.
*/
struct ficl_system 
{
    FICL_SYSTEM *link;
    void *pExtend;      /* Initializes VM's pExtend pointer (for application use) */
    FICL_VM *vmList;
    FICL_DICT *dp;
    FICL_DICT *envp;
#ifdef FICL_WANT_LOCALS
    FICL_DICT *localp;
#endif
    FICL_WORD *pInterp[3];
    FICL_WORD *parseList[FICL_MAX_PARSE_STEPS];
	OUTFUNC    textOut;

	FICL_WORD *pBranchParen;
	FICL_WORD *pDoParen;
	FICL_WORD *pDoesParen;
	FICL_WORD *pExitInner;
	FICL_WORD *pExitParen;
	FICL_WORD *pBranch0;
	FICL_WORD *pInterpret;
	FICL_WORD *pLitParen;
	FICL_WORD *pTwoLitParen;
	FICL_WORD *pLoopParen;
	FICL_WORD *pPLoopParen;
	FICL_WORD *pQDoParen;
	FICL_WORD *pSemiParen;
	FICL_WORD *pOfParen;
	FICL_WORD *pStore;
	FICL_WORD *pDrop;
	FICL_WORD *pCStringLit;
	FICL_WORD *pStringLit;

#if FICL_WANT_LOCALS
	FICL_WORD *pGetLocalParen;
	FICL_WORD *pGet2LocalParen;
	FICL_WORD *pGetLocal0;
	FICL_WORD *pGetLocal1;
	FICL_WORD *pToLocalParen;
	FICL_WORD *pTo2LocalParen;
	FICL_WORD *pToLocal0;
	FICL_WORD *pToLocal1;
	FICL_WORD *pLinkParen;
	FICL_WORD *pUnLinkParen;
	FICL_INT   nLocals;
	CELL *pMarkLocals;
#endif

	FICL_BREAKPOINT bpStep;
};

struct ficl_system_info
{
	int size;           /* structure size tag for versioning */
	int nDictCells;     /* Size of system's Dictionary */
	OUTFUNC textOut;    /* default textOut function */
	void *pExtend;      /* Initializes VM's pExtend pointer - for application use */
    int nEnvCells;      /* Size of Environment dictionary */
};


#define ficlInitInfo(x) { memset((x), 0, sizeof(FICL_SYSTEM_INFO)); \
         (x)->size = sizeof(FICL_SYSTEM_INFO); }

/*
** External interface to FICL...
*/
/* 
** f i c l I n i t S y s t e m
** Binds a global dictionary to the interpreter system and initializes
** the dict to contain the ANSI CORE wordset. 
** You can specify the address and size of the allocated area.
** Using ficlInitSystemEx you can also specify the text output function.
** After that, ficl manages it.
** First step is to set up the static pointers to the area.
** Then write the "precompiled" portion of the dictionary in.
** The dictionary needs to be at least large enough to hold the
** precompiled part. Try 1K cells minimum. Use "words" to find
** out how much of the dictionary is used at any time.
*/
FICL_SYSTEM *ficlInitSystemEx(FICL_SYSTEM_INFO *fsi);

/* Deprecated call */
FICL_SYSTEM *ficlInitSystem(int nDictCells);

/*
** f i c l T e r m S y s t e m
** Deletes the system dictionary and all virtual machines that
** were created with ficlNewVM (see below). Call this function to
** reclaim all memory used by the dictionary and VMs.
*/
void       ficlTermSystem(FICL_SYSTEM *pSys);

/*
** f i c l E v a l u a t e
** Evaluates a block of input text in the context of the
** specified interpreter. Also sets SOURCE-ID properly.
**
** PLEASE USE THIS FUNCTION when throwing a hard-coded
** string to the FICL interpreter.
*/
int        ficlEvaluate(FICL_VM *pVM, char *pText);

/*
** f i c l E x e c
** Evaluates a block of input text in the context of the
** specified interpreter. Emits any requested output to the
** interpreter's output function. If the input string is NULL
** terminated, you can pass -1 as nChars rather than count it.
** Execution returns when the text block has been executed,
** or an error occurs.
** Returns one of the VM_XXXX codes defined in ficl.h:
** VM_OUTOFTEXT is the normal exit condition
** VM_ERREXIT means that the interp encountered a syntax error
**      and the vm has been reset to recover (some or all
**      of the text block got ignored
** VM_USEREXIT means that the user executed the "bye" command
**      to shut down the interpreter. This would be a good
**      time to delete the vm, etc -- or you can ignore this
**      signal.
** VM_ABORT and VM_ABORTQ are generated by 'abort' and 'abort"'
**      commands.
** Preconditions: successful execution of ficlInitSystem,
**      Successful creation and init of the VM by ficlNewVM (or equiv)
**
** If you call ficlExec() or one of its brothers, you MUST
** ensure pVM->sourceID was set to a sensible value.
** ficlExec() explicitly DOES NOT manage SOURCE-ID for you.
*/
int        ficlExec (FICL_VM *pVM, char *pText);
int        ficlExecC(FICL_VM *pVM, char *pText, FICL_INT nChars);
int        ficlExecXT(FICL_VM *pVM, FICL_WORD *pWord);

/*
** ficlExecFD(FICL_VM *pVM, int fd);
 * Evaluates text from file passed in via fd.
 * Execution returns when all of file has been executed or an
 * error occurs.
 */
int        ficlExecFD(FICL_VM *pVM, int fd);

/*
** Create a new VM from the heap, and link it into the system VM list.
** Initializes the VM and binds default sized stacks to it. Returns the
** address of the VM, or NULL if an error occurs.
** Precondition: successful execution of ficlInitSystem
*/
FICL_VM   *ficlNewVM(FICL_SYSTEM *pSys);

/*
** Force deletion of a VM. You do not need to do this 
** unless you're creating and discarding a lot of VMs.
** For systems that use a constant pool of VMs for the life
** of the system, ficltermSystem takes care of VM cleanup
** automatically.
*/
void ficlFreeVM(FICL_VM *pVM);


/*
** Set the stack sizes (return and parameter) to be used for all
** subsequently created VMs. Returns actual stack size to be used.
*/
int ficlSetStackSize(int nStackCells);

/*
** Returns the address of the most recently defined word in the system
** dictionary with the given name, or NULL if no match.
** Precondition: successful execution of ficlInitSystem
*/
FICL_WORD *ficlLookup(FICL_SYSTEM *pSys, char *name);

/*
** f i c l G e t D i c t
** Utility function - returns the address of the system dictionary.
** Precondition: successful execution of ficlInitSystem
*/
FICL_DICT *ficlGetDict(FICL_SYSTEM *pSys);
FICL_DICT *ficlGetEnv (FICL_SYSTEM *pSys);
void       ficlSetEnv (FICL_SYSTEM *pSys, char *name, FICL_UNS value);
void       ficlSetEnvD(FICL_SYSTEM *pSys, char *name, FICL_UNS hi, FICL_UNS lo);
#if FICL_WANT_LOCALS
FICL_DICT *ficlGetLoc (FICL_SYSTEM *pSys);
#endif
/* 
** f i c l B u i l d
** Builds a word into the system default dictionary in a thread-safe way.
** Preconditions: system must be initialized, and there must
** be enough space for the new word's header! Operation is
** controlled by ficlLockDictionary, so any initialization
** required by your version of the function (if you "overrode"
** it) must be complete at this point.
** Parameters:
** name  -- the name of the word to be built
** code  -- code to execute when the word is invoked - must take a single param
**          pointer to a FICL_VM
** flags -- 0 or more of FW_IMMEDIATE, FW_COMPILE, use bitwise OR! 
**          Most words can use FW_DEFAULT.
** nAllot - number of extra cells to allocate in the parameter area (usually zero)
*/
int        ficlBuild(FICL_SYSTEM *pSys, char *name, FICL_CODE code, char flags);

/* 
** f i c l C o m p i l e C o r e
** Builds the ANS CORE wordset into the dictionary - called by
** ficlInitSystem - no need to waste dict space by doing it again.
*/
void       ficlCompileCore(FICL_SYSTEM *pSys);
void       ficlCompilePrefix(FICL_SYSTEM *pSys);
void       ficlCompileSearch(FICL_SYSTEM *pSys);
void       ficlCompileSoftCore(FICL_SYSTEM *pSys);
void       ficlCompileTools(FICL_SYSTEM *pSys);
void       ficlCompileFile(FICL_SYSTEM *pSys);
#if FICL_WANT_FLOAT
void       ficlCompileFloat(FICL_SYSTEM *pSys);
int        ficlParseFloatNumber( FICL_VM *pVM, STRINGINFO si ); /* float.c */
#endif
#if FICL_PLATFORM_EXTEND
void       ficlCompilePlatform(FICL_SYSTEM *pSys);
#endif
int        ficlParsePrefix(FICL_VM *pVM, STRINGINFO si);

/*
** from words.c...
*/
void       constantParen(FICL_VM *pVM);
void       twoConstParen(FICL_VM *pVM);
int        ficlParseNumber(FICL_VM *pVM, STRINGINFO si);
void       ficlTick(FICL_VM *pVM);
void       parseStepParen(FICL_VM *pVM);

/*
** From tools.c
*/
int        isAFiclWord(FICL_DICT *pd, FICL_WORD *pFW);

/* 
** The following supports SEE and the debugger.
*/
typedef enum  
{
    BRANCH,
    COLON, 
    CONSTANT, 
    CREATE,
    DO,
    DOES, 
    IF,
    LITERAL,
    LOOP,
    OF,
    PLOOP,
    PRIMITIVE,
    QDO,
    STRINGLIT,
    CSTRINGLIT,
#if FICL_WANT_USER
    USER, 
#endif
    VARIABLE, 
} WORDKIND;

WORDKIND   ficlWordClassify(FICL_WORD *pFW);

/*
** Dictionary on-demand resizing
*/
extern CELL dictThreshold;
extern CELL dictIncrease;

/*
** Various FreeBSD goodies
*/

#if defined(__i386__) && !defined(TESTMAIN)
extern void ficlOutb(FICL_VM *pVM);
extern void ficlInb(FICL_VM *pVM);
#endif

extern void ficlSetenv(FICL_VM *pVM);
extern void ficlSetenvq(FICL_VM *pVM);
extern void ficlGetenv(FICL_VM *pVM);
extern void ficlUnsetenv(FICL_VM *pVM);
extern void ficlCopyin(FICL_VM *pVM);
extern void ficlCopyout(FICL_VM *pVM);
extern void ficlFindfile(FICL_VM *pVM);
extern void ficlCcall(FICL_VM *pVM);
#if !defined(TESTMAIN)
extern void ficlPnpdevices(FICL_VM *pVM);
extern void ficlPnphandlers(FICL_VM *pVM);
#endif

/*
** Used with File-Access wordset.
*/
#define FICL_FAM_READ	1
#define FICL_FAM_WRITE	2
#define FICL_FAM_APPEND	4
#define FICL_FAM_BINARY	8

#define FICL_FAM_OPEN_MODE(fam)	((fam) & (FICL_FAM_READ | FICL_FAM_WRITE | FICL_FAM_APPEND))


#if (FICL_WANT_FILE)
typedef struct ficlFILE
{
	FILE *f;
	char filename[256];
} ficlFILE;
#endif

#include <sys/linker_set.h>

typedef void ficlCompileFcn(FICL_SYSTEM *);
#define FICL_COMPILE_SET(func)	\
	DATA_SET(Xficl_compile_set, func)
SET_DECLARE(Xficl_compile_set, ficlCompileFcn);

#ifdef LOADER_VERIEXEC
#include <verify_file.h>
#endif

#ifdef __cplusplus
}
#endif

#endif /* __FICL_H__ */