Post Reply 
HP 48GX Indefinite Loops
03-28-2022, 01:11 AM
Post: #1
HP 48GX Indefinite Loops
When using indefinite loops, is there a logical way to end the loop before it executes one more time? Take a WHILE loop for example. I have a string that contains two line feed characters. The third line has no line feed character because no line proceeds it. My test condition is the value of POS when searching for the position of a line feed character. While POS isn't zero the loop continues. My program fails because the loop executes one more time, and there's no starting position for the final SUB. Any thoughts?
Find all posts by this user
Quote this message in a reply
03-28-2022, 03:33 AM
Post: #2
RE: HP 48GX Indefinite Loops
What about a DO... UNTIL... END loop? It works like a WHILE loop but the loop ends when a condition is met.

DO
loop-clause
UNTIL
"string" "return character" POS 0 ==
END
Visit this user's website Find all posts by this user
Quote this message in a reply
03-28-2022, 04:11 AM
Post: #3
RE: HP 48GX Indefinite Loops
(03-28-2022 01:11 AM)MNH Wrote:  ...While POS isn't zero the loop continues. My program fails because the loop executes one more time, and there's no starting position for the final SUB. Any thoughts?

If you're using the WHILE-REPEAT-END construct, keep in mind that REPEAT will take the value it's checking from the stack. You'd almost certainly want to make a copy of that value before REPEAT is executed so that you can use it later as needed. The "execution clause" between REPEAT and END definitely won't be executed if there's a 0 in stack level 1 when REPEAT is executed. Any value other than 0 (including negative numbers) will cause the execution clause to execute.

Seeing your code in context along with sample input would be helpful to see what you're trying to do and perhaps why things aren't working as expected.
Find all posts by this user
Quote this message in a reply
03-28-2022, 06:13 PM
Post: #4
RE: HP 48GX Indefinite Loops
I've seen some inelegant tricks of throwing an error inside an IFERR structure to act as an ersatz BREAK statement, but this is a case where a proper GOTO or BREAK would be very useful.
Visit this user's website Find all posts by this user
Quote this message in a reply
03-28-2022, 07:13 PM
Post: #5
RE: HP 48GX Indefinite Loops
(03-28-2022 06:13 PM)Dave Britten Wrote:  I've seen some inelegant tricks of throwing an error inside an IFERR structure to act as an ersatz BREAK statement (…)

E.g. in this earlier thread: RPL equivalents to BREAK, CYCLE, EXIT, etc.?
Find all posts by this user
Quote this message in a reply
03-29-2022, 12:30 PM
Post: #6
RE: HP 48GX Indefinite Loops
I don't see a problem with just using the standard WHILE...REPEAT...END structure for something like this. The following will take a string with embedded linefeeds as input and return a list of the substrings delineated by those linefeeds. I'm sure this could be optimized more, but I just wanted to show a fairly straightforward approach.

Code:
\<<
   DEPTH 1 - \-> d            @ save current depth in d
   \<<
      WHILE                   @ check condition - position of linefeed
         DUP
         10 CHR POS
         DUP
      REPEAT                  @ execute if linefeed found:
         DUP2                 @ make a copy of string & pos
         1 SWAP OVER - SUB    @ SUB everything before the linefeed
         ROT ROT 1 + 1E8 SUB  @ SUB everything after linefeed
      END
      DROP                    @ DROP the 0 indicating no more linefeeds
      DEPTH d - \->LIST       @ result is all found substrings in a list
   \>>
\>>
Find all posts by this user
Quote this message in a reply
03-30-2022, 01:02 AM
Post: #7
RE: HP 48GX Indefinite Loops
I've used two methods for the 50g (depending on other items). One is the DO...WHILE..END pattern and the other is to use the FOR...NEXT and set the FOR statement's bound dummy outside the correct range to trigger a stop. Either works.

