def enterHelpMode( terms ): ''' When using rpn interactively, help is a special mode, which allows the user to navigate the help contents with much fewer keystrokes than having to invoke help over and over. ''' printHelpModeHelp( ) while True: try: line = input( 'rpn help>' ) except EOFError: break line = line.strip( ) if line in [ 'exit', 'quit' ]: break terms = line.split( ' ' ) if terms[ 0 ] == 'help': printHelpModeHelp( ) elif terms[ 0 ] == 'topics': printInteractiveHelp( ) else: for term in terms: printHelp( operators, constants, listOperators, modifiers, term, True )
def rpn( cmd_args ): ''' This is the main function which processes the command-line arguments, handling both options and the expression to evaluate. This function is mainly concerned with parsing and handling the command-line options. It finally calls evaluate( ) with the expression to be calculated, and returns the results, which can be formatted for output or used in another way (such as the unit test functionality). ''' # initialize globals g.debugMode = False g.outputRadix = 10 getDataPath( ) # look for help argument before we start setting everything up (because it's faster this way) help = False helpArg = '' for i in range( 0, len( cmd_args ) ): if cmd_args[ i ] == 'help': help = True else: if help: helpArg = cmd_args[ i ] if help: parser = argparse.ArgumentParser( prog = g.PROGRAM_NAME, description = g.PROGRAM_NAME + PROGRAM_VERSION_STRING + g.PROGRAM_DESCRIPTION + '\n ' + COPYRIGHT_MESSAGE, add_help = False, formatter_class = argparse.RawTextHelpFormatter, prefix_chars = '-' ) parser.add_argument( 'terms', nargs = '*', metavar = 'term' ) parser.add_argument( '-l', '--line_length', type = int, action = 'store', default = g.defaultLineLength ) args = parser.parse_args( cmd_args ) loadUnitNameData( ) g.operatorAliases.update( operatorAliases ) printHelp( operators, constants, listOperators, modifiers, helpArg ) return # set up the command-line options parser parser = argparse.ArgumentParser( prog = g.PROGRAM_NAME, description = g.PROGRAM_NAME + PROGRAM_VERSION_STRING + g.PROGRAM_DESCRIPTION + '\n ' + COPYRIGHT_MESSAGE, add_help = False, formatter_class = argparse.RawTextHelpFormatter, prefix_chars = '-' ) parser.add_argument( '-a', '--output_accuracy', nargs = '?', type = int, action = 'store', default = g.defaultOutputAccuracy, const = g.defaultOutputAccuracy ) parser.add_argument( '-b', '--input_radix', type = str, action = 'store', default = g.defaultInputRadix ) parser.add_argument( '-c', '--comma', action = 'store_true' ) parser.add_argument( '-d', '--decimal_grouping', nargs = '?', type = int, action = 'store', default = 0, const = g.defaultDecimalGrouping ) parser.add_argument( '-D', '--DEBUG', action = 'store_true' ) parser.add_argument( '-e', '--profile', action = 'store_true' ) parser.add_argument( '-g', '--integer_grouping', nargs = '?', type = int, action = 'store', default = 0, const = g.defaultIntegerGrouping ) parser.add_argument( '-h', '--help', action = 'store_true' ) parser.add_argument( '-i', '--identify', action = 'store_true' ) parser.add_argument( '-l', '--line_length', type = int, action = 'store', default = g.defaultLineLength ) parser.add_argument( '-m', '--maximum_fixed', type = int, action = 'store', default = g.defaultMaximumFixed ) parser.add_argument( '-n', '--numerals', type = str, action = 'store', default = g.defaultNumerals ) parser.add_argument( '-o', '--octal', action = 'store_true' ) parser.add_argument( '-p', '--precision', type = int, action = 'store', default = g.defaultPrecision ) parser.add_argument( '-r', '--output_radix', type = str, action = 'store', default = g.defaultOutputRadix ) parser.add_argument( '-R', '--output_radix_numerals', type = int, action = 'store', default = 0 ) parser.add_argument( '-s', '--list_format_level', nargs = '?', type = int, action = 'store', default = 0, const = g.defaultListFormatLevel ) parser.add_argument( '-t', '--timer', action = 'store_true' ) parser.add_argument( '-T', '--time_limit', nargs = '?', type = int, action = 'store', default = 0, const = g.timeLimit ) parser.add_argument( '-v', '--verbose', action = 'store_true' ) parser.add_argument( '-w', '--bitwise_group_size', type = int, action = 'store', default = g.defaultBitwiseGroupSize ) parser.add_argument( '-x', '--hex', action = 'store_true' ) parser.add_argument( '-z', '--leading_zero', action = 'store_true' ) parser.add_argument( '-!', '--print_options', action = 'store_true' ) parser.add_argument( '-?', '--other_help', action = 'store_true' ) # pull out the options and the terms options = [ ] terms = [ ] for i, arg in enumerate( cmd_args ): if ( len( arg ) > 1 ) and ( arg[ 0 ] == '-' ): if arg[ 1 ].isdigit( ): # a negative number, not an option terms.append( arg ) else: options.append( arg ) else: terms.append( arg ) # OK, let's parse and validate the options args = parser.parse_args( options ) g.operatorAliases.update( operatorAliases ) if args.help or args.other_help: loadUnitNameData( ) printHelp( operators, constants, listOperators, modifiers, '' ) return valid, errorString = validateOptions( args ) if not valid: print( 'rpn: ' + errorString ) return # these are either globals or can be modified by other options (like -x) g.bitwiseGroupSize = args.bitwise_group_size g.integerGrouping = args.integer_grouping g.leadingZero = args.leading_zero # handle -a - set precision to be at least 2 greater than output accuracy setAccuracy( args.output_accuracy ) # handle -b g.inputRadix = int( args.input_radix ) # handle -c g.comma = args.comma # handle -d g.decimalGrouping = args.decimal_grouping # handle -D if args.DEBUG: g.debugMode = True # handle -i g.identify = args.identify # handle -l g.lineLength = args.line_length # handle -m g.maximumFixed = args.maximum_fixed # handle -n g.numerals = parseNumerals( args.numerals ) # handle -o if args.octal: g.outputRadix = 8 g.leadingZero = True g.integerGrouping = 3 g.bitwiseGroupSize = 9 # handle -p setPrecision( args.precision ) # handle -r if args.output_radix == 'phi': g.outputRadix = g.phiBase elif args.output_radix == 'fib': g.outputRadix = g.fibBase elif args.output_radix == 'fac' or args.output_radix == '!': g.outputRadix = g.facBase elif args.output_radix == 'fac2' or args.output_radix == 'double_fac' or args.output_radix == '!!': g.outputRadix = g.doublefacBase elif args.output_radix == 'square' or args.output_radix == 'sqr': g.outputRadix = g.squareBase elif args.output_radix == 'lucas': g.outputRadix = g.lucasBase elif args.output_radix == 'triangular' or args.output_radix == 'tri': g.outputRadix = g.triangularBase elif args.output_radix == 'primorial': g.outputRadix = g.primorialBase elif args.output_radix == 'e': g.outputRadix = g.eBase elif args.output_radix == 'pi': g.outputRadix = g.piBase elif args.output_radix == 'sqrt2': g.outputRadix = g.sqrt2Base else: try: # if g.outputRadix was already set (e.g., by -o) then we don't want to override it if g.outputRadix == 10: g.outputRadix = int( args.output_radix ) except ValueError: print( 'rpn: can\'t interpret output radix \'%s\' as a number' % args.output_radix ) return [ nan ] # handle -R if args.output_radix_numerals > 0: g.outputBaseDigits = True g.outputRadix = args.output_radix_numerals else: g.outputBaseDigits = False # -r/-R validation if g.outputBaseDigits: if ( g.outputRadix < 2 ): print( 'rpn: output radix must be greater than 1' ) return [ nan ] elif ( ( g.outputRadix < g.maxSpecialBase ) or ( g.outputRadix == 0 ) or ( g.outputRadix == 1 ) or ( g.outputRadix > 62 ) ): print( 'rpn: output radix must be from 2 to 62, fib, phi, fac, doublefac, square, lucas' ) return [ nan ] # handle -s g.listFormatLevel = args.list_format_level # handle -t g.timer = args.timer # handle -T g.timeLimit = args.time_limit # handle -v g.verbose = args.verbose # handle -x if args.hex: g.outputRadix = 16 g.leadingZero = True g.integerGrouping = 4 g.bitwiseGroupSize = 16 # handle -u and -y: mpmath wants precision of at least 53 for these functions if args.identify and mp.dps < 53: setAccuracy( 53 ) if args.print_options: print( '--output_accuracy: %d' % g.outputAccuracy ) print( '--input_radix: %d' % g.inputRadix ) print( '--comma: ' + ( 'true' if g.comma else 'false' ) ) print( '--decimal_grouping: %d' % g.decimalGrouping ) print( '--integer_grouping: %d' % g.integerGrouping ) print( '--line_length: %d' % g.lineLength ) print( '--numerals: ' + g.numerals ) print( '--octal: ' + ( 'true' if args.octal else 'false' ) ) print( '--precision: %d' % args.precision ) print( '--output_radix: %d' % g.outputRadix ) print( '--output_radix_numerals: %d' % args.output_radix_numerals ) print( '--list_format_level: %d' % g.listFormatLevel ) print( '--timer: ' + ( 'true' if args.timer else 'false' ) ) print( '--verbose: ' + ( 'true' if g.verbose else 'false' ) ) print( '--bitwise_group_size: %d' % g.bitwiseGroupSize ) print( '--hex: ' + ( 'true' if args.hex else 'false' ) ) print( '--identify: ' + ( 'true' if args.identify else 'false' ) ) print( '--leading_zero: ' + ( 'true' if g.leadingZero else 'false' ) ) print( ) g.creatingFunction = False # enter interactive mode if there are no arguments if not terms: if not loadUnitNameData( ): return enterInteractiveMode( ) return # let's check out the arguments before we start to do any calculations if not validateArguments( terms ): return #newTerms = preprocessTerms( terms ) #print( 'newTerms', newTerms ) # waiting until we've validated the arguments to do this because it's slow if not loadUnitNameData( ): return if g.timer: g.startTime = time.process_time( ) return evaluate( terms )