Training courses

Kernel and Embedded Linux

Bootlin training courses

Embedded Linux, kernel,
Yocto Project, Buildroot, real-time,
graphics, boot time, debugging...

Bootlin logo

Elixir Cross Referencer

   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__ */