Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

HALT alternative

18 views
Skip to first unread message

Tito Nuno Santos

unread,
Dec 2, 1998, 3:00:00 AM12/2/98
to
Hi there !

I've made a program for the HP48 but I can't find an alternative to the HALT
command which interrupts the execution of a program. I would like to do the
same but with other command like END or STOP from Basic.

Thanks

Note: reply to my email adress.


----
Tito Nuno Alves Santos
titvsv...@mail.telepac.pt

John H Meyers

unread,
Dec 3, 1998, 3:00:00 AM12/3/98
to
In article <744fdu$rsc$1...@duke.telepac.pt>,

"Tito Nuno Santos" <titvsv...@mail.telepac.pt> writes:

> I've made a program for the HP48 but I can't find an alternative
> to the HALT command which interrupts the execution of a program.
> I would like to do the same but with other command
> like END or STOP from Basic.

If you mean that you would like a command to exit from anywhere in
the middle of a UserRPL program, without having to follow "structured
programming" requirements (where programs only exit at the very end):

Either a KILL or CONT command will terminate a UserRPL program;
however, this also terminates any higher-level program which might
have contained (or called) the program which issued KILL or CONT.

A slightly more elegant (and useful) solution is to store the
following program in HOME, perhaps in a variable called 'EXIT'

You can then use the EXIT command in your UserRPL programs, and
only the specific user program which calls EXIT will be terminated.

