How do you specify the 8th namespaces in an array? - forth

8th uses namespaces instead of vocabularies. Each namespace has its own integer representation.
ok> ns:a . cr ns:n . cr
4
2
So, 2 is for the number namespace, and 4 is for arrays.
I want to construct an array holding the namespaces which I can then place at the TOS (top of stack).
However, if I just write this
ok> [ ns:a , ns:n ]
Exception: invalid JSON array: at line 1 char 3 in ....: cr (G:;;; +000004c2)
Exception: can't find: :a: at line 1 char 6 in (null): cr (G:??? +00000029)
Exception: can't find: ,: at line 1 char 8 in (null): cr (G:??? +00000029)
Exception: can't find: ]: at line 1 char 15 in (null): n (G:??? +00000029)

I'm the developer of 8th. The solution with ' ns:a is not really what you want, since that puts the word in the array instead of the value that word would return.
You can accomplish what you're looking for by using the backtick:
[ ` ns:a ` ]
The backtick feeds the text up to the next backtick to eval and puts the value (whatever it is) in the JSON you're creating (it's not limited to JSON, it's a general construct).

You can store the function address instead in the array
[ ' ns:n , ' ns:a ]
and access the values by grabbing an array value and exec it
0 a:# w:exec . cr
2
ok>
You can also use anonymous functions
[ ( ns:a ) , ( ns:m ) ]

Related

Print double quotes in Forth

