- Notifications
You must be signed in to change notification settings - Fork1
CCurl/c4a
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
- c4a supports control characters (tags) in the whitespace that change the state.
- c4a has 4 states: INTERPRET, COMPILE, DEFINE, AND COMMENT.
- c4a also supports the standard state-change words.
- c4a has a built-in editor. It has a VI-like feel.
- For details, see theEditor documentation.
- c4a has 'a', 'b', and 't' words.
- c4a reads 'blocks.fth' into memory on load.
- This is what it uses to edit and load blocks.
- Use 'flush' to write it back to disk/flash.
Tag | Word | State | Description |
---|---|---|---|
$01 | ] | 1 | Compile |
$02 | : | 2 | Define |
$03 | [ | 3 | Interpret/execute/immediate |
$04 | 4 | Comment | |
( | 4 | Comment, save current state | |
) | End comment, restores saved state |
NOTE: In the DEFINE state, c4a changes the state to COMPILE after adding the next word.
NOTE: Unlike ColorForth, ';' compiles EXIT and then changes the state to INTERPRET.
- In c4a, a program is a sequence of WORD-CODEs.
- A WORD-CODE is a 16-bit unsigned number.
- Primitives are assigned numbers sequentially from 0 to [BYE].
- If a WORD-CODE is less than or equal to [BYE], it is a primitive.
- If the top 4 bits are set, it is 13-bit unsigned literal, 0-$0FFF.
- If it is between 'BYE' and $F000, it is the code address of a word to execute.
- c4a is intended to be used with development boards via the Arduino IDE.
- However, it can be built for PCs as well for testing.
- I am not aware of 64-bit dev boards.
- So aCELL in c4a is 32-bits.
- C4A has many built-in primitives, for the following reasons:
- Program flash is often quite large, so why not use it?
- To give C4A more functionality out of the box.
- C4A also runs faster because of it.
- Windows: there is a c4a.sln file for Visual Studio
- only the x86 target (32-bit) is supported
- Linux: there is a makefile
- only the 32-bit configuration (-m32) is supported
- Others:
- c4a is simple enough that it should be easy to migrate it to any platform
- I use the Arduino IDE v2.x
- There is a c4a.ino file
- File 'c4a.h' controls parameters for the target board
- Edit the section where
IS_BOARD
is defined to set the configuration for the board - Use
#define FILE_NONE
to disable support for blocks and LittleFS - For the RPI Pico:
- Use the arduino-pico from earlephilhower (https://github.com/earlephilhower/arduino-pico)
- The version must be 4.2.0 or later. Versions older than 4.0.0 do not support boards usingthe RP2350 microcontroller.
- Use
#define FILE_PICO
to include support for LittleFS
- For the Teensy-4.x:
- Use
#define FILE_TEENSY
to include support for LittleFS
- Use
c4a provides a single memory area. See 'mem-sz' (MEM_SZ in c4a.h) for its size.
- It is broken into 3 areas: CODE, VARS, and DICTIONARY.
- The CODE area is an aray of WORD-CODEs starting at the beginning of the memory.
here
is an offset into the CODE area.- The size of the CODE area is
code-sz
. See CODE_SZ in c4a.h. - NOTE: Use
wc@
andwc!
to get and set 16-bit values in the code area. - NOTE: Use
cv@
andcv!
to get and set 32-bit values in the code area. - NOTE: CODE slots 0-25 (
0 wc@ .. 25 wc@
) are reserved for c4a system values. - NOTE: CODE slots 26-(BYE) are unused by c4a.
- NOTE: Using
wc@
andwc!
, c4a provides storage space for many 16-bit variables. - NOTE: Using
cv@
andcv!
, c4a provides storage space for many 32-bit variables. - NOTE: These are free for the user/application to use as desired.
- The VARS area is defined to begin at address
code-sz wc-sz * memory +
.vhere
is the absolute address of the first free byte the VARS area.
- The DICTIONARY is at the end of the memory. 'last' grows toward the beginning of the memory.
last
is the address of the most recently created word.- A dictionary entry is [xt:2][flags:1][len:1][name:NAME_LEN][0:1]
- The default NAME_LEN is 11 (see c4a.h), so 'de-sz' is 16.
- Use
->memory
to turn an offset into an address.
WORD | STACK | DESCRIPTION |
---|---|---|
memory | (--A) | A: starting address of the c4a memory |
mem-sz | (--N) | N: size in BYTEs of the c4a memory |
code-sz | (--N) | N: number of in WORD-CODE slots in the code area |
dstk-sz | (--N) | N: size in CELLs of the DATA and RETURN stacks |
tstk-sz | (--N) | N: size in CELLs of the A and T stacks |
wc-sz | (--N) | N: size in BYTEs of a WORD-CODE |
de-sz | (--N) | N: size in BYTEs of a dictionary entry |
(dsp) | (--N) | N: Address of the data stack pointer |
(rsp) | (--N) | N: Address of the return stack pointer |
(lsp) | (--N) | N: Address of the loop stack pointer |
(asp) | (--N) | N: Address of the A stack pointer |
(bsp) | (--N) | N: Address of the B stack pointer |
(tsp) | (--N) | N: Address of the T stack pointer |
(here) | (--N) | N: Address of the HERE variable |
(last) | (--N) | N: Address of the LAST variable |
base | (--N) | N: Address of the BASE variable |
state | (--N) | N: Address of the STATE variable |
Strings in c4a are NULL-terminated with no count byte.
Similar to the printf() function in C, c4a supports formatted output using '%'.
For example: ascii dup dup dup ." char: %c, decimal: #%d, binary: %%%b, hex: $%x%n" ;
.
Format | Stack | Description |
---|---|---|
%b | (N--) | Print TOS in base 2. |
%c | (N--) | EMIT TOS. |
%d | (N--) | Print TOS in base 10. |
%e | (--) | EMITescape (#27). |
%i | (N--) | Print TOS in the current base. |
%n | (--) | Print CR/LF (13/10). |
%q | (--) | EMIT" (#34). |
%s | (A--) | Print TOS as a string (formatted). |
%S | (A--) | Print TOS as a string (unformatted). |
%x | (N--) | Print TOS in base 16. |
%B | (--) | Change foreground to blue. |
%G | (--) | Change foreground to green. |
%P | (--) | Change foreground to purple. |
%R | (--) | Change foreground to red. |
%W | (--) | Change foreground to white. |
%Y | (--) | Change foreground to yellow. |
%[x] | (--) | EMIT [x]. |
c4a has a built-in editor. It colorizes the code based on tags in the text.
For details, see theEditor documentation.
c4a includes A, B, and T stacks.
These are somewhat similar to ColorForth's operations for a and b, but in c4a, they are stacks.
The size of the stacks is configurable (seestk-sz
).
The words below are available for all 3 stacks.
Note that there are also additional wordsr!
r@+
andr@-
for the return stack.
WORD | STACK | DESCRIPTION |
---|---|---|
>a | (N--) | Push N onto the A stack. |
a! | (N--) | Set A-TOS to N. |
a@ | (--N) | N: copy of A-TOS. |
a@ | (--N) | N: copy of A-TOS, then increment A-TOS. |
a@ | (--N) | N: copy of A-TOS, then decrement A-TOS. |
a> | (--N) | Pop N from the A stack. |
adrop | (--) | Drop A-TOS |
c4a provides 10 temporary words, 't0' .. 't9'.
- They are case-sensitive.
- 't0' is a temporary word; 'T0' is NOT.
- They do not take valuable dictionary space.
- They can be used to improve factoring, or as variable or constant names.
- t0:t5 are normal words, t6:t9 are INLINE.
- c4a supports simple a very simple cooperative multi-tasking system.
- The task system is not preemptive.
- Words
add-task (xt--n)
,yield (--)
,del-task (n--)
are provided. - Each task has its own data stack, return stack, and loop stack.
- The A, B, and T stacks are shared by all tasks.
NOTE: Since c4a is intended for dev boards, it has many more primitives than C4.
This is primarily because there is more program memory than RAM.
It provides more built-in functionality.
And the system is faster.
The primitives:
WORD | STACK | DESCRIPTION |
---|---|---|
(lit) | (--WC) | WC: WORD-CODE for LIT primitive |
(jmp) | (--WC) | WC: WORD-CODE for JMP primitive |
(jmpz) | (--WC) | WC: WORD-CODE for JMPZ primitive |
(jmpnz) | (--WC) | WC: WORD-CODE for JMPNZ primitive |
(njmpz) | (--WC) | WC: WORD-CODE for NJMPZ primitive |
(njmpnz) | (--WC) | WC: WORD-CODE for NJMPNZ primitive |
(exit) | (--WC) | WC: WORD-CODE for EXIT primitive |
exit | (--) | EXIT word |
dup | (X--X X) | Duplicate TOS (Top-Of-Stack) |
?dup | (X--X | X X) |
swap | (X Y--Y X) | Swap TOS and NOS (Next-On-Stack) |
drop | (N--) | Drop TOS |
2dup | (X Y--X Y X Y) | Duplicate TOS and NOS |
2drop | (X Y--) | Drop TOS and NOS |
over | (X Y--X Y X) | Push NOS |
nip | (X Y--Y) | Drop NOS |
tuck | (X Y--Y X Y) | Perform SWAP, OVER |
c@ | (A--C) | C: the CHAR at absolute address A |
w@ | (A--W) | W: the WORD at absolute address A |
@ | (A--N) | N: the CELL at absolute address A |
wc@ | (N--WC) | WC: the WORD-CODE in CODE slot N |
cv@ | (N--) | Code-Variable: Fetch a 32-bit value from CODE slots N/N+1 |
c! | (C A--) | Store CHAR C to absolute address A |
w! | (W A--) | Store WORD W to absolute address A |
! | (N A--) | Store CELL N to absolute address A |
wc! | (WC N--) | Store WORD-CODE WC to CODE slot N |
cv! | (N--) | Code-Variable: Store a 32-bit value to CODE slots N/N+1 |
+ | (X Y--N) | N: X + Y |
if | (X--) | Jump to 'then' if X == 0 (IMMEDIATE) |
if0 | (X--) | Jump to 'then' if X <> 0 (IMMEDIATE) |
-if | (X--X) | Jump to 'then' if X == 0 (IMMEDIATE) |
then | (--) | Target for 'if' branch (IMMEDIATE) |
begin | (--) | Begin a loop (IMMEDIATE) |
again | (--) | Jump to matching 'begin' (IMMEDIATE) |
while | (X--) | Jump to matching 'begin' if X <> 0 (IMMEDIATE) |
-while | (X--X) | Jump to matching 'begin' if X <> 0 (IMMEDIATE) |
until | (X--) | Jump to matching 'begin' if X == 0 (IMMEDIATE) |
- | (X Y--N) | N: X - Y |
* | (X Y--N) | N: X * Y |
*/ | (N X Y--N') | N': (N * X) / Y - Scale N by X/Y |
/ | (X Y--N) | N: X / Y (integer division) |
mod | (X Y--M) | M: X modulo Y |
/mod | (X Y--M Q) | M: X modulo Y, Q: quotient of X / Y |
<< | (X Y--Z) | Z: X left-shifted Y bits |
>> | (X Y--Z) | Z: X right-shifted Y bits |
1+ | (X--Y) | Increment TOS |
1- | (X--Y) | Decrement TOS |
2+ | (X--Y) | Y: X + 2 |
2* | (X--Y) | Y: X * 2 |
2/ | (X--Y) | Y: X / 2 |
CELLS | (X--Y) | Y: X * CELL |
CELL+ | (X--Y) | Y: X + CELL |
< | (X Y--F) | F: 1 if (X < Y), else 0 |
<= | (X Y--F) | F: 1 if (X <= Y), else 0 |
= | (X Y--F) | F: 1 if (X == Y), else 0 |
>= | (X Y--F) | F: 1 if (X >= Y), else 0 |
> | (X Y--F) | F: 1 if (X > Y), else 0 |
0= | (N--F) | F: 1 if (N == 0), else 0 |
and | (X Y--N) | N: X AND Y |
or | (X Y--N) | N: X OR Y |
xor | (X Y--N) | N: X XOR Y |
com | (X--Y) | Y: X with all bits flipped (one's complement) |
min | (X Y--Z) | Z: the minimum of (X and Y) |
max | (X Y--Z) | Z: the maximum of (X and Y) |
negate | (X--Y) | Y: -X |
abs | (X--Y) | Y: the absolute value of X |
for | (N--) | Begin FOR loop with bounds 0 and N-1. |
i | (--I) | N: Current FOR loop index. |
next | (--) | Increment I. If I >= N, exit, else start loop again. |
unloop | (--) | Unwind the loop stack.NOTE: does NOT exit the loop. |
>r | (N--) | Push N onto the return stack |
r! | (N--) | Set R to N |
r@ | (--N) | N: copy of R |
r@+ | (--N) | N: copy of R, then increment it |
r@- | (--N) | N: copy of R, then decrement it |
r> | (--N) | Pop N from the return stack |
rdrop | (--) | Drop R-TOS |
>t | (N--) | Push N onto the T stack |
t! | (N--) | Set T to N |
t@ | (--N) | N: copy of T |
t@+ | (--N) | N: copy of T, then increment T |
t@- | (--N) | N: copy of T, then decrement T |
t> | (--N) | Pop N from the T stack |
tdrop | (--) | Drop T-TOS |
>a | (N--) | Push N onto the A stack |
a! | (N--) | Set A to N |
a@ | (--N) | N: copy of A |
a@+ | (--N) | N: copy of A, then increment A |
a@- | (--N) | N: copy of A, then decrement A |
@a | (--C) | Fetch BYTE C through A |
@a+ | (--C) | Fetch BYTE C through A, then increment A |
@a- | (--C) | Fetch BYTE C through A, then decrement A |
!a | (C--) | Store BYTE C through A |
!a+ | (C--) | Store BYTE C through A, then increment A |
!a- | (C--) | Store BYTE C through A, then decrement A |
a> | (--N) | Pop N from the A stack |
adrop | (--) | Drop A-TOS |
>b | (N--) | Push N onto the B stack |
b! | (N--) | Set B to N |
b@ | (--N) | N: copy of B |
b@+ | (--N) | N: copy of B, then increment B |
b@- | (--N) | N: copy of B, then decrement B |
@b | (--C) | Fetch BYTE C through B |
@b+ | (--C) | Fetch BYTE C through B, then increment B |
@b- | (--C) | Fetch BYTE C through B, then decrement B |
!b | (C--) | Store BYTE C through B |
!b+ | (C--) | Store BYTE C through B, then increment B |
!b- | (C--) | Store BYTE C through B, then decrement B |
b> | (--N) | Pop N from the B stack |
bdrop | (--) | Drop B-TOS |
emit | (C--) | Output char C |
; | (--) | Compile EXIT, set STATE=INTERPRET (IMMEDIATE) |
lit, | (N--) | Compile a push of number N |
next-wd | (--L) | L: length of the next word from the input stream |
immediate | (--) | Mark the last created word as IMMEDIATE |
inline | (--) | Mark the last created word as INLINE |
outer | (S--) | Send string S to the c4a outer interpreter |
addword | (--) | Add the next word to the dictionary |
timer | (--N) | N: Current time |
see X | (--) | Output the definition of word X |
ztype | (S--) | Print string at S (unformatted) |
ftype | (S--) | Print string at S (formatted) |
s-len | (S--N) | N: Length of string S |
s-cpy | (D S--D) | Copy string S to D |
s-cat | (D S--D) | Concatenate string S to D |
s-eq | (D S--F) | F: 1 if string S is equal to D (case sensitive) |
s-eqi | (D S--F) | F: 1 if string S is equal to D (NOT case sensitive) |
ltrim | (S1--S2) | S2: Trim whitespace from the beginning of S1 |
rtrim | (S--S) | Trim whitespace from the end of S |
fill | (A N C--) | Fill N bytes from A with BYTE C |
cmove | (F T N--) | Copy N bytes from F to T - low to high |
cmove> | (F T N--) | Copy N bytes from F to T - high to low |
lower | (X--Y) | Y: lower-case of X if 'A' <= X <= 'Z', else X |
upper | (X--Y) | Y: upper-case of X if 'a' <= X <= 'a', else X |
z" | (--) | -COMPILE: Create string S to next" (IMMEDIATE) |
(--S) | -RUN: push address S of string | |
." | (--) | -COMPILE: executez" , compileftype (IMMEDIATE) |
(--) | -RUN:ftype on string | |
loaded? | (XT A--) | Stops current load if A <> 0 (seefind ) |
fopen | (NM MD--FH) | NM: File Name, MD: Mode, FH: File Handle (0 if error/not found) |
fclose | (FH--) | FH: File Handle to close |
fdelete | (NM--) | NM: File Name to delete |
fread | (A N FH--X) | A: Buffer, N: Size, FH: File Handle, X: num chars read |
fwrite | (A N FH--X) | A: Buffer, N: Size, FH: File Handle, X: num chars written |
load | (N--) | N: Block number to load |
load-next | (N--) | Close the current block and load block N next |
blocks | (--) | Dump block cache |
block-addr | (N--A) | N: Block number, A: Address in cache |
flush | (--) | Write RAM disk to flash/disk |
edit | (N--) | N: Block number to edit |
find | (--XT A) | XT: Execution Token, A: Dict Entry address (0 0 if not found) |
system | (S--) | PC ONLY: S: String to send tosystem() |
bye | (--) | PC ONLY: Exit c4a |
Default words are defined in functionsys_load()
in file sys-load.cpp.
For details, or to add or change the default words, modify that function.
About
C4 for the Arduino and PC
Topics
Resources
License
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Uh oh!
There was an error while loading.Please reload this page.