python将c语言程序转变为抽象语法树(ast)

python使用pycparser库将c语言程序转变为抽象语法树(ast)

pycparser库github地址:
https://github.com/eliben/pycparser

封装好的方法

from __future__ import print_function

from pycparser.c_ast import *

from util.remove_zs import rm_emptyline, rm_includeline, rmCommentsInCFile

sys.path.extend(['.', '..'])

from pycparser import c_parser


# 读取c文件程序的内容并去除注释、空行以及头文件,最后生成ast
# 返回内容为处理后的源代码 和 ast
def translate_to_c(filename):
    # 这里展示不用本地编译器的方法
    # 但读取的文本序列,需去除#include #define 以及注释 这类语句才能生成AST
    with open(filename, encoding='utf-8') as f:
        txt = f.read()
    txt = rmCommentsInCFile(txt)  # 去除注释
    txt = rm_emptyline(txt)  # 去除空行
    txt = rm_includeline(txt)  # 去除头文件
    # print(txt)
    ast = c_parser.CParser().parse(txt)
    # print(ast)
    return txt, ast


# 直接将 源代码字符串 转变为 ast
# 返回内容为处理后的源代码 和 ast
def translate_to_c_txt(txt):
    txt = rmCommentsInCFile(txt)  # 去除注释
    txt = rm_emptyline(txt)  # 去除空行
    txt = rm_includeline(txt)  # 去除头文件
    # print(txt)
    ast = c_parser.CParser().parse(txt)
    # print(ast)
    return txt, ast


if __name__ == "__main__":
    filename = 'D:/desktop/t1.c'
    # filename = 'D:/desktop/学习/down的代码库/pycparser-master/examples/c_files/basic.c'

    txt, ast = translate_to_c(filename)
    ast.show()
    print(ast)

下面的类用于格式化程序(去除注释、空行、头文件)

# 用于去除cpp文件中注释和空行的工具类

import logging

logging.basicConfig(level=logging.INFO)


# 判断dictSymbols的key中,最先出现的符号是哪个,并返回其所在位置以及该符号
def get1stSymPos(s, fromPos=0):
    # 清除注释用,对能干扰清除注释的东西,进行判断
    g_DictSymbols = {'"': '"', '/*': '*/', '//': '\n'}
    listPos = []  # 位置,符号
    for b in g_DictSymbols:
        pos = s.find(b, fromPos)
        listPos.append((pos, b))  # 插入位置以及结束符号
    minIndex = -1  # 最小位置在listPos中的索引
    index = 0  # 索引
    while index < len(listPos):
        pos = listPos[index][0]  # 位置
        if minIndex < 0 and pos >= 0:  # 第一个非负位置
            minIndex = index
        if 0 <= pos < listPos[minIndex][0]:  # 后面出现的更靠前的位置
            minIndex = index
        index = index + 1
    if minIndex == -1:  # 没找到
        return (-1, None)
    else:
        return (listPos[minIndex])


# print(get1stSymPos(r'sdjfljkej""/*\'\'\'//\''))
# print(get1stSymPos('adsofiuwioghsdahg*kdhieghkhgkdjhg/'))

# 去掉cpp文件的注释
def rmCommentsInCFile(s):
    # 全局变量,清除注释用,对能干扰清除注释的东西,进行判断
    g_DictSymbols = {'"': '"', '/*': '*/', '//': '\n'}
    if not isinstance(s, str):
        raise TypeError(s)
    fromPos = 0
    while (fromPos < len(s)):
        result = get1stSymPos(s, fromPos)
        logging.info(result)
        if result[0] == -1:  # 没有符号了
            return s
        else:
            endPos = s.find(g_DictSymbols[result[1]], result[0] + len(result[1]))
            if result[1] == '//':  # 单行注释
                if endPos == -1:  # 没有换行符也可以
                    endPos = len(s)
                s = s.replace(s[result[0]:endPos], '', 1)
                fromPos = result[0]
            elif result[1] == '/*':  # 区块注释
                if endPos == -1:  # 没有结束符就报错
                    raise ValueError("块状注释未闭合")
                s = s.replace(s[result[0]:endPos + 2], '', 1)
                fromPos = result[0]
            else:  # 字符串
                if endPos == -1:  # 没有结束符就报错
                    raise ValueError("符号未闭合")
                fromPos = endPos + len(g_DictSymbols[result[1]])
    return s


# 去除程序中的空行
def rm_emptyline(ms):
    if not isinstance(ms, str):
        raise TypeError(ms)
    ms = "".join([s for s in ms.splitlines(True) if s.strip()])
    return ms


# 去除程序中的头文件
def rm_includeline(ms):
    if not isinstance(ms, str):
        raise TypeError(ms)
    ms = "".join([s for s in ms.splitlines(True) if '#include' not in s])
    return ms


if __name__ == '__main__':
    # func_def = open("D:/desktop/t1.c", encoding='utf-8').read()
    # s1 = rmCommentsInCFile(func_def)
    # print(repr(s1))
    ms = '   #include awf   as\n\nfae\nqae\n\n\n\n\nde'
    print(ms)
    ms = rm_emptyline(ms)
    s = rm_includeline(ms)
    print(s)

你可能感兴趣的:(python,c语言,开发语言)