Public Member Functions | Public Attributes | Private Member Functions | List of all members
translator.Transl Class Reference

Public Member Functions

def __init__ (self, fname, manager)
 
def collectPureVirtualPrototypes (self)
 
def collectAdapterPrototypes (self)
 
def processing (self)
 
def report (self, fout)
 
def getmtime (self)
 

Public Attributes

 fname
 
 manager
 
 classId
 
 baseClassId
 
 readableStatus
 
 status
 
 lang
 
 langReadable
 
 note
 
 prototypeDic
 
 translateMeText
 
 translateMeFlag
 
 txtMAX_DOT_GRAPH_HEIGHT_flag
 
 obsoleteMethods
 
 missingMethods
 
 implementedMethods
 
 adaptMinClass
 

Private Member Functions

def __tokenGenerator (self)
 
def __collectClassInfo (self, tokenIterator)
 
def __unexpectedToken (self, status, tokenId, tokenLineNo)
 
def __collectPublicMethodPrototypes (self, tokenIterator)
 

Detailed Description

One instance is build for each translator.

The abbreviation of the source file--part after 'translator_'--is used as
the identification of the object. The empty string is used for the
abstract Translator class from translator.h. The other information is
extracted from inside the source file.

Definition at line 119 of file translator.py.

Constructor & Destructor Documentation

def translator.Transl.__init__ (   self,
  fname,
  manager 
)
Bind to the manager and initialize.

Definition at line 127 of file translator.py.

127  def __init__(self, fname, manager):
128  """Bind to the manager and initialize."""
129 
130  # Store the filename and the reference to the manager object.
131  self.fname = fname
132  self.manager = manager
133 
134  # The instance is responsible for loading the source file, so it checks
135  # for its existence and quits if something goes wrong.
136  if not os.path.isfile(fname):
137  sys.stderr.write("\a\nFile '%s' not found!\n" % fname)
138  sys.exit(1)
139 
140  # Initialize the other collected information.
141  self.classId = None
142  self.baseClassId = None
143  self.readableStatus = None # 'up-to-date', '1.2.3', '1.3', etc.
144  self.status = None # '', '1.2.03', '1.3.00', etc.
145  self.lang = None # like 'Brasilian'
146  self.langReadable = None # like 'Brasilian Portuguese'
147  self.note = None # like 'should be cleaned up'
148  self.prototypeDic = {} # uniPrototype -> prototype
149  self.translateMeText = 'translate me!'
150  self.translateMeFlag = False # comments with "translate me!" found
151  self.txtMAX_DOT_GRAPH_HEIGHT_flag = False # found in string in trLegendDocs()
152  self.obsoleteMethods = None # list of prototypes to be removed
153  self.missingMethods = None # list of prototypes to be implemented
154  self.implementedMethods = None # list of implemented required methods
155  self.adaptMinClass = None # The newest adapter class that can be used
156 
def __init__(self, fname, manager)
Definition: translator.py:127

Member Function Documentation

def translator.Transl.__collectClassInfo (   self,
  tokenIterator 
)
private
Collect the information about the class and base class.

The tokens including the opening left curly brace of the class are
consumed.

Definition at line 411 of file translator.py.

411  def __collectClassInfo(self, tokenIterator):
412  """Collect the information about the class and base class.
413 
414  The tokens including the opening left curly brace of the class are
415  consumed."""
416 
417  status = 0 # initial state
418 
419  while status != 777: # final state
420 
421  # Always assume that the previous tokens were processed. Get
422  # the next one.
423  tokenId, tokenStr, tokenLineNo = next(tokenIterator)
424 
425  # Process the token and never return back.
426  if status == 0: # waiting for the 'class' keyword.
427  if tokenId == 'class':
428  status = 1
429 
430  elif status == 1: # expecting the class identification
431  if tokenId == 'id':
432  self.classId = tokenStr
433  status = 2
434  else:
435  self.__unexpectedToken(status, tokenId, tokenLineNo)
436 
437  elif status == 2: # expecting the curly brace or base class info
438  if tokenId == 'lcurly':
439  status = 777 # correctly finished
440  elif tokenId == 'colon':
441  status = 3
442  else:
443  self.__unexpectedToken(status, tokenId, tokenLineNo)
444 
445  elif status == 3: # expecting the 'public' in front of base class id
446  if tokenId == 'public':
447  status = 4
448  else:
449  self.__unexpectedToken(status, tokenId, tokenLineNo)
450 
451  elif status == 4: # expecting the base class id
452  if tokenId == 'id':
453  self.baseClassId = tokenStr
454  status = 5
455  else:
456  self.__unexpectedToken(status, tokenId, tokenLineNo)
457 
458  elif status == 5: # expecting the curly brace and quitting
459  if tokenId == 'lcurly':
460  status = 777 # correctly finished
461  elif tokenId == 'comment':
462  pass
463  else:
464  self.__unexpectedToken(status, tokenId, tokenLineNo)
465 
466  # Extract the status of the TranslatorXxxx class. The readable form
467  # will be used in reports the status form is a string that can be
468  # compared lexically (unified length, padding with zeros, etc.).
469  if self.baseClassId:
470  lst = self.baseClassId.split('_')
471  if lst[0] == 'Translator':
472  self.readableStatus = 'up-to-date'
473  self.status = ''
474  elif lst[0] == 'TranslatorAdapter':
475  self.status = lst[1] + '.' + lst[2]
476  self.readableStatus = self.status
477  if len(lst) > 3: # add the last part of the number
478  self.status += '.' + ('%02d' % int(lst[3]))
479  self.readableStatus += '.' + lst[3]
480  else:
481  self.status += '.00'
482  elif lst[0] == 'TranslatorEnglish':
483  # Obsolete or Based on English.
484  if self.classId[-2:] == 'En':
485  self.readableStatus = 'English based'
486  self.status = 'En'
487  else:
488  self.readableStatus = 'obsolete'
489  self.status = '0.0.00'
490 
491  # Check whether status was set, or set 'strange'.
492  if self.status == None:
493  self.status = 'strange'
494  if not self.readableStatus:
495  self.readableStatus = 'strange'
496 
497  # Extract the name of the language and the readable form.
498  self.lang = self.classId[10:] # without 'Translator'
499  if self.lang == 'Brazilian':
500  self.langReadable = 'Brazilian Portuguese'
501  elif self.lang == 'Chinesetraditional':
502  self.langReadable = 'Chinese Traditional'
503  else:
504  self.langReadable = self.lang
505 
506 
def __unexpectedToken(self, status, tokenId, tokenLineNo)
Definition: translator.py:507
def __collectClassInfo(self, tokenIterator)
Definition: translator.py:411
def translator.Transl.__collectPublicMethodPrototypes (   self,
  tokenIterator 
)
private
Collects prototypes of public methods and fills self.prototypeDic.

