code fragment storage initial check-in.
[people/mcb30/basetools.git] / Source / Python / Ecc / CodeFragmentCollector.py
1 ## @file\r
2 # preprocess source file\r
3 #\r
4 #  Copyright (c) 2007, Intel Corporation\r
5 #\r
6 #  All rights reserved. This program and the accompanying materials\r
7 #  are licensed and made available under the terms and conditions of the BSD License\r
8 #  which accompanies this distribution.  The full text of the license may be found at\r
9 #  http://opensource.org/licenses/bsd-license.php\r
10 #\r
11 #  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12 #  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13 #\r
14 \r
15 ##\r
16 # Import Modules\r
17 #\r
18 \r
19 import re\r
20 import os\r
21 import sys\r
22 import FileProfile\r
23 from CodeFragment import Comment\r
24 from CodeFragment import PP_Directive\r
25 from ParserWarning import Warning\r
26 \r
27 \r
28 ##define T_CHAR_SPACE                ' '\r
29 ##define T_CHAR_NULL                 '\0'\r
30 ##define T_CHAR_CR                   '\r'\r
31 ##define T_CHAR_TAB                  '\t'\r
32 ##define T_CHAR_LF                   '\n'\r
33 ##define T_CHAR_SLASH                '/'\r
34 ##define T_CHAR_BACKSLASH            '\\'\r
35 ##define T_CHAR_DOUBLE_QUOTE         '\"'\r
36 ##define T_CHAR_SINGLE_QUOTE         '\''\r
37 ##define T_CHAR_STAR                 '*'\r
38 ##define T_CHAR_HASH                 '#'\r
39 \r
40 (T_CHAR_SPACE, T_CHAR_NULL, T_CHAR_CR, T_CHAR_TAB, T_CHAR_LF, T_CHAR_SLASH, \\r
41 T_CHAR_BACKSLASH, T_CHAR_DOUBLE_QUOTE, T_CHAR_SINGLE_QUOTE, T_CHAR_STAR, T_CHAR_HASH) = \\r
42 (' ', '\0', '\r', '\t', '\n', '/', '\\', '\"', '\'', '*', '#')\r
43 \r
44 SEPERATOR_TUPLE = ('=', '|', ',', '{', '}') \r
45 \r
46 (T_COMMENT_TWO_SLASH, T_COMMENT_SLASH_STAR) = (0, 1)\r
47 \r
48 (T_PP_INCLUDE, T_PP_DEFINE, T_PP_OTHERS) = (0, 1, 2)\r
49 \r
50 ## The collector for source code fragments.\r
51 #\r
52 # PreprocessFile method should be called prior to ParseFile\r
53 #\r
54 # GetNext*** procedures mean these procedures will get next token first, then make judgement.\r
55 # Get*** procedures mean these procedures will make judgement on current token only.\r
56 #        \r
57 class CodeFragmentCollector:\r
58     ## The constructor\r
59     #\r
60     #   @param  self        The object pointer\r
61     #   @param  FileName    The file that to be parsed\r
62     #\r
63     def __init__(self, FileName):\r
64         self.Profile = FileProfile.FileProfile(FileName)\r
65         self.Profile.FileLinesList.append(list(T_CHAR_LF))\r
66         self.FileName = FileName\r
67         self.CurrentLineNumber = 1\r
68         self.CurrentOffsetWithinLine = 0\r
69 \r
70         self.__Token = ""\r
71         self.__SkippedChars = ""\r
72 \r
73     ## __IsWhiteSpace() method\r
74     #\r
75     #   Whether char at current FileBufferPos is whitespace\r
76     #\r
77     #   @param  self        The object pointer\r
78     #   @param  Char        The char to test\r
79     #   @retval True        The char is a kind of white space\r
80     #   @retval False       The char is NOT a kind of white space\r
81     #\r
82     def __IsWhiteSpace(self, Char):\r
83         if Char in (T_CHAR_NULL, T_CHAR_CR, T_CHAR_SPACE, T_CHAR_TAB, T_CHAR_LF):\r
84             return True\r
85         else:\r
86             return False\r
87 \r
88     ## __SkipWhiteSpace() method\r
89     #\r
90     #   Skip white spaces from current char, return number of chars skipped\r
91     #\r
92     #   @param  self        The object pointer\r
93     #   @retval Count       The number of chars skipped\r
94     #\r
95     def __SkipWhiteSpace(self):\r
96         Count = 0\r
97         while not self.__EndOfFile():\r
98             Count += 1\r
99             if self.__CurrentChar() in (T_CHAR_NULL, T_CHAR_CR, T_CHAR_LF, T_CHAR_SPACE, T_CHAR_TAB):\r
100                 self.__SkippedChars += str(self.__CurrentChar())\r
101                 self.__GetOneChar()\r
102 \r
103             else:\r
104                 Count = Count - 1\r
105                 return Count\r
106 \r
107     ## __EndOfFile() method\r
108     #\r
109     #   Judge current buffer pos is at file end\r
110     #\r
111     #   @param  self        The object pointer\r
112     #   @retval True        Current File buffer position is at file end\r
113     #   @retval False       Current File buffer position is NOT at file end\r
114     #\r
115     def __EndOfFile(self):\r
116         NumberOfLines = len(self.Profile.FileLinesList)\r
117         SizeOfLastLine = len(self.Profile.FileLinesList[-1])\r
118         if self.CurrentLineNumber == NumberOfLines and self.CurrentOffsetWithinLine >= SizeOfLastLine - 1:\r
119             return True\r
120         else:\r
121             return False\r
122 \r
123     ## __EndOfLine() method\r
124     #\r
125     #   Judge current buffer pos is at line end\r
126     #\r
127     #   @param  self        The object pointer\r
128     #   @retval True        Current File buffer position is at line end\r
129     #   @retval False       Current File buffer position is NOT at line end\r
130     #\r
131     def __EndOfLine(self):\r
132         SizeOfCurrentLine = len(self.Profile.FileLinesList[self.CurrentLineNumber - 1])\r
133         if self.CurrentOffsetWithinLine >= SizeOfCurrentLine - 1:\r
134             return True\r
135         else:\r
136             return False\r
137     \r
138     ## Rewind() method\r
139     #\r
140     #   Reset file data buffer to the initial state\r
141     #\r
142     #   @param  self        The object pointer\r
143     #\r
144     def Rewind(self):\r
145         self.CurrentLineNumber = 1\r
146         self.CurrentOffsetWithinLine = 0\r
147     \r
148     ## __UndoOneChar() method\r
149     #\r
150     #   Go back one char in the file buffer\r
151     #\r
152     #   @param  self        The object pointer\r
153     #   @retval True        Successfully go back one char\r
154     #   @retval False       Not able to go back one char as file beginning reached\r
155     #    \r
156     def __UndoOneChar(self):\r
157         \r
158         if self.CurrentLineNumber == 1 and self.CurrentOffsetWithinLine == 0:\r
159             return False\r
160         elif self.CurrentOffsetWithinLine == 0:\r
161             self.CurrentLineNumber -= 1\r
162             self.CurrentOffsetWithinLine = len(self.__CurrentLine()) - 1\r
163         else:\r
164             self.CurrentOffsetWithinLine -= 1\r
165         return True\r
166         \r
167     ## __GetOneChar() method\r
168     #\r
169     #   Move forward one char in the file buffer\r
170     #\r
171     #   @param  self        The object pointer\r
172     #  \r
173     def __GetOneChar(self):\r
174         if self.CurrentOffsetWithinLine == len(self.Profile.FileLinesList[self.CurrentLineNumber - 1]) - 1:\r
175                 self.CurrentLineNumber += 1\r
176                 self.CurrentOffsetWithinLine = 0\r
177         else:\r
178                 self.CurrentOffsetWithinLine += 1\r
179 \r
180     ## __CurrentChar() method\r
181     #\r
182     #   Get the char pointed to by the file buffer pointer\r
183     #\r
184     #   @param  self        The object pointer\r
185     #   @retval Char        Current char\r
186     #  \r
187     def __CurrentChar(self):\r
188         CurrentChar = self.Profile.FileLinesList[self.CurrentLineNumber - 1][self.CurrentOffsetWithinLine]\r
189 #        if CurrentChar > 255:\r
190 #            raise Warning("Non-Ascii char found At Line %d, offset %d" % (self.CurrentLineNumber, self.CurrentOffsetWithinLine), self.FileName, self.CurrentLineNumber)\r
191         return CurrentChar\r
192     \r
193     ## __NextChar() method\r
194     #\r
195     #   Get the one char pass the char pointed to by the file buffer pointer\r
196     #\r
197     #   @param  self        The object pointer\r
198     #   @retval Char        Next char\r
199     #\r
200     def __NextChar(self):\r
201         if self.CurrentOffsetWithinLine == len(self.Profile.FileLinesList[self.CurrentLineNumber - 1]) - 1:\r
202             return self.Profile.FileLinesList[self.CurrentLineNumber][0]\r
203         else:\r
204             return self.Profile.FileLinesList[self.CurrentLineNumber - 1][self.CurrentOffsetWithinLine + 1]\r
205         \r
206     ## __SetCurrentCharValue() method\r
207     #\r
208     #   Modify the value of current char\r
209     #\r
210     #   @param  self        The object pointer\r
211     #   @param  Value       The new value of current char\r
212     #\r
213     def __SetCurrentCharValue(self, Value):\r
214         self.Profile.FileLinesList[self.CurrentLineNumber - 1][self.CurrentOffsetWithinLine] = Value\r
215         \r
216     ## __CurrentLine() method\r
217     #\r
218     #   Get the list that contains current line contents\r
219     #\r
220     #   @param  self        The object pointer\r
221     #   @retval List        current line contents\r
222     #\r
223     def __CurrentLine(self):\r
224         return self.Profile.FileLinesList[self.CurrentLineNumber - 1]\r
225         \r
226     ## PreprocessFile() method\r
227     #\r
228     #   Preprocess file contents, replace comments with spaces.\r
229     #   In the end, rewind the file buffer pointer to the beginning\r
230     #   BUGBUG: No !include statement processing contained in this procedure\r
231     #   !include statement should be expanded at the same FileLinesList[CurrentLineNumber - 1]\r
232     #\r
233     #   @param  self        The object pointer\r
234     #   \r
235     def PreprocessFile(self):\r
236         \r
237         self.Rewind()\r
238         InComment = False\r
239         DoubleSlashComment = False\r
240         HashComment = False\r
241         PPExtend = False\r
242         CommentObj = None\r
243         PPDirectiveObj = None \r
244 \r
245         while not self.__EndOfFile():\r
246             \r
247             # meet new line, then no longer in a comment for // and '#'\r
248             if self.__CurrentChar() == T_CHAR_LF:\r
249                 if HashComment and PPDirectiveObj != None:\r
250                     if PPDirectiveObj.Content.rstrip(T_CHAR_CR).endswith(T_CHAR_BACKSLASH):\r
251                         PPDirectiveObj.Content += T_CHAR_LF\r
252                         PPExtend = True\r
253                     else:\r
254                         PPExtend = False\r
255                         \r
256                 EndLinePos = (self.CurrentLineNumber, self.CurrentOffsetWithinLine)\r
257                 self.CurrentLineNumber += 1\r
258                 self.CurrentOffsetWithinLine = 0\r
259                 if InComment and DoubleSlashComment:\r
260                     InComment = False\r
261                     DoubleSlashComment = False\r
262                     CommentObj.Content += T_CHAR_LF\r
263                     CommentObj.EndPos = EndLinePos\r
264                     FileProfile.CommentList.append(CommentObj)\r
265                     CommentObj = None\r
266                 if InComment and HashComment and not PPExtend:\r
267                     InComment = False\r
268                     HashComment = False\r
269                     PPDirectiveObj.Content += T_CHAR_LF\r
270                     PPDirectiveObj.EndPos = EndLinePos\r
271                     FileProfile.PPDirectiveList.append(PPDirectiveObj)\r
272                     PPDirectiveObj = None\r
273                     \r
274             # check for */ comment end\r
275             elif InComment and not DoubleSlashComment and not HashComment and self.__CurrentChar() == T_CHAR_STAR and self.__NextChar() == T_CHAR_SLASH:\r
276                 CommentObj.Content += self.__CurrentChar()\r
277                 self.__SetCurrentCharValue(T_CHAR_SPACE)\r
278                 self.__GetOneChar()\r
279                 CommentObj.Content += self.__CurrentChar()\r
280                 self.__SetCurrentCharValue(T_CHAR_SPACE)\r
281                 CommentObj.EndPos = (self.CurrentLineNumber, self.CurrentOffsetWithinLine)\r
282                 FileProfile.CommentList.append(CommentObj)\r
283                 CommentObj = None\r
284                 self.__GetOneChar()\r
285                 InComment = False\r
286             # set comments to spaces\r
287             elif InComment:                   \r
288                 if HashComment:\r
289                     # // follows hash PP directive\r
290                     if self.__CurrentChar() == T_CHAR_SLASH and self.__NextChar() == T_CHAR_SLASH:\r
291                         InComment = False\r
292                         HashComment = False\r
293                         PPDirectiveObj.EndPos = (self.CurrentLineNumber, self.CurrentOffsetWithinLine - 1)\r
294                         FileProfile.PPDirectiveList.append(PPDirectiveObj)\r
295                         PPDirectiveObj = None\r
296                         continue\r
297                     else:\r
298                         PPDirectiveObj.Content += self.__CurrentChar()\r
299                 else:\r
300                     CommentObj.Content += self.__CurrentChar()\r
301                 self.__SetCurrentCharValue(T_CHAR_SPACE)\r
302                 self.__GetOneChar()\r
303             # check for // comment\r
304             elif self.__CurrentChar() == T_CHAR_SLASH and self.__NextChar() == T_CHAR_SLASH:\r
305                 InComment = True\r
306                 DoubleSlashComment = True\r
307                 CommentObj = Comment('', (self.CurrentLineNumber, self.CurrentOffsetWithinLine), None, T_COMMENT_TWO_SLASH)\r
308             # check for '#' comment\r
309             elif self.__CurrentChar() == T_CHAR_HASH:\r
310                 InComment = True\r
311                 HashComment = True\r
312                 PPDirectiveObj = PP_Directive('', (self.CurrentLineNumber, self.CurrentOffsetWithinLine), None)\r
313             # check for /* comment start\r
314             elif self.__CurrentChar() == T_CHAR_SLASH and self.__NextChar() == T_CHAR_STAR:\r
315                 CommentObj = Comment('', (self.CurrentLineNumber, self.CurrentOffsetWithinLine), None, T_COMMENT_SLASH_STAR)\r
316                 CommentObj.Content += self.__CurrentChar()\r
317                 self.__SetCurrentCharValue( T_CHAR_SPACE)\r
318                 self.__GetOneChar()\r
319                 CommentObj.Content += self.__CurrentChar()\r
320                 self.__SetCurrentCharValue( T_CHAR_SPACE)\r
321                 self.__GetOneChar()\r
322                 InComment = True\r
323             else:\r
324                 self.__GetOneChar()\r
325 \r
326         # restore from ListOfList to ListOfString\r
327         self.Profile.FileLinesList = ["".join(list) for list in self.Profile.FileLinesList]\r
328         self.Rewind()\r
329 \r
330         \r
331 if __name__ == "__main__":\r
332     \r
333     collector = CodeFragmentCollector(sys.argv[1])\r
334     collector.PreprocessFile()\r
335     print "For Test."\r