def apply_macros(self): """ Recursively apply macros to the output of `process()` To be called after `process()`. The `output` variable is overwritten by this. Returns: The final source code after applying all macro replacements. """ if len(self.output) == 0: print('There is no source code.') return rd = CodeReader(self.output) applied_count = 0 out = '' while not rd.has_end(): out += self._handle_whitespace(rd) if rd.has_end(): break if rd.has_identifier(): ident = rd.consume_identifier() ident_whitesp = rd.consume_inline_whitespace() if ident in self.defines: macros = self.defines[ident] replacement = None if rd.has_bracket(): # array macro bracket = rd.consume_block()[1:-1] for mm in macros: if mm.is_arraylike(): if mm.can_use_args([bracket]): replacement = mm.generate([bracket]) break if replacement is None: out += ident + ident_whitesp out += '[%s]' % bracket else: out += replacement applied_count += 1 elif rd.has_paren(): # func macro paren = rd.consume_block() t = T_Paren(paren) t.set_type(ParenType.ARGVALS) t.tokenize() args = [] for a in t.tokens: args.append(a.value) # print(args) for mm in macros: if mm.is_functionlike(): if mm.can_use_args(args): replacement = mm.generate(args) break if replacement is None: out += ident + ident_whitesp + paren print( '[W] Macro "%s" defined, but can\'t use arguments (%s)' % (ident, ', '.join(args) )) else: out += replacement applied_count += 1 else: # const macro for mm in macros: if mm.can_use_args(None): replacement = mm.generate(None) break if replacement is None: out += ident + ident_whitesp else: out += replacement + ident_whitesp applied_count += 1 else: out += ident + ident_whitesp # give it back # "...", and "sdgfsd""JOINED" "This too" elif rd.has_string(): # handle string concatenation s = '' while rd.has_string(): s += rd.consume_string()[1:-1] # drop quotes rd.sweep() out += '"%s"' % s # //... elif rd.has_inline_comment(): rd.consume_line() # /* ... */ elif rd.has_block_comment(): rd.consume_block_comment() # any char... else: out += rd.consume() self.output = out # take care of macros in macros if applied_count > 0: return self.apply_macros() else: return out