The dictionary is filled by items: uniPrototype -> prototype.
The method is expected to be called only for TranslatorXxxx classes,
i.e. for the classes that implement translation to some language.
It assumes that the openning curly brace of the class was already
consumed. The source is consumed until the end of the class.
The caller should consume the source until the eof to cause closing
the source file.

Definition at line 724 of file translator.py.

724  def __collectPublicMethodPrototypes(self, tokenIterator):
725  """Collects prototypes of public methods and fills self.prototypeDic.
726 
727  The dictionary is filled by items: uniPrototype -> prototype.
728  The method is expected to be called only for TranslatorXxxx classes,
729  i.e. for the classes that implement translation to some language.
730  It assumes that the openning curly brace of the class was already
731  consumed. The source is consumed until the end of the class.
732  The caller should consume the source until the eof to cause closing
733  the source file."""
734 
735  assert(self.classId != 'Translator')
736  assert(self.baseClassId != None)
737 
738  # The following finite automaton slightly differs from the one
739  # inside self.collectPureVirtualPrototypes(). It produces the
740  # dictionary item just after consuming the body of the method
741  # (transition from from state 10 to state 2). It also does not allow
742  # definitions of public pure virtual methods, except for
743  # TranslatorAdapterBase (states 8 and 9). Argument identifier inside
744  # method argument lists can be omitted or commented.
745  #
746  # Let's collect readable form of all public method prototypes in
747  # the readable form -- as defined in the source file.
748  # Let's collect also unified form of the same prototype that omits
749  # everything that can be omitted, namely 'virtual' and argument
750  # identifiers.
751  prototype = '' # readable prototype (with everything)
752  uniPrototype = '' # unified prototype (without arg. identifiers)
753  warning = '' # warning message -- if something special detected
754  methodId = None # processed method id
755 
756  # Collect the method prototypes. Stop on the closing
757  # curly brace followed by the semicolon (end of class).
758  status = 0
759  curlyCnt = 0 # counter for the level of curly braces
760 
761  # Loop until the final state 777 is reached. The errors are processed
762  # immediately. In this implementation, it always quits the application.
763  while status != 777:
764 
765  # Get the next token.
766  tokenId, tokenStr, tokenLineNo = next(tokenIterator)
767 
768  if status == 0: # waiting for 'public:'
769  if tokenId == 'public':
770  status = 1
771  elif tokenId == 'eof': # non-public things until the eof
772  status = 777
773 
774  elif status == 1: # colon after the 'public'
775  if tokenId == 'colon':
776  status = 2
777  else:
778  self.__unexpectedToken(status, tokenId, tokenLineNo)
779 
780  elif status == 2: # waiting for 'virtual' (can be omitted)
781  if tokenId == 'virtual':
782  prototype = tokenStr # but not to unified prototype
783  status = 3
784  elif tokenId == 'id': # 'virtual' was omitted
785  prototype = tokenStr
786  uniPrototype = tokenStr # start collecting the unified prototype
787  status = 4
788  elif tokenId == 'comment':
789  pass
790  elif tokenId == 'protected' or tokenId == 'private':
791  status = 0
792  elif tokenId == 'rcurly':
793  status = 11 # expected end of class
794  else:
795  self.__unexpectedToken(status, tokenId, tokenLineNo)
796 
797  elif status == 3: # return type of the method expected
798  if tokenId == 'id':
799  prototype += ' ' + tokenStr
800  uniPrototype = tokenStr # start collecting the unified prototype
801  status = 4
802  else:
803  self.__unexpectedToken(status, tokenId, tokenLineNo)
804 
805  elif status == 4: # method identifier expected
806  if tokenId == 'id':
807  prototype += ' ' + tokenStr
808  uniPrototype += ' ' + tokenStr
809  methodId = tokenStr # for reporting
810  status = 5
811  else:
812  self.__unexpectedToken(status, tokenId, tokenLineNo)
813 
814  elif status == 5: # left bracket of the argument list expected
815  if tokenId == 'lpar':
816  prototype += tokenStr
817  uniPrototype += tokenStr
818  status = 6
819  else:
820  self.__unexpectedToken(status, tokenId, tokenLineNo)
821 
822  elif status == 6: # collecting arguments of the method
823  if tokenId == 'rpar':
824  prototype += tokenStr
825  uniPrototype += tokenStr
826  status = 7
827  elif tokenId == 'const':
828  prototype += tokenStr
829  uniPrototype += tokenStr
830  status = 12
831  elif tokenId == 'id': # type identifier
832  prototype += tokenStr
833  uniPrototype += tokenStr
834  status = 13
835  else:
836  self.__unexpectedToken(status, tokenId, tokenLineNo)
837 
838  elif status == 7: # left curly brace expected
839  if tokenId == 'lcurly':
840  curlyCnt = 1 # method body entered
841  status = 10
842  elif tokenId == 'comment':
843  pass
844  elif tokenId == 'assign': # allowed only for TranslatorAdapterBase
845  assert(self.classId == 'TranslatorAdapterBase')
846  status = 8
847  else:
848  self.__unexpectedToken(status, tokenId, tokenLineNo)
849 
850  elif status == 8: # zero expected (TranslatorAdapterBase)
851  assert(self.classId == 'TranslatorAdapterBase')
852  if tokenId == 'num' and tokenStr == '0':
853  status = 9
854  else:
855  self.__unexpectedToken(status, tokenId, tokenLineNo)
856 
857  elif status == 9: # after semicolon (TranslatorAdapterBase)
858  assert(self.classId == 'TranslatorAdapterBase')
859  if tokenId == 'semic':
860  status = 2
861  else:
862  self.__unexpectedToken(status, tokenId, tokenLineNo)
863 
864  elif status == 10: # consuming the body of the method, then dic item
865  if tokenId == 'rcurly':
866  curlyCnt -= 1
867  if curlyCnt == 0:
868  # Check for possible copy/paste error when name
869  # of the method was not corrected (i.e. the same
870  # name already exists).
871  if uniPrototype in self.prototypeDic:
872  msg = "'%s' prototype found again (duplicity)\n"
873  msg += "in '%s'.\n" % self.fname
874  msg = msg % uniPrototype
875  sys.stderr.write(msg)
876  assert False
877 
878  assert(uniPrototype not in self.prototypeDic)
879  # Insert new dictionary item.
880  self.prototypeDic[uniPrototype] = prototype
881  status = 2 # body consumed
882  methodId = None # outside of any method
883  elif tokenId == 'lcurly':
884  curlyCnt += 1
885 
886  # Warn in special case.
887  elif methodId == 'trLegendDocs' and tokenId == 'string' \
888  and tokenStr.find('MAX_DOT_GRAPH_HEIGHT') >= 0:
889  self.txtMAX_DOT_GRAPH_HEIGHT_flag = True
890 
891 
892  elif status == 11: # probably the end of class
893  if tokenId == 'semic':
894  status = 777
895  else:
896  self.__unexpectedToken(status, tokenId, tokenLineNo)
897 
898  elif status == 12: # type id for argument expected
899  if tokenId == 'id':
900  prototype += ' ' + tokenStr
901  uniPrototype += ' ' + tokenStr
902  status = 13
903  else:
904  self.__unexpectedToken(status, tokenId, tokenLineNo)
905 
906  elif status == 13: # :: or * or & or id or ) expected
907  if tokenId == 'colon': # was namespace id
908  prototype += tokenStr
909  uniPrototype += tokenStr
910  status = 14
911  elif tokenId == 'star' or tokenId == 'amp': # pointer or reference
912  prototype += ' ' + tokenStr
913  uniPrototype += ' ' + tokenStr
914  status = 16
915  elif tokenId == 'id': # argument identifier
916  prototype += ' ' + tokenStr
917  # don't put this into unified prototype
918  status = 17
919  elif tokenId == 'comment': # probably commented-out identifier
920  prototype += tokenStr
921  elif tokenId == 'rpar':
922  prototype += tokenStr
923  uniPrototype += tokenStr
924  status = 7
925  elif tokenId == 'comma':
926  prototype += ', '
927  uniPrototype += ', '
928  status = 6
929  else:
930  self.__unexpectedToken(status, tokenId, tokenLineNo)
931 
932  elif status == 14: # second colon for namespace:: expected
933  if tokenId == 'colon':
934  prototype += tokenStr
935  uniPrototype += tokenStr
936  status = 15
937  else:
938  self.__unexpectedToken(status, tokenId, tokenLineNo)
939 
940  elif status == 15: # type after namespace:: expected
941  if tokenId == 'id':
942  prototype += tokenStr
943  uniPrototype += tokenStr
944  status = 13
945  else:
946  self.__unexpectedToken(status, tokenId, tokenLineNo)
947 
948  elif status == 16: # argument identifier or ) expected
949  if tokenId == 'id':
950  prototype += ' ' + tokenStr
951  # don't put this into unified prototype
952  status = 17
953  elif tokenId == 'rpar':
954  prototype += tokenStr
955  uniPrototype += tokenStr
956  status = 7
957  elif tokenId == 'comment':
958  prototype += tokenStr
959  else:
960  self.__unexpectedToken(status, tokenId, tokenLineNo)
961 
962  elif status == 17: # comma or ')' after argument identifier expected
963  if tokenId == 'comma':
964  prototype += ', '
965  uniPrototype += ', '
966  status = 6
967  elif tokenId == 'rpar':
968  prototype += tokenStr
969  uniPrototype += tokenStr
970  status = 7
971  else:
972  self.__unexpectedToken(status, tokenId, tokenLineNo)
973 
974 
975 
def __unexpectedToken(self, status, tokenId, tokenLineNo)
Definition: translator.py:507
def __collectPublicMethodPrototypes(self, tokenIterator)
Definition: translator.py:724
def translator.Transl.__tokenGenerator (   self)
private
Generator that reads the file and yields tokens as 4-tuples.

