2012-07-09 74 views
2

对于个人项目,我需要编写一个简单的词法分析器来处理用户输入命令。它们可以包含四种模式和支架:如何在Python中为用户输入命令编写简单的词法分析器/解析器?

  • 运营商:.+-%
  • 名([A-ZA-Z0-9]):例如foobarfooZbar2
  • 过滤器([AZ] {1} “[一些文本]”):例如a"hello world"p"escaped \"string\""
  • 其他过滤器([AZ] {1}〜 “[一些文本]”):例如a~"hello world"p~"escaped \"string\""

我想为了有一个分级列表(根据括号)拆分命令包含每个运营商的条目,每个名称的条目(单个字符串),并为每个过滤器的项(字典,例如{'a': 'hello world'}{'p~': 'escaped "string"'})。

所以这里是什么,我想用这个输入一个例子(各地运营空间是可选):

foo . bar - (a"hello \"world\"" % (b~"foo" + bar) . (fooZ.(bar2+(c"foo bar".d"bar foo"))))

[ 
    'foo', 
    '.', 
    'bar', 
    '-', 
    [ 
    {'a': 'hello "world"'}, 
    '%', 
    [ 
     {'b~': 'foo'}, 
     '+', 
     'bar' 
    ] 
    '.', 
    [ 
     'fooZ', 
     '.', 
     [ 
     'bar2', 
     '+', 
     [ 
      {'c': 'foo bar'}, 
      '.', 
      {'d': 'bar foo'} 
     ] 
     ] 
    ] 
    ] 
] 

我看了一下pyparsing,厚度,pyPEG,Yapps,等等,但他们都似乎很难使用,我不知道我是否需要这种工具,因为我需要的语法不是很复杂。在此先感谢您的建议!

+2

这是更好地使用的工具,用于分析一个,无论多么简单的语法如下:)这方式,如果需要,您可以轻松扩展到未来的需求。我会推荐Python PLY :) – 2012-07-09 12:03:54

+0

这是一个个人项目更多沿着学习如何解析?或者,它只是解析输入然后用它做什么?取决于哪一个会根据您想要使用的内容而有所不同。第一个说实话更有趣,虽然是的,你正在重塑一匹非常彪悍的马匹,但有助于个人的理解。 – sean 2012-07-09 13:00:35

+0

感谢Mihai,我会尝试深入PLY。 – Nicolas 2012-07-09 13:13:11

回答

3

看到这个pyparsing解决方案如何满足您所陈述的语法:

from pyparsing import * 
ParserElement.enablePackrat() 
import string 

name = Word(alphanums) 

filter = (Combine(oneOf(list(string.ascii_lowercase)) + Optional('~')) + 
      dblQuotedString.setParseAction(removeQuotes)) 
# convert parsed filter to dict 
filter.setParseAction(lambda t:{t[0]:t[1]}) 

expr = operatorPrecedence(filter | name, 
      [ 
      (oneOf('. % -'), 2, opAssoc.LEFT), 
      ('+', 2, opAssoc.LEFT), 
      ]) 

test = r'foo . bar - (a"hello \"world\"" % (b~"foo" + bar) . (fooZ.(bar2+(c"foo bar".d"bar foo"))))' 

print expr.parseString(test, parseAll=True).asList() 

打印:

[['foo', 
    '.', 
    'bar', 
    '-', 
    [{'a': 'hello \\"world\\"'}, 
    '%', 
    [{'b~': 'foo'}, '+', 'bar'], 
    '.', 
    ['fooZ', '.', ['bar2', '+', [{'c': 'foo bar'}, '.', {'d': 'bar foo'}]]]]]] 
+0

非常有趣,非常感谢! – Nicolas 2012-07-09 13:59:41

+0

现在我不太确定一个操作符的优先级高于另一个操作符的优先级,因此示例中的分组可能只是归因于括号嵌套。如果是这种情况,您可以将'operatorPrecedence'中的两个级别合并到'(oneOf('。%+ - '),2,opAssoc.LEFT)'。 – PaulMcG 2012-07-09 14:18:47