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

Rosetta Code Comma Quibbling

255 views
Skip to first unread message

foxaudio...@gmail.com

unread,
Jan 16, 2016, 9:38:52 PM1/16/16
to
I used the string stack concept mentioned by Mark Wills
to write a solution to the comma quibbling problem in Rosetta Code.

http://rosettacode.org/wiki/Comma_quibbling#Forth

It runs the same under my HSF2000 16 bit Forth and iForth 32 bit.

Note: I wrote it to try and promote Forth; show that Forth is not gibberish.
It's not the most efficient code, but may be more accessible by a
computer professional versed in other languages. (My opinion)

hughag...@gmail.com

unread,
Jan 16, 2016, 9:42:09 PM1/16/16
to
I don't remember the string-stack concept --- can you describe it?

I'll look over your code.

foxaudio...@gmail.com

unread,
Jan 16, 2016, 9:57:21 PM1/16/16
to
I built this thing forself years ago to wean me off of BASIC. :-)

I used counted strings. All string functions work by pushing arguments onto the string stack and return the result on the top of the string stack.

2 magic words $! (string store) and $. (string dot)

do their normal thing but then collapse the string stack.
cheap automatic garbage collection.

This code looked like this:

$VARIABLE A$
$VARIABLE B$

A$ :=" this is string A$"
B$ :=" this is string B$"

A$ B$ +$ 5 17 MID$ $.

etc...

Julian Fondren

unread,
Jan 16, 2016, 10:06:13 PM1/16/16
to
On Saturday, January 16, 2016 at 8:38:52 PM UTC-6, foxaudio...@gmail.com wrote:
> http://rosettacode.org/wiki/Comma_quibbling#Forth

With more than 2 uses of S" on a line:

0 constant {
: } ( 0 ... -- )
dup 0= if drop ." {}" exit then
0 begin over while -rot 2>r 1+ repeat nip
." {" begin dup while
1- 2r> [char] " emit type [char] " emit
dup 1 = if ." and " else
dup 1 > if ." , " then then
repeat drop ." }" ;

cr { }
cr { s" ABC" }
cr { s" ABC" s" DEF" }
cr { s" ABC" s" DEF" s" G" s" H" }
bye

Outputs:

{}
{"ABC"}
{"ABC" and "DEF"}
{"ABC", "DEF", "G" and "H"}

} isn't doing anything clever. It moves strings to the return
stack until it finds a 0, then prints strings from the return
stack with {""} decoration. It counted the strings while moving
them to the return stack and so can, counting down, follow these
comma rules:

If there are no remaining strings, print nothing
If there's one remaining string, print " and "
If there's more than one remaining string, print ", "

To get a string result, use your Forth's facility to vector
output to a string. Doing that beats requiring every little
string word to decide how to store the result.


-- Julian

Paul Rubin

unread,
Jan 16, 2016, 10:32:45 PM1/16/16
to
\ this "redefines the problem" by giving the quibbled words as a
\ word count then the words, instead of using delimters.

: gtype ( "word" -- ) bl word count type ;
: gtype2 ( "word1" "word2" -- ) gtype ." and " gtype ;
: gtype-n ( n>2 "words..." -- ) 2 - 0 do gtype ." , " loop gtype2 ;
: quibble ( n "words..." -- )
case
1 of gtype endof
2 of gtype2 endof
dup gtype-n
endcase cr ;

\ examples
1 quibble abc
2 quibble abc def
4 quibble abc def g h
bye

foxaudio...@gmail.com

unread,
Jan 16, 2016, 10:33:40 PM1/16/16
to
LOL. This is why I was moved into management.

Nicely done Julian.

Is it required in the specification that S" returns a different address if it is used more that once?

BF

hughag...@gmail.com

unread,
Jan 17, 2016, 12:49:00 AM1/17/16
to
No, it is not --- some ANS-Forth's don't allow this --- I fix the problem in my novice-package.