The tokens have the form (tokenId, tokenString, lineNo). The
last returned token has the form ('eof', None, None). When trying
to access next token afer that, the exception would be raised.

Definition at line 157 of file translator.py.

157  def __tokenGenerator(self):
158  """Generator that reads the file and yields tokens as 4-tuples.
159 
160  The tokens have the form (tokenId, tokenString, lineNo). The
161  last returned token has the form ('eof', None, None). When trying
162  to access next token afer that, the exception would be raised."""
163 
164  # Set the dictionary for recognizing tokenId for keywords, separators
165  # and the similar categories. The key is the string to be recognized,
166  # the value says its token identification.
167  tokenDic = { 'class': 'class',
168  'const': 'const',
169  'public': 'public',
170  'protected': 'protected',
171  'private': 'private',
172  'static': 'static',
173  'virtual': 'virtual',
174  ':': 'colon',
175  ';': 'semic',
176  ',': 'comma',
177  '[': 'lsqbra',
178  ']': 'rsqbra',
179  '(': 'lpar',
180  ')': 'rpar',
181  '{': 'lcurly',
182  '}': 'rcurly',
183  '=': 'assign',
184  '*': 'star',
185  '&': 'amp',
186  '+': 'plus',
187  '-': 'minus',
188  '!': 'excl',
189  '?': 'qmark',
190  '<': 'lt',
191  '>': 'gt',
192  "'": 'quot',
193  '"': 'dquot',
194  '.': 'dot',
195  '%': 'perc',
196  '~': 'tilde',
197  '^': 'caret',
198  }
199 
200  # Regular expression for recognizing identifiers.
201  rexId = re.compile(r'^[a-zA-Z]\w*$')
202 
203  # Open the file for reading and extracting tokens until the eof.
204  # Initialize the finite automaton.
205  f = xopen(self.fname)
206  lineNo = 0
207  line = '' # init -- see the pos initialization below
208  linelen = 0 # init
209  pos = 100 # init -- pos after the end of line
210  status = 0
211 
212  tokenId = None # init
213  tokenStr = '' # init -- the characters will be appended.
214  tokenLineNo = 0
215 
216  while status != 777:
217 
218  # Get the next character. Read next line first, if necessary.
219  if pos < linelen:
220  c = line[pos]
221  else:
222  lineNo += 1
223  line = f.readline()
224  linelen = len(line)
225  pos = 0
226  if line == '': # eof
227  status = 777
228  else:
229  c = line[pos]
230 
231  # Consume the character based on the status
232 
233  if status == 0: # basic status
234 
235  # This is the initial status. If tokenId is set, yield the
236  # token here and only here (except when eof is found).
237  # Initialize the token variables after the yield.
238  if tokenId:
239  # If it is an unknown item, it can still be recognized
240  # here. Keywords and separators are the example.
241  if tokenId == 'unknown':
242  if tokenStr in tokenDic:
243  tokenId = tokenDic[tokenStr]
244  elif tokenStr.isdigit():
245  tokenId = 'num'
246  elif rexId.match(tokenStr):
247  tokenId = 'id'
248  else:
249  msg = '\aWarning: unknown token "' + tokenStr + '"'
250  msg += '\tfound on line %d' % tokenLineNo
251  msg += ' in "' + self.fname + '".\n'
252  sys.stderr.write(msg)
253 
254  yield (tokenId, tokenStr, tokenLineNo)
255 
256  # If it is a comment that contains the self.translateMeText
257  # string, set the flag -- the situation will be reported.
258  if tokenId == 'comment' and tokenStr.find(self.translateMeText) >= 0:
259  self.translateMeFlag = True
260 
261  tokenId = None
262  tokenStr = ''
263  tokenLineNo = 0
264 
265  # Now process the character. When we just skip it (spaces),
266  # stay in this status. All characters that will be part of
267  # some token cause moving to the specific status. And only
268  # when moving to the status == 0 (or the final state 777),
269  # the token is yielded. With respect to that the automaton
270  # behaves as Moore's one (output bound to status). When
271  # collecting tokens, the automaton is the Mealy's one
272  # (actions bound to transitions).
273  if c.isspace():
274  pass # just skip whitespace characters
275  elif c == '/': # Possibly comment starts here, but
276  tokenId = 'unknown' # it could be only a slash in code.
277  tokenStr = c
278  tokenLineNo = lineNo
279  status = 1
280  elif c == '#':
281  tokenId = 'preproc' # preprocessor directive
282  tokenStr = c
283  tokenLineNo = lineNo
284  status = 5
285  elif c == '"': # string starts here
286  tokenId = 'string'
287  tokenStr = c
288  tokenLineNo = lineNo
289  status = 6
290  elif c == "'": # char literal starts here
291  tokenId = 'charlit'
292  tokenStr = c
293  tokenLineNo = lineNo
294  status = 8
295  elif c in tokenDic: # known one-char token
296  tokenId = tokenDic[c]
297  tokenStr = c
298  tokenLineNo = lineNo
299  # stay in this state to yield token immediately
300  else:
301  tokenId = 'unknown' # totally unknown
302  tokenStr = c
303  tokenLineNo = lineNo
304  status = 333
305 
306  pos += 1 # move position in any case
307 
308  elif status == 1: # possibly a comment
309  if c == '/': # ... definitely the C++ comment
310  tokenId = 'comment'
311  tokenStr += c
312  pos += 1
313  status = 2
314  elif c == '*': # ... definitely the C comment
315  tokenId = 'comment'
316  tokenStr += c
317  pos += 1
318  status = 3
319  else:
320  status = 0 # unrecognized, don't move pos
321 
322  elif status == 2: # inside the C++ comment
323  if c == '\n': # the end of C++ comment
324  status = 0 # yield the token
325  else:
326  tokenStr += c # collect the C++ comment
327  pos += 1
328 
329  elif status == 3: # inside the C comment
330  if c == '*': # possibly the end of the C comment
331  tokenStr += c
332  status = 4
333  else:
334  tokenStr += c # collect the C comment
335  pos += 1
336 
337  elif status == 4: # possibly the end of the C comment
338  if c == '/': # definitely the end of the C comment
339  tokenStr += c
340  status = 0 # yield the token
341  elif c == '*': # more stars inside the comment
342  tokenStr += c
343  else:
344  tokenStr += c # this cannot be the end of comment
345  status = 3
346  pos += 1
347 
348  elif status == 5: # inside the preprocessor directive
349  if c == '\n': # the end of the preproc. command
350  status = 0 # yield the token
351  else:
352  tokenStr += c # collect the preproc
353  pos += 1
354 
355  elif status == 6: # inside the string
356  if c == '\\': # escaped char inside the string
357  tokenStr += c
358  status = 7
359  elif c == '"': # end of the string
360  tokenStr += c
361  status = 0
362  else:
363  tokenStr += c # collect the chars of the string
364  pos += 1
365 
366  elif status == 7: # escaped char inside the string
367  tokenStr += c # collect the char of the string
368  status = 6
369  pos += 1
370 
371  elif status == 8: # inside the char literal
372  tokenStr += c # collect the char of the literal
373  status = 9
374  pos += 1
375 
376  elif status == 9: # end of char literal expected
377  if c == "'": # ... and found
378  tokenStr += c
379  status = 0
380  pos += 1
381  else:
382  tokenId = 'error' # end of literal was expected
383  tokenStr += c
384  status = 0
385 
386  elif status == 333: # start of the unknown token
387  if c.isspace():
388  pos += 1
389  status = 0 # tokenId may be determined later
390  elif c in tokenDic: # separator, don't move pos
391  status = 0
392  else:
393  tokenStr += c # collect
394  pos += 1
395 
396  # We should have finished in the final status. If some token
397  # have been extracted, yield it first.
398  assert(status == 777)
399  if tokenId:
400  yield (tokenId, tokenStr, tokenLineNo)
401  tokenId = None
402  tokenStr = ''
403  tokenLineNo = 0
404 
405  # The file content is processed. Close the file. Then always yield
406  # the eof token.
407  f.close()
408  yield ('eof', None, None)
409 
410 
def xopen(fname, mode='r', encoding='utf-8-sig')
Definition: translator.py:79
def __tokenGenerator(self)
Definition: translator.py:157
def translator.Transl.__unexpectedToken (   self,
  status,
  tokenId,
  tokenLineNo 
)
private
Reports unexpected token and quits with exit code 1.

