]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/Python/Eot/CodeFragmentCollector.py
BaseTools: Various typo
[mirror_edk2.git] / BaseTools / Source / Python / Eot / CodeFragmentCollector.py
CommitLineData
52302d4d
LG
1## @file\r
2# preprocess source file\r
3#\r
231fdbb2 4# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>\r
52302d4d 5#\r
40d841f6 6# This program and the accompanying materials\r
52302d4d
LG
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
72443dd2 18from __future__ import print_function\r
64429fbd 19from __future__ import absolute_import\r
52302d4d 20import re\r
1be2ed90 21import Common.LongFilePathOs as os\r
52302d4d
LG
22import sys\r
23\r
8189be6f
FB
24if sys.version_info.major == 3:\r
25 import antlr4 as antlr\r
26 from Eot.CParser4.CLexer import CLexer\r
27 from Eot.CParser4.CParser import CParser\r
28else:\r
29 import antlr3 as antlr\r
30 antlr.InputStream = antlr.StringStream\r
31 from Eot.CParser3.CLexer import CLexer\r
32 from Eot.CParser3.CParser import CParser\r
52302d4d 33\r
8189be6f
FB
34from Eot import FileProfile\r
35from Eot.CodeFragment import PP_Directive\r
36from Eot.ParserWarning import Warning\r
52302d4d
LG
37\r
38\r
39##define T_CHAR_SPACE ' '\r
40##define T_CHAR_NULL '\0'\r
41##define T_CHAR_CR '\r'\r
42##define T_CHAR_TAB '\t'\r
43##define T_CHAR_LF '\n'\r
44##define T_CHAR_SLASH '/'\r
45##define T_CHAR_BACKSLASH '\\'\r
46##define T_CHAR_DOUBLE_QUOTE '\"'\r
47##define T_CHAR_SINGLE_QUOTE '\''\r
48##define T_CHAR_STAR '*'\r
49##define T_CHAR_HASH '#'\r
50\r
51(T_CHAR_SPACE, T_CHAR_NULL, T_CHAR_CR, T_CHAR_TAB, T_CHAR_LF, T_CHAR_SLASH, \\r
52T_CHAR_BACKSLASH, T_CHAR_DOUBLE_QUOTE, T_CHAR_SINGLE_QUOTE, T_CHAR_STAR, T_CHAR_HASH) = \\r
53(' ', '\0', '\r', '\t', '\n', '/', '\\', '\"', '\'', '*', '#')\r
54\r
55SEPERATOR_TUPLE = ('=', '|', ',', '{', '}')\r
56\r
57(T_COMMENT_TWO_SLASH, T_COMMENT_SLASH_STAR) = (0, 1)\r
58\r
59(T_PP_INCLUDE, T_PP_DEFINE, T_PP_OTHERS) = (0, 1, 2)\r
60\r
61## The collector for source code fragments.\r
62#\r
63# PreprocessFile method should be called prior to ParseFile\r
64#\r
65# GetNext*** procedures mean these procedures will get next token first, then make judgement.\r
66# Get*** procedures mean these procedures will make judgement on current token only.\r
67#\r
68class CodeFragmentCollector:\r
69 ## The constructor\r
70 #\r
71 # @param self The object pointer\r
72 # @param FileName The file that to be parsed\r
73 #\r
74 def __init__(self, FileName):\r
75 self.Profile = FileProfile.FileProfile(FileName)\r
76 self.Profile.FileLinesList.append(T_CHAR_LF)\r
77 self.FileName = FileName\r
78 self.CurrentLineNumber = 1\r
79 self.CurrentOffsetWithinLine = 0\r
80\r
81 self.__Token = ""\r
82 self.__SkippedChars = ""\r
83\r
52302d4d
LG
84 ## __EndOfFile() method\r
85 #\r
86 # Judge current buffer pos is at file end\r
87 #\r
88 # @param self The object pointer\r
89 # @retval True Current File buffer position is at file end\r
90 # @retval False Current File buffer position is NOT at file end\r
91 #\r
92 def __EndOfFile(self):\r
93 NumberOfLines = len(self.Profile.FileLinesList)\r
94 SizeOfLastLine = len(self.Profile.FileLinesList[-1])\r
95 if self.CurrentLineNumber == NumberOfLines and self.CurrentOffsetWithinLine >= SizeOfLastLine - 1:\r
96 return True\r
97 elif self.CurrentLineNumber > NumberOfLines:\r
98 return True\r
99 else:\r
100 return False\r
101\r
102 ## __EndOfLine() method\r
103 #\r
104 # Judge current buffer pos is at line end\r
105 #\r
106 # @param self The object pointer\r
107 # @retval True Current File buffer position is at line end\r
108 # @retval False Current File buffer position is NOT at line end\r
109 #\r
110 def __EndOfLine(self):\r
111 SizeOfCurrentLine = len(self.Profile.FileLinesList[self.CurrentLineNumber - 1])\r
112 if self.CurrentOffsetWithinLine >= SizeOfCurrentLine - 1:\r
113 return True\r
114 else:\r
115 return False\r
116\r
117 ## Rewind() method\r
118 #\r
119 # Reset file data buffer to the initial state\r
120 #\r
121 # @param self The object pointer\r
122 #\r
123 def Rewind(self):\r
124 self.CurrentLineNumber = 1\r
125 self.CurrentOffsetWithinLine = 0\r
126\r
127 ## __UndoOneChar() method\r
128 #\r
129 # Go back one char in the file buffer\r
130 #\r
131 # @param self The object pointer\r
132 # @retval True Successfully go back one char\r
133 # @retval False Not able to go back one char as file beginning reached\r
134 #\r
135 def __UndoOneChar(self):\r
136\r
137 if self.CurrentLineNumber == 1 and self.CurrentOffsetWithinLine == 0:\r
138 return False\r
139 elif self.CurrentOffsetWithinLine == 0:\r
140 self.CurrentLineNumber -= 1\r
141 self.CurrentOffsetWithinLine = len(self.__CurrentLine()) - 1\r
142 else:\r
143 self.CurrentOffsetWithinLine -= 1\r
144 return True\r
145\r
146 ## __GetOneChar() method\r
147 #\r
148 # Move forward one char in the file buffer\r
149 #\r
150 # @param self The object pointer\r
151 #\r
152 def __GetOneChar(self):\r
153 if self.CurrentOffsetWithinLine == len(self.Profile.FileLinesList[self.CurrentLineNumber - 1]) - 1:\r
154 self.CurrentLineNumber += 1\r
155 self.CurrentOffsetWithinLine = 0\r
156 else:\r
157 self.CurrentOffsetWithinLine += 1\r
158\r
159 ## __CurrentChar() method\r
160 #\r
161 # Get the char pointed to by the file buffer pointer\r
162 #\r
163 # @param self The object pointer\r
164 # @retval Char Current char\r
165 #\r
166 def __CurrentChar(self):\r
167 CurrentChar = self.Profile.FileLinesList[self.CurrentLineNumber - 1][self.CurrentOffsetWithinLine]\r
168\r
169 return CurrentChar\r
170\r
171 ## __NextChar() method\r
172 #\r
173 # Get the one char pass the char pointed to by the file buffer pointer\r
174 #\r
175 # @param self The object pointer\r
176 # @retval Char Next char\r
177 #\r
178 def __NextChar(self):\r
179 if self.CurrentOffsetWithinLine == len(self.Profile.FileLinesList[self.CurrentLineNumber - 1]) - 1:\r
180 return self.Profile.FileLinesList[self.CurrentLineNumber][0]\r
181 else:\r
182 return self.Profile.FileLinesList[self.CurrentLineNumber - 1][self.CurrentOffsetWithinLine + 1]\r
183\r
184 ## __SetCurrentCharValue() method\r
185 #\r
186 # Modify the value of current char\r
187 #\r
188 # @param self The object pointer\r
189 # @param Value The new value of current char\r
190 #\r
191 def __SetCurrentCharValue(self, Value):\r
192 self.Profile.FileLinesList[self.CurrentLineNumber - 1][self.CurrentOffsetWithinLine] = Value\r
193\r
194 ## __SetCharValue() method\r
195 #\r
196 # Modify the value of current char\r
197 #\r
198 # @param self The object pointer\r
199 # @param Value The new value of current char\r
200 #\r
201 def __SetCharValue(self, Line, Offset, Value):\r
202 self.Profile.FileLinesList[Line - 1][Offset] = Value\r
203\r
204 ## __CurrentLine() method\r
205 #\r
206 # Get the list that contains current line contents\r
207 #\r
208 # @param self The object pointer\r
209 # @retval List current line contents\r
210 #\r
211 def __CurrentLine(self):\r
212 return self.Profile.FileLinesList[self.CurrentLineNumber - 1]\r
213\r
214 ## __InsertComma() method\r
215 #\r
216 # Insert ',' to replace PP\r
217 #\r
218 # @param self The object pointer\r
219 # @retval List current line contents\r
220 #\r
221 def __InsertComma(self, Line):\r
222\r
223\r
224 if self.Profile.FileLinesList[Line - 1][0] != T_CHAR_HASH:\r
225 BeforeHashPart = str(self.Profile.FileLinesList[Line - 1]).split(T_CHAR_HASH)[0]\r
226 if BeforeHashPart.rstrip().endswith(T_CHAR_COMMA) or BeforeHashPart.rstrip().endswith(';'):\r
227 return\r
228\r
229 if Line - 2 >= 0 and str(self.Profile.FileLinesList[Line - 2]).rstrip().endswith(','):\r
230 return\r
231\r
232 if Line - 2 >= 0 and str(self.Profile.FileLinesList[Line - 2]).rstrip().endswith(';'):\r
233 return\r
234\r
235 if str(self.Profile.FileLinesList[Line]).lstrip().startswith(',') or str(self.Profile.FileLinesList[Line]).lstrip().startswith(';'):\r
236 return\r
237\r
238 self.Profile.FileLinesList[Line - 1].insert(self.CurrentOffsetWithinLine, ',')\r
239\r
240 ## PreprocessFileWithClear() method\r
241 #\r
242 # Run a preprocess for the file to clean all comments\r
243 #\r
244 # @param self The object pointer\r
245 #\r
246 def PreprocessFileWithClear(self):\r
247\r
248 self.Rewind()\r
249 InComment = False\r
250 DoubleSlashComment = False\r
251 HashComment = False\r
252 PPExtend = False\r
253 PPDirectiveObj = None\r
254 # HashComment in quoted string " " is ignored.\r
255 InString = False\r
256 InCharLiteral = False\r
257\r
258 self.Profile.FileLinesList = [list(s) for s in self.Profile.FileLinesListFromFile]\r
259 while not self.__EndOfFile():\r
260\r
261 if not InComment and self.__CurrentChar() == T_CHAR_DOUBLE_QUOTE:\r
262 InString = not InString\r
263\r
264 if not InComment and self.__CurrentChar() == T_CHAR_SINGLE_QUOTE:\r
265 InCharLiteral = not InCharLiteral\r
266 # meet new line, then no longer in a comment for // and '#'\r
267 if self.__CurrentChar() == T_CHAR_LF:\r
4231a819 268 if HashComment and PPDirectiveObj is not None:\r
52302d4d
LG
269 if PPDirectiveObj.Content.rstrip(T_CHAR_CR).endswith(T_CHAR_BACKSLASH):\r
270 PPDirectiveObj.Content += T_CHAR_LF\r
271 PPExtend = True\r
272 else:\r
273 PPExtend = False\r
274\r
275 EndLinePos = (self.CurrentLineNumber, self.CurrentOffsetWithinLine)\r
276\r
277 if InComment and DoubleSlashComment:\r
278 InComment = False\r
279 DoubleSlashComment = False\r
280\r
281 if InComment and HashComment and not PPExtend:\r
282 InComment = False\r
283 HashComment = False\r
284 PPDirectiveObj.Content += T_CHAR_LF\r
285 PPDirectiveObj.EndPos = EndLinePos\r
286 FileProfile.PPDirectiveList.append(PPDirectiveObj)\r
287 PPDirectiveObj = None\r
288\r
289 if InString or InCharLiteral:\r
290 CurrentLine = "".join(self.__CurrentLine())\r
291 if CurrentLine.rstrip(T_CHAR_LF).rstrip(T_CHAR_CR).endswith(T_CHAR_BACKSLASH):\r
292 SlashIndex = CurrentLine.rindex(T_CHAR_BACKSLASH)\r
293 self.__SetCharValue(self.CurrentLineNumber, SlashIndex, T_CHAR_SPACE)\r
294\r
295 self.CurrentLineNumber += 1\r
296 self.CurrentOffsetWithinLine = 0\r
297 # check for */ comment end\r
298 elif InComment and not DoubleSlashComment and not HashComment and self.__CurrentChar() == T_CHAR_STAR and self.__NextChar() == T_CHAR_SLASH:\r
299\r
300 self.__SetCurrentCharValue(T_CHAR_SPACE)\r
301 self.__GetOneChar()\r
302 self.__SetCurrentCharValue(T_CHAR_SPACE)\r
303 self.__GetOneChar()\r
304 InComment = False\r
305 # set comments to spaces\r
306 elif InComment:\r
307 if HashComment:\r
308 # // follows hash PP directive\r
309 if self.__CurrentChar() == T_CHAR_SLASH and self.__NextChar() == T_CHAR_SLASH:\r
310 InComment = False\r
311 HashComment = False\r
312 PPDirectiveObj.EndPos = (self.CurrentLineNumber, self.CurrentOffsetWithinLine - 1)\r
313 FileProfile.PPDirectiveList.append(PPDirectiveObj)\r
314 PPDirectiveObj = None\r
315 continue\r
316 else:\r
317 PPDirectiveObj.Content += self.__CurrentChar()\r
318\r
319 self.__SetCurrentCharValue(T_CHAR_SPACE)\r
320 self.__GetOneChar()\r
321 # check for // comment\r
322 elif self.__CurrentChar() == T_CHAR_SLASH and self.__NextChar() == T_CHAR_SLASH:\r
323 InComment = True\r
324 DoubleSlashComment = True\r
325\r
326 # check for '#' comment\r
327 elif self.__CurrentChar() == T_CHAR_HASH and not InString and not InCharLiteral:\r
328 InComment = True\r
329 HashComment = True\r
330 PPDirectiveObj = PP_Directive('', (self.CurrentLineNumber, self.CurrentOffsetWithinLine), None)\r
331 # check for /* comment start\r
332 elif self.__CurrentChar() == T_CHAR_SLASH and self.__NextChar() == T_CHAR_STAR:\r
333\r
334 self.__SetCurrentCharValue( T_CHAR_SPACE)\r
335 self.__GetOneChar()\r
336 self.__SetCurrentCharValue( T_CHAR_SPACE)\r
337 self.__GetOneChar()\r
338 InComment = True\r
339 else:\r
340 self.__GetOneChar()\r
341\r
342 EndLinePos = (self.CurrentLineNumber, self.CurrentOffsetWithinLine)\r
343\r
344 if InComment and HashComment and not PPExtend:\r
345 PPDirectiveObj.EndPos = EndLinePos\r
346 FileProfile.PPDirectiveList.append(PPDirectiveObj)\r
347 self.Rewind()\r
348\r
349 ## ParseFile() method\r
350 #\r
351 # Parse the file profile buffer to extract fd, fv ... information\r
352 # Exception will be raised if syntax error found\r
353 #\r
354 # @param self The object pointer\r
355 #\r
356 def ParseFile(self):\r
357 self.PreprocessFileWithClear()\r
358 # restore from ListOfList to ListOfString\r
359 self.Profile.FileLinesList = ["".join(list) for list in self.Profile.FileLinesList]\r
360 FileStringContents = ''\r
361 for fileLine in self.Profile.FileLinesList:\r
362 FileStringContents += fileLine\r
8189be6f 363 cStream = antlr.InputStream(FileStringContents)\r
52302d4d 364 lexer = CLexer(cStream)\r
8189be6f 365 tStream = antlr.CommonTokenStream(lexer)\r
52302d4d
LG
366 parser = CParser(tStream)\r
367 parser.translation_unit()\r
368\r
369 ## CleanFileProfileBuffer() method\r
370 #\r
371 # Reset all contents of the profile of a file\r
372 #\r
373 def CleanFileProfileBuffer(self):\r
374\r
375 FileProfile.PPDirectiveList = []\r
376 FileProfile.AssignmentExpressionList = []\r
377 FileProfile.FunctionDefinitionList = []\r
378 FileProfile.VariableDeclarationList = []\r
379 FileProfile.EnumerationDefinitionList = []\r
380 FileProfile.StructUnionDefinitionList = []\r
381 FileProfile.TypedefDefinitionList = []\r
382 FileProfile.FunctionCallingList = []\r
383\r
384 ## PrintFragments() method\r
385 #\r
386 # Print the contents of the profile of a file\r
387 #\r
388 def PrintFragments(self):\r
389\r
72443dd2 390 print('################# ' + self.FileName + '#####################')\r
52302d4d 391\r
72443dd2 392 print('/****************************************/')\r
fb0b35e0 393 print('/************** ASSIGNMENTS *************/')\r
72443dd2 394 print('/****************************************/')\r
fb0b35e0
AC
395 for assign in FileProfile.AssignmentExpressionList:\r
396 print(str(assign.StartPos) + assign.Name + assign.Operator + assign.Value)\r
52302d4d 397\r
72443dd2
GL
398 print('/****************************************/')\r
399 print('/********* PREPROCESS DIRECTIVES ********/')\r
400 print('/****************************************/')\r
52302d4d 401 for pp in FileProfile.PPDirectiveList:\r
72443dd2 402 print(str(pp.StartPos) + pp.Content)\r
52302d4d 403\r
72443dd2
GL
404 print('/****************************************/')\r
405 print('/********* VARIABLE DECLARATIONS ********/')\r
406 print('/****************************************/')\r
52302d4d 407 for var in FileProfile.VariableDeclarationList:\r
72443dd2 408 print(str(var.StartPos) + var.Modifier + ' '+ var.Declarator)\r
52302d4d 409\r
72443dd2
GL
410 print('/****************************************/')\r
411 print('/********* FUNCTION DEFINITIONS *********/')\r
412 print('/****************************************/')\r
52302d4d 413 for func in FileProfile.FunctionDefinitionList:\r
72443dd2 414 print(str(func.StartPos) + func.Modifier + ' '+ func.Declarator + ' ' + str(func.NamePos))\r
52302d4d 415\r
72443dd2
GL
416 print('/****************************************/')\r
417 print('/************ ENUMERATIONS **************/')\r
418 print('/****************************************/')\r
52302d4d 419 for enum in FileProfile.EnumerationDefinitionList:\r
72443dd2 420 print(str(enum.StartPos) + enum.Content)\r
52302d4d 421\r
72443dd2
GL
422 print('/****************************************/')\r
423 print('/*********** STRUCTS/UNIONS *************/')\r
424 print('/****************************************/')\r
52302d4d 425 for su in FileProfile.StructUnionDefinitionList:\r
72443dd2 426 print(str(su.StartPos) + su.Content)\r
52302d4d 427\r
72443dd2
GL
428 print('/****************************************/')\r
429 print('/************** TYPEDEFS ****************/')\r
430 print('/****************************************/')\r
52302d4d 431 for typedef in FileProfile.TypedefDefinitionList:\r
72443dd2 432 print(str(typedef.StartPos) + typedef.ToType)\r
52302d4d
LG
433\r
434##\r
435#\r
436# This acts like the main() function for the script, unless it is 'import'ed into another\r
437# script.\r
438#\r
439if __name__ == "__main__":\r
440\r
72443dd2 441 print("For Test.")\r