-
Notifications
You must be signed in to change notification settings - Fork 6
/
rpn.py
executable file
·151 lines (120 loc) · 5.19 KB
/
rpn.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#!/usr/bin/env python
from __future__ import print_function
import sys
import os
import readline
import argparse
from rpnpy import Calculator
def setupReadline():
"""Initialize the readline library and command history.
@return: A C{bool} to indicate whether standard input is a terminal
(and therefore interactive).
"""
if not os.isatty(0):
# Standard input is closed or is a pipe etc. So there's no user
# typing at us, and so no point in setting up readline.
return False
# Readline code from https://docs.python.org/3.7/library/readline.html
histfile = os.path.join(os.path.expanduser('~'), '.pycalc_history')
try:
readline.read_history_file(histfile)
historyLen = readline.get_current_history_length()
except FileNotFoundError:
open(histfile, 'wb').close()
historyLen = 0
try:
readline.append_history_file
except AttributeError:
# We won't be able to save readline history. This can happen on
# Python 3.5 at least - not sure why.
pass
else:
import atexit
def saveHistory(prevHistoryLen, histfile):
newHistoryLen = readline.get_current_history_length()
readline.set_history_length(1000)
readline.append_history_file(newHistoryLen - prevHistoryLen,
histfile)
atexit.register(saveHistory, historyLen, histfile)
return True
def parseArgs():
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
description=(
'An RPN calculator for Python. Reads commands from standard input '
'and/or files or interactively with a read-eval-print loop and '
'(optionally) writes the final stack to standard output.'))
parser.add_argument(
'--prompt', default='--> ',
help='The prompt to print at the start of each line when interactive.')
parser.add_argument(
'files', nargs='*',
help=('Files to read input from. If you use this option and you also '
'want standard input to be read at some point, use "-" as a '
'name in the list of file names.'))
parser.add_argument(
'--separator',
help=('The character to use to split lines of standard input into '
'separate commands (unless --noSplit is given).'))
parser.add_argument(
'--debug', action='store_true', default=False,
help='Print verbose information about how commandsa are run.')
parser.add_argument(
'--print', action='store_true', default=False,
help='Print the result of each command')
parser.add_argument(
'--version', action='store_true', default=False,
help='Print the version number and exit.')
parser.add_argument(
'--noSplit', action='store_false', default=True, dest='splitLines',
help=('If given, do not split lines read from standard input into '
'separate commands, treat each line as an entire command.'))
parser.add_argument(
'--noFinalPrint', action='store_false', default=True,
dest='finalPrint',
help=('If given, do not print the stack after processing all commands '
'from standard input.'))
parser.add_argument(
'--stdin', action='store_true', default=False,
help=('If the arguments on the command line are passed as input to '
'the calculator, you can use this option to also read commands '
'from standard input once the command line has been executed.'))
parser.add_argument(
'--startupFile',
help=('Python file to be parsed at startup. Usually used to define '
'custom functions'))
return parser.parse_args()
if __name__ == '__main__':
args = parseArgs()
if args.version:
from rpnpy import __version__
print(__version__)
else:
calc = Calculator(autoPrint=args.print, splitLines=args.splitLines,
separator=args.separator, debug=args.debug)
if args.startupFile:
try:
with open(args.startupFile) as f:
exec(f.read(), globals(), calc._variables)
except FileNotFoundError:
calc.err('Startup file %s not found' % args.startupFile)
interactive = setupReadline()
if args.files:
if all(os.path.exists(f) or f == '-' for f in args.files):
# All arguments are existing files (or are '-', for stdin).
for filename in args.files:
if filename == '-':
calc.repl(args.prompt)
else:
with open(filename) as fp:
calc.batch(fp, False)
else:
# Execute the command line as a set of commands, following
# great suggestion by David Pattinson.
calc.batch((' '.join(args.files),), args.finalPrint)
if args.stdin:
calc.repl(args.prompt)
elif interactive:
calc.repl(args.prompt)
else:
calc.batch(sys.stdin, args.finalPrint)