Definition at line 507 of file translator.py.

507  def __unexpectedToken(self, status, tokenId, tokenLineNo):
508  """Reports unexpected token and quits with exit code 1."""
509 
510  import inspect
511  calledFrom = inspect.stack()[1][3]
512  msg = "\a\nUnexpected token '%s' on the line %d in '%s'.\n"
513  msg = msg % (tokenId, tokenLineNo, self.fname)
514  msg += 'status = %d in %s()\n' % (status, calledFrom)
515  sys.stderr.write(msg)
516  sys.exit(1)
517 
518 
def __unexpectedToken(self, status, tokenId, tokenLineNo)
Definition: translator.py:507
def translator.Transl.collectAdapterPrototypes (   self)
Returns the dictionary of prototypes implemented by adapters.

It is created to process the translator_adapter.h. The returned
dictionary has the form: unifiedPrototype -> (version, classId)
thus by looking for the prototype, we get the information what is
the newest (least adapting) adapter that is sufficient for
implementing the method.

Definition at line 976 of file translator.py.

977  """Returns the dictionary of prototypes implemented by adapters.
978 
979  It is created to process the translator_adapter.h. The returned
980  dictionary has the form: unifiedPrototype -> (version, classId)
981  thus by looking for the prototype, we get the information what is
982  the newest (least adapting) adapter that is sufficient for
983  implementing the method."""
984 
985  # Start the token generator which parses the class source file.
986  assert(os.path.split(self.fname)[1] == 'translator_adapter.h')
987  tokenIterator = self.__tokenGenerator()
988 
989  # Get the references to the involved dictionaries.
990  reqDic = self.manager.requiredMethodsDic
991 
992  # Create the empty dictionary that will be returned.
993  adaptDic = {}
994 
995 
996  # Loop through the source of the adapter file until no other adapter
997  # class is found.
998  while True:
999  try:
1000  # Collect the class and the base class identifiers.
1001  self.__collectClassInfo(tokenIterator)
1002 
1003  # Extract the comparable version of the adapter class.
1004  # Note: The self.status as set by self.__collectClassInfo()
1005  # contains similar version, but is related to the base class,
1006  # not to the class itself.
1007  lst = self.classId.split('_')
1008  version = ''
1009  if lst[0] == 'TranslatorAdapter': # TranslatorAdapterBase otherwise
1010  version = lst[1] + '.' + lst[2]
1011  if len(lst) > 3: # add the last part of the number
1012  version += '.' + ('%02d' % int(lst[3]))
1013  else:
1014  version += '.00'
1015 
1016  # Collect the prototypes of implemented public methods.
1017  self.__collectPublicMethodPrototypes(tokenIterator)
1018 
1019  # For the required methods, update the dictionary of methods
1020  # implemented by the adapter.
1021  for protoUni in self.prototypeDic:
1022  if protoUni in reqDic:
1023  # This required method will be marked as implemented
1024  # by this adapter class. This implementation assumes
1025  # that newer adapters do not reimplement any required
1026  # methods already implemented by older adapters.
1027  assert(protoUni not in adaptDic)
1028  adaptDic[protoUni] = (version, self.classId)
1029 
1030  # Clear the dictionary object and the information related
1031  # to the class as the next adapter class is to be processed.
1032  self.prototypeDic.clear()
1033  self.classId = None
1034  self.baseClassId = None
1035 
1036  except StopIteration:
1037  break
1038 
1039  # Return the result dictionary.
1040  return adaptDic
1041 
1042 
def __tokenGenerator(self)
Definition: translator.py:157
def collectAdapterPrototypes(self)
Definition: translator.py:976
def __collectPublicMethodPrototypes(self, tokenIterator)
Definition: translator.py:724
def __collectClassInfo(self, tokenIterator)
Definition: translator.py:411
def translator.Transl.collectPureVirtualPrototypes (   self)
Returns dictionary 'unified prototype' -> 'full prototype'.

