- •Contents
- •List of Figures
- •List of Tables
- •Welcome!
- •About the Forth Programming Language
- •About This Book
- •How to Use This Book
- •Reference Materials
- •How to Proceed
- •1. Introduction
- •1.1.1 Definitions of Terms
- •1.1.2 Dictionary
- •1.1.3 Data Stack
- •1.1.4 Return Stack
- •1.1.5 Text Interpreter
- •1.1.6 Numeric Input
- •1.1.7 Two-stack Virtual Machine
- •1.2 Forth Operating System Features
- •1.3 The Forth Assembler
- •1.3.1 Notational Differences
- •1.3.1.1 Instruction Mnemonics
- •1.3.1.2 Addressing Modes
- •1.3.1.3 Instruction Format
- •1.3.1.4 Labels, Branches, and Structures
- •1.3.2 Procedural Differences
- •1.3.2.1 Resident Assembler
- •1.3.2.2 Immediately Executable Code
- •1.3.2.3 Relationship to Other Routines
- •1.3.2.4 Register Usage
- •1.4 Documentation and Programmer Aids
- •1.4.1 Comments
- •1.4.2 Locating Command Source
- •1.4.3 Cross-references
- •1.4.4 Decompiler and Disassembler
- •1.5 Interactive Programming—An Example
- •2. Forth Fundamentals
- •2.1 Stack Operations
- •2.1.1 Stack Notation
- •2.1.2 Data Stack Manipulation Operations
- •2.1.3 Memory Stack Operations
- •2.1.4 Return Stack Manipulation Operations
- •2.1.5 Programmer Conveniences
- •2.2 Arithmetic and Logical Operations
- •2.2.1 Arithmetic and Shift Operators
- •Single-Precision Operations
- •Double-precision Operations
- •Mixed-precision Operations
- •2.2.2 Logical and Relational Operations
- •Single-Precision Logical Operations
- •Double-Precision Logical Operations
- •2.2.3 Comparison and Testing Operations
- •2.3 Character and String Operations
- •2.3.1 The PAD—Scratch Storage for Strings
- •2.3.2 Single-Character Reference Words
- •2.3.3 String Management Operations
- •2.3.4 Comparing Character Strings
- •2.4 Numeric Output Words
- •2.4.1 Standard Numeric Output Words
- •2.4.2 Pictured Number Conversion
- •2.4.2.1 Using Pictured Numeric Output Words
- •2.4.2.2 Using Pictured Fill Characters
- •2.4.2.3 Processing Special Characters
- •2.5 Program Structures
- •2.5.1 Indefinite Loops
- •2.5.2 Counting (Finite) Loops
- •2.5.3 Conditionals
- •2.5.4 CASE Statement
- •2.5.5 Un-nesting Definitions
- •2.5.6 Vectored Execution
- •2.6 Exception Handling
- •3. System Functions
- •3.1 Vectored Routines
- •3.2 System Environment
- •3.3 Serial I/O
- •3.3.1 Terminal Input
- •3.3.2 Terminal Output
- •3.3.3 Support of Special Terminal Features
- •3.4 Block-Based Disk Access
- •3.4.1 Overview
- •3.4.2 Block-Management Fundamentals
- •3.4.3 Loading Forth Source Blocks
- •3.4.3.1 The LOAD Operation
- •3.4.3.2 Named Program Blocks
- •3.4.3.3 Block-based Programmer Aids and Utilities
- •3.5 File-Based Disk Access
- •3.5.1 Overview
- •3.5.2 Global File Operations
- •3.5.3 File Reading and Writing
- •3.5.4 File Support Words
- •3.6 Time and Timing Functions
- •3.7 Dynamic Memory Management
- •3.8 Floating Point
- •3.8.1 Floating-Point System Guidelines
- •3.8.2 Input Number Conversion
- •3.8.3 Output Formats
- •3.8.4 Floating-Point Constants, Variables, and Literals
- •3.8.5 Memory Access
- •3.8.6 Floating-Point Stack Operators
- •3.8.7 Floating-Point Arithmetic
- •3.8.8 Floating-Point Conditionals
- •3.8.9 Logarithmic and Trigonometric Functions
- •3.8.10 Address Management
- •3.8.11 Custom I/O
- •4. The Forth Interpreter and Compiler
- •4.1 The Text Interpreter
- •4.1.1 Input Sources
- •4.1.2 Source Selection and Parsing
- •4.1.3 Dictionary Searches
- •4.1.4 Input Number Conversion
- •4.1.5 Character String Processing
- •4.1.5.1 Scanning Characters to a Delimiter
- •4.1.5.2 Compiling and Interpreting Strings
- •4.1.6 Text Interpreter Directives
- •4.2 Defining Words
- •4.2.1 Creating a Dictionary Entry
- •4.2.2 Variables
- •4.2.3 CONSTANTs and VALUEs
- •4.2.4 Colon Definitions
- •4.2.5 Code Definitions
- •4.2.6 Custom Defining Words
- •4.2.6.1 Basic Principles of Defining Words
- •4.2.6.2 High-level Defining Words
- •4.3 Compiling Words and Literals
- •4.3.1 ALLOTing Space in the Dictionary
- •4.3.2 Use of , and C, to Compile Values
- •4.3.3 The Forth Compiler
- •4.3.4 Use of Literals and Constants in : Definitions
- •4.3.5 Explicit Literals
- •4.3.6 Use of ['] to Compile Literal Addresses
- •4.3.7 Compiling Strings
- •4.4 Compiler Directives
- •4.4.1 Making Compiler Directives
- •4.5 Overlays
- •4.6 Word Lists
- •4.6.1 Basic Principles
- •4.6.2 Managing Word Lists
- •4.6.3 Sealed Word Lists
- •5. The Assembler
- •5.1 Code Definitions
- •5.2 Code Endings
- •5.3 Assembler Instructions
- •5.4 Notational Conventions
- •5.5 Use of the Stack in Code
- •5.6 Addressing Modes
- •5.7 Macros
- •5.8 Program Structures
- •5.9 Literals
- •5.10 Device Handlers
- •5.11 Interrupts
- •5.12 Example
- •6.1 Guidelines for BLOCK-based source
- •6.1.1 Stack Effects
- •6.1.2 General Comments
- •6.1.3 Spacing Within Source
- •6.2.1 Typographic Conventions
- •6.2.2 Use of Spaces
- •6.2.3 Conditional Structures
- •6.2.4 do…loop Structures
- •6.2.5 begin…while…repeat Structures
- •6.2.6 begin…until…again Structures
- •6.2.7 Block Comments
- •6.2.8 Stack Comments
- •6.2.9 Return Stack Comments
- •6.2.10 Numbers
- •6.3 Wong’s Rules for Readable Forth
- •6.3.1 Example: Magic Numbers
- •6.3.2 Example: Factoring
- •6.3.3 Example: Simplicity
- •6.3.4 Example: Testing Assumptions
- •6.3.5 Example: IF Avoidance
- •6.3.6 Example: Stack Music
- •6.3.7 Summary
- •6.4 Naming Conventions
- •Appendix A: Bibliography
- •Appendix B: Glossary & Notation
- •B.1 Abbreviations
- •B.2 Glossary
- •B.3 Data Types in Stack Notation
- •B.4 Flags and IOR Codes
- •B.5 Forth Glossary Notation
- •Appendix C: Index to Forth Words
- •General Index
Forth Programmer’s Handbook
a token, such as an index into a table, which is more compact than an absolute address. Token threading is a key element in MacForth. In other respects, such an implementation resembles an indirect-threaded model.
!An additional implementation strategy that may be combined with any of the above VM implementations supports segmented architectures. For example, the 80x86 family supports segmented address spaces. Some Forth systems take advantage of this to enable a 16-bit system to support programs larger than 64K, by using different segments for dictionary, data space, stacks, etc.
References :, Section 4.2.4
Compiling words and literals, Section 4.3
1.2 FORTH OPERATING SYSTEM FEATURES
Many Forth products are based on a multitasking executive; some are multi-user as well. Some implementations run in a fully standalone mode, in which Forth provides all drivers for the hardware attached to the system. Other versions of Forth run in a co-resident mode, with a host operating system such as Windows.
In the latter case, the drivers that supply I/O services for peripherals such as disk and terminals do so by issuing calls to the host system. Although co-resi- dent systems may be somewhat slower than the standalone versions, they offer full file compatibility with the host OS, and usually are more flexible in hardware configuration. Co-resident versions of Forth usually offer all the system-level features of the native systems (including, in some cases, multiuser support on otherwise single-user systems such as MS-DOS), plus added commands for interacting with the host OS; the latter are documented in the system’s product documentation.
Disk I/O is handled by Forth systems in different ways, depending on the system environment. Many systems use standard blocks of 1024 bytes. This fixed block size applies both to Forth source program text and to data used by Forth programs. This standard format allows I/O on different media with different physical sector or record sizes, or even on different operating systems, to be handled by one standard block handler. Forth systems in a Windows or Macintosh environment access disk using a file-based system. Blocks and files are discussed further in Section 3.4 and Section 3.5, respectively. Also see your
Introduction 17
Forth Programmer’s Handbook
product documentation for details.
Forth makes it easy to control multiple tasks, either asynchronous background tasks or independent terminal service tasks. A small set of commands controls the multitasking facility. The limit on the number of tasks in the system is usually set by memory size. Since Forth definitions are naturally re-entrant, tasks rarely require much memory.
A terminal task has associated hardware that allows it to perform text input and output. Each terminal task has a partition that contains its stacks, private (or user) variable area, a scratch PAD (for text strings), and dictionary. A selected word list may be compiled into this partition to do a particular kind of processing which is a subset of the application but which is not available to other users.
A background task has a much smaller area, with only enough space for its stacks; there is no terminal associated with it, and it cannot perform text I/O. The routines the background task executes are located in a shared area or in the dictionary of one of the terminal tasks.
Forth normally runs with interrupts enabled. Interrupt vectors branch directly to the code which services the interrupting device, without any system intervention or overhead. The interrupt code is responsible for saving and restoring any registers it needs.
Interrupt code (actual assembler code) is responsible for performing any timecritical actions needed, such as reading a value from an analog device and storing it in a temporary location. The interrupt routine must also notify the task responsible for the device. Notification may take many forms, ranging from incrementing a counter, to “awakening” the task by storing in the task’s status area a pointer to code that will cause the task to become active the next time the task is available. Many interrupt handlers do nothing else.
Any processing which is not time-critical can be done by a task running a routine written in high-level Forth. In effect, the time-critical aspect of servicing an interrupt is decoupled from the more logically complex aspects of dealing with the consequences of the event signalled by the interrupt. Thus, it is guaranteed that interrupts will be serviced promptly, without having to wait for task scheduling, and yet as a programmer you have the convenience of using high-level Forth executed by the responding task for the main logic of the application.
18 Introduction