Development Tips

Just a few handy debug methods I’ve developed along the way ...

PR: Monitor Stack Values and Program Flow

This is really simple, yet I use it all the time to find my bugs. Used with VIM Mapping, it’s fast to use. I’m still a Forth beginner and I need all the help I can get, so being able to rapidly insert print statements to follow the stack and program flow, plus show nothing is left on the stack on word completion, has made debugging a lot easier for me.
: pr ( identifier -- identifier print stack ) . .s cr ;           \ A debugging stack printer

PR: Usage Example

\ Program Name: pr-example.fs  for Mecrisp-Stellaris by Matthias Koch and licensed under the GPL
\ This program: 'pr' is a debugging 'print statement' 
\ Hardware: STM32F0 Discovery board
\ Terminal: e4thcom by Copyright (C) 2013-2017 Manfred Mahlow and licensed under the GPL
\ Copyright 2017 t.porter <terry@tjporter.com.au> and licensed under the GPL
\
\ ...................... screenpic .....................
\   pr-example 
\   1 [0 ] 0 
\   2 [0 ] 0 
\   3 [1 ] 0 0 
\   4 [3 ] 0 0 0 0 
\   Loop#0 
\   5 [2 ] 0 0 0 
\   6 [1 ] 0 0 
\   2 [0 ] 0 
\   3 [1 ] 0 1 
\   4 [3 ] 0 1 1 1 
\   Loop#1 
\   5 [2 ] 0 1 1 
\   6 [1 ] 0 2 
\   2 [0 ] 0 
\   3 [1 ] 0 2 
\   4 [3 ] 0 2 2 2 
\   Loop#2 
\   5 [2 ] 0 2 2 
\   6 [1 ] 0 4 
\   2 [0 ] 0 
\   3 [1 ] 0 3 
\   4 [3 ] 0 3 3 3 
\   Loop#3 
\   5 [2 ] 0 3 3 
\   6 [1 ] 0 6 
\   7 [0 ] 0
\    ok.
\ ...................... screenpic .....................

 : pr . .s cr ;	 \ print the stack and follow program flow for debugging

 :  pr-example cr
   1 pr	 								   
      4 0 do
   2 pr	 
     I 
   3 pr
       dup dup
   4 pr
     ." Loop#" . cr
   5 pr
      +
   6 pr
      drop
      loop
   7 pr
 ;

pr-example

Balancing The Return Stack

Forth Does have a ‘local vartiable’, it’s called The Return stack, but it must be balanced or your program will crash.

Example program

This program splits a number into digits, and utilises the Return Stack as a local variable, but how to make sure that the Return Stack is balanced ?
: split
   >R                      \ Save the input on the Return Stack
   BEGIN
       R> ?DUP 0 > WHILE   \ Fetch from the Return Stack, duplicate because " 0 >" and "/MOD" both use it, then continue WHILE greater than zero. ?DUP is used instead of DUP to prevent a zero being left on the stack after the program has completed.
       10 /MOD >R . cr     \ divide by 10 and save the result on the Return Stack, print each remainder on a new line
   REPEAT
;

123456789 split
9
8
7
6
5
4
3
2
1

In this case, I used a variable (rb) to tally my Return Stack pushes and pulls. A ‘rb’ total of 0 shows the Return Stack is balanced.

Of course, if the Return Stack isn’t balanced, this is bad and if it doesn’t crash now, it will cause problems later.

Return Stack Operation code Description
Push >R rb @ 1+ rb ! Add one to ‘rb’
Pull R> rb @ 1- rb ! Subtract one from ‘rb’

Example Program Including Return Stack Accounting

Every Return Stack ADD is worth 1 and REMOVE is worth -1. A total of 0 shows the Return Stack is balanced, so no visual comparison is required.

0 variable rb
: split-rbalance cr
>R rb @ 1+ rb !
BEGIN
R> rb @ 1- rb !
?DUP 0 > WHILE
10 /MOD
>R rb @ 1+ rb !
.  cr
REPEAT
cr
rb @ 0= if
."  The Return Stack is balanced " cr cr
else
."  UNBALANCED ! The Return Stack is NOT balanced! rb =  " rb @ . cr cr
then
;

Return Stack Accounting Output

123456789 split-rbalance

 9
 8
 7
 6
 5
 4
 3
 2
 1

 The Return Stack is balanced

ok.