The method is expected to be called only for the translator.h. It
extracts only the pure virtual method and build the dictionary where
key is the unified prototype without argument identifiers.

Definition at line 519 of file translator.py.

520  """Returns dictionary 'unified prototype' -> 'full prototype'.
521 
522  The method is expected to be called only for the translator.h. It
523  extracts only the pure virtual method and build the dictionary where
524  key is the unified prototype without argument identifiers."""
525 
526  # Prepare empty dictionary that will be returned.
527  resultDic = {}
528 
529  # Start the token generator which parses the class source file.
530  tokenIterator = self.__tokenGenerator()
531 
532  # Collect the class and the base class identifiers.
533  self.__collectClassInfo(tokenIterator)
534  assert(self.classId == 'Translator')
535 
536  # Let's collect readable form of the public virtual pure method
537  # prototypes in the readable form -- as defined in translator.h.
538  # Let's collect also unified form of the same prototype that omits
539  # everything that can be omitted, namely 'virtual' and argument
540  # identifiers.
541  prototype = '' # readable prototype (with everything)
542  uniPrototype = '' # unified prototype (without arg. identifiers)
543 
544  # Collect the pure virtual method prototypes. Stop on the closing
545  # curly brace followed by the semicolon (end of class).
546  status = 0
547  curlyCnt = 0 # counter for the level of curly braces
548 
549  # Loop until the final state 777 is reached. The errors are processed
550  # immediately. In this implementation, it always quits the application.
551  while status != 777:
552 
553  # Get the next token.
554  tokenId, tokenStr, tokenLineNo = next(tokenIterator)
555 
556  if status == 0: # waiting for 'public:'
557  if tokenId == 'public':
558  status = 1
559 
560  elif status == 1: # colon after the 'public'
561  if tokenId == 'colon':
562  status = 2
563  else:
564  self.__unexpectedToken(status, tokenId, tokenLineNo)
565 
566  elif status == 2: # waiting for 'virtual'
567  if tokenId == 'virtual':
568  prototype = tokenStr # but not to unified prototype
569  status = 3
570  elif tokenId == 'comment':
571  pass
572  elif tokenId == 'rcurly':
573  status = 11 # expected end of class
574  else:
575  self.__unexpectedToken(status, tokenId, tokenLineNo)
576 
577  elif status == 3: # return type of the method expected
578  if tokenId == 'id':
579  prototype += ' ' + tokenStr
580  uniPrototype = tokenStr # start collecting the unified prototype
581  status = 4
582  elif tokenId == 'tilde':
583  status = 4
584  else:
585  self.__unexpectedToken(status, tokenId, tokenLineNo)
586 
587  elif status == 4: # method identifier expected
588  if tokenId == 'id':
589  prototype += ' ' + tokenStr
590  uniPrototype += ' ' + tokenStr
591  status = 5
592  else:
593  self.__unexpectedToken(status, tokenId, tokenLineNo)
594 
595  elif status == 5: # left bracket of the argument list expected
596  if tokenId == 'lpar':
597  prototype += tokenStr
598  uniPrototype += tokenStr
599  status = 6
600  else:
601  self.__unexpectedToken(status, tokenId, tokenLineNo)
602 
603  elif status == 6: # collecting arguments of the method
604  if tokenId == 'rpar':
605  prototype += tokenStr
606  uniPrototype += tokenStr
607  status = 7
608  elif tokenId == 'const':
609  prototype += tokenStr
610  uniPrototype += tokenStr
611  status = 12
612  elif tokenId == 'id': # type identifier
613  prototype += tokenStr
614  uniPrototype += tokenStr
615  status = 13
616  else:
617  self.__unexpectedToken(status, tokenId, tokenLineNo)
618 
619  elif status == 7: # assignment expected or left curly brace
620  if tokenId == 'assign':
621  status = 8
622  elif tokenId == 'lcurly':
623  curlyCnt = 1 # method body entered
624  status = 10
625  else:
626  self.__unexpectedToken(status, tokenId, tokenLineNo)
627 
628  elif status == 8: # zero expected
629  if tokenId == 'num' and tokenStr == '0':
630  status = 9
631  else:
632  self.__unexpectedToken(status, tokenId, tokenLineNo)
633 
634  elif status == 9: # after semicolon, produce the dic item
635  if tokenId == 'semic':
636  assert(uniPrototype not in resultDic)
637  resultDic[uniPrototype] = prototype
638  status = 2
639  else:
640  self.__unexpectedToken(status, tokenId, tokenLineNo)
641 
642  elif status == 10: # consuming the body of the method
643  if tokenId == 'rcurly':
644  curlyCnt -= 1
645  if curlyCnt == 0:
646  status = 2 # body consumed
647  elif tokenId == 'lcurly':
648  curlyCnt += 1
649 
650  elif status == 11: # probably the end of class
651  if tokenId == 'semic':
652  status = 777
653  else:
654  self.__unexpectedToken(status, tokenId, tokenLineNo)
655 
656  elif status == 12: # type id for argument expected
657  if tokenId == 'id':
658  prototype += ' ' + tokenStr
659  uniPrototype += ' ' + tokenStr
660  status = 13
661  else:
662  self.__unexpectedToken(status, tokenId, tokenLineNo)
663 
664  elif status == 13: # namespace qualification or * or & expected
665  if tokenId == 'colon': # was namespace id
666  prototype += tokenStr
667  uniPrototype += tokenStr
668  status = 14
669  elif tokenId == 'star' or tokenId == 'amp': # pointer or reference
670  prototype += ' ' + tokenStr
671  uniPrototype += ' ' + tokenStr
672  status = 16
673  elif tokenId == 'id': # argument identifier
674  prototype += ' ' + tokenStr
675  # don't put this into unified prototype
676  status = 17
677  else:
678  self.__unexpectedToken(status, tokenId, tokenLineNo)
679 
680  elif status == 14: # second colon for namespace:: expected
681  if tokenId == 'colon':
682  prototype += tokenStr
683  uniPrototype += tokenStr
684  status = 15
685  else:
686  self.__unexpectedToken(status, tokenId, tokenLineNo)
687 
688  elif status == 15: # type after namespace:: expected
689  if tokenId == 'id':
690  prototype += tokenStr
691  uniPrototype += tokenStr
692  status = 13
693  else:
694  self.__unexpectedToken(status, tokenId, tokenLineNo)
695 
696  elif status == 16: # argument identifier expected
697  if tokenId == 'id':
698  prototype += ' ' + tokenStr
699  # don't put this into unified prototype
700  status = 17
701  else:
702  self.__unexpectedToken(status, tokenId, tokenLineNo)
703 
704  elif status == 17: # comma or ')' after argument identifier expected
705  if tokenId == 'comma':
706  prototype += ', '
707  uniPrototype += ', '
708  status = 6
709  elif tokenId == 'rpar':
710  prototype += tokenStr
711  uniPrototype += tokenStr
712  status = 7
713  else:
714  self.__unexpectedToken(status, tokenId, tokenLineNo)
715 
716  # Eat the rest of the source to cause closing the file.
717  while tokenId != 'eof':
718  tokenId, tokenStr, tokenLineNo = next(tokenIterator)
719 
720  # Return the resulting dictionary with 'uniPrototype -> prototype'.
721  return resultDic
722 
723 
def __tokenGenerator(self)
Definition: translator.py:157
def __unexpectedToken(self, status, tokenId, tokenLineNo)
Definition: translator.py:507
def collectPureVirtualPrototypes(self)
Definition: translator.py:519
def __collectClassInfo(self, tokenIterator)
Definition: translator.py:411
def translator.Transl.getmtime (   self)
Returns the last modification time of the source file.

