Post Reply 
Python to RPN converter
11-04-2018, 06:06 AM
Post: #41
RE: Python to RPN converter
(11-03-2018 07:32 PM)Namir Wrote:  How can I write Python code that translates into:

"Prompt message"
PROMPT
STO <reg>

myvar = PROMPT("Prompt message")

You cannot strictly speaking store into a specific register, because from the Python point of view registers don't exist. You just have to think in Python and stick to Python variables - and treat the generated RPN as "machine code" ;-) Thus:

Code:
myvar = PROMPT("length?")
print("sine of", myvar, "is", SIN(myvar))

You can however store into a HP42S named variable - they are ok to specify. Check out the the "Prompting for input" section in the online examples help.
Find all posts by this user
Quote this message in a reply
11-04-2018, 02:02 PM
Post: #42
RE: Python to RPN converter
Can't you access registers like REGS[index]?
You could also implement a special case for REGS, so that REGS[0] can be translated directly to RCL 00 or STO 00, avoiding the use of STOIJ and RCLEL/STOEL.
Visit this user's website Find all posts by this user
Quote this message in a reply
11-04-2018, 08:07 PM
Post: #43
RE: Python to RPN converter
In displaying the contents of the Alpha register (translated from a Python print statement), would it be better to generate PROMPT statements instead of AVIEW?

Namir
Find all posts by this user
Quote this message in a reply
11-04-2018, 09:59 PM
Post: #44
RE: Python to RPN converter
(11-04-2018 08:07 PM)Namir Wrote:  In displaying the contents of the Alpha register (translated from a Python print statement), would it be better to generate PROMPT statements instead of AVIEW?

Namir

You are correct that print() is a synonym for AVIEW(). In Python print doesn't stop program execution so I wanted to keep that behaviour. If you want to stop program execution so that the user can take a good look at something, then simply use PROMPT(msg) and don't worry about assigning the return value of PROMPT to a variable.

Keep in mind that in the converter, print/AVIEW, PROMPT, PRA and alpha all:
  • take arbitrarily long strings
  • accept multiple parameters e.g. alpha("Ans: n=", n, "result is", myvar)
  • support the Python keyword parameters append= and sep=
For more information see the help page section entitled "Text and the Alpha register".

-Andy
Find all posts by this user
Quote this message in a reply
11-04-2018, 10:25 PM
Post: #45
RE: Python to RPN converter
(11-04-2018 02:02 PM)Thomas Okken Wrote:  Can't you access registers like REGS[index]?
You could also implement a special case for REGS, so that REGS[0] can be translated directly to RCL 00 or STO 00, avoiding the use of STOIJ and RCLEL/STOEL.

I suppose I could open up access to the registers in the way you suggest. Keep in mind however that by default, numbered registers are used to store Python variables, so registers are being pretty much being overwritten all the time and thus don't have much value.

Specifically, all lowercase python variables are mapped to RPN registers in the order that the converter parser sees them. Thus a = 10 and b = 20 will be mapped to registers 00 and 01 respectively.

The Python to RPN converter does offer ways of mapping Python variables to RPN named variables, by using uppercase Python variable names, or the special comment directive 'named' e.g.
Code:
y = 100  # rpn: named

however the default behaviour is to use registers, to avoid polluting the HP42S/Free42 global namespace with dozens of variable names from your Python programs.

In retrospect, perhaps the better implementation would have been to store all the Python variables in a dedicated HP42S matrix and grow the matrix as necessary to house new variables etc. This would have been more work to implement and would result in more verbose generated RPN. However now that the converter is built, it's an area that I may revisit one day.

-Andy
Find all posts by this user
Quote this message in a reply
12-11-2018, 07:05 PM
Post: #46
RE: Python to RPN converter
Has the converter moved? I'm getting 404 errors for all the links…

Cambridge, UK
41CL/DM41X 12/15C/16C DM15/16 17B/II/II+ 28S 42S/DM42 32SII 48GX 50g 35s WP34S PrimeG2 WP43S/pilot/C47
Casio, Rockwell 18R
Find all posts by this user
Quote this message in a reply
12-11-2018, 10:46 PM
Post: #47
RE: Python to RPN converter
(12-11-2018 07:05 PM)cdmackay Wrote:  Has the converter moved? I'm getting 404 errors for all the links…

Try http://pyrpn.atug.com/