In a language I developed (along with another colleague), I used several types of loops. (It still didn't fix the common DO...UNTIL...UNLESS..IN WHICH CASE... method of thinking.

Just to make things complicated, any combination of conditions could be combined. Loops could be named and these names were part of the syntax. The basic syntax for a Fortran style loop (the 50g FOR is like Fortran 66 rather than like Fortran 77 and later) Some of these structures might be useful if anyone makes another calculator language.

Loops initiated by DO followed by any of several conditions

I:j:k:l (I is the bound variable and j, k, l as the beginning, end, and increment. Default start and increment were each 1 (though, like Fortran, any values could be used to match the ability to index with negative numbers).)

WHILE logical_value (evaluated before the loop executes.)

k TIMES (k is the number of times the loop executes_

k IN (ENUMERATED SET) (Goes through an enumerated set defined elsewhere)

(There may have been more, I don't remember.)

Loops did have two types of ending.

END_DO

UNTIL logical_value

One could write things like:

LOOP: DO WHILE x > .001 100000 TIMES

LOOP: UNTIL Y < .007

The point of putting labels first is for ease of reading; it's psychologically hard not to left-justify each loop.

The statements CYCLE and EXIT or CYCLE_IF and EXIT _IF allow for "emergency" exits.

Nested loops CYCLE or EXIT from the inside out or to the label with LABEL: EXIT or the like.

There were some other weird but useful things like a BLOCK and END_BLOCK statement which can have and EXIT or newly defined variables with scope within the block.

And while I'm rambling. The GOTO statement could only target numbered labels like GOTO 234
and the statement 234: CONTINUE as a target. The idea is that one could put these labels in numerical order for ease of reading. Numerical labels were "nonstructured" but alphanumeric labels were "structured" thought with lots of exits.

Lots of array stuff and other numerical stuff, including unlimited integers and reals (though the latters two were not guaranteed to be fast.)
Find all posts by this user
Quote this message in a reply
04-02-2022, 02:15 PM
Post: #8
RE: HP 48GX Indefinite Loops
(03-28-2022 03:33 AM)Eddie W. Shore Wrote:  What about a DO... UNTIL... END loop? It works like a WHILE loop but the loop ends when a condition is met.

Thanks for replying! I tried the following.

Program: CSV→
Checksum: # CAC6h
Bytes: 282.5
Purpose: Remove line feed characters from a string. Store
the resulting strings in a list.

\<< 1 CF CSV DUP SIZE
10 CHR { } 1 \→ csv
size char points
position
\<<
DO csv DUP DUP
char POS DUP DUP 0
==
\<< 1 SF
\>> IFT
'position' STO 2 -
1 SWAP SUB points
SWAP + 'points' STO
position 1 + size
SUB 'csv' STO
UNTIL 1 FS?
END points
\>>
\>>

@ Source: Notepad .csv file.
248,1529945.48000,521921.77300,100.60300,IRC 5/8 IL
249,1530002.95100,521922.24500,99.85000,AXLE
250,1530006.67800,521982.23700,102.17700,IRC 1/2 IL

@ Input: Load Object... to Emu48.
"248,1529945.48000,521921.77300,100.60300,IRC 5/8 IL ■
249,1530002.95100,521922.24500,99.85000,AXLE ■
250,1530006.67800,521982.23700,102.17700,IRC 1/2 IL"

@ First iteration: Substring stored in 'points.'
"248,1529945.48000,521921.77300,100.60300,IRC 5/8 IL"

@ First iteration: Remaining string stored in 'csv.'
"249,1530002.95100,521922.24500,99.85000,AXLE ■
250,1530006.67800,521982.23700,102.17700,IRC 1/2 IL"

@ Second iteration: Substring stored in 'points.'
"249,1530002.95100,521922.24500,99.85000,AXLE"

@ Second iteration: Remaining string stored in 'csv.'
"250,1530006.67800,521982.23700,102.17700,IRC 1/2 IL"

@ Third iteration: POS 0 ==, end WHILE loop

@ Output: Error!
@ Last string is empty.
{
"248,1529945.48000,521921.77300,100.60300,IRC 5/8 IL"
"249,1530002.95100,521922.24500,99.85000,AXLE"
"" }

@ Desired output.
{
"248,1529945.48000,521921.77300,100.60300,IRC 5/8 IL"
"249,1530002.95100,521922.24500,99.85000,AXLE"
"250,1530006.67800,521982.23700,102.17700,IRC 1/2 IL"
}
Find all posts by this user
Quote this message in a reply
04-03-2022, 01:59 AM (This post was last modified: 04-03-2022 02:16 AM by MNH.)
Post: #9
RE: HP 48GX Indefinite Loops
(03-29-2022 12:30 PM)DavidM Wrote:  I don't see a problem with just using the standard WHILE...REPEAT...END structure for something like this. The following will take a string with embedded linefeeds as input and return a list of the substrings delineated by those linefeeds. I'm sure this could be optimized more, but I just wanted to show a fairly straightforward approach.

Code:
\<<
   DEPTH 1 - \-> d            @ save current depth in d
   \<<
      WHILE                   @ check condition - position of linefeed
         DUP
         10 CHR POS
         DUP
      REPEAT                  @ execute if linefeed found:
         DUP2                 @ make a copy of string & pos
         1 SWAP OVER - SUB    @ SUB everything before the linefeed
         ROT ROT 1 + 1E8 SUB  @ SUB everything after linefeed
      END
      DROP                    @ DROP the 0 indicating no more linefeeds
      DEPTH d - \->LIST       @ result is all found substrings in a list
   \>>
\>>

Thanks for your effort! I ran your code and didn't get the expected results.

Input:

1: CSV @ .txt file (comma-separated values)

Output:

4: "248,1529945.48000...
3: 0.0000
2: '→d'
1: << WHILE DUP 10.000...

I had trouble debugging your code as evidenced by stack level one above. My second attempt at writing a solution appears below.

Program: CSV→
Checksum: # 3AFBh
Bytes: 305.0
Purpose: Remove line feed characters from a string. Store
the resulting strings in a list.

\<< 1 CF CSV DUP SIZE
10 CHR { } 1 \→ csv
size char points
position
\<<
DO csv DUP DUP
char POS DUP DUP 0

\<< 'position'
STO 2 - 1 SWAP SUB
'points' STO
position 1 + size
SUB 'csv' STO
\>>
\<< 1 SF 3
DROPN points SWAP +
\>> IFTE
UNTIL 1 FS?
END
\>>
\>>

Although the desired output has been attained, the DO...UNTIL...END
structure still repeats one more time after the test condition returns a
true (nonzero) result. I have to clean up the stack, which I shouldn't have
to do if the program worked as expected. Any thoughts?
Find all posts by this user
Quote this message in a reply
04-03-2022, 02:39 AM
Post: #10
RE: HP 48GX Indefinite Loops
(03-29-2022 12:30 PM)DavidM Wrote:  I'm sure this could be optimized more (…)

Mostly copied but using local variables str and pos:
Code:
\<<
   { } SWAP
   WHILE                      @ check condition - position of linefeed
      DUP
      10 CHR POS
      DUP
   REPEAT \-> str pos         @ execute if linefeed found:
      \<<
         str 1 pos 1 - SUB +  @ SUB everything before the linefeed
         str pos 1 + 1E8 SUB  @ SUB everything after linefeed
      \>>
   END
   DROP                       @ DROP the 0 indicating no more linefeeds
   +
\>>

I try to avoid modifying local variables using STO.
Find all posts by this user
Quote this message in a reply
04-03-2022, 03:09 AM
Post: #11
RE: HP 48GX Indefinite Loops
(04-03-2022 01:59 AM)MNH Wrote:  2: '→d'

This looks like a typo. Make sure to use:
Code:
→ d
Find all posts by this user
Quote this message in a reply
04-03-2022, 10:58 AM
Post: #12
RE: HP 48GX Indefinite Loops
(04-03-2022 01:59 AM)MNH Wrote:  Thanks for your effort! I ran your code and didn't get the expected results.

As Thomas has indicated, there's very likely at least one typo in your transcription. In particular, there should be a space between the "→" and the "d". I should have included the size/checksum for verification so that you'd be able to compare it. I'll include that now:

Size: 115 bytes
Checksum: #1A7Bh

You can avoid typos for something like this if you use a program that can translate a string using "trigraphs" into a compiled program. That way you can just copy and paste the program straight from the post into your emulated 48GX, translate it, and then store the result into a global variable of your choosing. No typing of the program required!

One such program can be found in this post (usually referred to as INOUT). That program also converts a compiled program object that's on the stack into a string, with all special characters replaced by their trigraph equivalents. You can think of it as toggling what's in stack level 1 between text and compiled program forms.

That should allow you to get the program entered into your emulated 48GX successfully for testing.
Find all posts by this user
Quote this message in a reply
04-03-2022, 11:39 AM
Post: #13
RE: HP 48GX Indefinite Loops
(04-03-2022 01:59 AM)MNH Wrote:  \<< 1 CF CSV DUP SIZE
10 CHR { } 1 \→ csv
...
\>>

Although the desired output has been attained, the DO...UNTIL...END
structure still repeats one more time after the test condition returns a
true (nonzero) result. I have to clean up the stack, which I shouldn't have
to do if the program worked as expected. Any thoughts?

Hmmm.... several thoughts.

See the above post about INOUT, which would make it easier for others to be able to test the code. Also, placing the code into a code block (see the "#" button above the text when typing a post/response) would at least preserve the original ascii text along with the intended indentation. It also makes it a little easier to copy and paste (IMHO).

I loaded your program into an emulated 48GX for testing and stepped through the flow with SST. If I'm understanding things correctly, you're wanting the 'points' local to have a list with each line in it. That local is only a list for a very short time, however, namely when it is first created as an empty list with the local assignment operator (→). Your code replaces that list with a string assignment in the THEN clause by using STO instead of STO+. Also, if you want the strings to be in the same order they are encountered in CSV, then you'll want to swap the new string and 'points' prior to STO+ being executed.

In its current form, your program simply concatenates the previous string with the final string and leaves it on the stack. I don't believe that's what you intended, but I could be confused about exactly what your code is trying to achieve.

Stepping through the code, the main loop is terminated correctly if flag 1 is set. Have you tried single-stepping through the code to see what it is doing?

In summary:

If I change this
Code:
'points' STO
into
Code:
'points' SWAP STO+
...then it appears to leave the list of strings on the stack that you wanted. If that's not what you intended, please provide further clarification.

Hope this helps!
Find all posts by this user
Quote this message in a reply
04-03-2022, 12:57 PM
Post: #14
RE: HP 48GX Indefinite Loops
(04-03-2022 03:09 AM)Thomas Klemm Wrote:  
(04-03-2022 01:59 AM)MNH Wrote:  2: '→d'

This looks like a typo. Make sure to use:
Code:
→ d

You are correct, sir!
Find all posts by this user
Quote this message in a reply
04-03-2022, 02:31 PM
Post: #15
RE: HP 48GX Indefinite Loops
(04-03-2022 11:39 AM)DavidM Wrote:  Also, placing the code into a code block (see the "#" button above the text when typing a post/response) would at least preserve the original ascii text along with the intended indentation. It also makes it a little easier to copy and paste (IMHO).

Cf. How to Indent in MoHPC Forum
Find all posts by this user
Quote this message in a reply
04-03-2022, 04:25 PM
Post: #16
RE: HP 48GX Indefinite Loops
(04-03-2022 02:31 PM)Thomas Klemm Wrote:  
(04-03-2022 11:39 AM)DavidM Wrote:  Also, placing the code into a code block (see the "#" button above the text when typing a post/response) would at least preserve the original ascii text along with the intended indentation. It also makes it a little easier to copy and paste (IMHO).

Cf. How to Indent in MoHPC Forum

Wow! My first post!
Find all posts by this user
Quote this message in a reply
04-03-2022, 05:39 PM (This post was last modified: 04-03-2022 05:52 PM by MNH.)
Post: #17
RE: HP 48GX Indefinite Loops
(04-03-2022 11:39 AM)DavidM Wrote:  In summary:

If I change this
Code:
'points' STO
into
Code:
'points' SWAP STO+
...then it appears to leave the list of strings on the stack that you wanted. If that's not what you intended, please provide further clarification.

Hope this helps!

All of the information you provided helps. Thanks! I need some time to go over everything. I need to improve my programming skills. The use of 1E8 in your program is interesting. I'll be using my text file line feed character removal program to transfer files between my Emu48 and a tablet computer I use at work. The surveying software on the tablet is not very easy to use in some instances, so I'm trying to make my life easier by writing my own. Will I need a program to append line feed characters to a list of strings in order to send data to the tablet? I bought a thumb drive adapter for my Samsung phone for all of this.
Find all posts by this user
Quote this message in a reply
Post Reply 




User(s) browsing this thread: 1 Guest(s)