Coder Social home page Coder Social logo

zforth's Introduction

zForth

zForth

From Wikipedia:

A Forth environment combines the compiler with an interactive shell, where the user defines and runs subroutines called words. Words can be tested, redefined, and debugged as the source is entered without recompiling or restarting the whole program. All syntactic elements, including variables and basic operators are defined as words. Forth environments vary in how the resulting program is stored, but ideally running the program has the same effect as manually re-entering the source.

zForth is yet another Forth, but with some special features not found in most other forths. Note that zForth was written for engineers, not for language purists or Forth aficionados. Its main intention is to be a lightweight scripting language for extending embedded applications on small microprocessors. It is not particularly fast, but should be easy to integrate on any platform with a few kB's of ROM and RAM.

Also note that zForth is just a forth, but does not specifically implement or care about any of the standards like ANS Forth - the kernel might or might not behave as the standard, and the current standard library is rather limited.

For a lot of programmers Forth seems to belong to the domain of alien languages: it does not look like any mainstream language most people encounter, and is built on a number of philosophies that takes some time to get used to. Still, it is one of the more efficient ways of bringing a interpreter and compiler to a platform with restricted resources.

Some of zForth's highlights:

  • Small dictionary: instead of relying on a fixed cell size, the dictionary is written in variable length cells: small and common numbers take less space then larger, resulting in 30% to 50% space saving

  • Portable: zForth is written in 100% ANSI C, and runs on virtually all operating systems and all architectures. Tested on x86 Linux/Win32/MS-DOS (Turbo-C 1.0!), x86_64, ARM, ARM thumb, MIPS, Atmel AVR and the 8051.

  • Small footprint: the kernel C code compiles to about 3 or 4 kB of machine code, depending on the architecture and chosen cell data types.

  • Tracing: zForth is able to show a nice trace of what it is doing under the hood, see below for an example.

  • VM: Implemented as a small virtual machine: not the fastest, but safe and flexible. Instead of having direct access to host memory, the forth VM memory is abstracted, allowing proper boundary checking on memory accesses and stack operations.

  • Flexible data types: at compile time the user is free to choose what C data type should be used for the dictionary and the stacks. zForth supports signed integer sizes from 16 to 128 bit, but also works seamlessly with floating point types like float and double (or even the C99 'complex' type!)

  • Ease interfacing: calling C code from forth is easy through a host system call primitive, and code has access to the stack for exchanging data between Forth and C. Calling forth from C is easy, just one function to evaluate forth code.

Source layout

./forth         : core zforth library and various snippets and examples
./src/zforth    : zfort core source; embed these into your program
./src/linux     : example linux application
./src/atmega8   : example AVR atmega8 application

Usage

zForth consists of only two files: zforth.c and zforth.h. Add both to your project and call zf_init() and zf_bootstrap() during initialisation. Read forth statements from a file or terminal and pass the strings to zf_eval() to interpret, compile and run the code. Check the embedded documentation in zforth.h for details.

zforth.c depends on a number preprocessor constants for configuration which you can choose to fit your needs. Documentation is included in the file zfconf.h.

A demo application for running zForth in linux is provided here, simply run make to build.

To start zForth and load the core forth code, run:

./src/linux/zforth forth/core.zf

And zForth will welcome you with the startup message:

Welcome to zForth, 786 bytes used

zForth is now ready to use. Try some of the following:

Adding one and one or calculate the 144 squared:

1 1 + .
144 dup * .

Print the sine of 10 numbers between 0 and PI

: pi 3.141592654 ;
: demo pi 0 do i sin . pi 10 / loop+ ;
demo

Load and run the demo Mandelbrot fractal:

include forth/mandel.zf

