3 import cPickle as pickle
6 from pyparsing import Word, CharsNotIn, Optional, OneOrMore, ZeroOrMore, Group, Forward, ParseException, Literal, Suppress, replaceWith, StringEnd, lineno, QuotedString, White, NotAny, ParserElement, MatchFirst
9 def __init__(self, s, loc, toks):
12 return "[%s]" % self.str
15 def argfun(s, loc, toks):
16 return Argument(s, loc, toks)
19 def __init__(self, s, loc, toks):
20 self.str = toks[0].asList()
22 return '{' + "".join([str(s) for s in self.str]) + '}'
23 return "{%s}" % self.str
25 return "".join([str(s) for s in self.str])
26 def paramfun(s, loc, toks):
27 return Parameter(s, loc, toks)
30 def __init__(self, s, loc, toks):
31 self.cmd = str(toks[0])[1:]
32 #print 'cmd', self.cmd
33 self.args = toks[1].asList()
34 self.params = toks[2].asList()
35 self.lineno = lineno(loc, s)
38 return '\\' + self.cmd + "".join([repr(a) for a in self.args]) + "".join([repr(p) for p in self.params])
40 class ZeroOrMoreAsList(ZeroOrMore):
41 def __init__(self, *args):
42 ZeroOrMore.__init__(self, *args)
43 def listify(s, loc, toks):
45 self.setParseAction(listify)
47 ParserElement.setDefaultWhitespaceChars("\n\t")
51 filler = CharsNotIn(backslash + '$')
52 filler2 = CharsNotIn(backslash + '$' + '{}')
54 arg = '[' + CharsNotIn("]") + ']'
55 arg.setParseAction(argfun)
57 dollarmath = QuotedString('$', multiline=True, unquoteResults=False)
58 param = Suppress(Literal('{')) + ZeroOrMoreAsList(dollarmath | filler2 | QuotedString('{', endQuoteChar='}', unquoteResults=False) | texcmd) + Suppress(Literal('}'))
59 param.setParseAction(paramfun)
60 def bs(c): return Literal("\\" + c)
61 singles = bs("[") | bs("]") | bs("{") | bs("}") | bs("\\") | bs("&") | bs("_") | bs(",") | bs("#") | bs("\n") | bs(";") | bs("|") | bs("%") | bs("*")
62 texcmd << (singles | Word("\\", "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", min = 2)) + ZeroOrMoreAsList(arg) + ZeroOrMoreAsList(param)
63 def texcmdfun(s, loc, toks):
64 return TexCmd(s, loc, toks)
65 texcmd.setParseAction(texcmdfun)
67 #legal = "".join([chr(x) for x in set(range(32, 127)) - set(backslash)])
69 document = ZeroOrMore(dollarmath | texcmd | filler) + StringEnd().suppress()
72 s = "This is \\\\ test"
74 for t in document.parseString(s):
75 if isinstance(t, TexCmd):
76 print '====> cmd=[%s]' % t.cmd, t
81 selfstr = open( __file__).read() # Own source as a string. Used as part of hash.
82 hashbase = hashlib.md5(selfstr)
84 def tokenize(filename):
85 f = open(filename, "rt")
88 if '%' in s and not '\\%' in s:
89 return s[:s.index('%')] + '\n'
93 docstr = "".join([uncomment(l) for l in f])
94 hash = hashbase.copy()
96 cache_filename = os.path.join("parse-cache", hash.hexdigest())
98 return pickle.load(open(cache_filename))
102 r = document.parseString(docstr)
104 if isinstance(x, TexCmd) and not x.filename:
105 x.filename = filename
106 pickle.dump(r, open(cache_filename, 'w'))
108 except ParseException, pe:
109 print 'Fatal problem at %s line %d col %d' % (filename, pe.lineno, pe.col)
113 def latexparser(filename):
114 tokens = tokenize(filename)
116 if isinstance(t, TexCmd) and t.cmd == "input":
117 filename = "../" + str(t.params[0].str[0]) + ".tex"
119 return latexparser(filename)
122 return sum([expand(t) for t in tokens], [])