I will look into this string-stack --- maybe put that in my novice-package --- I don't like what I have currently.

Julian Fondren

unread,
Jan 17, 2016, 1:24:27 AM1/17/16
to
On Saturday, January 16, 2016 at 11:49:00 PM UTC-6, hughag...@gmail.com wrote:
> On Saturday, January 16, 2016 at 8:33:40 PM UTC-7, foxaudio...@gmail.com wrote:
> >
> > Is it required in the specification that S" returns a different address if it is used more that once?
> >
>
> No, it is not --- some ANS-Forth's don't allow this --- I fix the problem in my novice-package.
>

I'd thought that the files version of S" came with a guarantee
of at least two buffers, for RENAME-FILE , but when I scanned
dpans94 and forth-200x I couldn't find a confirmation of that.

But the following ouputs what you'd expect on gforth,
SwiftForth, iForth, ciforth, kforth... so in practice, at least
outside of embedded environments, 'multiple S" buffers' is not a
hard requirement to satisfy.

S" a" S" b" S" c" S" d"
TYPE TYPE TYPE TYPE


-- Julian

Raimond Dragomir

unread,
Jan 17, 2016, 2:36:46 AM1/17/16
to
> But the following ouputs what you'd expect on gforth,
> SwiftForth, iForth, ciforth, kforth... so in practice, at least
> outside of embedded environments, 'multiple S" buffers' is not a
> hard requirement to satisfy.
>
> S" a" S" b" S" c" S" d"
> TYPE TYPE TYPE TYPE
>
>
> -- Julian

In my implementation I have just two buffers:
1. Input buffer (not TIB, because it's not neccesarily 'terminal')
2. Parse buffer.
Parse buffer is kind of circular, the strings are appended from the IB
until there is no more room, and then the strings starts to overwrite
the older ones from the start of the buffer.

I have only a 256 byte parse buffer. It can store a lot of typical small
strings. It is not only for S" strings, it's for ANY strings (including
the source tokens). Works very nice and it's very eficient in terms of
memory.

The only drawback is that it silently overwrite the oldest strings without
any warning.

WJ

unread,
Jan 17, 2016, 3:42:23 AM1/17/16
to
Ruby:

def quib a
"{" + a.join(', ').sub(/(.*), /, '\1 and ') + "}"
end

[[],["ABC"],["ABC","DEF"],["ABC","DEF","G","H"]].each{|a| puts quib(a)}
===>
{}
{ABC}
{ABC and DEF}
{ABC, DEF, G and H}


Another way:

def quib a
result = "{"
until a.empty?
word = a.shift
result <<
case a.size
when 0
word
when 1
word + " and "
else
word + ", "
end
end
result + "}"
end


Another way:

def quib a
separators =
if a.size < 2
[]
else
a.drop(2).map{", "} << " and "
end
"{" + a.zip(separators).flatten.compact.join + "}"
end


--
Amazon bans book. After nearly a month on the site, all traces of the book and
its 80 reviews have been removed.
http://jamesfetzer.blogspot.com/2015/11/debunking-sandy-hook-debunkers-5.html
https://www.youtube.com/watch?v=EEl_1HWFRfo

WJ

unread,
Jan 17, 2016, 3:56:24 AM1/17/16
to
Julian Fondren wrote:

> Outputs:
>
> {}
> {"ABC"}
> {"ABC" and "DEF"}
> {"ABC", "DEF", "G" and "H"}

3 of those 4 are wrong.

E.g., {"ABC" and "DEF"} ought to be {ABC and DEF}.

WJ

unread,
Jan 17, 2016, 5:30:42 AM1/17/16
to
Oforth:

: quibble {|input,result|
asListBuffer -> input
[] asListBuffer -> result
while (input notEmpty) [
result add(input removeFirst)
result add(["", " and ", ", "] at( input size 1 + 3 min )) ]
"{" result asString "}" + +}

