17 return "beginning of file"
20 def removeHeaderQuotes (orig
):
23 elif orig
[0] == orig
[-1] == '"':
25 elif orig
[0] == '<' and orig
[-1] == '>':
31 def dumpTokens (tokens
, toError
=False):
41 chars
+= indent
*scope
+ line
+ "\n"
43 chars
+= indent
*scope
+ token
+ "\n"
48 chars
+= indent
*scope
+ line
+ "\n"
51 chars
+= indent
*scope
+ token
55 chars
+= indent
*scope
+ line
+ ";\n"
66 sys
.stderr
.write(chars
)
68 sys
.stdout
.write(chars
)
71 class HeaderData(object):
77 class SrcLexer(object):
78 """Lexicographical analyzer for .src format.
80 The role of a lexer is to parse the source file and break it into
81 appropriate tokens. Such tokens are later passed to a parser to
82 build the syntax tree.
90 def __init__ (self
, chars
, filepath
= None):
91 self
.filepath
= filepath
92 self
.parentLexer
= None
94 self
.bufsize
= len(self
.chars
)
96 # TODO: use parameters for this
97 # Properties that can be copied.
98 self
.headerDict
= dict ()
100 self
.debugMacro
= False
101 self
.includeDirs
= list ()
102 self
.expandHeaders
= True
103 self
.inMacroDefine
= False
104 self
.stopOnHeader
= False
106 def copyProperties (self
, other
):
107 """Copy properties from another instance of SrcLexer."""
109 # TODO: use parameters for this
110 self
.headerDict
= other
.headerDict
111 self
.debug
= other
.debug
112 self
.debugMacro
= other
.debugMacro
113 self
.includeDirs
= other
.includeDirs
[:]
114 self
.expandHeaders
= other
.expandHeaders
115 self
.inMacroDefine
= other
.inMacroDefine
116 self
.stopOnHeader
= other
.stopOnHeader
119 self
.firstNonBlank
= ''
123 self
.visibilityStack
= []
125 def getTokens (self
):
128 def getDefines (self
):
131 def nextPos (self
, i
):
144 def prevPos (self
, i
):
157 def isCodeVisible (self
):
158 if len(self
.visibilityStack
) == 0:
160 for item
in self
.visibilityStack
:
161 if item
!= SrcLexer
.VISIBLE
:
172 if self
.firstNonBlank
== '' and not c
in [' ', "\n", "\t"]:
173 # Store the first non-blank in a line.
174 self
.firstNonBlank
= c
176 self
.firstNonBlank
= ''
183 i
= self
.lineBreak(i
)
185 i
= self
.doubleQuote(i
)
186 elif c
in [' ', "\t"]:
188 elif c
in ";()[]{}<>,=+-*":
189 # Any outstanding single-character token.
190 i
= self
.anyToken(i
, c
)
191 elif self
.isCodeVisible():
200 self
.tokens
.append(self
.token
)
202 if not self
.parentLexer
and self
.debug
:
203 progress ("-"*68 + "\n")
204 progress ("All defines found in this translation unit:\n")
205 keys
= self
.defines
.keys()
208 progress ("@ %s\n"%key
)
210 def dumpTokens (self
, toError
=False):
211 dumpTokens(self
.tokens
, toError
)
214 def maybeAddToken (self
):
215 if len(self
.token
) > 0:
216 self
.tokens
.append(self
.token
)
220 #--------------------------------------------------------------------
224 if not self
.isCodeVisible():
233 if self
.inMacroDefine
:
236 if not self
.firstNonBlank
== '#':
240 # We are in preprocessing mode.
242 # Get the macro command name '#<command> .....'
244 command
, define
, buf
= '', '', ''
245 firstNonBlank
= False
250 if c
== '\\' and self
.chars
[self
.nextPos(i
)] == "\n":
257 if len(buf
) > 0 and len(command
) == 0:
261 elif c
in [' ', "\t"]:
262 if not firstNonBlank
:
263 # Ignore any leading blanks after the '#'.
266 if len(command
) == 0:
272 if len(buf
) > 0 and len(command
) == 0:
276 if not firstNonBlank
:
280 if command
== 'define':
281 self
.handleMacroDefine(buf
)
282 elif command
== 'include':
283 self
.handleMacroInclude(buf
)
284 elif command
== 'ifdef':
285 defineName
= buf
.strip()
286 if self
.defines
.has_key(defineName
):
287 self
.visibilityStack
.append(SrcLexer
.VISIBLE
)
289 self
.visibilityStack
.append(SrcLexer
.INVISIBLE_PRE
)
291 elif command
== 'ifndef':
292 defineName
= buf
.strip()
293 if self
.defines
.has_key(defineName
):
294 self
.visibilityStack
.append(SrcLexer
.INVISIBLE_PRE
)
296 self
.visibilityStack
.append(SrcLexer
.VISIBLE
)
298 elif command
== 'if':
299 if self
.evalCodeVisibility(buf
):
300 self
.visibilityStack
.append(SrcLexer
.VISIBLE
)
302 self
.visibilityStack
.append(SrcLexer
.INVISIBLE_PRE
)
304 elif command
== 'elif':
305 if len(self
.visibilityStack
) == 0:
306 raise ParseError ('')
308 if self
.visibilityStack
[-1] == SrcLexer
.VISIBLE
:
309 self
.visibilityStack
[-1] = SrcLexer
.INVISIBLE_POST
310 elif self
.visibilityStack
[-1] == SrcLexer
.INVISIBLE_PRE
:
311 # Evaluate only if the current visibility is false.
312 if self
.evalCodeVisibility(buf
):
313 self
.visibilityStack
[-1] = SrcLexer
.VISIBLE
315 elif command
== 'else':
316 if len(self
.visibilityStack
) == 0:
317 raise ParseError ('')
319 if self
.visibilityStack
[-1] == SrcLexer
.VISIBLE
:
320 self
.visibilityStack
[-1] = SrcLexer
.INVISIBLE_POST
321 if self
.visibilityStack
[-1] == SrcLexer
.INVISIBLE_PRE
:
322 self
.visibilityStack
[-1] = SrcLexer
.VISIBLE
324 elif command
== 'endif':
325 if len(self
.visibilityStack
) == 0:
326 raise ParseError ('')
327 self
.visibilityStack
.pop()
329 elif command
== 'undef':
331 elif command
in ['error', 'pragma']:
334 print "'%s' '%s'"%(command
, buf
)
341 def evalCodeVisibility (self
, buf
):
347 def handleMacroDefine (self
, buf
):
349 mparser
= macroparser
.MacroParser(buf
)
350 mparser
.debug
= self
.debugMacro
352 macro
= mparser
.getMacro()
354 self
.defines
[macro
.name
] = macro
356 def handleMacroInclude (self
, buf
):
358 # Strip excess string if any.
362 headerSub
= removeHeaderQuotes(buf
)
364 if not self
.expandHeaders
:
365 # We don't want to expand headers. Bail out.
367 progress ("%s ignored\n"%headerSub
)
372 for includeDir
in self
.includeDirs
:
373 hpath
= includeDir
+ '/' + headerSub
374 if os
.path
.isfile(hpath
) and hpath
!= self
.filepath
:
379 error("included header file " + headerSub
+ " not found\n", self
.stopOnHeader
)
383 progress ("%s found\n"%headerPath
)
385 if headerPath
in self
.headerDict
:
387 progress ("%s already included\n"%headerPath
)
390 if SrcLexer
.headerCache
.has_key(headerPath
):
392 progress ("%s in cache\n"%headerPath
)
393 for key
in SrcLexer
.headerCache
[headerPath
].defines
.keys():
394 self
.defines
[key
] = SrcLexer
.headerCache
[headerPath
].defines
[key
]
397 chars
= open(headerPath
, 'r').read()
398 mclexer
= SrcLexer(chars
, headerPath
)
399 mclexer
.copyProperties(self
)
400 mclexer
.parentLexer
= self
402 hdrData
= HeaderData()
403 hdrData
.tokens
= mclexer
.getTokens()
404 headerDefines
= mclexer
.getDefines()
405 for key
in headerDefines
.keys():
406 defines
[key
] = headerDefines
[key
]
407 hdrData
.defines
[key
] = headerDefines
[key
]
409 self
.headerDict
[headerPath
] = True
410 SrcLexer
.headerCache
[headerPath
] = hdrData
412 # Update the list of headers that have already been expaneded.
413 for key
in mclexer
.headerDict
.keys():
414 self
.headerDict
[key
] = True
417 progress ("defines found in header %s:\n"%headerSub
)
418 for key
in defines
.keys():
419 progress (" '%s'\n"%key
)
421 for key
in defines
.keys():
422 self
.defines
[key
] = defines
[key
]
426 if not self
.isCodeVisible():
429 if i
< self
.bufsize
- 1 and self
.chars
[i
+1] == '/':
430 # Parse line comment.
433 while i
< self
.bufsize
:
435 if ord(c
) in [0x0A, 0x0D]:
440 elif i
< self
.bufsize
- 1 and self
.chars
[i
+1] == '*':
443 while i
< self
.bufsize
:
445 if c
== '/' and self
.chars
[i
-1] == '*':
450 return self
.anyToken(i
, '/')
455 def lineBreak (self
, i
):
456 if not self
.isCodeVisible():
464 def doubleQuote (self
, i
):
465 if not self
.isCodeVisible():
470 while i
< self
.bufsize
:
473 self
.tokens
.append('"'+literal
+'"')
481 def anyToken (self
, i
, token
):
482 if not self
.isCodeVisible():