2012-06-13 20 views
0

朋友。任何用於定製BNF解析器的python模塊?

我有一個'make'風格的文件需要解析。語法是這樣的:

samtools=/path/to/samtools 
picard=/path/to/picard 

task1: 
    des: description 
    path: /path/to/task1 
    para: [$global.samtools, 
      $args.input, 
      $path 
      ] 

task2: task1 

$global包含在全局範圍內定義的變量。 $path是一個'本地'變量。 $args包含用戶傳入的鍵/值對。

我想通過一些python庫解析這個文件。最好返回一些分析樹。如果有一些錯誤,最好報告。我發現這一個:CodeTalkeryeanpypa。他們可以在這種情況下使用嗎?還有其他建議嗎?

回答

6

我猜你的makefile結構允許根據你的榜樣是什麼,但是這應該讓你關閉:

from pyparsing import * 
# elements of the makefile are delimited by line, so we must 
# define skippable whitespace to include just spaces and tabs 
ParserElement.setDefaultWhitespaceChars(' \t') 
NL = LineEnd().suppress() 

EQ,COLON,LBRACK,RBRACK = map(Suppress, "=:[]") 
identifier = Word(alphas+'_', alphanums) 

symbol_assignment = Group(identifier("name") + EQ + empty + 
          restOfLine("value"))("symbol_assignment") 
symbol_ref = Word("$",alphanums+"_.") 

def only_column_one(s,l,t): 
    if col(l,s) != 1: 
     raise ParseException(s,l,"not in column 1") 
# task identifiers have to start in column 1 
task_identifier = identifier.copy().setParseAction(only_column_one) 

task_description = "des:" + empty + restOfLine("des") 
task_path = "path:" + empty + restOfLine("path") 
task_para_body = delimitedList(symbol_ref) 
task_para = "para:" + LBRACK + task_para_body("para") + RBRACK 
task_para.ignore(NL) 
task_definition = Group(task_identifier("target") + COLON + 
     Optional(delimitedList(identifier))("deps") + NL + 
     (
     Optional(task_description + NL) & 
     Optional(task_path + NL) & 
     Optional(task_para + NL) 
     ) 
    )("task_definition") 

makefile_parser = ZeroOrMore(
    symbol_assignment | 
    task_definition | 
    NL 
    ) 


if __name__ == "__main__": 
    test = """\ 
samtools=/path/to/samtools 
picard=/path/to/picard 

task1: 
    des: description 
    path: /path/to/task1 
    para: [$global.samtools, 
      $args.input, 
      $path 
      ] 

task2: task1 
""" 

# dump out what we parsed, including results names 
for element in makefile_parser.parseString(test): 
    print element.getName() 
    print element.dump() 
    print 

打印:

symbol_assignment 
['samtools', '/path/to/samtools'] 
- name: samtools 
- value: /path/to/samtools 

symbol_assignment 
['picard', '/path/to/picard'] 
- name: picard 
- value: /path/to/picard 

task_definition 
['task1', 'des:', 'description ', 'path:', '/path/to/task1 ', 'para:', 
'$global.samtools', '$args.input', '$path'] 
- des: description 
- para: ['$global.samtools', '$args.input', '$path'] 
- path: /path/to/task1 
- target: task1 

task_definition 
['task2', 'task1'] 
- deps: ['task1'] 
- target: task2 

轉儲()輸出顯示你什麼名字你可以使用它來獲取解析元素中的字段,或者區分你擁有什麼樣的元素。 dump()是一個方便的通用工具,用於輸出pyparsing解析出的任何內容。下面是一些代碼,更具體到您的特定的解析器,展示瞭如何使用字段名稱要麼虛對象引用(element.targetelement.depselement.name等)或字典樣式引用(element[key]):

for element in makefile_parser.parseString(test): 
    if element.getName() == 'task_definition': 
     print "TASK:", element.target, 
     if element.deps: 
      print "DEPS:(" + ','.join(element.deps) + ")" 
     else: 
      print 
     for key in ('des', 'path', 'para'): 
      if key in element: 
       print " ", key.upper()+":", element[key] 

    elif element.getName() == 'symbol_assignment': 
     print "SYM:", element.name, "->", element.value 

打印:

SYM: samtools -> /path/to/samtools 
SYM: picard -> /path/to/picard 
TASK: task1 
    DES: description 
    PATH: /path/to/task1 
    PARA: ['$global.samtools', '$args.input', '$path'] 
TASK: task2 DEPS:(task1)