[[],["ABC"],["ABC","DEF"],["ABC","DEF","G","H"]] apply(#[quibble println])

{}
{ABC}
{ABC and DEF}
{ABC, DEF, G and H}


Anton Ertl

unread,
Jan 17, 2016, 5:37:12 AM1/17/16
to
Julian Fondren <julian....@gmail.com> writes:
>I'd thought that the files version of S" came with a guarantee
>of at least two buffers, for RENAME-FILE , but when I scanned
>dpans94 and forth-200x I couldn't find a confirmation of that.

|11.3.4 Other transient regions
|
|The system provides transient buffers for S" and S\" strings. These
|buffers shall be no less than 80 characters in length, and there shall
|be at least two buffers. The system should be able to store two
|strings defined by sequential use of S" or S\". RAM-limited systems
|may have environmental restrictions on the number of buffers and their
|lifetimes.

- anton
--
M. Anton Ertl http://www.complang.tuwien.ac.at/anton/home.html
comp.lang.forth FAQs: http://www.complang.tuwien.ac.at/forth/faq/toc.html
New standard: http://www.forth200x.org/forth200x.html
EuroForth 2015: http://www.rigwit.co.uk/EuroForth2015/

WJ

unread,
Jan 17, 2016, 5:48:27 AM1/17/16
to
WJ wrote:

> foxaudio...@gmail.com wrote:
>
> > I used the string stack concept mentioned by Mark Wills
> > to write a solution to the comma quibbling problem in Rosetta Code.
> >
> > http://rosettacode.org/wiki/Comma_quibbling#Forth
> >
> > It runs the same under my HSF2000 16 bit Forth and iForth 32 bit.
> >
> > Note: I wrote it to try and promote Forth; show that Forth is not gibberish.
> > It's not the most efficient code, but may be more accessible by a
> > computer professional versed in other languages. (My opinion)
>
> Oforth:
>
> : quibble {|input,result|
> asListBuffer -> input
> [] asListBuffer -> result
> while (input notEmpty) [
> result add(input removeFirst)
> result add(["", " and ", ", "] at( input size 1 + 3 min )) ]
> "{" result asString "}" + +}
>
> [[],["ABC"],["ABC","DEF"],["ABC","DEF","G","H"]] apply(#[quibble println])
>
> {}
> {ABC}
> {ABC and DEF}
> {ABC, DEF, G and H}

Ruby:

def quibble input
result = "{"
until input.empty?
result << input.shift
result << ["", " and ", ", "][[input.size,2].min]
end
result + "}"
end

WJ

unread,
Jan 17, 2016, 7:47:15 AM1/17/16
to
Oforth:

: quibble {|input|
asListBuffer -> input
StringBuffer new "{" <<
while (input notEmpty) [
input removeFirst <<
["", " and ", ", "] at(input size 1 + 3 min) << ]
"}" <<}

[[],["ABC"],["ABC","DEF"],["ABC","DEF","G","H"]] apply(#[quibble println])

{}
{ABC}
{ABC and DEF}
{ABC, DEF, G and H}

Albert van der Horst

unread,
Jan 17, 2016, 8:15:57 AM1/17/16
to
This one of the reasons I came up with denotations. A ciforth string
starting with " is permanent. You can stop thinking about buffers,
let alone multiple buffers.

>-- Julian

Groetjes Albert
--
Albert van der Horst, UTRECHT,THE NETHERLANDS
Economic growth -- being exponential -- ultimately falters.
albert@spe&ar&c.xs4all.nl &=n http://home.hccnet.nl/a.w.m.van.der.horst

foxaudio...@gmail.com

unread,
Jan 17, 2016, 8:28:02 AM1/17/16
to
In my original version it was for a Fig-forth variant and PAD was in memory
above HERE, so the string stack just extended out into free memory space like
multiple PAD spaces. PAD does not work that way on all systems so for the
Rosetta demo I just created a fixed space for pedagogical clarity.

BF

Albert van der Horst

unread,
Jan 17, 2016, 8:55:02 AM1/17/16
to
You don't need a buffer at all.
This is the crucial part of the code in ciforth, no 0 or 1 string cases.

(ACCEPT) \ Get string
BEGIN &, $/ 2OVER OR WHILE TYPE SPACE REPEAT " AND " TYPE TYPE

>BF

Doug Hoffman

unread,
Jan 17, 2016, 11:01:09 AM1/17/16
to
On 1/16/16 9:38 PM, foxaudio...@gmail.com wrote:
> I used the string stack concept mentioned by Mark Wills
> to write a solution to the comma quibbling problem in Rosetta Code.
>
> http://rosettacode.org/wiki/Comma_quibbling#Forth

I really like, and use, library code.
By eliminating <free below one can easily
hang on to the reference for the
input list for later manipulation.

-Doug

Works with any ANS Forth

Needs the FMS-SI (single inheritance) library code located here:
http://soton.mpeforth.com/flag/fms/index.html
include FMS-SI.f
include FMS-SILib.f

: foo { l | s -- }
cr ." {"
l size: dup 1- to s
0 ?do
i l at: p:
s i - 1 >
if ." , "
else s i <> if ." and " then
then
loop
." }" l <free ;

${ } foo
\ {}
${ ABC } foo
\ {ABC}
${ ABC DEF } foo
\ {ABC and DEF}
${ ABC DEF G } foo
\ {ABC, DEF and G}
${ ABC DEF G H } foo
\ {ABC, DEF, G and H}
${ ABC DEF G H I } foo
\ {ABC, DEF, G, H and I}


Mark Wills

unread,
Jan 18, 2016, 3:39:40 AM1/18/16
to
http://turboforth.net/resources/string_library.html

There's a PDF with an ANS implementation. Just look at the interfaces,
don't bother with the implementation - produce your own. You'll produce
much more efficient code if you implement using a heap and linked
lists. Of course, this can still be represented as a string stack to
the user, even if strings are scattered across the heap. The various
facilities within the Novice Package would be perfect for implementing
this. If you do implement these interfaces, or a selection of them,
it would be great if you published the code.

Gerry Jackson

unread,
Jan 18, 2016, 4:11:10 AM1/18/16
to
Looking at the source code on your web-site, you don't seem to have
fixed the bugs I reported a couple of months ago.

--
Gerry

Mark Wills

unread,
Jan 18, 2016, 4:58:23 AM1/18/16
to
You're right. It slipped my mind. I'll try and get to it this week.

Thanks for the reminder!

hughag...@gmail.com

unread,
Jan 18, 2016, 4:48:05 PM1/18/16
to
The string stuff in my novice-package is terrible --- I've never been happy with it --- I have been thinking of holding the strings in the heap as you suggest.

I'll look into your code as a possible way to go. If I do implement this in the novice package I'll give you credit. :-)

Albert van der Horst

unread,
Jan 19, 2016, 11:36:12 AM1/19/16
to
You're invited to investigate whether you can get by with ciforth's
$! $@ $+! $C+
and
$/ $^
without using dynamic buffers (until such time you need dynamic buffering
for other reasons.)

(I've never seen anything on c.l.f that required more heavy machinery.)

Groetjes Albert

hughag...@gmail.com

unread,
Jan 20, 2016, 12:57:55 AM1/20/16
to
On Tuesday, January 19, 2016 at 9:36:12 AM UTC-7, Albert van der Horst wrote:
> hughag...@gmail.com writes:
>
> >On Monday, January 18, 2016 at 1:39:40 AM UTC-7, Mark Wills wrote:
> >> On Sunday, 17 January 2016 05:49:00 UTC, hughag...@gmail.com wrote:
> >> > I will look into this string-stack --- maybe put that in my novice-package --- I don't like what I have currently.
> >>
> >> http://turboforth.net/resources/string_library.html
> >>
> >> There's a PDF with an ANS implementation. Just look at the interfaces,
> >> don't bother with the implementation - produce your own. You'll produce
> >> much more efficient code if you implement using a heap and linked
> >> lists. Of course, this can still be represented as a string stack to
> >> the user, even if strings are scattered across the heap. The various
> >> facilities within the Novice Package would be perfect for implementing
> >> this. If you do implement these interfaces, or a selection of them,
> >> it would be great if you published the code.
>
> >The string stuff in my novice-package is terrible --- I've never been happy with it --- I have been thinking of holding the strings in the heap as you suggest.
>
> >I'll look into your code as a possible way to go. If I do implement this in the novice package I'll give you credit. :-)
>
> You're invited to investigate whether you can get by with ciforth's
> $! $@ $+! $C+
> and
> $/ $^
> without using dynamic buffers (until such time you need dynamic buffering
> for other reasons.)
>
> (I've never seen anything on c.l.f that required more heavy machinery.)
>
> Groetjes Albert

I don't know what those functions you listed do.

I do need to have more than one level of string in use at one time though. For example, inside of <CSTR ... CSTR> I may call a function that itself uses <CSTR ... CSTR> --- I don't necessarily know if the function uses <CSTR ... CSTR> or not --- I just know that it returns a string and that string will be given to +CSTR to be concatenated into the string being built by <CSTR .. CSTR>.

What I have currently does work but it is not memory efficient.

What I have is also cumbersome because I have CSTR-NEXT needed --- Raimond told me how to get rid of this, but I haven't yet thought through his suggestion to make sure it works.

I haven't really given much thought to the novice package in quite a while, but I should put together the code I've got and do an upgrade --- the www.forth.org website is down now and may not return anytime soon, so I can't release an upgrade unless I set up my own website.

WJ

unread,
Feb 18, 2016, 3:39:05 PM2/18/16
to
Ruby:

def quib a
sep = " and "
result = [a.last]
a.reverse.drop(1).each{|x| result += [sep,x]; sep = ", "}
"{#{result.reverse.join}}"
end

[[],["ABC"],["ABC","DEF"],["ABC","DEF","G","H"]].each{|a| puts quib(a)}
===>
{}
{ABC}
{ABC and DEF}
{ABC, DEF, G and H}

--
[T]he number of Jews killed there was 800,000,000.... [T]he Talmud makes it all
clear by informing us that the blood of the holocausted Jews ran to the sea in
a huge tidal wave that swept boulders in its path and was so deep that it
reached the nostrils of the Romans' horses.
nationalvanguard.org/2014/09/disillusioned-part-1/

WJ

unread,
Jun 27, 2016, 10:44:45 PM6/27/16
to
foxaudio...@gmail.com wrote:

> I used the string stack concept mentioned by Mark Wills
> to write a solution to the comma quibbling problem in Rosetta Code.
>
> http://rosettacode.org/wiki/Comma_quibbling#Forth
>
> It runs the same under my HSF2000 16 bit Forth and iForth 32 bit.
>
> Note: I wrote it to try and promote Forth; show that Forth is not gibberish.
> It's not the most efficient code, but may be more accessible by a
> computer professional versed in other languages. (My opinion)

OCaml:

let rec quib = function
[] -> ""
| [s] -> s
| [s;t] -> s ^ " and " ^ t
| s::more -> s ^ ", " ^ quib more ;;

[[];["ABC"];["ABC";"DEF"];["ABC";"DEF";"G";"H"]]
|> List.iter (fun list -> print_endline ("{" ^ quib list ^ "}")) ;;

{}
{ABC}
{ABC and DEF}
{ABC, DEF, G and H}

--
Jewish drug dealers, child porn pushers, and slave traders are free
from prosecution in Israel. Israel does not consider these to be
crimes ... so long as the victims are non-Jews.
www.theoccidentalobserver.net/2009/08/the-culture-of-deceit/
0 new messages