<p>读取管道(<code>cat ... | python myprog.py</code>)的标准方法是</p>
<pre><code>import sys
for line in sys.stdin:
print ">", line
</code></pre>
<p><code>line</code>这里将包括最后的<code>'\n'</code></p>
<p>如果您想在命令行(<code>python myprog.py 3 4 1 + -</code>)上获取参数,您可以使用<code>sys.argv[1:]</code>(<code>sys.argv[0]</code>包含<code>myprog.py</code>)。你知道吗</p>
<p>要获得输入的一致词法,首先需要检查<code>sys.argv</code>,然后拆分<code>sys.stdin</code>:</p>
<pre><code>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
</code></pre>
<p>然后您只需要更改<code>infixPostfix()</code>函数来使用这个令牌数组(而不是在同一个函数中同时进行解析和求值)。你知道吗</p>
<p>附言:一个更简洁的方式写的个别条款将是:</p>
<pre><code>elif token == '+':
push(pop() + pop())
</code></pre>
<p>但这取决于你想完成什么。。你知道吗</p>
<p><strong>更新:</strong>完整解决方案</p>
<p><strong>更新2:</strong>带有调试语句以可视化堆栈(为了简洁起见,删除了堆栈类而使用常规列表)</p>
<pre><code>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]
</code></pre>
<p>测试:</p>
<pre><code>(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
</code></pre>
<p>(<code>cat rpn.txt | python rpn.py</code>将输出相同的东西,如果<code>rpn.txt</code>包含<code>3 4 1 + -</code>)。你知道吗</p>
<p>如果您尝试带有语法错误的rpn程序,则该程序将引发异常,例如:</p>
<pre><code>(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
</code></pre>
<p>在一个真正的编译器中,这是不好的,因为你不想让最终用户看到你实现的细节。相反,您应该给他们一个诊断错误消息,以及您的程序找到它的确切位置。你知道吗</p>
<p>在这种情况下,这并不难。我省略了用于打印堆栈的调试语句:</p>
<pre><code>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..
</code></pre>
<p>需要对结果打印进行小的更改,打印列表中的最后一个元素(<code>STACK[-1]</code>),它是堆栈的顶部,而不是依赖列表/堆栈的末尾只有一个元素:</p>
<pre><code>if __name__ == "__main__":
infixtoPostfix(lex_input())
# well formed programs should leave a single value on the STACK
print "\nResult is:", STACK[-1]
</code></pre>
<p>如果我们给这个版本的程序提供语法错误:</p>
<pre><code>(dev) go|c:\srv> python rpn.py 34 4 + -
Detected Syntax Error at token no.: 4
34 4 + -
-^
Result is: SYNTAX ERROR
</code></pre>
<p>我们得到了一个正确的错误消息,带有一个小的尖尖的“图形”指示错误被检测到的位置。你知道吗</p>
<p>我们可以更进一步,因为我们知道所有的操作都在堆栈上包含两个元素,并给出更详细的错误消息,例如:</p>
<pre><code>Syntax Error at token "-": Stack underflow
The "-" operation requires two stack arguments and the stack
contained only one:
Stack token
-
[37] '-'
</code></pre>
<p>我将把它的实现作为一个练习。你知道吗</p>
<p>如您所见,即使在这个简单的示例中,错误处理代码也比求值代码多,这在编写简单的编译器时并不奇怪。你知道吗</p>