2012-12-02 72 views
1

作爲一個任務,我必須寫一個計算器,將接受並解決用戶的輸入,如:使用遞歸解決用戶輸入表達式(計算器)

3 + 7 * (!3)^2 

必須解決本練習與遞歸

def solve(exp): 
    #Recursion if statement 
    for op in exp: 
     if op == "*": 
      ... 
     elif op == "/": 
      ... 
     ... 
    return solve(exp) 

這是我如何認爲我的代碼看起來像,但我無法決定什麼是遞歸的停止條件。
此外,我不確定這種循環是否有用,因爲我將無法處理多個案例,例如-3 +5或處理括號的使用。

我認爲我的關於如何解決這個問題的基本想法並不好,我想獲得關於如何做到這一點的建議。

+1

提示:把它變成一棵樹。你必須解析你的輸入。 http://penguin.ewu.edu/cscd300/Topic/ExpressionTree/index.html這不是一個簡單的任務。這類問題是在理論計算機科學課上學到的。但它仍然是可行的。閱讀網頁,看看您是否可以從java代碼中獲得洞察力。 – User007

+1

此外,遞歸意味着你有一些基本情況。如果你打算在'if-else'語句中再次調用'solve(..)',你實際上並沒有做正確的遞歸。首先使用're'庫解析它。 – User007

回答

0

兩點意見:

  1. 您當前的解決方案將不會返回任何有趣的,實際上它似乎循環無限,爲你傳遞給遞歸的下一階段exp不同於這是在傳遞不變原來,進一步沒有跡象表明任何一個循環通過遞歸實際上對最終解決方案都有影響。
  2. 停止條件應該是一個空的表達式,也就是說,如果您將表達式存儲爲字符串,它應該是「」。
3

烏姆魯解析使用「標準」的語法的表達式(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)) 

注意:這還沒有被測試!

+2

使用LL1語法的遞歸下降解析是最好的選擇。榮譽samy – davec

+0

莉奧說:「我必須解決這個練習與遞歸」。這有助於* Lior * **解決**這個練習。這可能是一個很好的答案,但你已經離開了莉奧沒有什麼可做的,只是複製並粘貼它。我相信這位大學教授也有一個答案,他/她可以與全班分享。我相信回答這些問題的正確方法是提供指導,但不是完整的答案。我很欣賞這樣的努力,不要誤會我的意思,但我認爲你做得太過分了,這對其他學生來說都是不公平的,對Lior的學習不利。 –

+0

就像我說過的,我通常不會這樣做,我認爲鏈接和語法已經足夠了。我花了很多時間來處理這些東西,理論很棒,但是他們的正確用詞(以及相當多的數學:)),看到從語法到代碼的實際翻譯應該幫助他建立他的編譯器,這個任務往往是第一個階段,他可以自由複製/粘貼,儘管我不認爲他會盲目地從他提出的類型問題,他的代表狀態和初始代碼中完成任務,但他可能會解剖和理解代碼,正如大多數人所認爲的,IMO –