The Museum of HP Calculators

HP Forum Archive 20

[ Return to Index | Top of Index ]

Better Late Than Never--VAL() in HP-71B BASIC
Message #1 Posted by Namir on 6 May 2011, 11:15 a.m.

I was looking at the HP-71B Math Solutions book. I discovered, to my surprise and delight, that the HP-71B function VAL goes way beyond the typical VAL implementations found in other BASIC interpreters. The HP-71B runs the argument of VAL through the BASIC interpreter engine allow you to evaluate strings as functions. For example, if I have already assigned the value of 1 to variable X, then VAL("X^2-3*x+6") yields 4!! Using this feature you can define the function:

DEF FNX(E$,X) = VAL(E$)

To evaluate functions dynamically as long as the expression in parameter E$ is a string that represents a valid expression of X. Of course the arguments for parameter X in FNX() can be any variable or expression, since VAL(E$) evaluates E$ using the argument for parameter X (and not a variable named X defined in the program).

I was delighted to discover this feature of VAL() .... Oh well .... better late than never!!

Namir

      
Re: Better Late Than Never--VAL() in HP-71B BASIC
Message #2 Posted by Marcus von Cube, Germany on 6 May 2011, 11:56 a.m.,
in response to message #1 by Namir

For those who want more info about the different BASIC variants: I've prepared a spreadsheet which compares many BASIC dialects. The VAL() functionality Namir has found should be in the sheet as the 71B is one of the systems discussed.

Here you are: http://www.mvcsys.de/doc/basic_compare.html.

            
Re: Better Late Than Never--VAL() in HP-71B BASIC
Message #3 Posted by Namir on 6 May 2011, 12:13 p.m.,
in response to message #2 by Marcus von Cube, Germany

Impressive comparison table!!!

As I suspected, the HP-71B and HP-75 implement the VAL() function that goes beyond simply converting a string image of a number into a number.

Using a function like VAL() (and EVAULATE() in Excel VBA) allows you to write programs that handle functions dynamically. Of course, the price to pay for this flexibility is speed.

Namir

Edited: 6 May 2011, 12:20 p.m.

                  
Re: Better Late Than Never--VAL() in HP-71B BASIC
Message #4 Posted by Bill Wiese on 6 May 2011, 2:20 p.m.,
in response to message #3 by Namir

This was always an irritant to me in other BASICs of the era - most if not all of those MS BASICs (Commodore, Apple, etc.) just implemented an "atof()" function.

I recall I was able to take C64 BASIC's "USR(x)" function and hotwire it to pull a string instead of numeric argument - and then call the FRMEVL routine at $AD9E to do 'formula evaluation'. I think I had to also tokenize the string before calling FRMEVL.

Bill Wiese
San Jose CA

Edited: 6 May 2011, 2:20 p.m.

                        
Re: Better Late Than Never--VAL() in HP-71B BASIC
Message #5 Posted by Mark Storkamp on 6 May 2011, 2:30 p.m.,
in response to message #4 by Bill Wiese

You could do something similar as well on the Apple ][. Another form of synthetic programming. Your program always started at the same location in memory, so if you made your first line:

10 ::::::::::::::::::::::::::::::::: RETURN

Then you could use POKE to enter your tokenized string in place of the :

CALL 10

would execute your line. And the manuals in those days were so thorough that they gave you all of the addresses and token values needed to pull off things like that.

                        
Re: Better Late Than Never--VAL() in HP-71B BASIC
Message #6 Posted by Namir on 6 May 2011, 2:52 p.m.,
in response to message #4 by Bill Wiese

While GW-BASIC implemented a simple VAL() function, I resorted to another trick to support dynamic functions at run time. I used this kind of trick in regression programs that allowed the user to enter transformations for data at run time. My program would convert the user's input into a short/small line-numbered BASIC program that's written out to disk and then use the CHAIN MERGE command to chain/merge the current program with that small programs. This approach turned the dynamic functions and expressions into BASIC statements that are then handled by the interpreter.

When I moved from GW-BASIC to Turbo-Pascal (a compiler) I sure missed that trick!

Namir

Edited: 6 May 2011, 2:53 p.m.

                              
Re: Better Late Than Never--VAL() in HP-71B BASIC
Message #7 Posted by Eric Smith on 6 May 2011, 4:05 p.m.,
in response to message #6 by Namir

Nowdays in C++, one can use LLVM to generate object code on the fly. It doesn't parse expressions from a human-readable string representation, though.

                              
Re: Better Late Than Never--VAL() in HP-71B BASIC
Message #8 Posted by Oliver Unter Ecker on 6 May 2011, 4:32 p.m.,
in response to message #6 by Namir

How does Val() deal with "2^8" (two power eight), or "5!" (five factorial)? ;-)

