On Wednesday, January 1, 2020 at 4:19:39 AM UTC-7, a...@littlepinkcloud.invalid wrote:
> Rod Pemberton <nomai...@trgzxcqvbe.cpm> wrote:
> > So, I'm not yet convinced "it's just a lie" that BLM isn't being
> > investigated. They probably are,
>
> Thank you. So your comment was "probably" wrong, then.
>
> > but it's not been publicly stated that they are.
>
> Like that matters.
None of this matters.
This is just off-topic trolling.
> >> > So, why not stick to on-topic conversations about Forth?
> >>
> >> Why not, indeed?
> >
> > Well, that goes for you too now ... It's a pity that you finally fell
> > into another cesspool Hugh started.
>
> From what I can see, he didn't start that, you did. If you make an
> untrue claim and get called on it, that's how it's supposed to work.
> Even in a .sig.
I didn't call him on his sig being untrue.
I don't care if BLM is being investigated by the FBI or not.
I called him on off-topic trolling --- always true about Rod Pemberton.
I told him: Piss off!
You can piss off too --- you responded to Rod Pemberton as a peer ---
this means that you are a jackass too.
You are dumber than dirt in regard to programming.
You failed badly at writing a <SWITCH construct --- instead, you went to
EuroForth-2018 and did a lot of braying about how you are the world's expert
on the subject. I've not seen any evidence that you know anything about
the subject however.
For your education, this is code that works:
---------------------------------------------------------------------------
\ ******
\ ****** 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
dalign here to adr \ use DALIGN so the element SLOW-SEARCH finds will be in the same data-cache line
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.
\ Testra had a switch construct written in UR/Forth assembly-language that built two arrays,
\ one of targ values and one of xt values. It generated code that would use SCASW to search the targ values.
\ I recommended using a binary search instead. I was told that SCASW is faster, even though it is sequential.
\ On the 80486, the ciscy instructions did usually provide better performance than hand-written code.
\ Because Testra was into building custom processors, they needed a fast simulator.
\ I didn't use their simulator for the MiniForth though --- I wrote my own in MFX.
\ The best way to write a simulator is to have your assembler not only generate the machine-code
\ for the target processor, but also generate a Forth program on the host machine that simulates it.
\ This generated simulation is much faster than a simulator that looks up opcodes at run-time.
\ This only works if you have the source-code for the target processor program that you are simulating.
---------------------------------------------------------------------------