Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.forth > #59132
| From | rickman <gnuarm@gmail.com> |
|---|---|
| Newsgroups | comp.lang.forth |
| Subject | Re: Rosetta: Caesar cipher |
| Date | 2017-05-12 13:41 -0400 |
| Organization | A noiseless patient Spider |
| Message-ID | <of4rtu$2ii$1@dont-email.me> (permalink) |
| References | <oet9tb$166r$1@gioia.aioe.org> <of09pp$k46$1@dont-email.me> <27244bc8-3cf8-445d-803e-bef86c1e6122@googlegroups.com> <of0tsi$6u0$1@dont-email.me> <f1076906-0347-405f-ba3d-dadf1e9a065e@googlegroups.com> |
On 5/11/2017 8:34 AM, Julian Fondren wrote:
> On Thursday, May 11, 2017 at 12:50:19 AM UTC-5, rickman wrote:
>> On 5/11/2017 12:12 AM, Julian Fondren wrote:
>>> On Wednesday, May 10, 2017 at 7:07:29 PM UTC-5, rickman wrote:
>>>> Here is my attempt. I had to work on this a bit as my string knowledge
>>>> is a bit rusty... no, positively seized up! I couldn't remember how to
>>>> create strings in the various modes.
>>>
>>> What do you mean by 'modes'?
>>
>> Compile, interpret. Seems interpretation is a tough mode to create
>> strings in unless I am totally misunderstanding what I've read in the
>> ANS standard.
>>
>
> Oh. It's not that bad: S" and C" come with permanent storage when
> compiled. When interpreted S" only comes with temporary storage, only
> two buffers guaranteed in the presence of the file wordset.
Ah, found it. In the core wordset S" is not defined for interpretation.
See? That's what I mean about it being complicated.
> So you create strings the same, you just have to think about where
> you're putting them, since it's no longer assumed that you want to
> hang onto them forever.
The details of the behavior wasn't my problem. My problem was figuring
out which of the many string words to use (some are only for printing,
some only for compiling...) I don't use Forth all the time and so
forget lots of the many details that are required.
> Forths often make it a little bit more convenient than that. Sometimes
> they make it so convenient that you want for a way to only have
> temporary strings again.
>
>>>> marker rotc
>>>>
>>>> : ScreenChar ( char -- char flag ) \ Check for alpha char
>>>> dup [char] A dup 26 + within if [char] A else
>>>> dup [char] a dup 26 + within if [char] a else
>>>> FALSE then then ;
>>>>
>>>> : RotChar ( char1 flag key -- char2 ) \ Rotate alpha char
>>>> -rot tuck - rot + 26 mod + ;
>>>
>>> The 'flag' has a more interesting type than the stack comment
>>> suggests. This is a good example of 'passing flags around' even so:
>>> you test the char in ScreenChar and then, instead of rotating it at
>>> once, you produce a value that's then tested again in RotCypher. Do
>>> you anticipate any other use for ScreenChar's output than later
>>> rotation?
>>
>> Look at the problem and figure out why I did it that way. There is a
>> specific reason which isn't all that hard to see. Maybe I missed
>> something that would make it simpler.
>
> I don't see it. If you think I didn't notice that the 'flag' is A|a|0
> and that you use that, yes I noticed that -- that doesn't explain why
> you don't immediately pass the 'flag' to RotChar in the A|a cases
> instead of testing it again.
I guess it seemed clearer to me originally that the third case was very
different. In the original code it did nothing since the encryption was
done in place. I was thinking the ScreenChar flow was three paths and
the following code was two paths, RotChar or not. The original code
used the KEY on the return stack which was not accessible inside
ScreenChar. Now that the Key is in a variable it's not a big deal to
call RotChar inside of ScreenChar. In fact I refactored the code and it
is a lot simpler with less on the stack. But it calls AlphaTest twice,
once for A-Z and again for a-z even if it was found in A-Z.
>> You've lost me. I don't write code thinking about optimizers or even
>> optimization in general. I try to write code to be easy to understand
>> and use. I can't remember the last time I wrote code that needed any
>> sort of optimization.
>
> : x [char] a [char] z 1+ within ;
> : y [char] a [ char z 1+ ] literal within ;
>
> The first is easier to follow than the second and it also has the
> overhead of an unnecessary 1+ every time it's run if you don't at
> least have a peephole optimizer. The second is not so hard to read
> that you'd worry about avoiding it though if you lacked an optimizer.
> Even in scripting languages people try to keep in mind the costs of
> different code and they tend to write code that's influenced by those
> expectations. It's not 'microoptimization' if you write the code the
> optimal way the first time you write it, right?
Uh, if it walks like a duck... If I am spending time at all thinking of
things like the above, they are optimizations. I'll let someone else
make the value judgements of "micro" or not. I'm more concerned with
*when* they are done. If they are done before I've found a need for
them they are 'pointless-optimizations', no?
> If you say you're above that -- then let's move on.
>
>> I have never gotten in a habit of locals. Why is that a significant
>> thing? I only did this when I totally forgot my forth and tried to
>> store it on the return stack inside the loop, lol, so I fixed it with a
>> value.
>
> Your code has the feature that someone can check and see what the
> last-used rotation key was. I was aware of that while reading your
> code and this awareness only distracted from the code because your
> actual intent was to use a local.
Ok, I understand. How about the new code. The key is stored at the
highest level and used at the lowest level of this code. Same argument
apply? I'd love to pass it into each of the words, but it is just in
the way as the stack is used resulting in much juggling if the key is
passed.
>> I started out writing this for modifications in place but decided to
>> change it. Instead of adding the index, I incremented the address. But
>> it was messy working with two addresses on the stack.
>
> OK. In general if you're having trouble with the stack you can back
> away from the immediate task and consider what factors would make life
> easier.
>
> : third ( a b c -- a b c a ) 2 pick ;
> : under+ ( a b c -- a+c b ) rot + swap ;
>
> ( destA srcA ) count third c! 1 under+
> \ copies a char from src to dest and increments both addresses
> \ you could use 2DUP 1 MOVE but you probably want to modify the char
>
> ( srcA destA ) over c@ over c! 1+ 1 under+
> \ same
>
> Two addresses isn't that bad. With the rotation key it gets more
> annoying, but you're already using a local for that.
>
> ( key srcA destA ) third third c@ rotate over c! 1+ 1 under+
>
> With ROTATE ( key c -- c' )
>
>> I understand why Hugh makes a big deal of the
>> lack of array handling in Forth and has a library.
>
> He makes too big of a deal about it. You can generally improve his
> code just by removing the crutch he's leaned it on.
>
>>> Not to propose those VALUEs , really, but just to say: *if* you're
>>> going to use a VALUE like this, there seems to be more use for source
>>> address in a VALUE than for the rotation 'key'.
>>
>> I'm not following this at all.
>
> : RotCypher ( caddr u key -- ) \ Output to tmpstr
> locals| rotkey |
> 0 do ( caddr -- )
> dup I + c@ ScreenChar dup if ( caddr char flag -- )
> rotkey RotChar else
> drop then ( caddr char -- )
> tmpstr I + c! ( caddr -- )
> loop
> drop ;
>
> vs.
>
> : RotChar ( key char1 flag -- char2 ) \ Rotate alpha char
> tuck - rot + 26 mod + ;
>
> : RotCypher ( caddr u key -- ) \ Output to tmpstr
> rot tmpstr locals| dest src |
> swap 0 do ( key -- )
> dup src I + c@ ScreenChar dup if
> RotChar else
> drop nip then
> dest I + c!
> loop
> drop ;
>
> It's just as easy, but if you use VALUEs instead of local variables
> then RotCypher's stack effect can become ( key u -- ) and you can set
> up the VALUEs before calling it.
Ok.
>>> Anyway, there's this alternative: loop over the addresses of the
>>> source string's characters. This means you have to manage the
>>> destination address differently. (And it's perfect for in-place
>>> mutation.) It also gets source string off the data stack, which may
>>> make the data stack easier to think about even if you end up
>>> maintaining the same depths through the loop.
>>>
>>> : RotCypher ( c-addr u key -- )
>>> tmpstr 2swap bounds ?do ( key tmpstr )
>>> i c@ ScreenChar dup if fourth RotChar else drop then
>>> over c! 1+
>>> loop 2drop ;
>>
>> Bounds?
>
> it's just OVER + SWAP ( c-addr1 u -- c-addr1+u c-addr )
>
> BOUNDS DO ( I is the address of each character of the string ) LOOP
>
>> It's late and I still need to pay my bills. I'll look at this again
>> tomorrow to see if I can figure out source and bounds.
>
> http://forth-standard.org/standard/core/SOURCE
>
> Modifying it is a hack of course.
Here is my latest version. Much simpler but still uses a value for
rotkey. I'm leaving it as a two buffer routine (although I could do
that with both addresses on the stack rather than one buffer implied) so
it will work with unalterable input buffers.
marker rotc
26 constant ModLength
0 value rotkey
create tmpstr 30 chars allot
: RotChar ( char1 flag -- char2 ) \ Rotate alpha char
tuck - rotkey + ModLength mod + ;
: AlphaTest ( char basechar -- char )
2dup dup ModLength + within if RotChar else drop then ;
\ Decrypt the Caesar cipher with key
: RotCypher ( caddr u -- ) \ Output to tmpstr
0 do
dup I + c@
[char] A AlphaTest
[char] a AlphaTest
tmpstr I + c!
loop
drop ;
: Encrypt ( caddr u key -- )
to rotkey RotCypher ;
: Decrypt ( caddr u key -- )
ModLength swap - to rotkey RotCypher ;
: "type" ( caddr u -- ) cr [char] " emit type [char] " emit .s ;
cr cr .( Start testing) .s
cr S" ABC mno 1, 2, 3" .s
2dup "type"
tuck 1 Encrypt tmpstr tuck over "type"
2dup 1 Decrypt "type"
--
Rick C
Back to comp.lang.forth | Previous | Next — Previous in thread | Find similar | Unroll thread
Rosetta: Caesar cipher "Robert L." <No_spamming@noWhere_7073.org> - 2017-05-09 20:47 +0000
Re: Rosetta: Caesar cipher Joel Rees <joel.rees@gmail.com> - 2017-05-09 20:20 -0700
Re: Rosetta: Caesar cipher hughaguilar96@gmail.com - 2017-05-12 13:52 -0700
Re: Rosetta: Caesar cipher rickman <gnuarm@gmail.com> - 2017-05-10 20:07 -0400
Re: Rosetta: Caesar cipher Julian Fondren <julian.fondren@gmail.com> - 2017-05-10 21:12 -0700
Re: Rosetta: Caesar cipher rickman <gnuarm@gmail.com> - 2017-05-11 01:50 -0400
Re: Rosetta: Caesar cipher Julian Fondren <julian.fondren@gmail.com> - 2017-05-11 05:34 -0700
Re: Rosetta: Caesar cipher Alex <alex@rivadpm.com> - 2017-05-11 14:39 +0100
Re: Rosetta: Caesar cipher anton@mips.complang.tuwien.ac.at (Anton Ertl) - 2017-05-11 16:04 +0000
Re: Rosetta: Caesar cipher Alex <alex@rivadpm.com> - 2017-05-11 21:35 +0100
Re: Rosetta: Caesar cipher mhx@iae.nl - 2017-05-11 10:21 -0700
Re: Rosetta: Caesar cipher rickman <gnuarm@gmail.com> - 2017-05-12 13:41 -0400
csiph-web