More Fun WIth HP35 Programming Message #30 Posted by Howard Owen on 21 July 2007, 1:36 a.m., in response to message #1 by Gene Wright
OK, so now I want the input routine to either prompt as before, or else decompose a number in the form:
ABCDEFGHIJKL
Where the letters are the decimal digits of an IP address. For example, 192.160.20.1 would be encoded as 192168020001. This is a form I plan to use for manipulating addresses in various ways. I need a way to "explode" such a number into its octets. (I already have the routine to compose a number like that from its octets, the second one above.)
I'll use flag 0 to decide which mode to use on input. Flag 0 set will mean do the non-prompting routine. Conversely, flag 0 clear will do the original prompting method. I will make heavy use of ALG mode shortcuts in the new code, just to see if I can reach their limits. (Sneak peek: I can.)
To decompose a 10 to 12 digit number into "trigraphs" representing octets, I need to divide the whole number by a divisor that will leave the digits of interest lying just to the right of the decimal place. I will then take the fractional portion (FP), multiply the result by 1000, and take the integer portion. Hey presto! The octet is then left standing on its own. (This technique is surely not original, though I developed it independently. I have no idea who is responsible for the first use, or I'd give them credit here.)
So that means I need to compute the proper divisor to get the octet I'm interested down to the right of the decimal. What I have on hand is the loop counter in I. In the loop, which skips the first octet, since that is a special case, The loop counter's integer portion varies from B+1 to B+3, where B is the base register number passed in. What I need to start is the loop counter integer portion minus the base register value. The following ALG code gets me that:
IP(I)-B
Assuming the base is stored in B.
That gives me the following mapping of loop counters to three digit groups of interest:
000 000 000 000
1 2 3
And what I need is a series of divisors, 1E9, 1E6 and 1E3. this equation gets me that:
ALOG(3+(3-N)*3)
Where ALOG() is what you get when you press 10^X in equation mode, and N is the loop counter normalized into the range 1..3.
Finally, I will implement the algorithm given above to isolate the octet of interest:
IP(FP(A/D)*1E3
Where A is the IP address and D is divisor computed in the last step.
Now, what about ALG mode limits? Well, the preceding expressions could be combined (if I'm not mistaken, and heaven knows I might be,) into this:
IP(FP(A/10^(3+(4-IP(I)+B)*3))*1E3)
What a mess! What does it do? Are the parentheses balanced correctly? RPN is much simpler. I might have errors in that expression, but since I'm not actually using it, I refuse to debug it! I'll implement the algorithm in its broken up form to save my sanity in working with the code later.
One last word before the code: I discovered (or rediscovered, actually,) the weaknesses in an auto-renumbering system that relies on the numbers as branch targets. Consider this code:
A001 FS? 0
A002 GTO A005
A003 SOMETHING OR OTHER (EQUATION)
A004 GTO A007
A005 ISG A
A006 GTO A005
A007 DEG
This is a two way branch skeleton waiting for the code to be filled in. I have a loop set up to go on line A005. But now I realize I need some set up before the loop, so I enter it. This is the result:
A001 FS? 0
A002 GTO A006
A003 SOMETHING OR OTHER (EQUATION)
A004 GTO A008
A005 STO A
A006 ISG A
A007 GTO A006
A008 DEG
Do you see the problem? Two out of three GTO lines renumbered as I expected. However the first one, on line A002, followed the ISG A command to line A006. I'll have to manually correct that one or leave a perhaps subtle bug in the code.
Now, the revised subroutine:
Subroutine to store the octets of an input IP Address
Copyright (C) 2007 Howard Owen
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Input an IP address in one of two forms, and place its separated
octets in four contiguous registers starting at the base register in
X. If flag 0 is clear, prompt for each successive octet before
storing it. If flag 0 is set, decompose the 10-12 digit integer
passed in Y into its constituent octets. Store these in the same way
as the flag 0 clear code does.
The address in Y is formatted as follows. If the octets are labeled
from left to right as 1, 2, 3 and 4, then the packed decimal IP
address is: 111222333444. For example, '192.168.20.1' would be
encoded as '192168020001'.
I001 LBL I
I002 DEC Ensure decimal entry
I003 FS? 0 Set = don't prompt. IP address is in Y
I004 GTO I009
I005 SF 10 Inhibit evaluation of the "equation"
I006 ENTER OCTET RS 4 TIMES Long, hey?
I007 CF 10 1st octet entered is now in X, base in Y
I008 GTO I014
I009 STO B Non-prompting needs base (in X) and address (in y) saved. Base register
I010 x<>y
I011 STO A IP address encoded as a 10-12 digit decimal integer
I012 RDN Base back in X
I013 IP(A/1E9) Leftmost (first) octet in X, base in Y
I014 (REGY+3)/1E3+REGY Back together. Compute loop control number
I015 STO I Loop counter and address pointer
I016 x<>y Get the first octet back in X
I017 STO(I) STOre it in the base register
I018 ISG I Second register is next
I019 DEG No-op. Thanks Gene. 8)
I020 FS? 0 Loop entry point Non prompt?
I021 GTO I026
I022 SF 10 Do octet-at-a-time prompting
I023 NEXT OCTET Not so long.
I024 CF 10 Octet is now in X
I025 GTO I029
I026 IP(I)-B Loop counter normalized to the range 1..3
I027 ALOG(3+(3-REGX)*3) Divisor to bring the current octet just to the right of the decimal
I028 IP(FP(A/REGX)*1E3) The octet, masked out from the IP address
I029 STO(I) Back to common code. Store the octet in the next register
I030 ISG I
I031 GTO I020 NOT My first line addressed GTO in 20 years.
I032 RTN Done
|