.........................----.....................
.....................----+--......................
.......................--*-.......................
........................- --.....--...............
...........----........--%---------...............
............-------------#---------...............
.............------------ ---------...............
.............------------ ---------...............
..............---------o   o--------..............
..............---------o   =----------------------
.............----o-oo         =o-=--------------..
...........-------#             *------------.....
........--------=-=             o-=--------.......
....--------------=             =---------........
......-------------+           +---------.........
.......-------------=#       %=-----------........
........--------=-               -=--------.......
.......------=                       =------------
.....---o   =                         =   =-------
---------                                 --------
---------o+                             +o--------
---------o                               =--------
---=#=# =                                 = #=#=--
---=                                           =--
-=- +                                         + ==
o---oo*==                                 -=*=o---
---------=                               =--------
---------#=                             =#--------
-----------%                           %------....
---...----=  =%          -          #=  =----.....
.......---=o----* =+*---------*+- *----o=----.....
........--------------------------------------....

Tracing

zForth can write verbose traces of the code it is compiling and running. To enable tracing, run ./zforth with the -t argument. Tracing can be enabled at run time by writing 1 in the trace variable:

1 trace !

Make sure the feature ZF_ENABLE_TRACING is enabled in zfconf.h to compile in tracing support.

The following symbols are used:

  • stack operations are prefixed with a double arrow, « means pop, » means push. for operations on the return stack the arrow is prefixed with an r

  • the current word being executed is shown in square brackets, the format is [<name>/<address>]

  • lines starting with a + show values being added to the dictionary

  • lines starting with a space show the current line being executed, format <address> <data>

  • lines starting with === show the creation of a new word

: square dup * ;
: test 5 square . ;
test

Executing the word test:

test

r»0 
[test/0326] 
 0326 0001 ┊  (lit) »5 
 0328 031c ┊  square/031c r»810 
 031c 000b ┊  ┊  (dup) «5 »5 »5 
 031d 0007 ┊  ┊  (*) «5 «5 »25 
 031e 0000 ┊  ┊  (exit) r«810 
 032a 0133 ┊  ./0133 r»812 
 0133 0001 ┊  ┊  (lit) »1 
 0135 0019 ┊  ┊  (sys) «1 «25 
 0136 0000 ┊  ┊  (exit) r«812 
 032c 0000 ┊  (exit) r«0 25 

This is the trace of the definition of the square and test words

: square dup * ;

r»0 
[:/002c] 
 002c 0003 ┊  (:) 
 002c 0003 ┊  (:) 
=== create 'square'
+0313 0006 ¹ 
+0314 02eb ² 
+0316 0000 s 'square'
===
 002d 0000 ┊  (exit) r«0 
+031c 000b ¹ +dup
+031d 0007 ¹ +*r»0 
[;/0031] 
 0031 0004 ┊  (;) 
+031e 0000 ¹ +exit
===
 0032 0000 ┊  (exit) r«0 

: test 5 square . ;

r»0 
[:/002c] 
 002c 0003 ┊  (:) 
 002c 0003 ┊  (:) 
=== create 'test'
+031f 0004 ¹ 
+0320 0313 ² 
+0322 0000 s 'test'
===
 002d 0000 ┊  (exit) r«0 
+0326 0001 ¹ +lit
+0327 0005 ¹ 
+0328 031c ² +square
+032a 0133 ² +.r»0 
[;/0031] 
 0031 0004 ┊  (;) 
+032c 0000 ¹ +exit
===
 0032 0000 ┊  (exit) r«0 

Dependencies

  • libreadline-dev

zforth's People

Contributors

beeflobill avatar jbdatko avatar larsbrinkhoff avatar martin-ac100 avatar pbrochard avatar phillipweinstock avatar rleigh-lumiradx avatar szsam avatar tomscii avatar zevv avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

zforth's Issues

GPL

Hi,

I am looking at zForth with a view to embedding into a product for use as to debug and test.

Since the product is an embedded system, and the whole thing is statically linked all of my code would then be covered by GPL (as I understand it) would it be possible to License zForth under more 'permissive' terms, such as LGPL or BSD ?

Regards,
Andrew

Loop iterator "j"

Hello zevv,

I recently forked your Forth to a minimal, self-contained PSoC 5 / USBUART test project with which I was learning Forth and testing its viability for use in a scary monster project I've been working on. It will effectively be taking the place of php, linked into all sorts of C helper functions, for a PSoC webserver as well as providing some low-level interfacing to an automation system.

