Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

140 lines
3.4 KiB

  1. import re
  2. class DLexToken:
  3. """
  4. DLexToken contains:
  5. 'id' - the ID of the token (match with the value DLexer.AddToken returns).
  6. 'val' - the token's string.
  7. 'lineNumber' - the line the token was encountered on.
  8. """
  9. pass
  10. class DLexState:
  11. pass
  12. class DLexer:
  13. """
  14. DLex is a simple lexer simulator. Here is how to use it.
  15. 1. Call AddToken to add the regular expressions that it will parse. Add them in
  16. order of precedence. Store the value returned from AddToken so you can compare
  17. it to the token ID returned by GetToken to determine what kind of token was found.
  18. 2. Call BeginRead or BeginReadFile to setup the initial file.
  19. 3. Repeatedly call GetToken.
  20. If it returns None, then there are no more tokens that match your specifications.
  21. If it returns a value, then it is a DLexToken with.
  22. """
  23. def __init__( self, bSkipWhitespace=1 ):
  24. self.__tokens = []
  25. self.__curTokenID = 0
  26. self.__notnewline = re.compile( '[^\\r\\n]*' )
  27. self.__bSkipWhitespace = bSkipWhitespace
  28. if bSkipWhitespace:
  29. self.__whitespace = re.compile( '[ \\t\\f\\v]+' )
  30. self.__newline = re.compile( '[\\r\\n]' )
  31. def GetErrorTokenID( self ):
  32. return -1
  33. def AddToken( self, expr, flags=0 ):
  34. tokenID = self.__curTokenID
  35. self.__tokens.append( [tokenID, re.compile( expr, flags )] )
  36. self.__curTokenID += 1
  37. return tokenID
  38. # Store and restore the state.
  39. def BackupState( self ):
  40. ret = DLexState()
  41. ret.lineNumber = self.__lineNumber
  42. ret.currentCharacter = self.__currentCharacter
  43. ret.fileLen = self.__fileLen
  44. return ret
  45. def RestoreState( self, state ):
  46. self.__lineNumber = state.lineNumber
  47. self.__currentCharacter = state.currentCharacter
  48. self.__fileLen = state.fileLen
  49. def BeginRead( self, str ):
  50. self.__curString = str
  51. self.__lineNumber = 1
  52. self.__currentCharacter = 0
  53. self.__fileLen = len( str )
  54. def BeginReadFile( self, fileName ):
  55. file = open( fileName, 'r' )
  56. self.BeginRead( file.read() )
  57. file.close()
  58. def GetToken( self ):
  59. # Skip whitespace.
  60. self.__SkipWhitespace()
  61. # Now return the first token that we have a match for.
  62. for token in self.__tokens:
  63. m = token[1].match( self.__curString, self.__currentCharacter )
  64. if m:
  65. ret = DLexToken()
  66. ret.id = token[0]
  67. ret.val = self.__curString[ m.start() : m.end() ]
  68. ret.lineNumber = self.__lineNumber
  69. self.__currentCharacter = m.end()
  70. return ret
  71. if self.__currentCharacter < self.__fileLen:
  72. print "NO MATCH FOR '%s'" % self.__curString[ self.__currentCharacter : self.__currentCharacter+35 ]
  73. ret = DLexToken()
  74. ret.id = self.GetErrorTokenID()
  75. ret.val = self.__curString[ self.__currentCharacter : ]
  76. self.__currentCharacter = self.__fileLen
  77. return ret
  78. #print "%d" % t
  79. return None
  80. def GetLineNumber( self ):
  81. return self.__lineNumber
  82. def GetPercentComplete( self ):
  83. return (self.__currentCharacter * 100) / self.__fileLen
  84. def GetLineContents( self ):
  85. m = self.__notnewline.match( self.__curString, self.__currentCharacter )
  86. if m:
  87. return self.__curString[ m.start() : m.end() ]
  88. else:
  89. return ""
  90. def __SkipWhitespace( self ):
  91. if self.__bSkipWhitespace:
  92. while 1:
  93. a = self.__whitespace.match( self.__curString, self.__currentCharacter )
  94. b = self.__newline.match( self.__curString, self.__currentCharacter )
  95. if a:
  96. self.__currentCharacter = a.end()
  97. continue
  98. elif b:
  99. self.__currentCharacter = b.end()
  100. self.__lineNumber += 1
  101. continue
  102. else:
  103. break