As other dynamic languages these days, JavaScript has an eval() function that allows you not only to evaluate constant expressions, but any JavaScript code. Also, functions are data and can be constructed on-the-fly.

If you want to write a calculator, though, you still need an expression parser to deal with cases like above (and types other than Reals).

One of the reasons why MorphEngine is called MorphEngine, is because it takes expressions and "morphs" them into dynamically-created functions (written via a LALR parser, fed by a BNR grammar).

I understand, (RPL) HPs have a compiler/decompiler to accomplish making expressions executable, and vice versa.

                                    
Re: Better Late Than Never--VAL() in HP-71B BASIC
Message #9 Posted by Marcus von Cube, Germany on 6 May 2011, 4:39 p.m.,
in response to message #8 by Oliver Unter Ecker

As implemented on the 71b, VAL() parses the string as BASIC text, so any functions known to the interpreter can be used. The string must represent a valid expression as defined for the language.

                                          
Re: Better Late Than Never--VAL() in HP-71B BASIC
Message #10 Posted by Paul Guertin on 7 May 2011, 1:01 a.m.,
in response to message #9 by Marcus von Cube, Germany

Quote:
As implemented on the 71b, VAL() parses the string as BASIC text, so any functions known to the interpreter can be used. The string must represent a valid expression as defined for the language.

What happens when you call VAL(E$) and E$ contains the string "VAL(E$)"?

                                                
Re: Better Late Than Never--VAL() in HP-71B BASIC
Message #11 Posted by Namir on 7 May 2011, 3:24 a.m.,
in response to message #10 by Paul Guertin

You get an "Invalid Arg" error.

                                                      
Re: Better Late Than Never--VAL() in HP-71B BASIC
Message #12 Posted by J-F Garnier on 7 May 2011, 4:01 a.m.,
in response to message #11 by Namir

No, the HP71B goes into infinite recursive calls!!

>endall
>destroyall
>mem
 9135
>e$="val(e$)"
>val(e$)
ERR:Insufficient Memory
>mem
 2810
>endall
>mem
 9128

(tested on Emu71. On a real HP-71B, you may have to break the long recursion time with INIT 1]

J-F

                                                            
Re: Better Late Than Never--VAL() in HP-71B BASIC
Message #13 Posted by Namir on 7 May 2011, 6:48 a.m.,
in response to message #12 by J-F Garnier

Interesting! The first time I tried:

E$="VAL(E$)"
VAL(E$)

I got the invalid arg error using the EMU71. When I do:

ENDALL
DESTROY ALL
E$="VAL(E$)"
VAL(E$)

I get "insufficient memory" with the EMU71.

Namir

Edited: 7 May 2011, 6:49 a.m.

                                                            
EMU71 for 64 Bit Windows?
Message #14 Posted by Namir on 7 May 2011, 6:53 a.m.,
in response to message #12 by J-F Garnier

Do you have any plans to re-implement the EMU71 so that it can run under Windows 7 64 Bit? To run the EMU71 I have to run "VMLite XP Mode" which runs as 32 Bit OS.

Namir

Edited: 7 May 2011, 6:53 a.m.

                                                                  
Re: EMU71 for 64 Bit Windows?
Message #15 Posted by Marcus von Cube, Germany on 7 May 2011, 7:07 a.m.,
in response to message #14 by Namir

As far as I understand, EMU71 is written in x86 16 Bit assembly. Porting will be a huge task!