This program is listed in SysRPL, then a downloadable binary
is given in ASC format (see the FAQ or Goodies Disk #1
or TASC.EXE on Goodies Disk #8 for the use of ASC format).


* EXIT from the current enclosing *UserRPL* program
* (without terminating any "higher level" program)
* E.g. \<< 123 EXIT 999 \>> ==> 123
::
CK0NOLASTWD
BEGIN R> R> SWAP >R ( pop one stream )
DUP ' x>>ABND EQUALPOSCOMP #0=?SKIP ABND ( local variables ? )
* \<< ... \-> vars \<< ... EXIT ... \>> ... skips this also ... \>>
DUPLENCOMP NTHELCOMP ?SKIP FALSE ( last token in composite )
{ x>> AtUserStack } ( User program, or popped all the way to SOL ? )
SWAP EQUALPOSCOMP #0<> UNTIL
* Abort one more user level, in case DO, WHILE, START, FOR, etc.
* (which have copied their "containing" runstream via BEGIN)
R@ DUPLENCOMP NTHELCOMP ?SKIP FALSE ' x>> EQUAL IT RDROP
* More examples:
* \<< 1 100 START 123 EXIT ... NEXT \>> ==> 123
* \<< WHILE 1 REPEAT 123 EXIT ... END \>> ==> 123
* \<< 123 P2 456 \>>, P2: \<< 789 EXIT ... \>> ==> 123 789 456
* \<< \<< \<< 123 EXIT ... \>> EVAL ... \>> EVAL 456 \>> ==> 123 456
* \<< 0 \-> x \<< \<< \<< 123 EXIT ... \>> EVAL ... \>> EVAL 456 \>> \>>
;


* ASC format: 90 Bytes, #045Fh
"D9D2051A812A170F1070F107032230F9F608813079E60EF5323A446A33367947
0132366B650A21700CA3047A20936329CB04B2130322303A4467CC308C170210
70132366B650A21700CA3079E609363279B30CB9167BF60B2130F540"

Standard Disclaimer: Back up your memory before use.


"You asked for it -- you got it!"

-----------------------------------------------------------
With best wishes from: John H Meyers <jhme...@mum.edu>

John H Meyers

unread,
Dec 3, 1998, 3:00:00 AM12/3/98
to
In article <746ncm$686$1...@news.iastate.edu>:

[snipped]

There are still some neglected loopholes in my posted EXIT program,
such as failing to do ABND if a START or FOR loop was exited;
this has no severe consequences, but I will repost a new version
whenever I think I've caught up with all the loose ends, thanks.

Save five bytes by replacing R> R> SWAP >R with RSWAP R> ...

"No Exit" - Jean Paul Sartre

"You can't get there from here" - Farmer Brown

John H Meyers

unread,
Dec 8, 1998, 3:00:00 AM12/8/98
to
[replacement for previous incomplete quick hack]

We sometimes hear complaints that there is not an "exit" command
for HP48 programs, the way other calculators (based on Basic, say)
seem to have. Well, the lack of such a command is somewhat
inherent in the fundamental nature of the RPL operating system,
which has "unlimited" stacks for both data and programs,
and does not create any artificial boundaries between programs;
there is a complex built-in method for aborting "user" commands
so that whatever they have done to the stacks and environments
is "cleaned up" on exit, but this system is applied to every
individual user command that you can use in your programs,
and there is not a duplicate arrangement available
for you to use to abort complete user programs.

The reason that 'just exiting' a program is not a trivial action
is that every RPL looping structure and local variable structure
(and some other conditional tests and branching structures)
appends things to hidden internal stacks and linked environments;
these actions will not get properly "unwound" if the user program
does not 'reach the end' of each one of these structures
which it had begun; these 'left-over' unremoved objects
may in turn cause undesirable effects.

The UserRPL compiler and user command functions take care of all the
necessary 'messy details' for you, and guarantee infallibly correct
processing, whereas with the SysRPL compiler, the responsibility
for all this 'bookkeeping' is up to you; SysRPL gives you access
to much more freedom to just 'break out' of programs, but in
return, it lets you very easily crash or lose memory contents
if you fail to 'balance the books' properly on your own.

All the same, there still exist ways to 'exit' from user programs:

Either a KILL or a CONT command will terminate a UserRPL program;


however, this also terminates any higher-level program which might
have contained (or called) the program which issued KILL or CONT.

Issuing nnn DOERR will also terminate a program; unlike KILL
or CONT, however, the 'error' can be trapped at a higher level;
0 DOERR produces the same effect as the CANCEL key, with no message,
while error numbers such as 5, 6, 7 or 8 never occur in programs,
and may be used as special codes to be tested via
IFERR <lower level> THEN ERRN ...

A slightly simpler alternative is to store the following program


in HOME, perhaps in a variable called 'EXIT'

You may then use an EXIT command anywhere in your UserRPL program,
to terminate the innermost \<< ... \>> within which EXIT is called.

This is trivial for you to do, but note how non-trivial it is
for the EXIT program itself to manage to take care of this for you,
given all possible cases of structures which may need completion.

The unique clue which makes this function possible, but for
*UserRPL* programs only, is that user programs always have
the \<< and \>> delimiters surrounding them, so that we
can "back out" of however many "return stack" levels it takes
to find one which ends with a \>>, which is where we stop.

It is faster to skip over portions of programs using the
standard user 'structured programming' commands than to go through
this detailed loop; it could be done faster here, if we took
the trouble, but trouble is not my middle name, so I didn't :)

At any rate, this demonstrates once again that it is possible
to accomplish what one wants in the HP48, even if what one wants
has very good reason for not having been available in the first place.

Caution: You will be sure to back up memory before using this, right?


* EXIT from the current enclosing *UserRPL* program,
* which means to the nearest subsequent \>>
* without terminating any "higher level" program, e.g.

* \<< 123 EXIT 999 \>> ==> 123
* \<< 123 \<< 456 EXIT 888 \>> EVAL 789 \>> ==> 123 456 789


* \<< 1 100 START 123 EXIT ... NEXT \>> ==> 123
* \<< WHILE 1 REPEAT 123 EXIT ... END \>> ==> 123

* \<< 0 \-> x \<< 123 EXIT ... \>> 456 \>> ==> 123 456

ASSEMBLE
STOPLOOP = #07321 ( unsupported, appears stable )
RPL
::
AtUserStack
BEGIN RSWAP R> ( pop one return level )

* Look for any incomplete DO, WHILE, START, FOR, or \-> \<< ... \>>
* (note that there may be nested levels of these, in any combination)
DUPNULLCOMP? ?SKIP

:: ZEROSWAP toLEN_DO ( counter, seco )
DUPUNROT INDEX@ NTHCOMPDROP SWAP ( seco, token, counter )

( count structure beginnings )
{ xDO xWHILE xSTART xSTARTVAR RPN-> }
3PICK EQUALPOSCOMP #0=?SKIP #1+

( subtract structure endings )
{ xENDDO xWHILEEND xNEXT xSTEP x>>ABND }
3PICK EQUALPOSCOMP #0=?SKIP
:: DUP#0=ITE
:: ( found innermost pending unmatched structure ending )

DROPSWAP INDEX@ STOPLOOP 3RDROP ( token, seco, index )

( remainder of popped secondary, token )
#1+ MINUSONE SUBCOMP SWAP

{ xNEXT xSTEP x>>ABND } ( these need ABND )
OVER EQUALPOSCOMP #0=?SKIP ABND

' x>>ABND EQUALcase
:: 2RDROP COMPEVAL ; ( resume prog after x>>ABND )

( xENDDO xWHILEEND xNEXT xSTEP )
RSWAP RDROP ( drop original do/while/start/for loop )
>R RSWAP AGAIN ( process remainder of current secondary )

;
#1- ( skip structures with matching end tokens )
;
SWAPDROP SWAPLOOP SWAPDROP ( counter, current popped seco )
;

DUPLENCOMP NTHELCOMP ?SKIP FALSE ( last token in secondary )
{ x>> AtUserStack } ( User program, or back to system level? )
SWAP EQUALPOSCOMP #0<> UNTIL ( stop after user prog was popped )

;


* ASC format: 217.5 bytes, #27E4h (note the superfluous line)
"D9D209CB042A170DBE06F1070D1236A2170D9D20A3E26894360831612270C9B2
63223047A203C03233032301320A1321C432B2130EF1163A446A3336FED3047A
209B63249632C423208332EF532B2130EF1163A446A3336D9D205CE36D9D20C0
this line is inserted for posting, and should be removed
726122701237006116FED30E9056128503223047A20C423208332EF532B21302
C2303A446A33367947079E60EF532EFC36D9D20E4116ABE81B2130DBE067BF60
F9F60DBE06BA170B2130E0E30B2130B9F06D4436B9F06B2130132366B650A217
00CA3047A20936329CB04B2130322303A4467CC308C170B21304E72"


It would be possible to modify the above program to accept an argument,
specifying *how*many* program levels to "back out of," just as is
available in some systems (e.g. the Bourne shell in Unix, and its
compatible descendents); details are left as a rainy-day exercise
(you may use the fact that a user program contains no *system*
"..._DO" loops, so you can use one more at the outermost level,
but don't forget that this covers the return stack with
one additional level which "belongs" to this program).

ExitAtLoop ....... LOOP!

John H Meyers

unread,
Dec 9, 1998, 3:00:00 AM12/9/98
to
[sorry for canceling/reposting again, want to make it *clear* !!!]

This is the simplest scheme I could come up with for
allowing a UserRPL program to exit at any point it wants to,
while also allowing any higher-level programs to continue:


Store the following programs ( EXIT and RUN ) in HOME:

\<< "Exit" DOERR \>> 'EXIT' STO

\<< IFERR EVAL THEN ERRM "Exit" \=/ { ERRN DOERR } IFT END \>>

'RUN' STO


Sample programs:

@ This program will exit and display "Exit"
@ (if called by another program, it will *not* return):
\<< 123 EXIT 888 \>> 'Prg1' STO

@ Similarly, but no message will appear, and this program
@ *can* be called from other programs, *without* aborting:
\<< \<< 123 EXIT 888 \>> RUN \>> 'Prg2' STO

@ This program also continues running (no messages):
\<< 'Prg1' RUN \<< 456 EXIT 999 \>> RUN 789 \>>

'Prg3' STO @ Final output of Prg3 is 123 456 789

Note that the RUN command suppresses only the specific message
used by the EXIT command; all other error messages act normally,
canceling the running program unless trapped by your own IFERR

0 new messages