c-cpp-inspector / app.py
rmayormartins's picture
b
6de29de
raw
history blame
14.5 kB
import gradio as gr
from clang.cindex import Index, CursorKind, TypeKind
from collections import Counter
from typing import Dict, List
import os
class CPPSyntaxAnalyzer:
"""C/C++-Inspector: Análise sintática e recursos específicos de C/C++"""
def __init__(self):
self.index = Index.create()
def analyze_syntax(self, code: str, filename: str) -> Dict[str, int]:
"""Analisa elementos sintáticos e estruturais do código"""
results = Counter()
try:
with open(filename, 'w') as f:
f.write(code)
tu = self.index.parse(filename)
def visit_node(node):
# Tipos primitivos
if node.kind == CursorKind.VAR_DECL:
if node.type.kind in [TypeKind.INT, TypeKind.FLOAT, TypeKind.DOUBLE,
TypeKind.CHAR_S, TypeKind.BOOL]:
results["Tipos Primitivos"] += 1
# Ponteiros
if node.type.kind == TypeKind.POINTER:
results["Ponteiros"] += 1
# Ponteiros para ponteiros (ponteiros múltiplos)
if node.type.get_pointee().kind == TypeKind.POINTER:
results["Ponteiros Múltiplos"] += 1
# Structs
if node.kind == CursorKind.STRUCT_DECL:
results["Structs"] += 1
# Unions
if node.kind == CursorKind.UNION_DECL:
results["Unions"] += 1
# Enums
if node.kind == CursorKind.ENUM_DECL:
results["Enums"] += 1
# Typedef
if node.kind == CursorKind.TYPEDEF_DECL:
results["Typedefs"] += 1
# Arrays
if node.type.kind == TypeKind.CONSTANTARRAY:
results["Arrays"] += 1
# Variáveis e Constantes
if node.kind == CursorKind.VAR_DECL:
results["Variáveis Declaradas"] += 1
if "const" in [token.spelling for token in node.get_tokens()]:
results["Constantes"] += 1
# Estruturas de Controle
if node.kind == CursorKind.IF_STMT:
results["If/Else"] += 1
elif node.kind == CursorKind.SWITCH_STMT:
results["Switch/Case"] += 1
elif node.kind == CursorKind.FOR_STMT:
results["For Loops"] += 1
elif node.kind == CursorKind.WHILE_STMT:
results["While Loops"] += 1
elif node.kind == CursorKind.DO_STMT:
results["Do-While Loops"] += 1
# Entrada/Saída
if node.kind == CursorKind.CALL_EXPR:
func_name = node.spelling.lower()
if func_name in ['printf', 'cout', 'puts', 'fprintf']:
results["Funções de Saída"] += 1
elif func_name in ['scanf', 'cin', 'gets', 'fscanf']:
results["Funções de Entrada"] += 1
# Análise recursiva
for child in node.get_children():
visit_node(child)
visit_node(tu.cursor)
# Análise de operadores e funções específicas via texto
code_text = code.lower()
# Operadores
operators = {
"Aritméticos": ["+", "-", "*", "/", "%"],
"Comparação": ["==", "!=", ">", "<", ">=", "<="],
"Lógicos": ["&&", "||", "!"],
"Bit a Bit": ["&", "|", "^", "<<", ">>", "~"],
"Atribuição": ["+=", "-=", "*=", "/=", "&=", "|=", ">>=", "<<="],
}
for category, ops in operators.items():
results[category] = sum(code_text.count(op) for op in ops)
# Gerenciamento de Memória
memory_funcs = {
"malloc": code_text.count("malloc("),
"calloc": code_text.count("calloc("),
"realloc": code_text.count("realloc("),
"free": code_text.count("free("),
"new": code_text.count("new "),
"delete": code_text.count("delete "),
"delete[]": code_text.count("delete[]"),
}
results["Alocação Dinâmica (malloc/new)"] = memory_funcs["malloc"] + memory_funcs["calloc"] + memory_funcs["new"]
results["Liberação de Memória (free/delete)"] = memory_funcs["free"] + memory_funcs["delete"] + memory_funcs["delete[]"]
results["Realocação (realloc)"] = memory_funcs["realloc"]
# Manipulação de Memória
memory_ops = {
"memcpy": code_text.count("memcpy("),
"memmove": code_text.count("memmove("),
"memset": code_text.count("memset("),
"memcmp": code_text.count("memcmp("),
}
results["Operações de Memória"] = sum(memory_ops.values())
except Exception as e:
results["Erro"] = str(e)
return dict(results)
def analyze_cpp_features(self, code: str, filename: str) -> Dict[str, int]:
"""Analisa recursos específicos de C++"""
results = Counter()
try:
with open(filename, 'w') as f:
f.write(code)
tu = self.index.parse(filename)
def visit_node(node):
# Classes
if node.kind == CursorKind.CLASS_DECL:
results["Classes"] += 1
# Templates
if node.kind == CursorKind.CLASS_TEMPLATE:
results["Templates"] += 1
# Namespace
if node.kind == CursorKind.NAMESPACE:
results["Namespaces"] += 1
# Referências
if node.type.kind == TypeKind.LVALUEREFERENCE:
results["Referências"] += 1
# Métodos
if node.kind == CursorKind.CXX_METHOD:
results["Métodos"] += 1
# Virtual
if "virtual" in [token.spelling for token in node.get_tokens()]:
results["Métodos Virtuais"] += 1
# Sobrecarga de Operadores
if node.kind == CursorKind.CXX_METHOD and node.spelling.startswith("operator"):
results["Sobrecarga de Operadores"] += 1
# Membros e Encapsulamento
if node.kind == CursorKind.FIELD_DECL:
results["Atributos"] += 1
if node.access_specifier.name == "PRIVATE":
results["Membros Private"] += 1
elif node.access_specifier.name == "PROTECTED":
results["Membros Protected"] += 1
# Herança
if node.kind == CursorKind.CXX_BASE_SPECIFIER:
results["Herança"] += 1
# Análise recursiva
for child in node.get_children():
visit_node(child)
visit_node(tu.cursor)
# Análise de recursos específicos via texto
code_text = code.lower()
# STL e Recursos Modernos
stl_containers = ["vector", "list", "map", "set", "queue", "stack", "deque"]
results["Uso de STL"] = sum(code_text.count(container) for container in stl_containers)
modern_features = ["auto", "nullptr", "constexpr", "static_assert", "decltype"]
results["Recursos C++ Moderno"] = sum(code_text.count(feature) for feature in modern_features)
except Exception as e:
results["Erro"] = str(e)
return dict(results)
def process_files(files) -> List[Dict]:
"""Processa múltiplos arquivos"""
analyzer = CPPSyntaxAnalyzer()
file_results = []
for file in files:
with open(file.name, 'r', encoding='utf-8') as f:
code = f.read()
syntax_results = analyzer.analyze_syntax(code, file.name)
cpp_results = analyzer.analyze_cpp_features(code, file.name)
combined_results = {**syntax_results, **cpp_results}
combined_results["Arquivo"] = file.name
file_results.append(combined_results)
return file_results
def analyze_files(files):
"""Analisa os arquivos e retorna os resultados separados por categoria"""
if not files:
return [], [], [], [], [], [], [], []
results = process_files(files)
# Separar resultados por categoria
file_info = [[result["Arquivo"]] for result in results]
basic_elements = [[
result.get("Tipos Primitivos", 0),
result.get("Constantes", 0),
result.get("Variáveis Declaradas", 0)
] for result in results]
pointers_structs = [[
result.get("Ponteiros", 0),
result.get("Ponteiros Múltiplos", 0),
result.get("Arrays", 0),
result.get("Structs", 0),
result.get("Unions", 0),
result.get("Enums", 0),
result.get("Typedefs", 0)
] for result in results]
flow_control = [[
result.get("If/Else", 0),
result.get("Switch/Case", 0),
result.get("For Loops", 0),
result.get("While Loops", 0),
result.get("Do-While Loops", 0)
] for result in results]
operators = [[
result.get("Aritméticos", 0),
result.get("Comparação", 0),
result.get("Lógicos", 0),
result.get("Bit a Bit", 0),
result.get("Atribuição", 0)
] for result in results]
io_ops = [[
result.get("Funções de Entrada", 0),
result.get("Funções de Saída", 0)
] for result in results]
memory = [[
result.get("Alocação Dinâmica (malloc/new)", 0),
result.get("Liberação de Memória (free/delete)", 0),
result.get("Realocação (realloc)", 0),
result.get("Operações de Memória", 0)
] for result in results]
cpp_features = [[
result.get("Classes", 0),
result.get("Templates", 0),
result.get("Namespaces", 0),
result.get("Referências", 0),
result.get("Métodos", 0),
result.get("Métodos Virtuais", 0),
result.get("Sobrecarga de Operadores", 0),
result.get("Membros Private", 0),
result.get("Membros Protected", 0),
result.get("Herança", 0),
result.get("Uso de STL", 0),
result.get("Recursos C++ Moderno", 0)
] for result in results]
return (file_info, basic_elements, pointers_structs, flow_control,
operators, io_ops, memory, cpp_features)
# Interface Gradio
with gr.Blocks(title="C/Cpp-Inspector") as demo:
gr.Markdown("# C/Cpp-Inspector: Code Analysis")
gr.Markdown("""
<p>Ramon Mayor Martins: <a href="https://rmayormartins.github.io/" target="_blank">Website</a> | <a href="https://huggingface.co/rmayormartins" target="_blank">Spaces</a> | <a href="https://github.com/rmayormartins" target="_blank">Github</a></p>
""")
gr.Markdown("Faça upload dos arquivos C/C++ para análise detalhada das estruturas e recursos da linguagem.")
with gr.Column():
file_input = gr.File(label="Arquivos C/C++", file_types=[".c", ".cpp", ".h", ".hpp"], file_count="multiple")
analyze_button = gr.Button("Analisar Arquivos")
gr.Markdown("## Resultados da Análise")
with gr.Tabs():
with gr.TabItem("📁 Informações do Arquivo"):
output_file = gr.Dataframe(
label="Arquivo",
headers=["Arquivo"]
)
with gr.TabItem("#️⃣ Elementos Básicos"):
output_basic = gr.Dataframe(
label="Elementos Básicos",
headers=["Tipos Primitivos", "Constantes", "Variáveis Declaradas"]
)
with gr.TabItem("*️⃣ Ponteiros e Estruturas"):
output_pointers = gr.Dataframe(
label="Ponteiros e Estruturas",
headers=["Ponteiros", "Ponteiros Múltiplos", "Arrays",
"Structs", "Unions", "Enums", "Typedefs"]
)
with gr.TabItem("🔄 Controle de Fluxo"):
output_flow = gr.Dataframe(
label="Controle de Fluxo",
headers=["If/Else", "Switch/Case", "For Loops", "While Loops", "Do-While Loops"]
)
with gr.TabItem("🔣 Operadores"):
output_operators = gr.Dataframe(
label="Operadores",
headers=["Aritméticos", "Comparação", "Lógicos", "Bit a Bit", "Atribuição"]
)
with gr.TabItem("↕️ Entrada/Saída"):
output_io = gr.Dataframe(
label="Entrada/Saída",
headers=["Funções de Entrada", "Funções de Saída"]
)
with gr.TabItem("⏺️ Gerenciamento de Memória"):
output_memory = gr.Dataframe(
label="Gerenciamento de Memória",
headers=["Alocação Dinâmica (malloc/new)", "Liberação de Memória (free/delete)",
"Realocação (realloc)", "Operações de Memória"]
)
with gr.TabItem("⏭️ Recursos C++"):
output_cpp = gr.Dataframe(
label="Recursos C++",
headers=["Classes", "Templates", "Namespaces", "Referências",
"Métodos", "Métodos Virtuais", "Sobrecarga de Operadores",
"Membros Private", "Membros Protected", "Herança",
"Uso de STL", "Recursos C++ Moderno"]
)
analyze_button.click(
fn=analyze_files,
inputs=file_input,
outputs=[output_file, output_basic, output_pointers, output_flow,
output_operators, output_io, output_memory, output_cpp]
)
if __name__ == "__main__":
demo.launch()