Have you tried DOSBOX or, as an alternative, plain DOS in any virtual machine like Virtual PC?

Edited: 7 May 2011, 7:08 a.m.

                                                                        
Re: EMU71 for 64 Bit Windows?
Message #16 Posted by Namir on 7 May 2011, 1:18 p.m.,
in response to message #15 by Marcus von Cube, Germany

I am using the regular DOS box in VMlite Windows XP.

I will try to locate DOSBOX. Thanks for the tip.

                                                                        
Re: EMU71 for 64 Bit Windows?
Message #17 Posted by Namir on 7 May 2011, 1:42 p.m.,
in response to message #15 by Marcus von Cube, Germany

Marcus,

I found DOSBOX and it works fine with EMU71. The only feature not supported from the plain DOS box is the ability to pasted source code into the emulator (J-F Garnier had suggested this tip on the site a few months ago). Garnier's tip works when I use the DOS box under VMlite Windows XP.

Namir

Edited: 7 May 2011, 2:02 p.m.

                              
OT: Re: Better Late Than Never--VAL() in HP-71B BASIC
Message #18 Posted by Katie Wasserman on 6 May 2011, 6:35 p.m.,
in response to message #6 by Namir

On my Commodore PET (8K original one) I used to do something similar. You could print an expression (or statement) on the screen followed by a RUN or GOTO command; then stuff the keystroke buffer with cursor moments and RETURN characters and end the program. The keystroke buffer would be read out by the "operating system" and execute your commands then start up the program again.

It, made for great self modifying code not just dynamic expression evaluation.

-Katie

                                    
Re: OT: Re: Better Late Than Never--VAL() in HP-71B BASIC
Message #19 Posted by Namir on 6 May 2011, 6:46 p.m.,
in response to message #18 by Katie Wasserman

That cool ... sounds similar to using CHAIN MERGE in GW-BASIC.

I doubled checked the HP-85 owner's manual to see how the VAL() function works. I was hoping that it matched the VAL() function in the HP-71B. My hopes were dashed :-(

Namir

Edited: 6 May 2011, 6:47 p.m.

      
Re: Better Late Than Never--VAL() in HP-71B BASIC
Message #20 Posted by Thomas Radtke on 7 May 2011, 3:34 a.m.,
in response to message #1 by Namir

Quote:
I discovered, to my surprise and delight, that the HP-71B function VAL goes way beyond the typical VAL implementations found in other BASIC interpreters. The HP-71B runs the argument of VAL through the BASIC interpreter engine allow you to evaluate strings as functions. For example, if I have already assigned the value of 1 to variable X, then VAL("X^2-3*x+6") yields 4!!
The Sinclair ZX Spectrum had this feature, too.

BTW, I'm using a similar function in php to have the user define some conditions inside a semiautomatic risk analysis software. Very useful.

            
Re: Better Late Than Never--VAL() in HP-71B BASIC
Message #21 Posted by Howard Owen on 7 May 2011, 2:26 p.m.,
in response to message #20 by Thomas Radtke

I have been playing with Rocky Mountain BASIC again the last couple of days. At least in version 2.1, there's no string evaluation routine. At least I can't find it in the reference manual. It seems like the people in Fort Collins could have taken a hint from the guys in Corvallis in this regard.

You can do recursion in RMB though.

                  
Re: Better Late Than Never--VAL() in HP-71B BASIC
Message #22 Posted by Garth Wilson on 7 May 2011, 8:51 p.m.,
in response to message #21 by Howard Owen

You can say that again! After having been quite familiar with my 71's BASIC (along with a lot of extensions from the user groups), I started working with HP Rocky Mountain BASIC 5.1 and was extremely disappointed. The HP-71 was far better.

                        
Re: Better Late Than Never--VAL() in HP-71B BASIC
Message #23 Posted by Katie Wasserman on 7 May 2011, 9:38 p.m.,
in response to message #22 by Garth Wilson

I think that the finest version of Basic that HP ever created was Business BASIC for the HP 3000 series computers. The statement called COMMAND could dynamically execute almost any command in Basic, not just evaluate an expression. It was also pretty fast because it had a compiler in addition to the interpreter. I wrote a ton of code in this language including a complete email system (before the internet was common place). One of my favorite languages, ever.

