Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Implementing loop in Forth clone

206 views
Skip to first unread message

Liang Ng

unread,
May 12, 2018, 6:59:01 AM5/12/18
to
Implementing loop in Forth clone

As some of you may know, I have been working on a "top down" Forth clone, called 5GL (the Fifth Generation Graph Language), where reverse polish notation commands get translated into function calls in high level programming languages such as JavaScript and PHP (see LinkedIn article below.)

I would like to hear from you concerning implementation of loop and if condition, as I am not quite sure where to find such documentation.

My initial thought is that, I would implement loop and if using the same structure, i.e. use a block marker to mark start and end of block, then loop or if will execute the block based on the condition.

e.g. Execute the commands in begin: end: block like PHP foreach():

array foreach: begin: command1: command2: .... end:

In 5GL, I use : (colon) as function name suffix as it was convenient to split() string in JavaScript.

Your comments are much appreciated.

Thank you very much.

----

LinkedIn article:

Forthification of Web Browser Programming

https://www.linkedin.com/pulse/forthification-web-browser-programming-%E4%BC%8D%E6%A8%91%E7%9B%9B-%E5%8D%9A%E5%A3%AB-liang-ng-ph-d-

foxaudio...@gmail.com

unread,
May 12, 2018, 8:33:34 AM5/12/18
to
This aspect of traditional threaded code Forth compilers is not obvious to the neophyte, at least it
was not to me when I started.

The Forth VM has no flags registers and instead just uses true or false on the top of stack for
the condition flag.

There are only two branch instructions. BRANCH and ?BRANCH sometimes called 0BRANCH.

?BRANCH if used for conditional loops and IF/THEN. BRANCH is used for indefinite loops and
implementing ELSE.

These VM instructions are almost never used "as is" but are compiled into your code by the
words IF ELSE THEN, BEGIN UNTIL etc...

Here is an implementation for CAMEL FORTH with a couple of non-standard words for my cross-
compiler. ( T[COMPILE] and XIMMEDIATE) These words do what you expect but work in the
cross-compiler, so think of them as [COMPILE] and IMMEDIATE.

https://github.com/bfox9900/CAMEL99/blob/master/CCLIB/TARGLOOP.HSF

It can take a bit of thought to grok this aspect of Forth for mere mortals like me. YMMV. :-)

I am sure others here can offer more insights.

And the disclaimer: This code applies to a threaded
code implementation. A native code compiler would do this very differently.

B

lsng....@gmail.com

unread,
May 12, 2018, 10:42:53 AM5/12/18
to
On Saturday, May 12, 2018 at 8:33:34 PM UTC+8, foxaudio...@gmail.com wrote:
> I am sure others here can offer more insights.
>
> And the disclaimer: This code applies to a threaded
> code implementation. A native code compiler would do this very differently.
>
> B

Thanks a lot for sharing.

That's tremendously inspiring.

Zbig

unread,
May 12, 2018, 11:39:44 AM5/12/18
to
> I would like to hear from you concerning implementation of loop and if condition, as I am not quite sure where to find such documentation.

http://forthfiles.net/ting/sysguidefig.pdf

c...@forthworks.com

unread,
May 12, 2018, 5:27:09 PM5/12/18
to
In my Forth, the low level loop word are `repeat` and `again`. `repeat`
pushes the address of the start of the loop to the stack, and `again`
compiles a jump to it.

These are defined in assembly:

~~~
: repeat
i lifere..
r Heap

: again
i lilica..
r _lit
r comma:opcode
i lica....
r comma
i liliju..
r _jump
r comma:opcode
~~~

At a higher level, these are basically:

~~~
:repeat here ; immediate
:again compile:jump ; immediate
~~~

Higher level loops are handled using quotations and combinators. These
are built over `repeat`/`again` in most cases. E.g.,