The word ." prints a string. More precisely it compiles the (.") and the string up to the next " in the currently compiled word.
But how can I print
That's the "question".
with Forth?
In a Forth-2012 System (e.g. Gforth) you can use string literals with escaping via the word s\" as:
: foo ( -- ) s\" That's the \"question\"." type ;
In a Forth-94 system (majority of standard systems) you can use arbitrary parsing and the word sliteral as:
: foo ( -- ) [ char | parse That's the "question".| ] sliteral type ;
A string can be also extracted up to the end of the line (without printable delimiter); a multi-line string can be extracted too.
Specific helpers for particular cases can be easily defined.
For example, see the word s$ for string literals that are delimited by any arbitrary printable character, e.g.:
s$ `"test" 'passed'` type
Old school:
34 emit
Output:
"
Using gforth:
: d 34 emit ;
cr ." That's the " d ." question" d ." ." cr
Output:
That's the "question".

Word signature in factor

i try to iterate over a an array which contains weather data. That works fine already and I also can load the datas from the array which are important for me. Therefore I wrote a helping word which looks like this:
: get-value ( hsh str -- str ) swap at* drop ;
[ "main" get-value "temp" get-value ] each 9 [ + ] times
This code pushes the temperature values from the array on the stack and builds the sum. "main" and "temp" are the key values of the arrays.
I execute it with this command: get-weather-list generates the array
"Vienna" get-weather-list [ "main" get-value "temp" get-value ] each 9 [ + ] times
The result is a number on the stack. Now I want to split this call into one or two words. For example:
: get-weather-information ( city -- str )
get-weather-list
[ "main" get-value "temp" get-value ] each 9 [ + ] times ;
The problem is that I don't really understand the word's signature. I always get "The input quotation to “each” doesn't match its expected effect". I tried a lot but can't find a solution to fix this problem. May anyone have an idea? I am grateful for any help :)
Cheers
Stefan
This is a very old question by now, but it still may be useful to someone.
First, about each: the stack effect of the quotation is (... x -- ...).
That means it consumes an input, and outputs nothing. Your quotation worked on the interpreter because it lets you get away with "wrong" code. But for calling each from a defined word, your quotation can't output anything.
So each is not what you want. If you try to push a variable amount of values to the stack, you'll have the same kind of trouble again. Sequence words all output a fixed amount of values.
What you want to do is one of two things:
Make a new sequence with just the values you want, and then call sum on it.
Use something like reduce, to accumulate the sum as you process your list.
For example, with reduce:
get-weather-list 0 [ "main" get-value "temp" get-value + ] reduce ;

Parse issue when using Change command (Rebol2)

I have the following parse issue. In the first sample text below, the parse will hit the two command blocks as it finds the parts in the text.
Give the below a try (Rebol 2).
sample-text: {deferred member}
remove-anchors: func [sample-text][
parse sample-text[
some [
to {<a href="javascript:gotoURL('displayContent.aspx?contentID=9}
begin:
thru {);">}
ending:
(print "Command 1 executed" )
to "<"
begin:
thru ">"
ending:
(print "Command 2 executed" )
]
]
return sample-text
]
Result:
remove-anchors sample-text
Command 1 executed
Command 2 executed
However, if I insert the change/part portion of the command, which is expected to remove the text it finds, the first change/part executes but it appears the second portion of the parse command stops as the second execution block doesn't trigger.
sample-text: {deferred member}
remove-anchors: func [sample-text][
parse sample-text[
some [
to {<a href="javascript:gotoURL('displayContent.aspx?contentID=9}
begin:
thru {);">}
ending:
(print "Command 1 executed" change/part begin "" ending) ;<<----- change
to "<"
begin:
thru ">"
ending:
(print "Command 2 executed" change/part begin "" ending) ;<<----- change
]
]
return sample-text
]
Result:
remove-anchors sample-text
Command 1 executed
== "deferred member</a>"
Note the second command didn't seem to execute both by the Print not executing and the parse not completing.
Since I have multiple different types of links in the texts I'm trying to remove these pieces of HTML from, and multiple occurrences in the same text, I figured PARSE was the right solution.
Can anyone see what I am doing wrong?
Your function should work if you use this
remove-anchors: func [sample-text][
parse sample-text[
some [
to {<a href="javascript:gotoURL('displayContent.aspx?contentID=9}
begin:
thru {);">}
ending:
(print "Command 1 executed" change/part begin "" ending)
:begin ; note this
to "<"
begin:
thru ">"
ending:
(print "Command 2 executed" change/part begin "" ending)
]
]
return sample-text
]
Explanation:
The internal parse pointer is at an internal numeric index of 95 after {);">}. After the change command the index is still at 95, but the sample-text is now much shorter and your parse pointer after your second search text "to "<", probably already after the end. You can see that if you use this line
(print "Command 1 executed" change/part begin "" ending print ending) ;<<----- change
in your function, giving you following error
** Script Error: Out of range or past end
** Where: remove-anchors
** Near: print ending
So you have to set back your parse index / pointer to the beginning of the point, where you changed/deleted your text. This you get with :begin after your alteration.
Best advice is to set back / initialize your internal parse pointer anew, if you modified your parse input: After deletion you should go back to the start of your deletion and after insertion / modification you should go first to the start and then to the end of the new item.

Error when appending string from word or variable

I'm trying to append two strings in gforth, but I get some scary looking error messages.
While s" foo" s" bar" append type cr works fine, as soon as I start storing strings in variables or creating them from words, I get errors. For instance:
: make-string ( -- s )
s" foo" ;
: append-print ( s s -- )
append type cr ;
make-string s" bar" append-print
Running it produces the following error:
$ gforth prob1.fs -e bye
gforth(41572,0x7fff79cc2310) malloc: *** error for object 0x103a551a0: pointer being realloc'd was not allocated
*** set a breakpoint in malloc_error_break to debug
Abort trap: 6.
I'm well versed in C, so it seems pretty clear that I'm using Forth incorrectly!
I suppose I need to learn something very basic about memory management in Forth.
Can anyone please explain what goes wrong here, and what I should do?
I also run into problems when I try to append a string that is stored in a variable:
variable foo
s" foo" foo !
foo s" bar " append type cr
This ends in a loop that I have to break:
$ gforth prob2.fs
foo��^C
in file included from *OS command line*:-1
prob2.fs:4: User interrupt
foo s" bar " append >>>type<<< cr
Backtrace:
$10C7C2E90 write-file
For reference, I'm using gforth 0.7.2 on Mac OS X. I would be very grateful for some good explanations on what's going on.
Update
I can see the definition of append:
see append
: append
>l >l >l >l #local0 #local1 #local3 + dup >l resize throw >l #local4 #local0 #local3 + #local5
move #local0 #local1 lp+!# 48 ; ok
So, it would seem I need to manage memory myself in Forth? If so, how?
Solution
Andreas Bombe provides the clue below. The final program that works would be
: make-string ( -- s )
s" foo" ;
: append-print
s+ type cr ;
make-string s" bar" append-print
Output is
$ gforth b.fs -e bye
foobar
append uses resize on the first string make space to append the second string. This requires that the string be allocated on the heap.
When you compile a string with s" into a word, it gets allocated in the dictionary. If you try resize (directly or indirectly through append) on that pointer you will get the error you see.
Normally s" has undefined interpretation semantics. Gforth defines its interpretation semantics for convenience as allocating the string on the heap. That's why it works (in gforth) as long as you don't compile it.
Edit:
I've found the definition of append, it's part of libcc.fs (a foreign function interface builder as it seems) and not a standard word. This is the definition in the source, more readable than the see decompile:
: append { addr1 u1 addr2 u2 -- addr u }
addr1 u1 u2 + dup { u } resize throw { addr }
addr2 addr u1 + u2 move
addr u ;
Immediately before that is a definition of s+:
: s+ { addr1 u1 addr2 u2 -- addr u }
u1 u2 + allocate throw { addr }
addr1 addr u1 move
addr2 addr u1 + u2 move
addr u1 u2 +
;
As you can see this one allocates new memory space instead of resizing the first string and concatenates both strings into it. You could use this one instead. It is not a standard word however and just happens to be in your environment as an internal implementation detail of libcc.fs in gforth so you can't rely on it being available elsewhere.
The usage of strings in Forth doesn't warrant dynamic allocation mostly and at least not in your example. You can get by nicely with buffers that you allocate yourself using ALLOT
and some very simple words to manipulate them.
[ALLOT uses the data space (ANSI term) in an incremental fashion for adding words and buffers. It is not dynamic, you can't release an item without removing at the same time all items ALLOT-ted later. It is also simple. Do not confuse with ALLOCATE which is dynamic and is in a separate extension wordset]
You make a fundamental mistake in leaving out the specification of your append-buffer.
It doesn't work, and we don't know how it is supposed to work!
In ciforth's an example could be:
: astring S" foo" ;
CREATE buffer 100 ALLOT \ space for 100 chars
\ Put the first string in `buffer and append the second string.
\ Also print the second string
: append-print ( s s -- )
type cr 2swap
buffer $!
buffer $+! ;
astring s" bar" append-print
bar OK \ answer
buffer $# TYPE
foobar OK \ answer
Other Forths have other non-standard words to manipulate simple strings. An excursion through malloc land is really not necessary. In the gforth documentation you can look up 'place' and find an equivalent family of words.
Also nowadays (Forth 2012) you can have strings like so "foo".

Best way to parse this in Rebol

How do I extract the transaction receipt datetime with the least bit of noise in my parse rule from the following HTML? (The output I'm looking to get is this: "Transaction Receipt: 04/28/2011 17:03:09")
<FONT COLOR=DARKBLUE>Transaction Receipt </FONT></TH></TR><TR></TR><TR></TR><TR><TD COLSPAN=4 ALIGN=CENTER><FONT SIZE=-1 COLOR=DARKBLUE>04/28/2011 17:03:09</FONT>
The following works but I don't get a good feeling! There is guaranteed to be a datetime following the words Transaction Receipt somewhere (although I wouldn't do a greedy match if I'm doing a grep)
parse d [
thru {<FONT COLOR=DARKBLUE>Transaction Receipt </FONT></TH></TR><TR></TR><TR></TR><TR><TD COLSPAN=4 ALIGN=CENTER><FONT SIZE=-1 COLOR=DARKBLUE>}
copy t to "</FONT>"
]
This is shorter...
parse d [thru <FONT SIZE=-1 COLOR=DARKBLUE> copy t to </FONT>]
but isn't specifically looking for the datetime pair. And unfortunately REBOL considers the date used an invalid one...
>> 04/28/2011
** Syntax Error: Invalid date -- 04/28/2011
** Near: (line 1) 04/28/2011
so you can't search for it specifically. If the date was 28/04/2011 (and there was a space after the time, though why it's needed for load I'm not sure), the following would work...
parse load d [to date! copy t to </FONT>]
Hmmm. Try this...
t: ""
parse d [
some [
to "<" thru ">" mark: copy text to "<" (if text [append t text]) :mark
]
]
That returns: "Transaction Receipt 04/28/2011 17:03:09"
It works by skipping all the tags, appending any text that's left to t.
Hope that helps!
Timely as per usual: if the format is consistent, you can always try to explicitly match dates:
rule: use [dg tag date value][
tag: use [chars][
chars: charset [#"a" - #"z" #"A" - #"Z" #"0" - #"9" " =-"]
["<" opt "/" some chars ">"]
]
date: use [dg mo dy yr tm][
dg: charset "0123456789"
[
copy mo [2 dg "/"] copy dy [2 dg "/"] copy yr 4 dg
" " copy tm [2 dg ":" 2 dg ":" 2 dg]
(value: load rejoin [dy mo yr "/" tm])
]
]
[
some [
"Transaction Receipt" (probe "Transaction Receipt")
| date (probe value)
; everything else
| some " " | tag ; | skip ; will parse the whole doc...
]
]
]

Resources