2016-09-22 31 views
0

我想要一個Python函數,它將字符串命令轉換爲AST(抽象語法樹)。將簡單命令轉換爲python中的AST

該命令的語法如下:

commandName(3, "hello", 5.0, x::int) 

命令可以接受任何數量的逗號分隔值的,可以是任一

  1. 整數
  2. 字符串
  3. 浮標
  4. 類型

假設函數被調用convert_to_ast,然後

convert_to_ast('commandName(3, "hello", 5.0, x::int)') 

應該產生以下AST:

{ 
    'type': 'command', 
    'name': 'commandName', 
    'args': [{ 
    'type': 'int', 
    'value': 3 
    }, { 
    'type': 'str', 
    'value': 'Hello' 
    }, { 
    'type': 'float', 
    'value': 5.0 
    }, { 
    'type': 'var', 
    'kind': 'int', 
    'name': 'x 
    }] 
+0

我要澄清:元組顯示爲一個字符串,是一個較大的字符串,通常是一個命令如「加(1的一部分,」你好「,3)' – TheSeamau5

+0

我認爲唯一剩下的就是問什麼是_rules_來決定什麼是事情。例如說「int」是「類型」的規則是什麼?它是否與Python標識符一樣解析?和命令只是後面有()的標識符?在這種情況下,你仍然可以使用'AST'來解析這個(這很有趣)。 – mgilson

+0

好問題。我剛剛更新我的示例稍微複雜一些。我用「變量」替換「類型」。你會看到現在的語法不再是Python了。重點是我稍後將添加此命令可以接受的不同類型的數據,並且其語法不應與Python的語法綁定。 – TheSeamau5

回答

5

好像你可以只是評估字符串,然後從那裏摘掉類型:

>>> items = ast.literal_eval('(404.5, "Hello", 5)') 
>>> [{'type': type(item).__name__, 'value': item} for item in items] 
[{'type': 'float', 'value': 404.5}, {'type': 'str', 'value': 'Hello'}, {'type': 'int', 'value': 5}] 

當然,如果你想做更多有趣的事情,你可以訪問AST di rectly:

>>> ast.dump(ast.parse('(404.5, "Hello", 5)')) 
"Module(body=[Expr(value=Tuple(elts=[Num(n=404.5), Str(s='Hello'), Num(n=5)], ctx=Load()))])" 
>>> ast.parse('(404.5, "Hello", 5)').body[0].value.elts 
[<_ast.Num object at 0x107fa1250>, <_ast.Str object at 0x107fa1290>, <_ast.Num object at 0x107fa12d0>] 

對於除解析一個元組(如你加入到這個問題),我們仍然可以使用Python的AST解析這個更一般的事情(只要你的語法有效的Python) 。在這種情況下,我們將創建一個ast.NodeVisitor,它將提取我們在訪問我們關心的Python AST的每個節點時的信息。在這種情況下,我們關心CallNumStrName節點:

import ast 

class Parser(ast.NodeVisitor): 

    def __init__(self): 
     self.calls = [] 
     self.current_command = None 

    def visit_Call(self, node): 
     name = node.func.id 
     self.current_command = { 
      'type': 'command', 
      'name': name, 
      'args': [] 
     } 
     self.calls.append(self.current_command) 
     for arg in node.args: 
      self.visit(arg) 
     self.current_command = None 

    def visit_Num(self, node): 
     if not self.current_command: 
      return 
     args = self.current_command['args'] 
     arg = { 
      'type': type(node.n).__name__, 
      'value': node.n 
     } 
     args.append(arg) 

    def visit_Str(self, node): 
     if not self.current_command: 
      return 
     args = self.current_command['args'] 
     arg = { 
      'type': 'str', 
      'value': node.s 
     } 
     args.append(arg) 

    def visit_Name(self, node): 
     if not self.current_command: 
      return 
     args = self.current_command['args'] 
     arg = { 
      'type': 'type', 
      'kind': node.id 
     } 
     args.append(arg) 


S = 'commandName(3, "hello", 5.0, int)' 

tree = ast.parse(S) 
p = Parser() 
p.visit(tree) 
print p.calls 
+0

謝謝你的回答。這將是完全孤立的元組。我已更新我的問題以澄清細節。基本上,元組通常是一些較大字符串的一部分,通常作爲命令的參數。此外,元組中的所有類型都不是Python類型。我只說了Python類型來保持簡單的問題。 在任何情況下,有關更多詳細信息,請參閱我在問題中的上述編輯。再次,非常感謝您的答覆。 – TheSeamau5

+0

@ TheSeamau5 - 不幸的是,這仍然不是那麼清楚......看起來你只想在結果中使用python文字,並且沒有''的條目?這似乎是一個解析問題,其中很多東西是未定義的,確實是一個非常困難的問題:-) – mgilson

+0

我很抱歉。我把''放在那裏說我正在尋找一種解決方案,即使對於非Python類型的元素也是如此。無論那種類型是什麼,我都會通過解析來解決它。 – TheSeamau5