On Wednesday, June 12, 2019 at 10:11:21 AM UTC-7, Anton Ertl wrote:
Eaker's CASE is the most useful aspect of ANS-Forth.
It is useful for supporting the claim by C programmers
that Forth programmers are low-functioning retards.
This is because any C programmer, even a high-school student,
can easily see that Eaker's CASE is utterly retarded.
Pretty much everything about ANS-Forth is retarded,
but most aspects are confusing and obscure.
For example, we have section
3.2.3.2:
--------------------------------------------------------
The control-flow stack may, but need not, physically exist
in an implementation. If it does exist, it may be, but need not be,
implemented using the data stack. The format of the control-flow stack
is implementation defined. Since the control-flow stack may be implemented
using the data stack, items placed on the data stack are unavailable
to a program after items are placed on the control-flow stack
and remain unavailable until the control-flow stack items are removed.
--------------------------------------------------------
This is utterly retarded! To understand how retarded this is though,
it is necessary to know what meta-compilation is.
Most C programmers don't know what meta-compilation is,
so they don't understand why it was retarded for Elizabeth Rather
to fail to provide a control-flow stack distinct from the data-stack.
On the other hand, Eaker's CASE is obviously retarded.
Anybody with one year of programming experience in C or pretty much
any other language (including HLA) can immediately understand
why putting Eaker's CASE in ANS-Forth was retarded.
If we follow Anton Ertl's link above we come to this:
http://www.complang.tuwien.ac.at/anton/paper-criteria.html
Anton Ertl is making a fool of himself by pretending that
EuroForth has academic standards.
He is ignoring the mental retardation stigma of ANS-Forth.
He asks questions such as these:
"Is the idea supported with an experimental implementation or data?"
"Is there enough evidence that the paper is at the edge of its domain?"
Within the context of the ANS-Forth' reputation for mental retardation,
pseudo-academic puffery such as this is going to result in gales of laughter,
even among high-school students who are just barely learning C.
I challenge the Forth-200x committee to put their heads together
and write a substitute for Eaker's CASE that isn't retarded.
So far, the only attempt made was by Andrew Haley:
https://wiki.forth-ev.de/doku.php/events:ef2018:case
His only Forth experience was teaching the Forth Inc. novice class,
so he unsurprisingly failed to write any working Forth code.
All he had was a vague dream about how a perfect hash function
would be super-duper (in a word: "perfect").
He isn't going to succeed in writing Forth code, but maybe if all
the Forth-200x committee members work together they can succeed.
These are the criteria they need to meet to succeed:
1.) Their code can be no more than twice as complicated as my code.
2.) Their generated code can be no less that half as efficient as my code.
3.) They can't copy my code or my algorithm.
This is my code (mostly written in 2016 IIRC):
----------------------------------------------------------------------
\ ******
\ ****** This is a <SWITCH control-structure like in C that generates a jump-table.
\ ******
\ You can build a colon word called XXX that switches on targ values. This is how:
\ <SWITCH
\ :NONAME ... ; targ CASE-OF
\ ...
\ :NONAME ... ; FAST-SWITCH> xxx ( selector -- )
\ There are some simple additions as well: RANGE-OF CHARS-OF for a range of values or a set of chars.
\ Also, we have CASE: suggested by DXForth that can be used instead of CASE-OF .
\ The colon word XXX executes a table-entry corresponding to the targ value.
\ If there is no match, then the xt value prior to FAST-SWITCH> is executed as the default.
\ All of the table-entries and the default are given the selector value which they DROP if not needed.
\ It was HAA's suggestion that the selector value be provided --- I had dropped it internally previously.
\ The targ values don't have to be provided in any particular order --- they get sorted internally.
\ If a duplicate targ value is provided, CASE-OF will abort with an error message at compile-time.
\ This is pretty crude because, unlike in C, the table entries can't have common local variables.
\ I would have liked to use my rquotations, but they don't have an xt that is known at compile-time,
\ so it is not possible to build a jump-table at compile-time. They have a "continuation" that is only known at run-time.
\ My <SWITCH that I have here uses :NONAME for the table entries --- they can have common global variables.
\ FAST-SWITCH> uses the selector value as an index to do the table look up. This is very fast.
\ If the range is too large however, then FAST-SWITCH> will abort with an error message to save memory.
\ In this case, use SLOW-SWITCH> instead. This builds a smaller table and uses BSEARCH to look up the table-entry.
\ Set JT-LIMIT to the range that you want FAST-SWITCH> to support.
\ It is currently set at 2^16 so you can have jump-tables with up to 64K entries. These consume a lot of memory.
\ If memory usage is an issue, then set JT-LIMIT to a smaller value. Use SLOW-SWITCH> instead of FAST-SWITCH>.
\ If the jump-table is sparse, SLOW-SWITCH> might be faster because there is less data-cache thrashing.
\ <SWITCH is primarily provided for writing VM simulators.
\ JT-LIMIT is currently set at 2^16, so it supports simulating a micro-processor with 16-bit opcodes (such as the AVR).
\ SLOW-SWITCH> would be needed for a micro-processor with 32-bit opcodes (such as the ARM or MIPS).
\ Some micro-processors (or byte-code VMs) have 8-bit opcodes, but also have post-bytes on some of the opcodes.
\ These variable-sized opcodes could be done with nested FAST-SWITCH> constructs.
list
w field .xt
w field .targ
constant jt
: init-jt ( xt targ node -- node )
init-list >r
r@ .targ !
r@ .xt !
r> ;
: new-jt ( xt targ -- node )
jt alloc
init-jt ;
: kill-jt ( head -- )
each[ dealloc ]each ;
: show-jt ( head -- )
each[ cr .targ @ . ]each ;
: jt> ( new-node node -- new-node flag ) \ used by INSERT-ORDERED to build an ascending list without duplicates
.targ @ over .targ @
2dup = abort" *** <SWITCH structures not allowed to have duplicate targ values ***"
> ;
: <switch ( -- head )
nil ;
: case-of ( head xt targ -- new-head ) \ provide a targ value
new-jt \ -- head node
['] jt> swap insert-ordered drop ;
: range-of { head xt lo hi -- new-head } \ provide a range from LO to HI inclusive
head
hi 1+ lo do
xt I case-of
loop ;
: chars-of { head xt adr cnt -- new-head } \ provide a string containing targ chars
head
adr cnt + adr do
xt I c@ case-of
loop ;
: digit-of ( head xt -- new-head )
[char] 0 [char] 9 range-of ;
: lower-of ( head xt -- new-head )
[char] a [char] z range-of ;
: upper-of ( head xt -- new-head )
[char] A [char] Z range-of ;
: alpha-of { head xt -- new-head }
head
xt lower-of xt upper-of ;
: punctuation-of ( head xt -- new-head )
s| .,!?'";:[]()@#$%&| chars-of ;
: blank-of ( head xt -- new-head )
0 32 range-of ;
1 16 lshift value jt-limit \ should be at least 256 so we can support byte-code simulators
\ JT-LIMIT is the index that is too big for the jump-table. This can be any reasonable size.
\ The jump-table size is limited so the programmer doesn't accidentally build a jump-table consuming megabytes.
\ I set it at 2^16 to support simulating a micro-processor with 16-bit opcodes.
: fast-switch> { head default | adr offset size -- } \ stream: name
align here to adr
head .targ @ to offset
head tail .targ @ offset - to size
size jt-limit u> abort" *** FAST-SWITCH> has too large of a range. Use SLOW-SWITCH> instead. ***"
offset head each[ >r \ -- targ
begin r@ .targ @ over <> while default , 1+ repeat
r> .xt @ , 1+ ]each drop
: ( selector -- )
dup, offset lit, -, \ -- selector index
dup, size lit, u>, if, drop, default lit, execute, end,
w lit, *, adr lit, +, @, execute, ;,
head kill-jt ;
: slow-search ( array limit target -- element|false ) \ hard-coded for use by SLOW-SWITCH>
>r \ -- array limit \ return: -- target
begin dup while
dup 1 rshift \ -- array limit mid
dup d * fourth + \ -- array limit mid mid-element
r@ over @ = if nip nip nip rdrop exit then \ if found, return MID-ELEMENT
r@ over @ < if \ search left side
drop nip \ -- array mid \ MID is the new limit
else
d + >r \ -- array limit mid \ return: -- target new-array \ NEW-ARRAY is one element above middle element
1+ - \ -- array new-limit \ the 1+ is so we don't include the middle element
nip r> swap \ -- new-array new-limit \ MID-ELEMENT is the new ARRAY
then
repeat \ LIMIT is zero, so it can be used as a FALSE flag
nip rdrop ; \ -- false
\ SLOW-SEARCH assumes that the array element is D in size (two cells),
\ and the first cell is the integer that we are comparing against.
: slow-switch> { head default | adr size -- } \ stream: name
align here to adr
head length to size
head each[ dup .targ @ , .xt @ , ]each
: ( selector -- )
adr lit, size lit, rover, postpone slow-search
dup, if, w lit, +, @, execute, end,
drop, default lit, execute, ;,
head kill-jt ;
\ CASE: and ;; were suggested by DXForth on comp.lang.forth to improve readability.
\ This works well when there is a list of integers, similar to CASE END-CASE in ANS-Forth.
get-current synonym case: :noname \ head targ -- head targ
: ;; ( head targ -- new-head ) \ this concludes the CASE: function (rather than ; as used in :NONAME usually)
postpone ; \ -- head targ xt
swap case-of ;
immediate
\ Note that the default should still be :NONAME and end with ; as usual.
----------------------------------------------------------------------