~~~
:while (q-) [ repeat dup dip swap 0; drop again ] call drop ;
:until (q-) [ repeat dup dip swap #-1 xor 0; drop again ] call drop ;
:times (nq-) swap [ repeat 0; #1 - push &call sip pop again ] call drop ;
~~~

In older versions (when I was still using x86 assembly) I did similar, though I inlined machine code for some things:

~~~
macro
: repeat here ;
: again compile ;
: until $48 1, $c009 2, $850f 2, here - 4 - , $ad 1, ;
~~~

(In this, `until` compiles code that's roughly [going from memory, since
it's been years since I last looked at this]):

dec eax
or eax, eax
jne <address>
lodsd

Mark Humphries

unread,
May 12, 2018, 10:21:05 PM5/12/18
to
Another more unusual possibility for implementing loops at the VM level is to use the return stack for backward jump addressing. Have an instruction push the IP onto the return stack at loop entry, and instructions that use that address to jump back to the beginning of the loop, or discard it when terminating the loop.

luser droog

unread,
May 13, 2018, 12:37:18 AM5/13/18
to
On Saturday, May 12, 2018 at 5:59:01 AM UTC-5, Liang Ng wrote:
> Implementing loop in Forth clone
>
> As some of you may know, I have been working on a "top down" Forth clone, called 5GL (the Fifth Generation Graph Language), where reverse polish notation commands get translated into function calls in high level programming languages such as JavaScript and PHP (see LinkedIn article below.)
>
> I would like to hear from you concerning implementation of loop and if condition, as I am not quite sure where to find such documentation.
>
> My initial thought is that, I would implement loop and if using the same structure, i.e. use a block marker to mark start and end of block, then loop or if will execute the block based on the condition.
>
> e.g. Execute the commands in begin: end: block like PHP foreach():
>
> array foreach: begin: command1: command2: .... end:
>
> In 5GL, I use : (colon) as function name suffix as it was convenient to split() string in JavaScript.
>
> Your comments are much appreciated.

If (as I assume/gather) you're working at a somewhat higher
level than a traditional forth, ie. with arrays and associative
arrays and stuff; then you should have some construct for
blocks or anonymous procedures like PostScript procedures
or quotations AIUT. Then my description of postscript
loops might be helpful. You can use the return/exec/aux stack
for bookkeeping info and if you're clever then the common
case falls through without much fuss.

https://stackoverflow.com/questions/6949434/how-to-implement-loop-in-a-forth-like-language-interpreter-written-in-c/6951850?s=1|52.6978#6951850

Liang Ng

unread,
May 13, 2018, 1:31:29 AM5/13/18
to
(Not sure if this post will show up correctly in the thread, as I am using mobile Google groups.)

I was going towards the direction of "program counter" while implementing condition and loop for my Forth clone 5GL.

1) Given 5GL commands:

Example #1:
array foreach: cmd1: cmd2: cmd3: ....

Example #2:
array foreach: begin: cmd1: cmd2: end: cmd3: ....

2) A 5GL command (equivalent to Forth word) has a colon ( : ) suffix, as it is easy to use JavaScript split() function to obtain an array of the commands.

3) The index of the array of commands is therefore equivalent to "program counter" in microprocessor.

4) Each 5GL command will be mapped to a JavaScript function with prefix fgl_ e.g. fgl_foreach(), fgl_cmd1(), ... etc.

5) As such, to implement loop ( foreach: equivalent to PHP foreach () ), in fgl_foreach(), it reads the next command, or the next block of commands, marked by begin: .... end:

At the end of loop, it returns the offset of the last command index (program counter) from the index of the loop command (foreach:) to the master control loop (MCL).

So, MCL will resume execution at cmd2: in Example #1 and at cmd3: in Example #2.

5) The current example concerns obtaining the 'id' from the array returned by document.body.getElementsByTagName('*')

I am not sure if Forthers would appreciate the irony of using a Forth clone for such high level applications. Forth and JavaScript DOM would represent the earliest and the latest in the evolution of computer programming.


6) I will enable 5gl.pagekite.me for readers to test and verified later.

Thank you very much.






Coos Haak

unread,
May 13, 2018, 8:21:23 AM5/13/18
to
Op Sat, 12 May 2018 14:27:08 -0700 (PDT) schreef c...@forthworks.com:

>:while (q-) [ repeat dup dip swap 0; drop again ] call drop ;
>:until (q-) [ repeat dup dip swap #-1 xor 0; drop again ] call drop ;
>:times (nq-) swap [ repeat 0; #1 - push &call sip pop again ] call drop ;

I know NIP, and understand PUSH and POP as 'short' for >R and R> .
But what are DIP and SIP ?

groet Coos

Charles Childers

unread,
May 13, 2018, 10:40:28 AM5/13/18
to
`dip` would be equivilent to `push ... pop` and `sip` is equivilent to
`dup push ... pop`.

Coos Haak

unread,
May 13, 2018, 11:11:32 AM5/13/18
to
Op Sun, 13 May 2018 10:40:26 -0400 schreef Charles Childers:
Sometimes Forth words are equivile ;-)
Sip forth my tea now, thanks.

groet Coos

Cecil Bayona

unread,
May 13, 2018, 3:30:48 PM5/13/18
to
I remember those words as part of document for Timbre where they were
part combinations of often used words, used to generate better code from
a peephole optimizer.

--
Cecil - k5nwa

Charles Childers

unread,
May 13, 2018, 5:06:13 PM5/13/18
to
I adopted them from Joy and Factor.

lsng....@gmail.com

unread,
May 14, 2018, 6:29:54 AM5/14/18
to
Latest updates:

1) Open the following:

http://5gl.pagekite.me/h/fe/glv.html

2) Enter the following in the text box:

document.body.getElementsByTagName('*') e: s: foreach: .getAttribute('id') e: s:

3) Output:

https://drive.google.com/open?id=13JE2Kp0SbYp5OF2JPPMGStR_3ZGg1MOj

bit.do/5gl-fe

Liang Ng

unread,
May 14, 2018, 6:56:01 AM5/14/18
to
In the example above, s: displays the stack using JavaScript alert().

The first s: displays the results of getElementsByClassName(), which is stored in an array, as shown in figures 2 and 3.

foreach: interates through the array, extracts the 'id' property of each DOM element, which are pushed onto the stack, as shown in figures 4 and 5.

0 new messages