The original 3000 series was equally awesome with it's stack-based architecture and (sort of) high-level systems programming language instead of assembly. The good old days.......

                        
Re: Better Late Than Never--VAL() in HP-71B BASIC
Message #24 Posted by Howard Owen on 8 May 2011, 1:21 a.m.,
in response to message #22 by Garth Wilson

There are things in RMB that the 71B lacks, however. Long variable names, COM blocks (ala FORTRAN) , REPEAT/UNTIL, WHILE, SELECT/CASE are all nice. The integrated code editor/execution environment was my first introduction to such things. It topped my list for productivity until I figured out how to use EMACS with gcc/gdb a couple of years later.

I used the 9816 professionally, and it was a capable little beast for the era. It had an 8Mhz MC68000, which was fast enough to do a whole lot of simultaneous I/O. That CPU had 16MB of addressable memory. I believe the 9816 could only use half that for user memory, but it was still huge by contemporary standards. It was actually practical to have 1MB loaded into the 9816, plus an RS232 card, which together with HPIB made for an extremely capable and portable little computing package. I used these in offshore environments in the mid-1980s.

Nonetheless, I'm very fond of my 71B. The BASIC on that machine has a lot of very nice features. The LEX file concept is very cool, allowing a user to extend the BASIC, but RMB had a similar mechanism.

                              
Re: Better Late Than Never--VAL() in HP-71B BASIC
Message #25 Posted by Garth Wilson on 8 May 2011, 3:45 a.m.,
in response to message #24 by Howard Owen

One of the 71 modules available had the program structures like CASE and so on, but I never got that one. For longer variable names and vertical alignment and white space for readability and so on, what I did sometimes was write the program in text with my full-featured text editor (waaaaay better than what came in the Forth module for example) and then use another program to take out the blank lines and formatting lines, combine things that had to be on the same line which I had separated for readability, give it line numbers, replace the variable names with HP71-legal ones, remove comments, and TRANSFORM it to BASIC (while keeping a copy of the original file).

One thing I remember from RMB 5.1 running on the HP9000-series 68000 computer was that I couldn't just take lines I had already written and copy them somewhere else outside the structure or subprogram or something like that to reduce the amount of typing where I wanted a near-duplicate somewhere else. It would say that wasn't allowed. One program could not also refer to another program or subprogram in another file like the 71 can. It all had to be written into the same one. My memory of it is pretty foggy now, but I do remember that I kept running up against walls.

Edited: 8 May 2011, 3:47 a.m.

                                    
Re: Better Late Than Never--VAL() in HP-71B BASIC
Message #26 Posted by Howard Owen on 8 May 2011, 11:50 a.m.,
in response to message #25 by Garth Wilson

Quote:
One of the 71 modules available had the program structures like CASE and so on ..

The JPCROM has that and more. I have that in EEPROM on m 71, and I love it.

I've set myself up to do editing of 71B programs on my Mac (in Aquamacs. Some habits die hard.) using the PIL-Box to transfer the programs back and forth as text. That's fine as far as it goes, but it doesn't get me an editing/execution environment like RMB's EDIT mode. The 71B itself provides a pretty nifty editor, but it's limited by the one line display.

Quote:
One thing I remember from RMB 5.1 running on the HP9000-series 68000 computer was that I couldn't just take lines I had already written and copy them somewhere else outside the structure or subprogram or something like that to reduce the amount of typing where I wanted a near-duplicate somewhere else.

You can do that with individual lines, by manually editing the line number, for example. But you can't delete or modify the FN or SUB definition or end markers once you've entered them. You have to delete the "entire context" meaning the whole sub or function. Also, you can't use REN to move lines relative to other lines. So if your renumber would cause the new lines to overlap other lines, or to move after or before preexisting lines, the renumber will fail.

That's annoying, but I have to say, quirks like that are one of the reasons I feel good about getting anything done on any of these old machines. :)

Regards,
Howard


[ Return to Index | Top of Index ]

Go back to the main exhibit hall