2015-10-31 3 views
2

Я создаю постфиксный калькулятор, который принимает арифметические выражения и сначала подталкивает операторов к stacl.Программа не принимает аргумент Python

./pythonfilename 3 4 1 + - был использован в качестве моего ввода. Однако, поскольку вывод не выводится, я попытался отладить мою программу, чтобы понять, почему моя программа не принимает мои аргументы. не приводит к печати какого-либо выхода. Я нажимаю Ctrl + C, чтобы отобразить Traceback Call, и он указывает 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 
    for lines in x:#for lines in fileinput.input(): 
     for 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() 

ответ

3

стандартным образом для чтения из трубы (cat ... | python myprog.py) является

import sys 

for line in sys.stdin: 
    print ">", line 

line здесь будет включать окончательный '\n'

Если вместо этого вы хотите, чтобы иметь аргументы в командной строке (python myprog.py 3 4 1 + -), можно использовать sys.argv[1:] (sys.argv[0] содержит myprog.py).

Чтобы получить последовательный лексический на входе вы должны сначала проверить sys.argv, а затем разделить sys.stdin:

def lex_input(): 
    "Returns a list of tokens." 
    tokens = [] 
    if len(sys.argv) > 1: 
     tokens = sys.argv[1:] 
    else: 
     for line in sys.stdin: 
      tokens += line.split() 
    return tokens 

тогда вам просто нужно изменить infixPostfix() функцию, чтобы использовать этот маркер-массив (а не делать так синтаксический анализ и оценка в той же функции).

пс: более лаконичный способ написания отдельных положений будет:

elif token == '+': 
    push(pop() + pop()) 

, но это зависит от того, что вы пытаетесь сделать ..

Update: full'ish решение

Update2: отладочные отчетности визуализируют стек (удален класс стека в пользу обычного списка для краткости)

import sys 

STACK = [] 
push = STACK.append 
pop = STACK.pop 

OPERATIONS = { 
    '+': lambda b, a: a + b, 
    '-': lambda b, a: 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 

    for 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 a list of tokens." 
    tokens = [] 
    if len(sys.argv) > 1: 
     tokens = sys.argv[1:] 
    else: 
     for line in sys.stdin: 
      tokens += line.split() 
    return tokens 

if __name__ == "__main__": 
    infixtoPostfix(lex_input()) 
    # well formed programs should leave a single value on the STACK 
    print "\nResult is:", STACK[0] 

испытания:

(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 будет выводить то же самое, если rpn.txt содержит 3 4 1 + -).

Если попробовать программу RPN с синтаксической ошибкой, то программа сгенерирует исключение, например:

(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 from empty list 

В реальной компилятор, который будет плохо, так как вы не хотите, чтобы конечный пользователь чтобы узнать подробности о вашей реализации. Вместо этого вы хотите дать им сообщение об ошибке диагностики с точным местом, где ваша программа его обнаружила.

В этом случае это не так сложно. Я опустил отладочные для печати стек:

def infixtoPostfix(tokens): 
    # make a copy of the input, for use in error handling 
    input_tokens = tokens[:] 
    try: 
     for 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 at token no.:', i + 1 # people count from 1.. 
     print ' '.join(input_tokens) 
     print '%s%s' % ('-' * (1 + len(' '.join(input_tokens[:i]))), '^') 
     push('SYNTAX ERROR') # the top of the stack contains the result of the current operation.. 

небольшое изменение результатов печати необходимо, печатая последний элемент в списке (STACK[-1]), который в верхней части стека вместо того, чтобы полагаться на список/стек только имея один элемент в конце:

if __name__ == "__main__": 
    infixtoPostfix(lex_input()) 
    # well formed programs should leave a single value on the STACK 
    print "\nResult is:", STACK[-1] 

если мы кормим эту версию нашей программы с синтаксической ошибки:

(dev) go|c:\srv> python rpn.py 34 4 + - 
Detected Syntax Error at token no.: 4 
34 4 + - 
-------^ 

Result is: SYNTAX ERROR 

мы получаем правильный е rror, с небольшим заостренным «графиком», указывающим, где была обнаружена ошибка.

Мы могли бы пойти дальше, так как мы знаем, что все наши операции принимают два элемента в стеке, и дать еще более подробное сообщение об ошибке, например:

Syntax Error at token "-": Stack underflow 
    The "-" operation requires two stack arguments and the stack 
    contained only one: 

     Stack  token 
     ---------- ----- 
     [37]  '-' 

Я оставлю реализацию, что, как упражнение.

Как вы можете видеть, даже в этом простом примере есть больше кода обработки ошибок, чем оценочный код, и это не удивительно при написании простых компиляторов.

+0

Я не вносил изменений, которые вы предложили, когда я впервые протестировал cat test.txt | python something.py, и я получил сообщение о том, что pop не определен. – syavatkar

+0

Traceback (самый последний вызов последнего): -bash: ошибка синтаксиса около неожиданной лексемы 'наиболее ' Файл "something.py", строка 75, в -bash: ошибка синтаксиса около неожиданной лексемы' новой строки' S $ infixtoPostfix() > Файл "something.py", строка 43, в infixtoPostfix -bash: ошибка синтаксиса около неожиданной лексемы 'File ' FirstNum = initStack.pop() -bash: ошибка синтаксиса около неожиданной лексемы' (' File «something.py», строка 17, в pop – syavatkar

+0

Пс был, может быть, слишком абстрактным .. Это подразумевалось как: «если вы определяете push и pop как простые функции (поскольку вы работаете только с одним стеком), тогда вы можете упростить оценку ».Это было просто в сторону вашего вопроса о токенизации. – thebjorn

0

./pythonfilename 3 4 1 + -

фактически 3 4 1 + - передаются в качестве аргумента не в качестве входных данных.

, если вы хотите прочитать из файла, пожалуйста, используйте открытый ('имя файла')

использование ./pythonfilename '3 4 1 + -'

х = [sys.argv [1]]

вместо х = sys.stdin.readlines()

Однако тогда ваш код обрабатывать только один вход в качестве аргумента

+0

Приношу свои извинения. Это правильный метод для передачи аргумента. Я на самом деле пытаюсь передать аргумент, используя cat – syavatkar

+0

, почему вы не передаете входной файл в качестве аргумента программы? ./pythonfilename имя файла. Это наиболее распространенное соглашение. –

+0

Да, я хочу, чтобы это было так. Если имя файла не передается он показал прочитать аргументы, переданные в консоли – syavatkar

Смежные вопросы