python - 在 Python 中自动检测 C/C++ 循环并放置大括号

标签 python regex python-3.x algorithm parsing

编辑概述和范围

这个问题归结为以下问题;给定源文件,自动为 C/C++ 中的可选控制 block 放置左大括号和右大括号。这些 block 是 if , else , do , while ,和for据我所知。

概述

我正在尝试跟踪和分析大量代码存储库中的各种循环、语句等,这些代码存储库不是我自己编写的。我的最终目标是对给定代码源中的所有循环执行计时统计(将来将扩展到其他事物,但超出了此问题的范围)。这些跟踪函数执行不同的操作,但它们都遵循类似的问题;被放置在感兴趣的 block 执行之前和之后。

本质上,我想转换代码:

for (i = 0; i < some_condition; i++) {
  some_code = goes(here);
}

for (i = 0; i < some_condition; i++)
{
  some_code = goes(here);
}

for (i = 0; i < some_condition; i++) { some_code = goes(here); }

for (i = 0; i < some_condition; i++)
  some_code = goes(here);

for (i = 0; i < some_condition; i++)
  for (i = 0; i < some_condition; i++)
    some_code = goes(here);

以下内容:

S_TRACE(); for (i = 0; i < some_condition; i++) {
  some_code = goes(here);
} E_TRACE();

S_TRACE(); for (i = 0; i < some_condition; i++)
{
  some_code = goes(here);
} E_TRACE();

S_TRACE(); for (i = 0; i < some_condition; i++) { some_code = goes(here); } E_TRACE();

S_TRACE(); for (i = 0; i < some_condition; i++) {
  some_code = goes(here); } E_TRACE();

S_TRACE(); for (i = 0; i < some_condition; i++) {
  S_TRACE(); for (i = 0; i < some_condition; i++) {
    some_code = goes(here); } E_TRACE(); } E_TRACE();

基本上,在不添加新代码的情况下,我想在语句开始之前插入一个函数(简单),之后> 声明(这可能很难)。例如,代码存储库中实际上有以下代码:

for( int i = 0; names[i]; i++ )
    if( !STRCMP( arg, names[i] ) )
    {
        *dst = names[i];
        return 0;
    }
return -1;

除了糟糕的可读性之外,我想在这种类型的循环上放置大括号,并插入我的跟踪函数。我省略了函数的参数(以解释嵌套)。

当前实现

我当前的实现使用 Python 中的正则表达式,因为我对这种语言相当熟悉和快速。相关实现环节如下:

import re
source = []
loops = [r"^\s*(for\s*\(.*\))\s*($|{\s*$|\s*)", r"^\s*(while\s*\(.*\))\s*($|{\s*$|\s*)", r"^\s*(do)\s*({?)$"]


def analyize_line(out_file):
    lnum, lstr = source.pop(0)

    for index, loop_type in enumerate(loops):
        match = re.findall(loop_type, lstr)
        if match:
            print(lnum + 1, ":", match[0][0])

            if '{' in match[0][1]:
                out_file.write(lstr.replace(match[0][0], "S_TRACE(); {}".format(match[0][0])))
                look_ahead_place()
                return
            else:
                last_chance = lstr + source[0][1]
                last_match = re.findall(loop_type, last_chance)
                if last_match and '{' in last_match[0][1]:
                    # same as above
                    out_file.write(lstr.replace(match[0][0], "S_TRACE(); {}".format(match[0][0])))
                    lcnum, lcstr = source.pop(0)
                    out_file.write(lcstr)
                    look_ahead_place()
                else:
                    # No matching bracket, make one
                    out_file.write(lstr.replace(match[0][0], "S_TRACE(); {} {{".format(match[0][0])))
                    look_ahead_and_place_bracket()
                return
    # if we did not match, just a normal line
    out_file.write(lstr)


def look_ahead_place():
    depth = 1
    for idx, nl in enumerate(source):
        substr = ""
        for c in nl[1]:
            substr += c
            if depth > 0:
                if c == '{':
                    depth += 1
                elif c == '}':
                    depth -= 1
                    if depth == 0:
                        substr += " E_TRACE(); "
        if depth == 0:
            source[idx][1] = substr
            return
    print("Error finding closing bracket here!")
    exit()


def look_ahead_and_place_bracket():
    for idx, nl in enumerate(source):
        # Is the next line a scopable? how to handle multiline? ???
        # TODO
        return


def trace_loops():
    global source
    src_filename = "./example.c"
    src_file = open(src_filename)
    out_file = open(src_filename + ".tr", 'w')
    source = [[number, line] for number, line in enumerate(src_file.readlines())]
    while len(source) > 0:
        analyize_line(out_file)

trace_loops()

example.c是上面出于演示目的提供的示例。我正在努力想出一种算法来处理内联循环、没有匹配大括号的循环以及不包含大括号但具有多行内部的循环。

任何对我的算法开发的帮助将不胜感激。如果还有什么需要解决的问题,请在评论中告诉我。

编辑::更多示例和预期结果

添加的字符被 < 包围和>可见性 token 。

嵌套无括号:

for( int i = 0; i < h->fdec->i_plane; i++ )
    for( int y = 0; y < h->param.i_height >> !!i; y++ )
        fwrite( &h->fdec->plane[i][y*h->fdec->i_stride[i]], 1, h->param.i_width >> !!i, f );

<S_TRACE(); >for( int i = 0; i < h->fdec->i_plane; i++ )< {>
    <S_TRACE(); >for( int y = 0; y < h->param.i_height >> !!i; y++ )< {>
        fwrite( &h->fdec->plane[i][y*h->fdec->i_stride[i]], 1, h->param.i_width >> !!i, f );< } E_TRACE();>< } E_TRACE();>

嵌套混合:

for( int i = 0; i < h->fdec->i_plane; i++ ) {
  for( int y = 0; y < h->param.i_height >> !!i; y++ )
    fwrite( &h->fdec->plane[i][y*h->fdec->i_stride[i]], 1, h->param.i_width >> !!i, ff );
}

<S_TRACE(); >for( int i = 0; i < h->fdec->i_plane; i++ ) {
  <S_TRACE(); >for( int y = 0; y < h->param.i_height >> !!i; y++ )< {>
    fwrite( &h->fdec->plane[i][y*h->fdec->i_stride[i]], 1, h->param.i_width >> !!i, ff );< } E_TRACE();>
}< E_TRACE();>

大型多行嵌套无括号:

for( int i = 0; i < h->sh.i_mmco_command_count; i++ )
    for( int j = 0; h->frames.reference[j]; j++ )
        if( h->frames.reference[j]->i_poc == h->sh.mmco[i].i_poc )
            x264_frame_push_unused(
                h, 
                x264_frame_shift( &h->frames.reference[j] ) 
            );

<S_TRACE(); >for( int i = 0; i < h->sh.i_mmco_command_count; i++ )< {>
    <S_TRACE(); >for( int j = 0; h->frames.reference[j]; j++ )< {>
        if( h->frames.reference[j]->i_poc == h->sh.mmco[i].i_poc )
            x264_frame_push_unused(
                h, 
                x264_frame_shift( &h->frames.reference[j] ) 
            );< } E_TRACE();>< } E_TRACE();>

这个粗略的多线:

for( int j = 0; 
  j < ((int) offsetof(x264_t,stat.frame.i_ssd) - (int) offsetof(x264_t,stat.frame.i_mv_bits)) / (int) sizeof(int); 
  j++ )
    ((int*)&h->stat.frame)[j] += ((int*)&t->stat.frame)[j];
for( int j = 0; j < 3; j++ )
    h->stat.frame.i_ssd[j] += t->stat.frame.i_ssd[j];
h->stat.frame.f_ssim += t->stat.frame.f_ssim;

<S_TRACE(); >for( int j = 0; 
  j < ((int) offsetof(x264_t,stat.frame.i_ssd) - (int) offsetof(x264_t,stat.frame.i_mv_bits)) / (int) sizeof(int); 
  j++ )< {>
    ((int*)&h->stat.frame)[j] += ((int*)&t->stat.frame)[j];< } E_TRACE();>
<S_TRACE(); >for( int j = 0; j < 3; j++ )< {>
    h->stat.frame.i_ssd[j] += t->stat.frame.i_ssd[j];< } E_TRACE();>
h->stat.frame.f_ssim += t->stat.frame.f_ssim;

If 语句边缘情况:

也许我的实现需要包含 if 语句来解决这个问题?

if( h->sh.i_type != SLICE_TYPE_I )
    for( int i_list = 0; i_list < 2; i_list++ )
        for( int i = 0; i < 32; i++ )
            h->stat.i_mb_count_ref[h->sh.i_type][i_list][i] += h->stat.frame.i_mb_count_ref[i_list][i];

最佳答案

你正在掉入兔子洞。你遇到的情况越多,你就会遇到的情况就越多,直到你必须为 C++ 编写一个实际的解析器,这将需要学习整个技术工具链。

相反,我强烈建议您使用 clang-format 这样的格式化工具来简化您的生活。已经知道如何解析 C++ 以首先使用一致的格式重写(因此大括号现在始终存在),然后您只需要担心平衡的大括号。

(如果这是构建过程的一部分,您可以复制代码,重新格式化它,然后分析重新格式化的代码。)

请注意,如果代码有趣地使用了模板,这可能还不够。但它有望帮助您顺利实现这一目标。

关于python - 在 Python 中自动检测 C/C++ 循环并放置大括号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60157749/

相关文章:

javascript - JavaScript 正则表达式问题

Linux 错误 : Unmet Dependencies

python - 将 Django 的 StaticLiveServerCase 与临时服务器一起使用

python - 如何使用 scipy/numpy 或 sympy 执行非线性优化?

c# - 使用正则表达式提取特定值

python - 为什么每次 PyQt5 项目都会收到警告 "QStandardPaths: XDG_RUNTIME_DIR not set"

python-3.x - 更新标签上的文本

python - Django-admin:无法访问管理后端 "attempt to write a readonly database"

python - Bokeh 显示从一开始就放大的图

python - 非贪婪正则表达式不会终止