During tests, I believe I've found an error in your "j" word. When I execute the following:

: CRLF 10 13 emit emit ;
: ts 10 0 do 10 0 do 42 i + j + emit loop CRLF loop ;
ts

j does not increment, as can be seen by the following output:

456789:;<=>
456789:;<=>
456789:;<=>
456789:;<=>
456789:;<=>
456789:;<=>
456789:;<=>
456789:;<=>
456789:;<=>
456789:;<=>
456789:;<=>

edit: Also note that the output doesn't begin with '*'!

Modifying the definition of j to:
: j ' lit , 2 , ' pickr , ; immediate
fixes the issue.

There's an outside chance that I introduced an error when I hacked-in a modification to your code to avoid getting stuck in zf_eval() during a forth loop, but I'm almost 100 % certain forth code still executes correctly. I've not run into any other oddities while I've been developing my forth skills!

Sadly, I'm still slightly confuddled trying to understand how the do/loop words operate, so I can't entirely trust my judgement as to whether j is incorrectly defined or not.

I'll be looking to see if j operates as intended in your implementation, because if it does it implies I have problems with my modifications!

Cheers,
Nick.

Floating Point segmentation fault 2017-07-23

Hello, I was using American Fuzzy Lop (afl-fuzz) to fuzz input to the zforth program on Linux. Is fixing the crashes from these input files something you're interested in? The input files can be found here: https://github.com/rwhitworth/zForth-fuzz/tree/master/2017-07-23

The files can be executed as ./zforth id_filename to cause seg faults.

Let me know if I can provide any more information to help narrow down this issue.

id:000000,sig:08,src:000098,op:flip4,pos:5

#0  0x0000000000405c84 in do_prim (op=<optimized out>, input=<optimized out>) at ../zforth/zforth.c:639
#1  run (input=<optimized out>) at ../zforth/zforth.c:465
#2  0x0000000000403404 in execute (addr=74) at ../zforth/zforth.c:497
#3  handle_word (buf=<optimized out>) at ../zforth/zforth.c:757
#4  handle_char (c=<optimized out>) at ../zforth/zforth.c:801
#5  zf_eval (buf=<optimized out>) at ../zforth/zforth.c:884
#6  0x00000000004017a6 in do_eval (src=<optimized out>, line=<optimized out>, buf=<optimized out>) at main.c:30
#7  include (fname=<optimized out>) at main.c:69
#8  0x0000000000402145 in main (argc=<optimized out>, argv=<optimized out>) at main.c:261

see for word definition

Hi Ico,
in dict.zf you define the word words to view the words in Dictionary. thats good. but how to define a word see to view the code of a word?

thx and greetings - kmatze

todo's and notes to self

Thinks I will probably add in the near future:

  • provide demo apps for some common embedded platforms like AVR atmega8, LPC1334, etc
  • provide primitives for accessing fixed sized words in the dictionary
  • write some documentation about things in which zForth differs from 'regular' forth, mostly considering the variable cell size in the dictionary

Does zforth support more memory than 16Kb

Hi :)
ZForth - Great job

However, I have a problem. Does zforth support more memory than 16Kb? I did a test and after exceeding the 16Kb limit, the words stop working properly. Please test:

#define ZF_DICT_SIZE 65536 ( zfconf.h )

20000 h ! (set core.zf somewhere at the beginning after the word "!" )
include core.zf (it throws errors)

Can you check this?

Thank you very much and sorry for my poor English. Regards

Port to Pico?

Many years ago I added a Forth interpreter to a Z80 controller for a vacuum subsystem in an electron microscope. Our field techs loved being able to hook a terminal and use it for diagnostics. Haven't done much with Forth since, but I still have a soft spot for the language.

These days I'm mostly retired but still messing about with software and, very recently, the Raspberry Pi Pico RP2040-based microcontroller.

I'm thinking I want to have a simple lightweight REPL to include in various projects built with the C/C++ SDK and it strikes me that zForth might make a good basis for that. As you may be aware, the Pico has 2 M0 cores so it seems sensible to let the REPL run in one of them leaving the other free to handle interrupts and otherwise do the actual work of the application.