Definition at line 1198 of file translator.py.

1198  def getmtime(self):
1199  """Returns the last modification time of the source file."""
1200  assert(os.path.isfile(self.fname))
1201  return os.path.getmtime(self.fname)
1202 
1203 
def getmtime(self)
Definition: translator.py:1198
def translator.Transl.processing (   self)
Processing of the source file -- only for TranslatorXxxx classes.

Definition at line 1043 of file translator.py.

1043  def processing(self):
1044  """Processing of the source file -- only for TranslatorXxxx classes."""
1045 
1046  # Start the token generator which parses the class source file.
1047  tokenIterator = self.__tokenGenerator()
1048 
1049  # Collect the class and the base class identifiers.
1050  self.__collectClassInfo(tokenIterator)
1051  assert(self.classId != 'Translator')
1052  assert(self.classId[:17] != 'TranslatorAdapter')
1053 
1054  # Collect the prototypes of implemented public methods.
1055  self.__collectPublicMethodPrototypes(tokenIterator)
1056 
1057  # Eat the rest of the source to cause closing the file.
1058  while True:
1059  try:
1060  t = next(tokenIterator)
1061  except StopIteration:
1062  break
1063 
1064  # Shorthands for the used dictionaries.
1065  reqDic = self.manager.requiredMethodsDic
1066  adaptDic = self.manager.adaptMethodsDic
1067  myDic = self.prototypeDic
1068 
1069  # Build the list of obsolete methods.
1070  self.obsoleteMethods = []
1071  for p in myDic:
1072  if p not in reqDic:
1073  self.obsoleteMethods.append(p)
1074  self.obsoleteMethods.sort()
1075 
1076  # Build the list of missing methods and the list of implemented
1077  # required methods.
1078  self.missingMethods = []
1079  self.implementedMethods = []
1080  for p in reqDic:
1081  if p in myDic:
1082  self.implementedMethods.append(p)
1083  else:
1084  self.missingMethods.append(p)
1085  self.missingMethods.sort()
1086  self.implementedMethods.sort()
1087 
1088  # Check whether adapter must be used or suggest the newest one.
1089  # Change the status and set the note accordingly.
1090  if self.baseClassId != 'Translator':
1091  if not self.missingMethods:
1092  self.note = 'Change the base class to Translator.'
1093  self.status = ''
1094  self.readableStatus = 'almost up-to-date'
1095  elif self.baseClassId != 'TranslatorEnglish':
1096  # The translator uses some of the adapters.
1097  # Look at the missing methods and check what adapter
1098  # implements them. Remember the one with the lowest version.
1099  adaptMinVersion = '9.9.99'
1100  adaptMinClass = 'TranslatorAdapter_9_9_99'
1101  for uniProto in self.missingMethods:
1102  if uniProto in adaptDic:
1103  version, cls = adaptDic[uniProto]
1104  if version < adaptMinVersion:
1105  adaptMinVersion = version
1106  adaptMinClass = cls
1107 
1108  # Test against the current status -- preserve the self.status.
1109  # Possibly, the translator implements enough methods to
1110  # use some newer adapter.
1111  status = self.status
1112 
1113  # If the version of the used adapter is smaller than
1114  # the required, set the note and update the status as if
1115  # the newer adapter was used.
1116  if adaptMinVersion > status:
1117  self.note = 'Change the base class to %s.' % adaptMinClass
1118  self.status = adaptMinVersion
1119  self.adaptMinClass = adaptMinClass
1120  self.readableStatus = adaptMinVersion # simplified
1121 
1122  # If everything seems OK, some explicit warning flags still could
1123  # be set.
1124  if not self.note and self.status == '' and \
1126  self.note = ''
1127  if self.translateMeFlag:
1128  self.note += 'The "%s" found in a comment.' % self.translateMeText
1129  if self.note != '':
1130  self.note += '\n\t\t'
1132  self.note += 'The MAX_DOT_GRAPH_HEIGHT found in trLegendDocs()'
1133 
1134  # If everything seems OK, but there are obsolete methods, set
1135  # the note to clean-up source. This note will be used only when
1136  # the previous code did not set another note (priority).
1137  if not self.note and self.status == '' and self.obsoleteMethods:
1138  self.note = 'Remove the obsolete methods (never used).'
1139 
1140  # If there is at least some note but the status suggests it is
1141  # otherwise up-to-date, mark is as ALMOST up-to-date.
1142  if self.note and self.status == '':
1143  self.readableStatus = 'almost up-to-date'
1144 
1145 
def __tokenGenerator(self)
Definition: translator.py:157
def __collectPublicMethodPrototypes(self, tokenIterator)
Definition: translator.py:724
def __collectClassInfo(self, tokenIterator)
Definition: translator.py:411
def processing(self)
Definition: translator.py:1043
def translator.Transl.report (   self,
  fout 
)
Returns the report part for the source as a multiline string.

