Now uses.py properly reads in tex (for its purposes)
[dwarf-doc.git] / dwarf5 / tools / uses.py
1 # Copyright 2012 DWARF Debugging Information Format Committee
2 #
3 # Handles the testing and update for all DW_* prefixes.
4 # Called by taglink and other convenience apps to do their work.
5 #
6 # Run as an app itself, the options are
7 #    python anylink [-t prefix] ... [-all] [file] ...
8 #    Use either -all or one or more -t, as in examples:
9 #    python anylink -t DW_ACCESS_ -t DW_OP_   test.in test2.in
10 #    python anylink -all    test.in test2.in 
11
12 import sys
13 import fileio
14
15 global linkdefinitionsdict
16 global linkusesdict
17 global labeldefinitionsdict
18 global labelusesdict
19 global ignorethesedict
20 global indexsetdict
21 global dupdefcount
22 global unresolveddwdict
23 # Links meaning \livelink \livetarg \livetargi macros
24 linkdefinitionsdict = {}
25 linkusesdict  = {}
26 # labels meaning \refersec (a ref) and \label  (a def)
27 labeldefinitionsdict = {}
28 labelusesdict =  {}
29 # The dict of indexed things.
30 indexsetdict ={}
31 # DW sorts of names not sensibly resolved.
32 unresolveddwdict = {}
33 dupdefcount = 0
34
35
36
37 # a list of words to ignore: silly stuff.
38 ignorethesedict = {"of":0, "a":0, "the":0, "and":0, "but":0,"DWARF":0,
39 "Standards":0,"Committee":0,"Version":0 }
40
41 class tokmention:
42   def __init__(self):
43     self._token = '' 
44     self._file = ""
45     self._line = 0
46     # Class is "id", "ind","other","none"
47   def __init__(self,tok,filename,line):
48     self._token = tok
49     self._file = filename
50     self._line = line
51
52
53
54
55 def ischar(tok,c):
56    if tok._class != "ind":
57       return "n"
58    if len(tok._tex) != 1:
59        return "n"
60    if tok._tex[0] != c:
61        return "n"
62    return "y"
63
64 def dwspace(tok):
65   if ischar(tok," ") == "y":
66     return "y"
67   if ischar(tok,"\t") == "y":
68     return "y"
69   return "n"
70   
71   
72 def isbrace(tok,brace):
73   if tok._class != "ind":
74      return "n"
75   if len(tok._tex) != 1:
76      return "n"
77   if brace == tok._tex[0]:
78      return "y"
79   return "n"
80
81
82 def pickup(linetoks,tnumin,pattern,myfile,linenum):
83   """ The token pattern characters are
84   i meaning identifier
85   [space] meaning whitespace
86   { meaning left brace
87   } meaning right brace
88   * meaning any token except } and end-line
89   
90   Precondition:  linetoks[tnumin] is identifier (meaning a command)
91   Returns: a token list, one per non-space in the pattern.
92      For the *, the token is itself a list of whatever it contains.
93   """
94   outtoks = []
95   numabsorbed = 1
96   inlen = len(linetoks) 
97   curnum = tnumin
98   curtok = linetoks[curnum]
99   outtoks += [curtok]
100   patterncharnum = -1
101   for c in pattern:
102     patterncharnum = patterncharnum + 1
103     if curnum >= inlen:
104       print "ERROR line ended surprisingly, pattern ", pattern,"  line ",linenum," file ",myfile._name
105       return outtoks,numabsorbed
106     curtok = linetoks[curnum]
107     if c == " ":
108       while dwspace(curtok) == "y":
109         curnum = curnum + 1
110         if curnum >= inlen:
111           print "ERROR line ended surprisingly in space, pattern ", pattern, " line ",linenum," file ",myfile._name
112           return outtoks,numabsorbed
113         numabsorbed = numabsorbed + 1
114         curtok = linetoks[curnum]
115       continue
116     elif c == "i":
117       if curtok._class != "id":
118         print "ERROR line  expected identifier got ",curtok._tex, "pattern" , pattern, " line " ,linenum," file ",myfile._name
119         return outtoks,numabsorbed
120       numabsorbed = numabsorbed + 1
121       outtoks += [curtok]
122       curnum = curnum + 1
123       continue
124     elif c == "{":
125       if isbrace(curtok,"{")  == "y":
126         outtoks += [curtok]
127         curnum = curnum + 1
128         numabsorbed = numabsorbed + 1
129       else:
130         print "ERROR line  expected {  got ",curtok._tex," pattern ",pattern," line " ,linenum," file ",myfile._name
131         return outtoks,numabsorbed
132     elif c == "}":
133       if isbrace(curtok,"}")  == "y":
134         outtoks += [curtok]
135         curnum = curnum + 1
136         numabsorbed = numabsorbed + 1
137       else:
138         print "ERROR line  expected }  got ",curtok._tex,"pattern",pattern," line " ,linenum," file ",myfile._name
139         return outtoks,numabsorbed
140     elif c == "*":
141       outlist = []
142       curtok = linetoks[curnum]
143       while isbrace(curtok,"}") == "n":
144         if dwspace(curtok) == "n":
145            outlist += [curtok]
146         curnum = curnum + 1
147         if curnum >= inlen:
148           outtoks += [outlist]
149           if patterncharnum < (len(pattern) -1): 
150             print "ERROR insufficient tokens on line for pattern ", pattern," line " ,linenum," file ",myfile._name
151           return outtoks,numabsorbed
152         numabsorbed = numabsorbed + 1
153         curtok = linetoks[curnum]
154       # Found a right brace, so done here.
155       outtoks += [outlist]
156     else:
157         print "ERROR pattern had unexpected character ",pattern
158         sys.exit(1)
159   return outtoks,numabsorbed
160
161 def reftodict(d,k,v):
162   keystring = ''.join(k._token._tex)
163   if d.has_key(keystring) == 0:
164      d[keystring] =  [v]
165   else:
166      existing = d.get(keystring)
167      existing += [v]
168      d[keystring] =  existing
169
170 def deftodict(d,k,v):
171   global dupdefcount
172   keystring = ''.join(k._token._tex)
173   if d.has_key(keystring) == 0:
174      d[keystring] =  [v]
175   else:
176      # This is a duplication, we just record it here,
177      # we will report on it shortly.
178      dupdefcount = dupdefcount + 1
179      existing = d.get(keystring)
180      existing += [v]
181      d[keystring] =  existing
182
183 def livetargprocess(linetoks,tnumin,myfile,linenum):
184   """ \livetarg{chap:DWTAGtemplatevalueparameter}{DW\-\_TAG\-\_template\-\_value\-\_parameter} """
185   global linkdefinitionsdict
186   global linkusesdict
187   global indexsetdict
188   t = linetoks[tnumin]
189   ourtoks,inlen = pickup(linetoks,tnumin,"i { i } { i }",myfile,linenum)
190   if len(ourtoks) > 5:
191     targlink= tokmention(ourtoks[2],myfile,linenum)
192     targname= tokmention(ourtoks[5],myfile,linenum)
193     deftodict(linkdefinitionsdict,targlink,targname)
194     reftodict(indexsetdict,targname,targname)
195   return inlen
196 def livetargiprocess(linetoks,tnumin,myfile,linenum):
197   """ \livetargi{chap:DWTAGtemplatevalueparameter}{DW\-\_TAG\-\_template\-\_value\-\_parameter}{name of targ} """
198   global linkdefinitionsdict
199   global linkusesdict
200   global indexsetdict
201   t = linetoks[tnumin]
202   ourtoks,inlen = pickup(linetoks,tnumin,"i { i } { i } { * }",myfile,linenum)
203   if len(ourtoks) > 5:
204     targlink= tokmention(ourtoks[2],myfile,linenum)
205     targname= tokmention(ourtoks[5],myfile,linenum)
206     deftodict(linkdefinitionsdict,targlink,targname)
207     reftodict(indexsetdict,targname,targname)
208   return inlen
209 def livelinkprocess(linetoks,tnumin,myfile,linenum):
210   """ \livelink{chap:DWTAGtemplatevalueparameter}{DW\-\_TAG\-\_template\-\_value\-\_parameter} """
211   global linkdefinitionsdict
212   global linkusesdict
213   global indexsetdict
214   t = linetoks[tnumin]
215   ourtoks,inlen = pickup(linetoks,tnumin,"i { i } { i }",myfile,linenum)
216   if len(ourtoks) > 5:
217     targlink= tokmention(ourtoks[2],myfile,linenum)
218     targname= tokmention(ourtoks[5],myfile,linenum)
219     reftodict(linkusesdict,targlink,targname)
220     reftodict(indexsetdict,targname,targname)
221   return inlen
222 def labelprocess(linetoks,tnumin,myfile,linenum):
223   """ \label{alabel} """
224   global labeldefinitionsdict
225   t = linetoks[tnumin]
226   ourtoks,inlen = pickup(linetoks,tnumin,"i { i }",myfile,linenum)
227   if len(ourtoks) > 2:
228     label = tokmention(ourtoks[2],myfile,linenum)
229     deftodict(labeldefinitionsdict,label,label)
230   return inlen
231 def addtoindexprocess(linetoks,tnumin,myfile,linenum):
232   """ \addtoindex{alabel} """
233   t = linetoks[tnumin]
234   ourtoks,inlen = pickup(linetoks,tnumin,"i { i }",myfile,linenum)
235   if len(ourtoks) > 2:
236     index = tokmention(ourtoks[2],myfile,linenum)
237     reftodict(indexsetdict,index,index)
238   return inlen
239 def indexprocess(linetoks,tnumin,myfile,linenum):
240   """ \index{indexentryname} """
241   global labelusesdict
242   t = linetoks[tnumin]
243   ourtoks,inlen = pickup(linetoks,tnumin,"i { i }",myfile,linenum)
244   if len(ourtoks) > 2:
245     myentry = tokmention(ourtoks[2],myfile,linenum)
246     reftodict(indexsetdict,myentry,myentry)
247   return inlen
248 def refersecprocess(linetoks,tnumin,myfile,linenum):
249   """ \refersec{label} """
250   global labelusesdict
251   t = linetoks[tnumin]
252   ourtoks,inlen = pickup(linetoks,tnumin,"i { i }",myfile,linenum)
253   if len(ourtoks) > 2:
254     label = tokmention(ourtoks[2],myfile,linenum)
255     reftodict(labelusesdict,label,label)
256   return inlen
257
258 def transfunc(linetoks,myfile,linenum):
259   if len(linetoks) < 1:
260     return linetoks
261   initialtok = linetoks[0]
262   if ''.join(initialtok._tex) == "\\newcommand":
263     # We ignore newcommand lines, they are not stuff
264     # we want to look at, they are new macros, not macro uses.
265     # We don't want to transform or touch them, nor report on them.
266     return linetoks
267   tnumin = 0
268   lasttoknum = len(linetoks)
269   while tnumin < lasttoknum:
270     t = linetoks[tnumin]
271     tnumcount = 1
272     rawtok = ''.join(t._tex)
273     stdname= ''.join(t._std)
274     if rawtok == "\\livetarg":
275       tnumcount = livetargprocess(linetoks,tnumin,myfile,linenum)
276     elif rawtok == "\\livetargi":
277       tnumcount = livetargiprocess(linetoks,tnumin,myfile,linenum)
278     elif rawtok == "\\livelink":
279       tnumcount = livelinkprocess(linetoks,tnumin,myfile,linenum)
280     elif rawtok == "\\label":
281       tnumcount = labelprocess(linetoks,tnumin,myfile,linenum)
282     elif rawtok == "\\refersec":
283       tnumcount = refersecprocess(linetoks,tnumin,myfile,linenum)
284     elif rawtok == "\\addtoindex":
285       tnumcount = addtoindexprocess(linetoks,tnumin,myfile,linenum)
286     elif rawtok == "\\index":
287       tnumcount = indexprocess(linetoks,tnumin,myfile,linenum)
288     else:  
289       if t._class == "id":
290         namemention = tokmention(t,myfile,linenum)
291         namestring = ''.join(t._std)
292         if namestring.startswith("DW"):
293           global unresolveddwdict
294           reftodict(unresolveddwdict,namemention,namemention)
295         # Else we might want to build a dict of all other words 
296         # while leaving out all \latex commands we don't know?
297     tnumin = tnumin + tnumcount
298     # End of for loop.
299   return linetoks
300
301 def process_files(filelist):
302   dwf = fileio.readFilelist(filelist)
303   # We will really just report, not transform
304   # anything, but this works.
305   dwf.dwtransformline(transfunc)
306
307   # Here we report on our discoveries.
308
309 def read_file_args(targlist):
310   cur = 1
311   filelist = []
312   while  len(sys.argv) > cur:
313     v = sys.argv[cur]
314     filelist += [v]
315     cur = int(cur) + 1
316   process_files(filelist)
317   
318
319
320
321 def read_all_args():
322   filelist = []
323   fileio.setkeepordeletecomments("d")
324   cur = 1
325   while  len(sys.argv) > cur:
326     v = sys.argv[cur]
327     filelist += [v]
328     cur = int(cur) + 1
329   if len(filelist) < 1:
330     print >> sys.stderr , "No files specified."
331     printlegals()
332     sys.exit(1)
333   process_files(filelist)
334
335 #  anylink [-t <class>] ... [file] ...
336
337 if __name__ == '__main__':
338   read_all_args()
339