The www. prefixed address was misconfigured due to a server change I did the other week, and should rectify itself shortly. Sorry for the scare!

-Andy
Find all posts by this user
Quote this message in a reply
12-11-2018, 11:27 PM
Post: #48
RE: Python to RPN converter
(12-11-2018 10:46 PM)tcab Wrote:  Try http://pyrpn.atug.com/

The www. prefixed address was misconfigured due to a server change I did the other week, and should rectify itself shortly. Sorry for the scare!

phew! thanks Andy Smile

Cambridge, UK
41CL/DM41X 12/15C/16C DM15/16 17B/II/II+ 28S 42S/DM42 32SII 48GX 50g 35s WP34S PrimeG2 WP43S/pilot/C47
Casio, Rockwell 18R
Find all posts by this user
Quote this message in a reply
05-22-2020, 05:53 PM
Post: #49
RE: Python to RPN converter
hello all,
as you can see I'm not a specialist ;-). I would like to know if there is a way to convert in the opposite way: RPN to python please?
Thanks for help

Pascal
Find all posts by this user
Quote this message in a reply
06-09-2020, 04:12 PM
Post: #50
RE: Python to RPN converter
Converting standard notation to an RPN

https://xrjunque.nom.es/ConvertAlg2RPN_RPL.aspx
Find all posts by this user
Quote this message in a reply
06-12-2020, 03:05 PM
Post: #51
RE: Python to RPN converter
This is excellent. I love this.

Two problems I ran into:
* the lack of ROUND equivalent for the HP 42S
* how to handle the int command (set number as an integer)
Visit this user's website Find all posts by this user
Quote this message in a reply
06-12-2021, 03:42 AM
Post: #52
RE: Python to RPN converter
(06-12-2020 03:05 PM)Eddie W. Shore Wrote:  This is excellent. I love this.

Two problems I ran into:
* the lack of ROUND equivalent for the HP 42S
* how to handle the int command (set number as an integer)

> This is excellent. I love this.

Thanks Eddie! - sorry for the late reply, somehow I just saw your post now.

> * the lack of ROUND equivalent for the HP 42S

HP42 has the built in command RND which you can invoke from Python e.g. you type RND(1.5) and convert it via https://pyrpn.atug.com which generates

1.5
RND

but since the built in HP42S/Free42 RND works via the current display format, we seem to have to call FIX as well to pull this off. Thus a full example might be Python code:

Code:
LBL("untitled")
FIX(0)
x = RND(1.5)
print("rounded is", x)

which generates:

Code:
01 LBL "untitle"
02 FIX 00
03 1.5
04 RND
05 STO 00
06 "rounded is"
07 ├" "
08 ARCL 00
09 AVIEW

> * how to handle the int command (set number as an integer)

Perhaps type IP(myvar) into the Python to RPN converter - which generates the built in Free42 command IP. That's the closest command I can find.

Here is a Python program to do both

Code:
def rndip(n):
  FIX(0)
  r = RND(n)
  i = IP(n)
  FIX(2)
  print(n, "rounded is", r, "integer portion", i)

After conversion, and pasting into Free42, run with

1.5 XEQ RNDIP

* Reminder: the Python to RPN converter is not related to Python in HP Prime CAS, nor the beta MicroPython App in HP Prime. It is a online website which converts Python into RPN which you can paste or type into Free42/HP42S/HP41. Help is https://pyrpn.atug.com/help
Find all posts by this user
Quote this message in a reply
06-12-2021, 03:54 AM
Post: #53
RE: Python to RPN converter
A new release of the converter today:
  • Fixed CLΣ access by providing Python function CLStat()
  • Allow access to statistical registers e.g. RCL(12)
  • Added statistical example to the help file.
Here is an example Python program which can be converted to RPN, which finds the sum of x^2 between numbers _from and _to using the built in feature of the HP statistics function Σ+ by accessing register 12.

Code:
def sumsigma(_from, _to):
  CLStat()  # CLΣ
  for i in range(_from, _to + 1):
    StatPlus(i, i) # Σ+
  x = RCL(12)  # recall summation register
  print("sum of x^2 from", _from, "to", _to, "is", x)

Use: On Free42 type

1 Enter 10 XEQ SUMSIGMA

and you'll get the answer 385.

