SHARE
TWEET

jetxee

a guest Sep 8th, 2009 635 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #!/usr/bin/env python
  2.  
  3. """
  4. Trying funcparserlib parser combinator library. I skip lexing step and
  5. use funcparserlib in pyparsing style (I had to define some one-line helpers to
  6. do so).
  7.  
  8. Number parsers:
  9.  
  10. Read sign of the number
  11. >>> [ sign.parse(c) for c in ["+42","42", "-42"] ]
  12. [1, 1, -1]
  13.  
  14. Parse integer
  15. >>> int_num.parse("-42")
  16. -42
  17.  
  18. Parse fractional number (float)
  19. >>> [ frac_num.parse(c) for c in ["-1.25", "1.25", "42"] ]
  20. [-1.25, 1.25, 42.0]
  21.  
  22. Helpers:
  23.  
  24. >>> to_int(['4','2'])
  25. 42
  26.  
  27. >>> powers(['4','2'])
  28. [('4', 1), ('2', 0)]
  29.  
  30. >>> add_digit(1,(2,3))
  31. 2001
  32.  
  33. Custom format parser:
  34.  
  35. Using `ws` to skip whitespaces
  36. >>> ws.parse("   ")
  37. _Ignored([' ', ' ', ' '])
  38.  
  39. Using `literal` to build literal parsers (to avoid explicit lexing)
  40. >>> literal("abc").parse("abc def")
  41. 'abc'
  42.  
  43. Packing a list of characters as a string
  44. >>> pack(['a','b','c'])
  45. 'abc'
  46.  
  47. Read a string of characters which satisfy given predicate
  48. >>> word(lambda c: c.isalpha() and c.isupper()).parse("ABCdef")
  49. 'ABC'
  50.  
  51. Read the rest of the input as a string
  52. >>> whatever.parse("abcdef")
  53. 'abcdef'
  54.  
  55. Finally,
  56. >>> raw = 'Inspection\\n#   2  SHOULD      Ref. Sys    1\\n' + \
  57.          'X 28.75 \\nY  78.500 \\nZ     -1.25 \\n\\n'
  58. >>> custom_format.parse(raw)
  59. (2, 1, [('X', 28.75), ('Y', 78.5), ('Z', -1.25)])
  60.  
  61.  
  62. """
  63.  
  64. import sys
  65. from funcparserlib.parser import *
  66.  
  67. ### helpers
  68.  
  69. powers = lambda digs: zip(digs,xrange(len(digs)-1,-1,-1))
  70. add_digit = lambda acc, dp: acc+int(dp[0])*10**dp[1]
  71. to_int = lambda digs: reduce(add_digit, powers(digs), 0)
  72. mk_int = lambda (s,i): s*i
  73. to_frac = lambda digs: to_int(digs)*1.0/10**len(digs)
  74. mk_frac = lambda (s,i,f): s*(i+f)
  75. pack = lambda cs: ''.join(cs)
  76.  
  77. ### parsers
  78.  
  79. sign = maybe(a("-")|a("+")) >> (lambda c: c == "-" and -1 or +1)
  80. digits = many(some(lambda c: c.isdigit()))
  81. int_num = sign + (digits >> to_int) >> mk_int
  82. frac_num = sign + (digits >> to_int) + (skip(maybe(a("."))) + (digits >> to_frac)) >> mk_frac
  83.  
  84. ws = skip(many(some(lambda c: c.isspace())))
  85. literal = lambda s: reduce(lambda a,b: a+b, map(a,s)) >> pack
  86. word = lambda p: oneplus(some(p)) >> pack
  87. whatever = word(lambda x:True)
  88.  
  89. ### custom format parser
  90.  
  91. varname = word(lambda c: c.isalpha())
  92. var = (ws + varname + ws + frac_num + ws)
  93.  
  94. custom_format = skip(literal("Inspection")) + \
  95.     ws + skip(literal("#")) + \
  96.     ws + int_num + \
  97.     ws + skip(literal("SHOULD")) + \
  98.     ws + skip(literal("Ref. Sys")) + \
  99.     ws + int_num + \
  100.     many(var)
  101.  
  102. if __name__ == '__main__':
  103.     if "--test" in sys.argv:
  104.         import doctest
  105.         doctest.testmod()
  106.     else:
  107.         raw = sys.stdin.read()
  108.         print custom_format.parse(raw)
RAW Paste Data
Top