tools/fileio.py was not tokenizing
[dwarf-doc.git] / dwarf5 / tools / fileio.py
1 # Copyright 2012 DWARF Debugging Information Format Committee
2
3 # All the little classes used in storing latex source data.
4 # Reads in the tex source and builds internal lists of the
5 # tokenized source.  The tokenization is adequate
6 # for our purposes, but just barely adequate.
7
8 import sys
9
10 # Keep if  "k" 
11 # Otherwise delete.
12 global keepcomments
13 keepcomments = "k"
14
15 def isIdStart(c):
16   if isIndivid(c) == "y":
17     return "n"
18   if  ord(c) >= ord('a') and ord(c) <= ord('z'):
19     return "y"
20   if  ord(c) >= ord('A') and ord(c) <= ord('Z'):
21     return "y"
22   # It is tex/latex, so backslash starts a word.
23   if c == "\\":
24     return "y"
25   if c == "_":
26     return "y"
27   return "n"
28
29 def isIdNext(c):
30   if isIndivid(c) == "y":
31     return "n"
32   if  ord(c) >= ord('a') and ord(c) <= ord('z'):
33     return "y"
34   if  ord(c) >= ord('A') and ord(c) <= ord('Z'):
35     return "y"
36   if  ord(c) >= ord('0') and ord(c) <= ord('9'):
37     return "y"
38   # This is so we allow the colon in our tags
39   # Unfortunately, this gives trouble if we have a
40   # : at the end of a DW* name on input.
41   if c == ":":
42     return "y"
43   # Do not allow \ in the middle of a name.
44   if c == "\\":
45     return "n"
46   if c == "-":
47     return "y"
48   if c == "_":
49     return "y"
50   return "n"
51 def isShift(c):
52   if ord(c) >= 128:
53     return "y"
54   return "n"
55 def isIndivid(c):
56   if c == "[":
57     return "y"
58   if c == "]":
59     return "y"
60   if c == "{":
61     return "y"
62   if c == "}":
63     return "y"
64   if c == " ":
65     return "y"
66   if c == "\t":
67     return "y"
68   return "n"
69
70 # self._tex        DW\-\_ATE and the like
71 # self._underbar   DW\_ATE  and the like
72 # self._std   the way a DW_ATE and the like looks in the standard
73 # self._label With all _ and - removed.  Like DWATE
74
75 class dwtoken:
76   """ Token types: 
77   id: identifier
78   ind: a character taken as an individual character.
79   none: No characters seen yet.
80   shift: A character with the high bit of 8 bits set, not something we expect.
81   -      In DW4 these high-bit-chars are special 3-character left and right quotes.
82   -      charfix.py  can replace these with Latex ascii quotes.
83   other: Some other character, but ascii, seemingly.  """
84   def __init__(self):
85     self._tex = []
86     self._underbar = []
87     self._std = []
88     self._label = []
89     # Class is "id", "ind","other","shift","none"
90     self._class = "none"
91     self._linenum = 0
92   def insertid(self,string,line):
93     self._class =  "id"
94     self._tex = list(string)
95     self._underbar = self._tex
96     self._std = self._tex
97     self._label = self._tex
98     self._linenum = line
99   def setIndivid(self,c,line):
100     self._tex = [c]
101     self._underbar = [c]
102     self._std = [c]
103     self._label = [c]
104     self._class =  "ind"
105     self._linenum = line
106   def setInitialIdChar(self,c,line):
107     self._tex = [c]
108     self._class =  "id"
109     self._linenum = line
110   def setNextIdChar(self,c):
111     self._tex += [c]
112
113   def setInitialShift(self,c,line):
114     self._tex = [c]
115     self._underbar = [c]
116     self._std = [c]
117     self._label = [c]
118     self._class =  "shift"
119     self._linenum = line
120   def setNextShift(self,c):
121     self._tex += [c]
122     self._underbar += [c]
123     self._std += [c]
124     self._label += [c]
125     self._class =  "shift"
126   def setInitialOther(self,c,line):
127     self._tex = [c]
128     self._underbar = [c]
129     self._std = [c]
130     self._label = [c]
131     self._class =  "other"
132     self._linenum = line
133   def setNextOther(self,c):
134     self._tex += [c]
135     self._underbar += [c]
136     self._std += [c]
137     self._label += [c]
138     self._class =  "other"
139   def finishUpId(self):
140     """ This transforms the strings from the input form into
141         the internal forms we want.
142     """
143     self._underbar = []
144     self._std = []
145     self._label = []
146     n = 0
147     # Drop \-
148     while int(n) < len(self._tex):
149       c = self._tex[n]
150       if n < (len (self._tex) - 1) and c == "\\" and self._tex[n+1] == "-":
151         n = n +2
152         continue
153       self._underbar += [c]
154       n = n +1
155     # Drop \ from \_
156     n = 0
157     while int(n) < len(self._underbar):
158       c = self._underbar[n]
159       if n < (len (self._underbar) - 1) and c == "\\" and self._underbar[n+1] == "_":
160         n = n +1
161         continue
162       self._std += [c]
163       n = n +1
164     # Drop  underbar
165     n = 0
166     while int(n) < len(self._std):
167       c = self._std[n]
168       if  c == "_":
169         n = n +1
170         continue
171       self._label += [c]
172       n = n +1
173
174   def dwprintquotedshortform(self,d):
175       print "'",self.shortform(d),"'",
176   def shortform(self,d):
177       return ''.join(d)
178   def dwprint(self):
179     if self._class == "ind":
180       print self._class, 
181       self.dwprintquotedshortform(self._tex)
182       print ""
183     else:
184       # This prints the token with end-line oddly.
185       print self._class, 
186       self.dwprintquotedshortform(self._tex)
187       self.dwprintquotedshortform(self._underbar)
188       self.dwprintquotedshortform(self._std)
189       self.dwprintquotedshortform(self._label)
190       print ""
191   def dwwrite(self,outfile):
192     for x in self._tex:
193       outfile.write(x)
194
195 class  dwline:
196   """using an input line, create a list of tokens for the line.
197      Legal class transitions in tokenize() are:
198      none->shift
199      none->other
200      none->id
201      none->ind
202
203      other->ind
204      other->id
205      other->shift
206
207      shift->id
208      shift->ind
209      shift->other
210
211      id->ind
212      id->other
213      id->shift
214   """
215   def __init__(self):
216     # list of dwtoken.
217     self._toks = []
218
219   
220   def tokenize(self,rec,filename,linenum):
221     """using an input line, create a list of tokens for the line.
222        Legal class transitions in tokenize() are:
223        none->other
224        none->id
225        none->ind
226        other->ind
227        other->id
228        id->ind
229        id->id  
230        id->other
231     """
232     dwclass = "none"
233     combotok = dwtoken()
234     charnum= -1 
235     global keepcomments
236     for c in rec:
237       charnum = charnum +1
238       if ord(c) >= 128:
239         print " Warning: encountered character ord:",ord(c), "at offset",charnum,"line",linenum,filename
240       if keepcomments == "d" and c == "%" and ( charnum == 0 or rec[charnum - 1] != "\\" ):  
241         # Not keeping comments. We drop % and following to end of line 
242         # unless preceeded by \ 
243         break
244
245       if c == "\n" or c == "\r":
246           # Just drop these for now. Allowing them
247           # would not be harmful.
248           continue
249       elif dwclass == "none" or dwclass == "ind":
250         if isShift(c) == "y":
251           combotok.setInitialShift(c,linenum)
252           dwclass = "shift"
253           continue
254         if isIndivid(c) == "y":
255           a = dwtoken()
256           a.setIndivid(c,linenum);
257           self._toks += [a]
258           continue
259         if isIdStart(c) == "y":
260           combotok.setInitialIdChar(c,linenum)
261           dwclass = "id"
262           continue
263         # is "other"
264         combotok.setInitialOther(c,linenum)
265         dwclass = "other"
266         continue
267       elif dwclass == "id": 
268         if isIdNext(c) == "y":
269           combotok.setNextIdChar(c)
270           continue
271         if isShift(c) == "y":
272           combotok.finishUpId()
273           self._toks += [combotok]
274           combotok = dwtoken()
275           combotok.setInitialShift(c,linenum);
276           dwclass = "shift"
277           continue
278         if isIndivid(c) == "y":
279           combotok.finishUpId()
280           self._toks += [combotok]
281           combotok = dwtoken()
282           a = dwtoken()
283           a.setIndivid(c,linenum);
284           dwclass = "ind"
285           self._toks += [a]
286           continue
287         if isIdStart(c) == "y":
288           # It is a valid initial character of an id.
289           # So we have id following id, like \a\a  
290           combotok.finishUpId()
291           self._toks += [combotok]
292           combotok = dwtoken()
293           combotok.setInitialIdChar(c,linenum)
294           dwclass = "id"
295           continue
296         # Other class input, other starts here.
297         combotok.finishUpId()
298         self._toks += [combotok]
299         combotok = dwtoken()
300         combotok.setInitialOther(c,linenum);
301         dwclass = "other"
302         continue
303       elif dwclass == "shift":
304         if isShift(c) == "y":
305           combotok.setNextShift(c);
306           continue
307         if isIndivid(c) == "y":
308           self._toks += [combotok]
309           combotok = dwtoken()
310           a = dwtoken()
311           a.setIndivid(c,linenum);
312           dwclass = "ind"
313           self._toks += [a]
314           continue
315         if isIdStart(c) == "y":
316           self._toks += [combotok]
317           combotok = dwtoken()
318           combotok.setInitialIdChar(c,linenum);
319           dwclass = "id"
320           continue
321         # Shift class input, other starts here.
322         self._toks += [combotok]
323         combotok = dwtoken()
324         combotok.setInitialOther(c,linenum);
325         dwclass = "other"
326         continue
327       elif dwclass == "other":
328         if isShift(c) == "y":
329           self._toks += [combotok]
330           combotok = dwtoken()
331           combotok.setInitialShift(c,linenum);
332           dwclass = "shift"
333           continue
334         if isIndivid(c) == "y":
335           self._toks += [combotok]
336           combotok = dwtoken()
337           a = dwtoken()
338           a.setIndivid(c,linenum);
339           dwclass = "ind"
340           self._toks += [a]
341           continue
342         if isIdStart(c) == "y":
343           self._toks += [combotok]
344           combotok = dwtoken()
345           combotok.setInitialIdChar(c,linenum);
346           dwclass = "id"
347           continue
348         combotok.setNextOther(c);
349         continue
350       # Else case impossible.
351      
352     #Finish up final non-empty other or id token
353     if dwclass == "id":
354       combotok.finishUpId()
355       self._toks += [combotok]
356       dwclass = "none"
357     if dwclass == "shift":
358       self._toks += [combotok]
359       dwclass = "none"
360     if dwclass == "other":
361       self._toks += [combotok]
362       dwclass = "none"
363   def dwprint(self,linenum):
364     print "Number of tokens in line ",linenum," : ",len(self._toks)
365     if len(self._toks) == 0:
366       #Just print an empty line.
367       print ""
368     else:
369       for t in self._toks:
370         t.dwprint()
371   def dwwrite(self, outfile, linenum):
372     for t in self._toks:
373       t.dwwrite(outfile)
374     outfile.write("\n")
375   def dwtransformline(self,callfunc,myfile,lnum):
376     toks = callfunc(self._toks,myfile,lnum)
377     self._toks = toks
378     
379
380 class dwfile:
381   def __init__(self,name):
382     # list of dwline.
383     self._name = name
384     # Name of the file.
385     self._lines = []
386     try:
387       file = open(name,"r");
388     except IOError, message:
389       print >> sys.stderr , "File could not be opened: ", name
390       sys.exit(1)
391     linenum=0
392     while 1:
393       try:
394         rec = file.readline()
395       except EOFError:
396         break
397       if len(rec) < 1:
398         # eof
399         break
400       linenum = linenum +1
401       aline = dwline()
402       aline.tokenize(rec,name,linenum)
403       self._lines += [aline]
404
405   def dwprint(self):
406     print "Number of lines in ", self._name, ":  ",len(self._lines)
407     lnum = 1
408     for l in self._lines:
409        l.dwprint(lnum)
410        lnum = lnum + 1
411   def dwwrite(self):
412     # The lnum is just for debugging messages.
413
414     outname = self._name + ".out"
415     print outname
416     try:
417       outfile = open(outname,"w");
418     except IOError, message:
419       print >> sys.stderr , "Output File could not be opened: ", name
420       sys.exit(1)
421     lnum = 1
422     for l in self._lines:
423       l.dwwrite(outfile,lnum)
424       lnum = lnum + 1
425   # transformtoks looks at the file as a token sequence,
426   # not a line sequence.
427   # New view required by recent changes to .tex
428   def dwtransformfiletoks(self,callfunc,myfile):
429      FIXME 
430
431   def dwtransformtoks(self,callfunc,myfile):
432     globaltoklist = [] 
433     for l in self._lines:
434       for t in l._toks:
435         globaltoklist += [t]
436     toknum = 0
437     tokmax = len(globaltoklist)
438     self.dwtransformfiletoks(callfunc,myfile)
439
440   def dwtransformline(self,callfunc,myfile):
441     lnum = 1
442     for l in self._lines:
443       l.dwtransformline(callfunc,myfile,lnum)
444       lnum = lnum + 1
445
446 class dwfiles:
447   def __init__(self):
448     # list of dwfile.
449     self._files = []
450
451   def addFile(self,name):
452     f = dwfile(name)
453     self._files += [f]
454     
455   def dwprint(self):
456     print "Number of files: ",len(self._files);
457     for f in self._files:
458       f.dwprint()
459   def dwwrite(self):
460     for f in self._files:
461       f.dwwrite()
462   def dwtransformline(self,callfunc):
463     for f in self._files:
464       f.dwtransformline(callfunc,f)
465   def dwtransformtoks(self,callfunc):
466     for f in self._files:
467       f.dwtransformtoks(callfunc,f)
468
469
470 def setkeepordeletecomments(val):
471   """ Pass in "k" or "d" to keep or delete comments, respectively """
472   global keepcomments
473   keepcomments = val
474
475 def readFilelist(filelist):
476   dwf = dwfiles()
477   for f in filelist:
478     dwf.addFile(f)
479   return dwf
480