0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Cコード解析】コード整形まとめ(備忘録)

Last updated at Posted at 2024-10-26

今まで書いた記事を1つのスクリプトにまとめる。

下記の記事で実践したことをまとめる。

スクリプト

main.py
import os
import shutil

import service.config as config
import service.anti_multiple_variable_declaration as AMVD
import service.anti_unused_variable as AUV
import service.anti_nothing_elseblock as ANE
import service.anti_blank_default_case as ABDC
import service.anti_nothing_default_case as ANDC

def main():
	target_dir, target_files = config.load_cfg("cfg.xml")

	# バックアップファイルの作成.
	backup_dir = target_dir + "_backup"
	if os.path.exists(backup_dir):
		shutil.rmtree(backup_dir)
	shutil.copytree(target_dir, backup_dir)

	for target_file in target_files:
		target_path = os.path.join(target_dir, target_file)

		AMVD.multiple_to_variable_declaration(target_path)
		AUV.delete_unused_variable(target_path)
		ANE.add_elseblock(target_path)
		ABDC.add_comment_default_case(target_path)
		ANDC.add_default_case(target_path)

if __name__ == "__main__":
	main()
config.py
import xml.etree.ElementTree as ET

def load_cfg(filename:str)->tuple[str, list]:
	# XMLファイルを読み込む
	tree = ET.parse(filename)
	root = tree.getroot()

	target_dir        = root.find('target_dir').text
	target_file_items = root.find('target_file')
	target_files      = [item.text for item in target_file_items]

	return target_dir, target_files
anti_unused_variable.py
import regex

def delete_unused_variable(filepath:str):
	pattern = r"(?:(?:auto|register|static|extern)\s+)?(?:(?:const|volatile|restrict|signed|unsigned|short|long)\s+)*\w+\s+\w+\s*\([^()]*\)\s*(\{([^{}]|(?1))*\})"

	pattern_val = r"[\t ]*(?:(?:auto|register|static|extern)\s+)?(?:(?:const|volatile|restrict|signed|unsigned|short|long)\s+)*\w+[\s*]+\w+\s*(?:=[^;]+)?;[^\n]*\n"

	with open(filepath, "r", encoding="utf-8", errors="ignore") as file_obj:
		codetext = file_obj.read()
		functions = regex.finditer(pattern, codetext, regex.DOTALL)
		for func in functions:
			functext = func.group()
			functext_edit = functext
			values = regex.finditer(pattern_val, functext, regex.DOTALL)
			for val in values:
				valtext = val.group()

				if "=" in valtext:
					# 代入演算子がある場合は=の左にある文字列が変数名.
					valname = regex.search(r"\w+(?=\s*=)", valtext).group()
				else:
					# 代入演算子がない場合は;の左にある文字列が変数名.
					valname = regex.search(r"\w+(?=\s*;)", valtext).group()


				valmatchs = regex.finditer(rf"\b{valname}\b", functext, regex.DOTALL)
				usedcount = 0
				for vallll in valmatchs:
					usedcount += 1

				if usedcount == 1:
					# 一度しか記述されていない場合は未使用変数と判断して削除.
					functext_edit = functext_edit.replace(valtext, "")
					pass
			
			codetext = codetext.replace(functext, functext_edit)
				
	with open(filepath, "w", encoding="utf-8", errors="ignore") as file_obj:
		file_obj.write(codetext)
anti_nothing_elseblock.py
import regex

def __elseblock_repl(match):
	elseblock = "\nelse\n{\n\t/* 処理なし */\n}"
	matchstr = match.group()

	# if文のインデントを取得する
	indent = regex.search(r"[\t ]*(?=\bif\b|\belse\b\s*\bif\b)", matchstr, regex.DOTALL).group()
	return matchstr + elseblock.replace("\n", "\n" + indent)


def add_elseblock(filepath:str):
	with open(filepath, "r", encoding="utf-8", errors="ignore") as file_obj:
		codetext = file_obj.read()
		edited_code = regex.sub(r"(?<=\n)\s*(?:\bif\b|\belse\b\s*\bif\b)\s*\([^()]*\)\s*(\{(?:[^{}]|(?1))*\})(?!\s*\belse\b\s*\bif\b|\s*\belse\b)", __elseblock_repl, codetext, regex.DOTALL)

	with open(filepath, "w", encoding="utf-8", errors="ignore") as file_obj:
		file_obj.write(edited_code)
anti_nothing_default_case.py
import regex

def __repl_add_default(match):
	matchstr = match.group()

	# 既にdefaultがある場合は、そのままの文字をreturn
	if not regex.search("\s*default\s*:", matchstr, regex.DOTALL):
		index = matchstr.rfind("}")

		indent = regex.search(r"[\t ]*(?=\bswitch\b)", matchstr, regex.DOTALL).group()
		matchstr = matchstr[:index] + "default: /* 処理なし */ break;\n"+ indent + matchstr[index:]

	return matchstr

def add_default_case(filepath:str):
	with open(filepath, "r", encoding="utf-8") as file_obj:
		codetext = file_obj.read()

		edited_code = regex.sub(r"(?<=\n)\s*switch\s*\([^()]*\)\s*(\{(?:[^{}]|(?1))*\})", __repl_add_default, codetext, flags=regex.DOTALL)

	with open(filepath, "w", encoding="utf-8", errors="ignore") as file_obj:
		file_obj.write(edited_code)
anti_multiple_variable_declaration.py
import regex

def __repldef(match:regex.Match)->str:
	matchtext:str = match.group()
	
	pattern = r"[\t ]*(?:(?:auto|register|static|extern)\s+)?(?:(?:const|volatile|restrict|signed|unsigned|short|long)\s+)*\w+\*?"
	datatype = regex.search(pattern, matchtext, regex.DOTALL).group()

	ret = matchtext.replace(",", f";\n{datatype}")
	return ret

def multiple_to_variable_declaration(file_path:str):
	pattern = r"(?<=[\n;])[\t ]*(?:(?:auto|register|static|extern)\s+)?(?:(?:const|volatile|restrict|signed|unsigned|short|long)\s+)*\w+[\s*]+\w+(?:\s*=[^,;]+)?\s*(,[\s*]*\w+(?:\s*=[^,;]+)?)+;"

	with open(file_path, "r", encoding="utf-8", errors="ignore") as file_obj:
		codetext = file_obj.read()
		edited_code = regex.sub(pattern, __repldef, codetext, flags=regex.DOTALL)

	with open(file_path, "w", encoding="utf-8", errors="ignore") as file_obj:
		file_obj.write(edited_code)
anti_blank_default_case.py
import regex

def add_comment_default_case(filepath:str):
	with open(filepath, "r", encoding="utf-8") as file_obj:
		codetext = file_obj.read()

		edited_code = regex.sub(r"(?<=default\s*:\s*);", "/* 処理なし */", codetext, flags=regex.DOTALL)

	with open(filepath, "w", encoding="utf-8", errors="ignore") as file_obj:
		file_obj.write(edited_code)

configファイル

こんな感じ

cfg.xml
<?xml version="1.0" encoding="UTF-8"?>
<config_data>
	<target_dir>C:\Users\XXXX\code</target_dir>
	<target_file>
		<item>main.c</item>
		<item>test.c</item>
		<item>func.c</item>
	</target_file>
</config_data>

ファイル構成

main.py
cfg.xml
service
┣ anti_blank_default_case.py
┣ anti_multiple_variable_declaration.py
┣ anti_nothing_default_case.py
┣ anti_nothing_elseblock.py
┣ anti_unused_variable.py
┣ config.py

以上

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?