Its just a fun exercise - easily accomplished on the HP Prime with the one liner e.g. Σ(X^2,X,1,10)
Find all posts by this user
Quote this message in a reply
09-15-2023, 11:09 AM
Post: #54
RE: Python to RPN converter
The code behind this project is now open source and available at https://github.com/abulka/pyrpn

You can run it locally on your own machine via docker e.g.

Code:
git clone git@github.com:abulka/pyrpn.git
cd pyrpn
docker-compose up

Plenty of information in the README.

Enjoy!
Find all posts by this user
Quote this message in a reply
09-29-2023, 08:26 PM
Post: #55
RE: Python to RPN converter
Thank you for opening it up!
Find all posts by this user
Quote this message in a reply
02-16-2024, 02:35 PM (This post was last modified: 02-16-2024 03:16 PM by Thomas Klemm.)
Post: #56
RE: Python to RPN converter
The following Python program leads to an error:
Code:
def d5(a, b):
    if a < 5:
        if b < 5:
            return (a + b) % 5
        else:
            return (a + b) % 5 + 5
    else:
        if b < 5:
            return (a - b) % 5 + 5
        else:
            return (a - b) % 5

Potential RPN stack overflow detected - expression too complex for 4 level stack - simplify! ['b', 5, '_result_', 'a', 'b'], line: 11
return (a - b) % 5


This is a possible translation for the HP-42S:
Code:
00 { 63-Byte Prgm }
01▸LBL "D5"
02 STO 01
03 R↓
04 STO 00
05 RCL 00
06 5
07 X≤Y?
08 GTO 01
09 RCL 01
10 5
11 X≤Y?
12 GTO 00
13 RCL 00
14 RCL 01
15 +
16 5
17 MOD
18 RTN
19▸LBL 00
20 RCL 00
21 RCL 01
22 +
23 5
24 MOD
25 5
26 +
27 RTN
28▸LBL 01
29 RCL 01
30 5
31 X≤Y?
32 GTO 02
33 RCL 00
34 RCL 01
35 -
36 5
37 MOD
38 5
39 +
40 RTN
41▸LBL 02
42 RCL 00
43 RCL 01
44 -
45 5
46 MOD
47 END

It is based on the disassembly of the d5 function:
Code:
  1           0 RESUME                   0

  2           2 LOAD_FAST                0 (a)
              4 LOAD_CONST               1 (5)
              6 COMPARE_OP               2 (<)
             10 POP_JUMP_IF_FALSE       24 (to 60)

  3          12 LOAD_FAST                1 (b)
             14 LOAD_CONST               1 (5)
             16 COMPARE_OP               2 (<)
             20 POP_JUMP_IF_FALSE        8 (to 38)

  4          22 LOAD_FAST                0 (a)
             24 LOAD_FAST                1 (b)
             26 BINARY_OP                0 (+)
             30 LOAD_CONST               1 (5)
             32 BINARY_OP                6 (%)
             36 RETURN_VALUE

  6     >>   38 LOAD_FAST                0 (a)
             40 LOAD_FAST                1 (b)
             42 BINARY_OP                0 (+)
             46 LOAD_CONST               1 (5)
             48 BINARY_OP                6 (%)
             52 LOAD_CONST               1 (5)
             54 BINARY_OP                0 (+)
             58 RETURN_VALUE

  8     >>   60 LOAD_FAST                1 (b)
             62 LOAD_CONST               1 (5)
             64 COMPARE_OP               2 (<)
             68 POP_JUMP_IF_FALSE       11 (to 92)

  9          70 LOAD_FAST                0 (a)
             72 LOAD_FAST                1 (b)
             74 BINARY_OP               10 (-)
             78 LOAD_CONST               1 (5)
             80 BINARY_OP                6 (%)
             84 LOAD_CONST               1 (5)
             86 BINARY_OP                0 (+)
             90 RETURN_VALUE

 11     >>   92 LOAD_FAST                0 (a)
             94 LOAD_FAST                1 (b)
             96 BINARY_OP               10 (-)
            100 LOAD_CONST               1 (5)
            102 BINARY_OP                6 (%)
            106 RETURN_VALUE

Therefore I don't think a stack overflow can happen.

Suggestion: I can imagine that it's not trivial to detect a potential stack overflow.
But in such cases I would rather just get a warning and still get the generated code.

Addendum:

This is the generated code when the exception is not thrown:
Code:
Generated 84 lines.
01 LBL "d5"
02 XEQ 65
03 STO 00
04 RDN
05 STO 01
06 RDN
07 RCL 00
08 5
09 XEQ 79
10 X≠0?
11 GTO 00
12 GTO 03
13 LBL 00
14 RCL 01
15 5
16 XEQ 79
17 X≠0?
18 GTO 04
19 GTO 06
20 LBL 04
21 RCL 00
22 RCL 01
23 +
24 5
25 MOD
26 RTN
27 GTO 05
28 LBL 06
29 RCL 00
30 RCL 01
31 +
32 5
33 MOD
34 5
35 +
36 RTN
37 LBL 05
38 GTO 01
39 LBL 03
40 RCL 01
41 5
42 XEQ 79
43 X≠0?
44 GTO 07
45 GTO 02
46 LBL 07
47 RCL 00
48 RCL 01
49 -
50 5
51 MOD
52 5
53 +
54 RTN
55 GTO 01
56 LBL 02
57 RCL 00
58 RCL 01
59 -
60 5
61 MOD
62 RTN
63 LBL 01
64 RTN
65 LBL 50
66 "-Utility Funcs-"
67 RTN
68 LBL 65
69 X<>Y
70 RTN
71 LBL 79
72 CF 00
73 X>Y?
74 SF 00
75 XEQ 61
76 RTN
77 LBL 61
78 RDN
79 RDN
80 FS? 00
81 1
82 FC? 00
83 0
84 RTN


For those interested, this function implements the Dihedral Group \(D_5\):

\(
\begin{bmatrix}
0 & 1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9\\
1 & 2 & 3 & 4 & 0 & 6 & 7 & 8 & 9 & 5\\
2 & 3 & 4 & 0 & 1 & 7 & 8 & 9 & 5 & 6\\
3 & 4 & 0 & 1 & 2 & 8 & 9 & 5 & 6 & 7\\
4 & 0 & 1 & 2 & 3 & 9 & 5 & 6 & 7 & 8\\
5 & 9 & 8 & 7 & 6 & 0 & 4 & 3 & 2 & 1\\
6 & 5 & 9 & 8 & 7 & 1 & 0 & 4 & 3 & 2\\
7 & 6 & 5 & 9 & 8 & 2 & 1 & 0 & 4 & 3\\
8 & 7 & 6 & 5 & 9 & 3 & 2 & 1 & 0 & 4\\
9 & 8 & 7 & 6 & 5 & 4 & 3 & 2 & 1 & 0
\end{bmatrix}
\)
Find all posts by this user
Quote this message in a reply
10-18-2024, 12:14 PM
Post: #57
Bug Report: Python to RPN converter
The following function is not translated properly:
Code:
def f(a, b):
    return -(a + b)

This is the generated code for the HP-42S:
Code:
LBL "f"
XEQ 65          // reorder 2 params for storage
STO 00          // param: a
RDN
STO 01          // param: b
RDN
RCL 00          // a
CHS
RCL 01          // b
+
RTN             // return
LBL 50          // PyRPN Support Library of
"-Utility Funcs-"
RTN             // ---------------------------
LBL 65          // Reverse params. (a,b) -> (b,a)
X<>Y
RTN

However CHS should be executed after the addition of a and b.
This calculates -a + b instead.

Compare it with the disassembly of the function f:
Code:
  1           0 RESUME                   0

  2           2 LOAD_FAST                0 (a)
              4 LOAD_FAST                1 (b)
              6 BINARY_OP                0 (+)
             10 UNARY_NEGATIVE
             12 RETURN_VALUE

This is the abstract syntax tree of the expression -(a + b):
Code:
Module(
    body=[
        Expr(
            value=UnaryOp(
                op=USub(),
                operand=BinOp(
                    left=Name(id='a', ctx=Load()),
                    op=Add(),
                    right=Name(id='b', ctx=Load()))))],
    type_ignores=[])

It looks good to me.
Therefore, I assume that it is a problem in the method visit_UnaryOp of RecursiveRpnVisitor:
Code:
    def visit_UnaryOp(self, node):
        """
        op=USub(),
        operand=Num(n=1))],
        """
        if isinstance(node.op, ast.Not):
            self.visit(node.operand)
            self.visit(node.op)
        else:
            # for parsing e.g. -1
            self.visit(node.op)
            self.visit(node.operand)
Find all posts by this user
Quote this message in a reply
Post Reply 




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