No output for up-to-date translators without problem.

Definition at line 1146 of file translator.py.

1146  def report(self, fout):
1147  """Returns the report part for the source as a multiline string.
1148 
1149  No output for up-to-date translators without problem."""
1150 
1151  # If there is nothing to report, return immediately.
1152  if self.status == '' and not self.note:
1153  return
1154 
1155  # Report the number of not implemented methods.
1156  fout.write('\n\n\n')
1157  fout.write(self.classId + ' (' + self.baseClassId + ')')
1158  percentImplemented = 100 # init
1159  allNum = len(self.manager.requiredMethodsDic)
1160  if self.missingMethods:
1161  num = len(self.missingMethods)
1162  percentImplemented = 100 * (allNum - num) / allNum
1163  fout.write(' %d' % num)
1164  fout.write(' method')
1165  if num > 1:
1166  fout.write('s')
1167  fout.write(' to implement (%d %%)' % (100 * num / allNum))
1168  fout.write('\n' + '-' * len(self.classId))
1169 
1170  # Write the info about the implemented required methods.
1171  fout.write('\n\n Implements %d' % len(self.implementedMethods))
1172  fout.write(' of the required methods (%d %%).' % percentImplemented)
1173 
1174  # Report the missing method, but only when it is not English-based
1175  # translator.
1176  if self.missingMethods and self.status != 'En':
1177  fout.write('\n\n Missing methods (should be implemented):\n')
1178  reqDic = self.manager.requiredMethodsDic
1179  for p in self.missingMethods:
1180  fout.write('\n ' + reqDic[p])
1181 
1182  # Always report obsolete methods.
1183  if self.obsoleteMethods:
1184  fout.write('\n\n Obsolete methods (should be removed, never used):\n')
1185  myDic = self.prototypeDic
1186  for p in self.obsoleteMethods:
1187  fout.write('\n ' + myDic[p])
1188 
1189  # For English-based translator, report the implemented methods.
1190  if self.status == 'En' and self.implementedMethods:
1191  fout.write('\n\n This English-based translator implements ')
1192  fout.write('the following methods:\n')
1193  reqDic = self.manager.requiredMethodsDic
1194  for p in self.implementedMethods:
1195  fout.write('\n ' + reqDic[p])
1196 
1197 
def report(self, fout)
Definition: translator.py:1146

