烏姆魯解析使用「標準」的語法的表達式(S),通過遞歸體面實際上是不可能的:
E = E + E | E - E | ... | VALUE
這是因爲主叫E
可以產生無限遞歸,還有其它問題,例如作爲運算符優先級以及相關性...
有兩種衆所周知的處理這些問題的方法,實際上這兩種方法都適用於大多數問題。
1)使用自下而上的方法,一個例子是shift-reduce解析http://en.wikipedia.org/wiki/Shift-reduce_parser這種方法保持您的語法的代碼複雜性的代價。
2)使用自上而下的方法,其中一個例子是遞歸不錯,但有不同的語法,http://en.wikipedia.org/wiki/LL_parser一個沒有左遞歸這通常是通過修改原有的語法和更新移除任何直接左遞歸調用所有規則進行。這會修改語法(如果可能的話),使其更長,但代碼更簡單。
由於您要求該方法是遞歸的,也許第二種方法是更好的方法。
我們首先必須定義這個新的語法,並簡單地爲每個規則創建一個新的函數。
你給出了這個例子:3 + 7 * (!3)^2
所以我按照優先級從高到低的順序推導出下面的運算符。
這裏是一個簡單的,衆所周知的LL(1)語法,它保持着優先...
<arith_expr> : <term> {+ <term>}
| <term> {- <term>}
<term> : <power> {* <power>}
| <power> {/ <power>}
<power> : <factor> <exponent>
<exponent> :^<factor> <exponent> | ''
<factor> | NUMERIC_VALUE
| - <factor>
| ! <factor>
| (<arith_expr>)
它的一些東西相當於以前的語法,但並沒有直接左遞歸調用,語法轉換爲LL(*)語法是有點機械的過程...
我通常穿上」不要給出任務代碼,特別簡單的代碼,但這只是爲了讓你開始,你應該能夠實現其餘部分。
因爲一般白色空間是被忽略的,所以我們將輸入量化爲一組適用於我們語法規則的值,排除任何空白,除非我們的語法規定它否則,這個過程被稱爲tokin化,每個值被引用作爲標記,而通常使用正則表達式這一點,我更喜歡手動方法的可讀性... Tokinization很簡單...
"""
`{}` means 0 or more
<arith_expr> : <term> {+ <term>}
| <term> {- <term>}
<term> : <factor> {* <factor>}
<factor> | NUMERIC_VALUE
| - <factor>
| (<arith_expr>)
"""
import string
def evaluate(str_value):
def tokenize(value):
all_symbols = set(('+', '-', '*',)) | set(('(', ')'))
white_space = set((' ', '\n', '\t'))
tokens = []
index = 0
while index < len(value):
current_char = value[index]
if current_char in white_space:
index += 1
continue
if current_char in all_symbols:
tokens.append(current_char)
index += 1
continue
if (current_char in string.digits) or (current_char == '.'):
numeric_value = current_char
index += 1
while (index < len(value)) and ((value[index] in string.digits) or (value[index] == '.')):
if (values[index] == '.') and ('.' in numeric_value):
raise Exception('Multiple decimal points detected while tokenizing numeric value!')
numeric_value.append(value[index])
index += 1
tokens.append(float(numeric_value) if '.' in numeric_value else int(numeric_value))
continue
raise Exception('Unable to tokenize symbol %s' % value[index])
return tokens
def factor(tokens):
'''
<factor> | NUMERIC_VALUE
| - <factor>
| (<arith_expr>)
'''
if not tokens:
return None
if type(tokens[0]) in set((int, float)): # NUMERIC_VALUE
return tokens.pop(0)
if tokens[0] == '-': # - <factor>
tokens.pop(0)
return -1 * factor(tokens)
if tokens[0] == '(': # (<arith_expr>)
tokens.pop(0)
value = arith_expr(tokens)
assert tokens.pop(0) == ')'
return value
def term(tokens):
'''
<term> : <factor> {* <factor>}
'''
left_value = factor(tokens)
operators = set(('*',))
while tokens and (tokens[0] in operators): # {* <factor>}
op = tokens.pop(0)
right_value = factor(tokens)
left_value *= right_value
return left_value
def arith_expr(tokens):
'''
<arith_expr> : <term> {+ <term>}
| <term> {- <term>}
'''
left_value = term(tokens)
operators = set(('+', '-'))
while tokens and (tokens[0] in operators):
op = tokens.pop(0)
right_value = term(tokens)
if op == '+':
left_value += right_value
else:
left_value -= right_value
return left_value
return arith_expr(tokenize(str_value))
注意:這還沒有被測試!
提示:把它變成一棵樹。你必須解析你的輸入。 http://penguin.ewu.edu/cscd300/Topic/ExpressionTree/index.html這不是一個簡單的任務。這類問題是在理論計算機科學課上學到的。但它仍然是可行的。閱讀網頁,看看您是否可以從java代碼中獲得洞察力。 – User007
此外,遞歸意味着你有一些基本情況。如果你打算在'if-else'語句中再次調用'solve(..)',你實際上並沒有做正確的遞歸。首先使用're'庫解析它。 – User007