stdin - Program does not accept argument Python -
i creating postfix calculator accepts arithmetic expressions , first pushes operators stacl.
./pythonfilename 3 4 1 + - used input. however, since no output displayed, tried debug program see why program not taking in argument. not result in printing output. hit ctrl+c display traceback call , points out x = sys.stdin.readlines.
#!/usr/bin/python import sys import fileinput class stack: def __init__(self): self.items = [] def isempty(self): return self.items == [] def push(self,item): self.items.append(item) def pop(self): return self.items(pop) def peek(self): return self.items[len(self.items)-1] def size(self): return len(self.items) def is_number(line): try: float(line) except valueerror: return false def infixtopostfix(): initstack=stack() x = sys.stdin.readlines() #read user input lines in x:#for lines in fileinput.input(): line in lines.strip().split(" "): if is_number(line): initstack.push(line) line = float(line) elif line =='+': firstnum = initstack.pop() secnum = initstack.pop() result = firstnum + secnum initstack.push(result) print initstack.peek() elif line == '-': firstnum = initstack.pop() secnum = initstack.pop() result = firstnum - secnum initstack.push(result) print initstack.peek() elif line == '*': firstnum = initstack.pop() secnum = initstack.pop() result = firstnum * secnum initstack.push(result) print initstack.peek() elif line == "/": firstnum = initstack.pop() secnum = initstack.pop() result = firstnum / secnum initstack.push(result) print initstack.peek() elif line == "%": firstnum = initstack.pop() secnum = initstack.pop() result = firstnum % secnum initstack.push(result) print initstack.peek() infixtopostfix()
the standard way read pipe (cat ... | python myprog.py
) is
import sys line in sys.stdin: print ">", line
line
here include final '\n'
if instead want take arguments on command line (python myprog.py 3 4 1 + -
), use sys.argv[1:]
(sys.argv[0]
contains myprog.py
).
to consistent lexing of input need first check sys.argv
, split sys.stdin
:
def lex_input(): "returns list of tokens." tokens = [] if len(sys.argv) > 1: tokens = sys.argv[1:] else: line in sys.stdin: tokens += line.split() return tokens
then need change infixpostfix()
function use token-array (instead of doing both parsing , evaluation in same function).
ps: more succinct way of writing individual clauses be:
elif token == '+': push(pop() + pop())
but depends on you're trying accomplish..
update: full'ish solution
update2: debug statements visualize stack (removed stack class in favor of regular list brevity)
import sys stack = [] push = stack.append pop = stack.pop operations = { '+': lambda b, a: + b, '-': lambda b, a: - b, '*': lambda b, a: b * a, '/': lambda b, a: b / a, } def infixtopostfix(tokens): print '%-15s %5s %-15s' % ('stack before', 'token', 'stack after') print '-'*15, '-'*5, '-'*15 token in tokens: print '%15s %5r' % (stack, token), if token not in operations: push(int(token)) else: push(operations[token](pop(), pop())) print '%15s' % stack def lex_input(): "returns list of tokens." tokens = [] if len(sys.argv) > 1: tokens = sys.argv[1:] else: line in sys.stdin: tokens += line.split() return tokens if __name__ == "__main__": infixtopostfix(lex_input()) # formed programs should leave single value on stack print "\nresult is:", stack[0]
testing:
(dev) go|c:\srv> python rpn.py 3 4 1 + - stack before token stack after --------------- ----- --------------- [] '3' [3] [3] '4' [3, 4] [3, 4] '1' [3, 4, 1] [3, 4, 1] '+' [3, 5] [3, 5] '-' [-2] result is: -2
(cat rpn.txt | python rpn.py
output same thing if rpn.txt
contains 3 4 1 + -
).
if try rpn program syntax error, program raise exception, e.g.:
(dev) go|c:\srv> python rpn.py 3 4 + - stack before token stack after --------------- ----- --------------- [] '3' [3] [3] '4' [3, 4] [3, 4] '+' [7] [7] '-' traceback (most recent call last): file "rpn.py", line 60, in <module> infixtopostfix(lex_input()) file "rpn.py", line 45, in infixtopostfix push(operations[token](pop(), pop())) file "rpn.py", line 26, in pop return stack.pop() indexerror: pop empty list
in real compiler bad, since don't want end user see details of implementation. instead you'd want give them diagnostic error message, exact place program found it.
in case isn't difficult. i've omitted debug statements print stack:
def infixtopostfix(tokens): # make copy of input, use in error handling input_tokens = tokens[:] try: i, token in enumerate(tokens): if token not in operations: push(int(token)) else: push(operations[token](pop(), pop())) except indexerror: print 'detected syntax error @ token no.:', + 1 # people count 1.. print ' '.join(input_tokens) print '%s%s' % ('-' * (1 + len(' '.join(input_tokens[:i]))), '^') push('syntax error') # top of stack contains result of current operation..
a small change result printing necessary, printing last element in list (stack[-1]
) top of stack instead of relying on list/stack having 1 element @ end:
if __name__ == "__main__": infixtopostfix(lex_input()) # formed programs should leave single value on stack print "\nresult is:", stack[-1]
if feed version our program syntax error:
(dev) go|c:\srv> python rpn.py 34 4 + - detected syntax error @ token no.: 4 34 4 + - -------^ result is: syntax error
we proper error message, little pointy 'graphic' indicating error detected.
we go further since know of our operations take 2 elements on stack, , give more detailed error message, e.g.:
syntax error @ token "-": stack underflow "-" operation requires 2 stack arguments , stack contained one: stack token ---------- ----- [37] '-'
i'll leave implementation of exercise.
as can see, in simple example there more error handling code evaluation code , isn't surprising when writing simple compilers.
Comments
Post a Comment