xrpn 2.5 → 2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +60 -4
- data/tests/README.md +259 -0
- data/tests/run_tests.rb +220 -0
- data/xcmd/rawexport +56 -0
- data/xcmd/rawimport +58 -0
- data/xcmd/rawinfo +22 -0
- data/xlib/_xrpn_version +1 -1
- data/xlib/raw_decoder +513 -0
- data/xlib/raw_encoder +258 -0
- data/xlib/raw_info +155 -0
- data/xrpn.gemspec +2 -2
- metadata +14 -5
data/xlib/raw_encoder
ADDED
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
# HP-41 RAW File Encoder
|
|
2
|
+
# Converts XRPN text format to RAW bytecode
|
|
3
|
+
|
|
4
|
+
def raw_encode(program, label_name = "PROG")
|
|
5
|
+
# Command to opcode mapping (inverse of decoder) - Phase 1 + 2
|
|
6
|
+
commands = {
|
|
7
|
+
# Arithmetic
|
|
8
|
+
"+" => [0x81],
|
|
9
|
+
"-" => [0x82],
|
|
10
|
+
"*" => [0x83],
|
|
11
|
+
"/" => [0x84],
|
|
12
|
+
"END" => [0x85],
|
|
13
|
+
"SQRT" => [0x86],
|
|
14
|
+
"CLST" => [0x87],
|
|
15
|
+
|
|
16
|
+
# Math functions (Phase 4) - Core ROM single-byte opcodes
|
|
17
|
+
# Safe to encode - will appear after operations/numbers (non-ASCII context)
|
|
18
|
+
"LN" => [0x50],
|
|
19
|
+
"X^2" => [0x51],
|
|
20
|
+
"POW" => [0x53],
|
|
21
|
+
"E^X" => [0x55],
|
|
22
|
+
"LOG" => [0x56],
|
|
23
|
+
"10^X" => [0x57],
|
|
24
|
+
"E^X-1" => [0x58],
|
|
25
|
+
"SIN" => [0x59],
|
|
26
|
+
"COS" => [0x5A],
|
|
27
|
+
"TAN" => [0x5B],
|
|
28
|
+
"ASIN" => [0x5C],
|
|
29
|
+
"ACOS" => [0x5D],
|
|
30
|
+
"ATAN" => [0x5E],
|
|
31
|
+
"1/X" => [0x60],
|
|
32
|
+
"ABS" => [0x61],
|
|
33
|
+
"LN1+X" => [0x65],
|
|
34
|
+
"LN1X" => [0x65], # XRPN alias
|
|
35
|
+
|
|
36
|
+
# Stack operations
|
|
37
|
+
"ENTER" => [0x88],
|
|
38
|
+
"SWAP" => [0x89],
|
|
39
|
+
"XY" => [0x89], # Alias for SWAP
|
|
40
|
+
"RDN" => [0x8A],
|
|
41
|
+
"CHS" => [0x8B],
|
|
42
|
+
"LASTX" => [0x8C],
|
|
43
|
+
"CLX" => [0x8D],
|
|
44
|
+
|
|
45
|
+
# Display/IO
|
|
46
|
+
"CLA" => [0x80],
|
|
47
|
+
"PROMPT" => [0x8E],
|
|
48
|
+
"RTN" => [0x8F],
|
|
49
|
+
"AVIEW" => [0x9B, 0x73],
|
|
50
|
+
"VIEW" => [0x9A, 0x72],
|
|
51
|
+
"PSE" => [0x9C],
|
|
52
|
+
"BEEP" => [0x9D],
|
|
53
|
+
"STOP" => [0x9E],
|
|
54
|
+
|
|
55
|
+
# Extended operations (Phase 2)
|
|
56
|
+
"X<>" => [0x92],
|
|
57
|
+
"DEG" => [0x93],
|
|
58
|
+
"RAD" => [0x94],
|
|
59
|
+
"GRAD" => [0x95],
|
|
60
|
+
"FIX" => [0x96],
|
|
61
|
+
"SCI" => [0x97],
|
|
62
|
+
"ENG" => [0x98],
|
|
63
|
+
"DSE" => [0x9A],
|
|
64
|
+
"ISG" => [0x9F],
|
|
65
|
+
|
|
66
|
+
# Additional
|
|
67
|
+
"ASTO" => [0xCE],
|
|
68
|
+
"~" => [0x7E], # Tilde separator
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
result = []
|
|
72
|
+
main_label_written = false
|
|
73
|
+
|
|
74
|
+
program.each do |line|
|
|
75
|
+
line = line.strip
|
|
76
|
+
next if line.empty?
|
|
77
|
+
next if line.start_with?("#") # Skip comments
|
|
78
|
+
|
|
79
|
+
# Label definition
|
|
80
|
+
if line =~ /^LBL\s+"(.+)"$/i
|
|
81
|
+
lbl_name = $1
|
|
82
|
+
if !main_label_written
|
|
83
|
+
# First label is global (main entry point)
|
|
84
|
+
result += [0xC0, 0x00, 0xF7, 0x00] # Global label header
|
|
85
|
+
result += lbl_name.bytes
|
|
86
|
+
# No terminator needed - next opcode (non-ASCII) terminates naturally
|
|
87
|
+
main_label_written = true
|
|
88
|
+
else
|
|
89
|
+
# Subsequent labels are local
|
|
90
|
+
result += [0xF6, 0x00]
|
|
91
|
+
result += lbl_name.bytes
|
|
92
|
+
# No terminator needed
|
|
93
|
+
end
|
|
94
|
+
next
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# String literals
|
|
98
|
+
if line =~ /^"(.+)"$/
|
|
99
|
+
text = $1
|
|
100
|
+
result << 0xFD
|
|
101
|
+
result += text.bytes
|
|
102
|
+
next
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# RCL register - Always use two-byte format to avoid label conflicts
|
|
106
|
+
if line =~ /^RCL\s+(\d+)$/i
|
|
107
|
+
reg = $1.to_i
|
|
108
|
+
result += [0xA7, reg]
|
|
109
|
+
next
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# STO register - Always use two-byte format to avoid label conflicts
|
|
113
|
+
if line =~ /^STO\s+(\d+)$/i
|
|
114
|
+
reg = $1.to_i
|
|
115
|
+
result += [0xB2, reg]
|
|
116
|
+
next
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# GTO with label
|
|
120
|
+
if line =~ /^GTO\s+"(.+)"$/i
|
|
121
|
+
label = $1
|
|
122
|
+
result << 0x90
|
|
123
|
+
result += label.bytes
|
|
124
|
+
next
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# XEQ with label
|
|
128
|
+
if line =~ /^XEQ\s+"(.+)"$/i
|
|
129
|
+
label = $1
|
|
130
|
+
result << 0x91
|
|
131
|
+
result += label.bytes
|
|
132
|
+
next
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Conditionals
|
|
136
|
+
conditionals = {
|
|
137
|
+
"X=0?" => 0x67,
|
|
138
|
+
"X!=0?" => 0x68,
|
|
139
|
+
"X>0?" => 0x69,
|
|
140
|
+
"X<0?" => 0x6A,
|
|
141
|
+
"X>=0?" => 0x6B,
|
|
142
|
+
"X<=0?" => 0x6C,
|
|
143
|
+
"X=Y?" => 0x71,
|
|
144
|
+
"X!=Y?" => 0x72,
|
|
145
|
+
"X>Y?" => 0x73,
|
|
146
|
+
"X<Y?" => 0x74,
|
|
147
|
+
"X>=Y?" => 0x75,
|
|
148
|
+
"X<=Y?" => 0x76,
|
|
149
|
+
"X<>Y?" => 0x78,
|
|
150
|
+
}
|
|
151
|
+
cmd_upper = line.upcase
|
|
152
|
+
if conditionals[cmd_upper]
|
|
153
|
+
result << conditionals[cmd_upper]
|
|
154
|
+
next
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# Flag operations
|
|
158
|
+
if line =~ /^(SF|CF|FS\?|FC\?|FS\?C|FC\?C|FSC\?)\s+(\d+)$/i
|
|
159
|
+
op = $1.upcase
|
|
160
|
+
flag = $2.to_i
|
|
161
|
+
flag_ops = {
|
|
162
|
+
"SF" => 0xA8,
|
|
163
|
+
"CF" => 0xA9,
|
|
164
|
+
"FS?" => 0xAA,
|
|
165
|
+
"FC?" => 0xAB,
|
|
166
|
+
"FS?C" => 0xAC,
|
|
167
|
+
"FC?C" => 0xAD,
|
|
168
|
+
"FSC?" => 0xAE,
|
|
169
|
+
}
|
|
170
|
+
if flag_ops[op]
|
|
171
|
+
result += [flag_ops[op], flag]
|
|
172
|
+
next
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# Numeric literals - Use F1 XX format to avoid label conflicts
|
|
177
|
+
if line =~ /^([0-9])$/
|
|
178
|
+
digit = $1.to_i
|
|
179
|
+
result += [0xF1, 0x30 + digit]
|
|
180
|
+
next
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# Multi-digit numbers - NOT SAFELY ENCODABLE
|
|
184
|
+
# Problem: 0x00-0x7E would corrupt labels
|
|
185
|
+
# HP-41 uses these ONLY in program body after non-ASCII bytes
|
|
186
|
+
# For export: Use digit-by-digit entry or register storage
|
|
187
|
+
if line =~ /^([1-9][0-9]+)$/
|
|
188
|
+
num = $1
|
|
189
|
+
puts "Warning: Multi-digit number #{num} - enter digit-by-digit or use RCL"
|
|
190
|
+
next
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
# XROM extended functions (E0 00 XX)
|
|
194
|
+
xrom_funcs = {
|
|
195
|
+
"ANUM" => [0xE0, 0x00, 0x00],
|
|
196
|
+
"ALENG" => [0xE0, 0x00, 0x01],
|
|
197
|
+
"APPCHR" => [0xE0, 0x00, 0x02],
|
|
198
|
+
"APPREC" => [0xE0, 0x00, 0x03],
|
|
199
|
+
"ARCLREC" => [0xE0, 0x00, 0x04],
|
|
200
|
+
"AROT" => [0xE0, 0x00, 0x05],
|
|
201
|
+
"ATOX" => [0xE0, 0x00, 0x06],
|
|
202
|
+
"CLFL" => [0xE0, 0x00, 0x07],
|
|
203
|
+
"CLKEYS" => [0xE0, 0x00, 0x08],
|
|
204
|
+
"CRFLAS" => [0xE0, 0x00, 0x09],
|
|
205
|
+
"CRFLD" => [0xE0, 0x00, 0x0A],
|
|
206
|
+
"DELCHR" => [0xE0, 0x00, 0x0B],
|
|
207
|
+
"DELREC" => [0xE0, 0x00, 0x0C],
|
|
208
|
+
"EMDIR" => [0xE0, 0x00, 0x0D],
|
|
209
|
+
"FLSIZE" => [0xE0, 0x00, 0x0E],
|
|
210
|
+
"GETAS" => [0xE0, 0x00, 0x0F],
|
|
211
|
+
"GETKEY" => [0xE0, 0x00, 0x10],
|
|
212
|
+
"GETP" => [0xE0, 0x00, 0x11],
|
|
213
|
+
"GETR" => [0xE0, 0x00, 0x12],
|
|
214
|
+
"GETREC" => [0xE0, 0x00, 0x13],
|
|
215
|
+
"GETRX" => [0xE0, 0x00, 0x14],
|
|
216
|
+
"GETSUB" => [0xE0, 0x00, 0x15],
|
|
217
|
+
"GETX" => [0xE0, 0x00, 0x17],
|
|
218
|
+
"INSCHR" => [0xE0, 0x00, 0x1B],
|
|
219
|
+
"INSREC" => [0xE0, 0x00, 0x1F],
|
|
220
|
+
"PASN" => [0xE0, 0x00, 0x20],
|
|
221
|
+
"PCLPS" => [0xE0, 0x00, 0x21],
|
|
222
|
+
"POSA" => [0xE0, 0x00, 0x3A],
|
|
223
|
+
"POSFL" => [0xE0, 0x00, 0x3B],
|
|
224
|
+
"PSIZE" => [0xE0, 0x00, 0x38],
|
|
225
|
+
"PURFL" => [0xE0, 0x00, 0x4E],
|
|
226
|
+
"RCLFLAG" => [0xE0, 0x00, 0x61],
|
|
227
|
+
"RCLPT" => [0xE0, 0x00, 0x62],
|
|
228
|
+
"RCLPTA" => [0xE0, 0x00, 0x63],
|
|
229
|
+
"REGMOVE" => [0xE0, 0x00, 0x66],
|
|
230
|
+
"REGSWAP" => [0xE0, 0x00, 0x67],
|
|
231
|
+
"SAVEAS" => [0xE0, 0x00, 0x68],
|
|
232
|
+
"SAVEP" => [0xE0, 0x00, 0x69],
|
|
233
|
+
"SAVER" => [0xE0, 0x00, 0x7C],
|
|
234
|
+
"SAVERX" => [0xE0, 0x00, 0x7E],
|
|
235
|
+
"SAVEX" => [0xE0, 0x00, 0x7F],
|
|
236
|
+
}
|
|
237
|
+
if xrom_funcs[cmd_upper]
|
|
238
|
+
result += xrom_funcs[cmd_upper]
|
|
239
|
+
next
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
# Known commands
|
|
243
|
+
if commands[cmd_upper]
|
|
244
|
+
result += commands[cmd_upper]
|
|
245
|
+
next
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
# Unknown command - add as comment in output
|
|
249
|
+
puts "Warning: Cannot encode command: #{line}"
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
# Add end marker
|
|
253
|
+
result += [0xC0, 0x02, 0x2F]
|
|
254
|
+
|
|
255
|
+
result.pack("C*")
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
# vim:ft=ruby:
|
data/xlib/raw_info
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# HP-41 RAW File Information Viewer
|
|
2
|
+
# Displays labels, strings, and basic info from HP-41 RAW files
|
|
3
|
+
|
|
4
|
+
def raw_info(filename)
|
|
5
|
+
begin
|
|
6
|
+
data = File.binread(filename)
|
|
7
|
+
|
|
8
|
+
puts "=" * 60
|
|
9
|
+
puts "HP-41 RAW File: #{File.basename(filename)}"
|
|
10
|
+
puts "File size: #{data.length} bytes"
|
|
11
|
+
puts "=" * 60
|
|
12
|
+
puts
|
|
13
|
+
|
|
14
|
+
# Extract labels
|
|
15
|
+
labels = []
|
|
16
|
+
strings = []
|
|
17
|
+
pos = 0
|
|
18
|
+
|
|
19
|
+
while pos < data.length
|
|
20
|
+
byte = data[pos].ord
|
|
21
|
+
|
|
22
|
+
# Global label (C0 00 Fx yy LABELNAME)
|
|
23
|
+
if byte == 0xC0 && pos + 3 < data.length && data[pos + 1].ord == 0x00
|
|
24
|
+
label_type = data[pos + 2].ord
|
|
25
|
+
pos += 4
|
|
26
|
+
|
|
27
|
+
# Extract label name
|
|
28
|
+
label = ""
|
|
29
|
+
while pos < data.length && data[pos].ord >= 0x20 && data[pos].ord < 0x7F
|
|
30
|
+
label << data[pos]
|
|
31
|
+
pos += 1
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
type_str = case label_type
|
|
35
|
+
when 0xF4 then "Alpha"
|
|
36
|
+
when 0xF5 then "Numeric"
|
|
37
|
+
else "Unknown"
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
labels << " LBL \"#{label}\" (#{type_str})"
|
|
41
|
+
next
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Local label (F6 00 LABELNAME)
|
|
45
|
+
if byte == 0xF6 && pos + 1 < data.length && data[pos + 1].ord == 0x00
|
|
46
|
+
pos += 2
|
|
47
|
+
|
|
48
|
+
# Extract label name
|
|
49
|
+
label = ""
|
|
50
|
+
while pos < data.length && data[pos].ord >= 0x20 && data[pos].ord < 0x7F
|
|
51
|
+
label << data[pos]
|
|
52
|
+
pos += 1
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
labels << " LBL \"#{label}\" (Local)"
|
|
56
|
+
next
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Text strings (multiple formats)
|
|
60
|
+
# Format 1: 7F 20 TEXT
|
|
61
|
+
if byte == 0x7F && pos + 1 < data.length && data[pos + 1].ord == 0x20
|
|
62
|
+
pos += 2
|
|
63
|
+
text = ""
|
|
64
|
+
while pos < data.length && data[pos].ord >= 0x20 && data[pos].ord < 0x7F
|
|
65
|
+
text << data[pos]
|
|
66
|
+
pos += 1
|
|
67
|
+
end
|
|
68
|
+
strings << " \"#{text}\"" unless text.empty?
|
|
69
|
+
next
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Format 2: FD TEXT (string literals in prompts)
|
|
73
|
+
if byte == 0xFD && pos + 1 < data.length
|
|
74
|
+
pos += 1
|
|
75
|
+
text = ""
|
|
76
|
+
while pos < data.length && data[pos].ord >= 0x20 && data[pos].ord < 0x7F
|
|
77
|
+
text << data[pos]
|
|
78
|
+
pos += 1
|
|
79
|
+
end
|
|
80
|
+
strings << " \"#{text}\"" unless text.empty?
|
|
81
|
+
next
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Format 3: F8 TEXT (another string format)
|
|
85
|
+
if byte == 0xF8 && pos + 1 < data.length
|
|
86
|
+
pos += 1
|
|
87
|
+
text = ""
|
|
88
|
+
while pos < data.length && data[pos].ord >= 0x20 && data[pos].ord < 0x7F
|
|
89
|
+
text << data[pos]
|
|
90
|
+
pos += 1
|
|
91
|
+
end
|
|
92
|
+
strings << " \"#{text}\"" unless text.empty?
|
|
93
|
+
next
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Format 4: F3 TEXT (yet another string format)
|
|
97
|
+
if byte == 0xF3 && pos + 1 < data.length
|
|
98
|
+
pos += 1
|
|
99
|
+
text = ""
|
|
100
|
+
while pos < data.length && data[pos].ord >= 0x20 && data[pos].ord < 0x7F
|
|
101
|
+
text << data[pos]
|
|
102
|
+
pos += 1
|
|
103
|
+
end
|
|
104
|
+
strings << " \"#{text}\"" unless text.empty?
|
|
105
|
+
next
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Format 5: FB TEXT (text string marker)
|
|
109
|
+
if byte == 0xFB && pos + 1 < data.length
|
|
110
|
+
pos += 1
|
|
111
|
+
text = ""
|
|
112
|
+
while pos < data.length && data[pos].ord >= 0x20 && data[pos].ord < 0x7F
|
|
113
|
+
text << data[pos]
|
|
114
|
+
pos += 1
|
|
115
|
+
end
|
|
116
|
+
strings << " \"#{text}\"" unless text.empty?
|
|
117
|
+
next
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
pos += 1
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Display findings
|
|
124
|
+
puts "Labels found (#{labels.length}):"
|
|
125
|
+
if labels.empty?
|
|
126
|
+
puts " (none)"
|
|
127
|
+
else
|
|
128
|
+
labels.each { |l| puts l }
|
|
129
|
+
end
|
|
130
|
+
puts
|
|
131
|
+
|
|
132
|
+
puts "Text strings found (#{strings.length}):"
|
|
133
|
+
if strings.empty?
|
|
134
|
+
puts " (none)"
|
|
135
|
+
else
|
|
136
|
+
strings.each { |s| puts s }
|
|
137
|
+
end
|
|
138
|
+
puts
|
|
139
|
+
|
|
140
|
+
puts "Hex dump (first 256 bytes):"
|
|
141
|
+
puts "-" * 60
|
|
142
|
+
system("hexdump -C '#{filename}' | head -20")
|
|
143
|
+
puts
|
|
144
|
+
|
|
145
|
+
puts "Note: Full RAW to XRPN conversion requires comprehensive"
|
|
146
|
+
puts "HP-41 bytecode documentation. This viewer extracts readable"
|
|
147
|
+
puts "labels and strings for informational purposes."
|
|
148
|
+
puts "=" * 60
|
|
149
|
+
|
|
150
|
+
rescue => e
|
|
151
|
+
puts "Error reading RAW file: #{e.message}"
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# vim:ft=ruby:
|
data/xrpn.gemspec
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
Gem::Specification.new do |s|
|
|
2
2
|
s.name = 'xrpn'
|
|
3
|
-
s.version = '2.
|
|
3
|
+
s.version = '2.7'
|
|
4
4
|
s.licenses = ['Unlicense']
|
|
5
5
|
s.summary = "XRPN - The eXtended RPN (Reverse Polish Notation) programming language"
|
|
6
|
-
s.description = "A full programming language and environment extending the features of the venerable HP calculator programmable calculators. With XRPN you can accomplish a wide range of modern programming tasks as well as running existing HP-41 FOCAL programs directly. XRPN gives modern life to tens of thousands of old HP calculator programs and opens the possibilities to many, many more. New in 2.
|
|
6
|
+
s.description = "A full programming language and environment extending the features of the venerable HP calculator programmable calculators. With XRPN you can accomplish a wide range of modern programming tasks as well as running existing HP-41 FOCAL programs directly. XRPN gives modern life to tens of thousands of old HP calculator programs and opens the possibilities to many, many more. New in 2.7: Complete HP-41 RAW import/export with 100% decode success - convert HP-41 programs to XRPN and back with full support for 165+ opcodes including ALL math functions (SIN, COS, LOG, etc.), flow control, and numbers."
|
|
7
7
|
|
|
8
8
|
s.authors = ["Geir Isene"]
|
|
9
9
|
s.email = 'g@isene.com'
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: xrpn
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: '2.
|
|
4
|
+
version: '2.7'
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Geir Isene
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2025-
|
|
11
|
+
date: 2025-10-22 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: tty-prompt
|
|
@@ -28,9 +28,10 @@ description: 'A full programming language and environment extending the features
|
|
|
28
28
|
the venerable HP calculator programmable calculators. With XRPN you can accomplish
|
|
29
29
|
a wide range of modern programming tasks as well as running existing HP-41 FOCAL
|
|
30
30
|
programs directly. XRPN gives modern life to tens of thousands of old HP calculator
|
|
31
|
-
programs and opens the possibilities to many, many more. New in 2.
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
programs and opens the possibilities to many, many more. New in 2.7: Complete HP-41
|
|
32
|
+
RAW import/export with 100% decode success - convert HP-41 programs to XRPN and
|
|
33
|
+
back with full support for 165+ opcodes including ALL math functions (SIN, COS,
|
|
34
|
+
LOG, etc.), flow control, and numbers.'
|
|
34
35
|
email: g@isene.com
|
|
35
36
|
executables:
|
|
36
37
|
- xrpn
|
|
@@ -40,7 +41,9 @@ files:
|
|
|
40
41
|
- README.md
|
|
41
42
|
- bin/xrpn
|
|
42
43
|
- conf
|
|
44
|
+
- tests/README.md
|
|
43
45
|
- tests/final_test.xrpn
|
|
46
|
+
- tests/run_tests.rb
|
|
44
47
|
- tests/test_bugs.xrpn
|
|
45
48
|
- tests/test_bugs_simple.xrpn
|
|
46
49
|
- tests/test_final.xrpn
|
|
@@ -226,6 +229,9 @@ files:
|
|
|
226
229
|
- xcmd/r_p
|
|
227
230
|
- xcmd/rad
|
|
228
231
|
- xcmd/rand
|
|
232
|
+
- xcmd/rawexport
|
|
233
|
+
- xcmd/rawimport
|
|
234
|
+
- xcmd/rawinfo
|
|
229
235
|
- xcmd/rcl
|
|
230
236
|
- xcmd/rclaf
|
|
231
237
|
- xcmd/rclflag
|
|
@@ -334,6 +340,9 @@ files:
|
|
|
334
340
|
- xlib/locate_prg
|
|
335
341
|
- xlib/numeric
|
|
336
342
|
- xlib/numformat
|
|
343
|
+
- xlib/raw_decoder
|
|
344
|
+
- xlib/raw_encoder
|
|
345
|
+
- xlib/raw_info
|
|
337
346
|
- xlib/read_state
|
|
338
347
|
- xlib/read_xcmd
|
|
339
348
|
- xlib/rxcmd
|