def parse_c(source: str, initial_scope: CParserScope) -> Tuple[ca.FileAST, CParserScope]: # This is a modified version of `CParser.parse()` which initializes `_scope_stack`, # which contains the only stateful part of the parser that needs to be preserved # when parsing multiple files. c_parser = CParser() c_parser.clex.filename = "<source>" c_parser.clex.reset_lineno() c_parser._scope_stack = [initial_scope.copy()] c_parser._last_yielded_token = None try: ast = c_parser.cparser.parse(input=source, lexer=c_parser.clex) except ParseError as e: msg = str(e) position, msg = msg.split(": ", 1) parts = position.split(":") if len(parts) >= 2: # Adjust the line number by 1 to correct for the added typedefs lineno = int(parts[1]) - 1 posstr = f" at line {lineno}" if len(parts) >= 3: posstr += f", column {parts[2]}" try: line = source.split("\n")[lineno].rstrip() posstr += "\n\n" + line except IndexError: posstr += "(out of bounds?)" else: posstr = "" raise DecompFailure( f"Syntax error when parsing C context.\n{msg}{posstr}") return ast, c_parser._scope_stack[0].copy()
def cparse(text, types, filename='', debuglevel=0) -> CType: parser = CParser() parser.clex.filename = filename parser.clex.reset_lineno() parser._last_yielded_token = None parser._scope_stack = [dict()] for i, (k, _) in enumerate(types.items()): parser._add_typedef_name(k, (i, 0)) try: result = parser.cparser.parse(input=text, lexer=parser.clex, debug=debuglevel) except Exception as e: raise RuntimeError(f'Could not parse `{text}`') from e return CType.from_ast(result)