I'd be happy to contribute the implementation to zForth if it turns out worthwhile.

I've read through your source. It seems clean and straightforward. Thanks for creating and maintaining it.

I like that it was designed for engineers rather than purists.

Any preliminary advice appreciated.

Missing some headers and C++ compatibility?

Hello !

While testing zforth, I had to add missing headers in zforth + C++ compatibility in zforth.h :

// C++ compatibility header guard
#ifdef __cplusplus
extern "C"
{
#endif

#include <stddef.h> // for size_t
#include <stdarg.h> // for va_arg
#include <stdint.h> // for int32_t

...

#ifdef __cplusplus
}
#endif

strings.zf missing

The README in the 'forth' directory mentions 'strings.zf' ,which is missing in the repo ...

include triggers ZF_ABORT_BUSY

Dear @zevv,

I just started playing with zForth, seems like big fun! However, while implementing include. I ran into a problem. When calling include interactively I get an error ZF_ABORT_BUSY. It looks like zf_eval is not reentrant. Am I doing something wrong?

With kind regards,
Matthias

I want to embed zForth into Tic-80

Hello :)

I like zForth, I haven't used it much yet, but it looks like the correct choise for embedding it into Tic-80 which is a Fantasy game console that supports many languages, I want to add forth to it.

My initial choice was implementing my own forth but I'm afraid that I make bugs. so zForth it is.

The reason I posted this is because I don't know much about opensource contribution, so here a afew questions:

  • Both repos are MIT so there are no problems, right?
  • I need to change afew stuff like zfConf, so I will fork this repo. I'm allowed to modify right?
  • Can I rename the language of my fork? for example call it ticForth? I don't want to right now but just asking.
  • Do you have any advise for me?

Thanks :)

crash under Asan

$ ./src/linux/zforth forth/core.zf 
AddressSanitizer:DEADLYSIGNAL
=================================================================
==79267==ERROR: AddressSanitizer: SEGV on unknown address 0x631d8c94ff10 (pc 0x716254052c47 bp 0x000000000000 sp 0x7ffeea78de60 T0)
==79267==The signal is caused by a READ memory access.
AddressSanitizer:DEADLYSIGNAL
AddressSanitizer: nested bug in the same thread, aborting.

How to set a variable

I've read through the code and the core functions. I don't see how a user can define a new variable. I see in other versions of forth you'd say something like:
VARIABLE varName

to define a new variable...

Does not build on Void Linux without libsanitizer-devel

I'm partly just opening this for some future searcher to find, but maybe there's documentation (README or otherwise) to come from this.

Anyway: after installing readline-devel, I still wound up with an interesting compiler error:

(woods) zForth  » master » make
make -C src/linux
make[1]: Entering directory '/home/j/src/zForth/src/linux'
gcc -I. -I../zforth -Os -g -std=c89 -ansi -pedantic -MMD -fsanitize=address -Wall -Wextra -Werror -Wno-unused-parameter -Wno-clobbered -Wno-unused-result -DUSE_READLINE   -c -o main.o main.c
gcc -I. -I../zforth -Os -g -std=c89 -ansi -pedantic -MMD -fsanitize=address -Wall -Wextra -Werror -Wno-unused-parameter -Wno-clobbered -Wno-unused-result -DUSE_READLINE   -c -o zforth.o ../zforth/zforth.c
gcc -fsanitize=address -g  -o zforth  main.o zforth.o -lm -lreadline
/bin/ld: cannot find libasan_preinit.o: No such file or directory
/bin/ld: cannot find -lasan
collect2: error: ld returned 1 exit status
make[1]: *** [Makefile:24: zforth] Error 1
make[1]: Leaving directory '/home/j/src/zForth/src/linux'
make: *** [Makefile:4: all] Error 2

Resolved by installing libsanitizer-devel as per https://nanxiao.me/en/fix-cannot-find-libasan_preinit-o-issue-in-void-linux/. This is, evidently, a gcc-only concern.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.