Member Data Documentation

translator.Transl.adaptMinClass

Definition at line 155 of file translator.py.

translator.Transl.baseClassId

Definition at line 142 of file translator.py.

translator.Transl.classId

Definition at line 141 of file translator.py.

translator.Transl.fname

Definition at line 131 of file translator.py.

translator.Transl.implementedMethods

Definition at line 154 of file translator.py.

translator.Transl.lang

Definition at line 145 of file translator.py.

translator.Transl.langReadable

Definition at line 146 of file translator.py.

translator.Transl.manager

Definition at line 132 of file translator.py.

translator.Transl.missingMethods

Definition at line 153 of file translator.py.

translator.Transl.note

Definition at line 147 of file translator.py.

translator.Transl.obsoleteMethods

Definition at line 152 of file translator.py.

translator.Transl.prototypeDic

Definition at line 148 of file translator.py.

translator.Transl.readableStatus

Definition at line 143 of file translator.py.

translator.Transl.status

Definition at line 144 of file translator.py.

translator.Transl.translateMeFlag

Definition at line 150 of file translator.py.

translator.Transl.translateMeText

Definition at line 149 of file translator.py.

translator.Transl.txtMAX_DOT_GRAPH_HEIGHT_flag

Definition at line 151 of file translator.py.


The documentation for this class was generated from the following file: