rmayormartins commited on
Commit
bb5b277
·
1 Parent(s): 194c064
Files changed (3) hide show
  1. README.md +97 -6
  2. app.py +367 -0
  3. requirements.txt +3 -0
README.md CHANGED
@@ -1,14 +1,105 @@
1
  ---
2
- title: C Cpp Inspector
3
- emoji: 📚
4
  colorFrom: blue
5
  colorTo: purple
6
  sdk: gradio
7
- sdk_version: 5.12.0
8
  app_file: app.py
9
  pinned: false
10
- license: ecl-2.0
11
- short_description: C Cpp Inspector
12
  ---
13
 
14
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: C-Cpp-Inspector
3
+ emoji: 🔍️©️/©️++💻
4
  colorFrom: blue
5
  colorTo: purple
6
  sdk: gradio
7
+ sdk_version: 4.7.1
8
  app_file: app.py
9
  pinned: false
10
+ license: mit
 
11
  ---
12
 
13
+ # C/C++ Syntax and Features Inspector
14
+ This project analyzes C/C++ code to extract insights about syntax elements, memory management, and C++ specific features. The tool identifies primitive types, pointers, structs, control structures, memory operations, and C++ features like classes and templates, helping developers understand and improve their C/C++ code.
15
+
16
+ ## Developer
17
+
18
+ Developed by Ramon Mayor Martins (2025)
19
+
20
+ - Email: [email protected]
21
+ - Homepage: https://rmayormartins.github.io/
22
+ - Twitter: @rmayormartins
23
+ - GitHub: https://github.com/rmayormartins
24
+ - Space: https://huggingface.co/rmayormartins
25
+
26
+ ## Key Features
27
+
28
+ ### Basic Analysis
29
+ - **Syntax Elements**:
30
+ - Detects primitive types and constants
31
+ - Identifies variable declarations
32
+ - Analyzes control structures (if/else, switch/case, loops)
33
+ - Tracks operators (arithmetic, logical, bitwise)
34
+
35
+ ### C-Specific Features
36
+ - **Memory Management**:
37
+ - Tracks malloc/calloc/realloc usage
38
+ - Monitors memory freeing operations
39
+ - Analyzes memory operations (memcpy, memmove, etc.)
40
+ - **Data Structures**:
41
+ - Identifies pointers and multiple pointers
42
+ - Detects structs, unions, and enums
43
+ - Analyzes arrays and typedefs
44
+
45
+ ### C++ Features
46
+ - **OOP Analysis**:
47
+ - Classes and objects
48
+ - Templates and namespaces
49
+ - Inheritance and polymorphism
50
+ - Member access specifiers
51
+ - **Modern C++**:
52
+ - STL usage detection
53
+ - Modern C++ features (auto, nullptr, etc.)
54
+ - References and operator overloading
55
+
56
+ ## Interface Features
57
+ - Upload multiple ©️/©️++ files (.c, .cpp, .h, .hpp)
58
+ - Results organized in categorized tabs:
59
+ - File Information
60
+ - Basic Elements
61
+ - Pointers and Structures
62
+ - Control Flow
63
+ - Operators
64
+ - Input/Output
65
+ - Memory Management
66
+ - C++ Features
67
+
68
+ ## How to Use
69
+ 1. Open the application interface
70
+ 2. Upload one or more C/C++ files
71
+ 3. Click "Analisar Arquivos" (Analyze Files)
72
+ 4. View detailed analysis in each category tab
73
+
74
+ ## Installation
75
+
76
+ ### Requirements
77
+ - Python 3.7+
78
+ - libclang
79
+ - gradio
80
+
81
+ ### Local Development
82
+ To run locally:
83
+
84
+ ```bash
85
+ # Install libclang (Ubuntu/Debian)
86
+ sudo apt-get install libclang-dev
87
+
88
+ # Install Python dependencies
89
+ pip install -r requirements.txt
90
+
91
+ # Run the application
92
+ python app.py
93
+ ```
94
+
95
+ ### Google Colab
96
+ To run in Google Colab:
97
+
98
+ ```python
99
+ !apt-get update
100
+ !apt-get install -y libclang-dev
101
+ !pip install libclang gradio
102
+ ```
103
+
104
+ ## License
105
+ MIT License
app.py ADDED
@@ -0,0 +1,367 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from clang.cindex import Index, CursorKind, TypeKind
3
+ from collections import Counter
4
+ from typing import Dict, List
5
+ import os
6
+
7
+ class CPPSyntaxAnalyzer:
8
+ """C/C++-Inspector: Análise sintática e recursos específicos de C/C++"""
9
+
10
+ def __init__(self):
11
+ self.index = Index.create()
12
+
13
+ def analyze_syntax(self, code: str, filename: str) -> Dict[str, int]:
14
+ """Analisa elementos sintáticos e estruturais do código"""
15
+ results = Counter()
16
+
17
+ try:
18
+ with open(filename, 'w') as f:
19
+ f.write(code)
20
+
21
+ tu = self.index.parse(filename)
22
+
23
+ def visit_node(node):
24
+ # Tipos primitivos
25
+ if node.kind == CursorKind.VAR_DECL:
26
+ if node.type.kind in [TypeKind.INT, TypeKind.FLOAT, TypeKind.DOUBLE,
27
+ TypeKind.CHAR_S, TypeKind.BOOL]:
28
+ results["Tipos Primitivos"] += 1
29
+
30
+ # Ponteiros
31
+ if node.type.kind == TypeKind.POINTER:
32
+ results["Ponteiros"] += 1
33
+ # Ponteiros para ponteiros (ponteiros múltiplos)
34
+ if node.type.get_pointee().kind == TypeKind.POINTER:
35
+ results["Ponteiros Múltiplos"] += 1
36
+
37
+ # Structs
38
+ if node.kind == CursorKind.STRUCT_DECL:
39
+ results["Structs"] += 1
40
+
41
+ # Unions
42
+ if node.kind == CursorKind.UNION_DECL:
43
+ results["Unions"] += 1
44
+
45
+ # Enums
46
+ if node.kind == CursorKind.ENUM_DECL:
47
+ results["Enums"] += 1
48
+
49
+ # Typedef
50
+ if node.kind == CursorKind.TYPEDEF_DECL:
51
+ results["Typedefs"] += 1
52
+
53
+ # Arrays
54
+ if node.type.kind == TypeKind.CONSTANTARRAY:
55
+ results["Arrays"] += 1
56
+
57
+ # Variáveis e Constantes
58
+ if node.kind == CursorKind.VAR_DECL:
59
+ results["Variáveis Declaradas"] += 1
60
+ if "const" in [token.spelling for token in node.get_tokens()]:
61
+ results["Constantes"] += 1
62
+
63
+ # Estruturas de Controle
64
+ if node.kind == CursorKind.IF_STMT:
65
+ results["If/Else"] += 1
66
+ elif node.kind == CursorKind.SWITCH_STMT:
67
+ results["Switch/Case"] += 1
68
+ elif node.kind == CursorKind.FOR_STMT:
69
+ results["For Loops"] += 1
70
+ elif node.kind == CursorKind.WHILE_STMT:
71
+ results["While Loops"] += 1
72
+ elif node.kind == CursorKind.DO_STMT:
73
+ results["Do-While Loops"] += 1
74
+
75
+ # Entrada/Saída
76
+ if node.kind == CursorKind.CALL_EXPR:
77
+ func_name = node.spelling.lower()
78
+ if func_name in ['printf', 'cout', 'puts', 'fprintf']:
79
+ results["Funções de Saída"] += 1
80
+ elif func_name in ['scanf', 'cin', 'gets', 'fscanf']:
81
+ results["Funções de Entrada"] += 1
82
+
83
+ # Análise recursiva
84
+ for child in node.get_children():
85
+ visit_node(child)
86
+
87
+ visit_node(tu.cursor)
88
+
89
+ # Análise de operadores e funções específicas via texto
90
+ code_text = code.lower()
91
+
92
+ # Operadores
93
+ operators = {
94
+ "Aritméticos": ["+", "-", "*", "/", "%"],
95
+ "Comparação": ["==", "!=", ">", "<", ">=", "<="],
96
+ "Lógicos": ["&&", "||", "!"],
97
+ "Bit a Bit": ["&", "|", "^", "<<", ">>", "~"],
98
+ "Atribuição": ["+=", "-=", "*=", "/=", "&=", "|=", ">>=", "<<="],
99
+ }
100
+ for category, ops in operators.items():
101
+ results[category] = sum(code_text.count(op) for op in ops)
102
+
103
+ # Gerenciamento de Memória
104
+ memory_funcs = {
105
+ "malloc": code_text.count("malloc("),
106
+ "calloc": code_text.count("calloc("),
107
+ "realloc": code_text.count("realloc("),
108
+ "free": code_text.count("free("),
109
+ "new": code_text.count("new "),
110
+ "delete": code_text.count("delete "),
111
+ "delete[]": code_text.count("delete[]"),
112
+ }
113
+ results["Alocação Dinâmica (malloc/new)"] = memory_funcs["malloc"] + memory_funcs["calloc"] + memory_funcs["new"]
114
+ results["Liberação de Memória (free/delete)"] = memory_funcs["free"] + memory_funcs["delete"] + memory_funcs["delete[]"]
115
+ results["Realocação (realloc)"] = memory_funcs["realloc"]
116
+
117
+ # Manipulação de Memória
118
+ memory_ops = {
119
+ "memcpy": code_text.count("memcpy("),
120
+ "memmove": code_text.count("memmove("),
121
+ "memset": code_text.count("memset("),
122
+ "memcmp": code_text.count("memcmp("),
123
+ }
124
+ results["Operações de Memória"] = sum(memory_ops.values())
125
+
126
+ except Exception as e:
127
+ results["Erro"] = str(e)
128
+
129
+ return dict(results)
130
+
131
+ def analyze_cpp_features(self, code: str, filename: str) -> Dict[str, int]:
132
+ """Analisa recursos específicos de C++"""
133
+ results = Counter()
134
+
135
+ try:
136
+ with open(filename, 'w') as f:
137
+ f.write(code)
138
+
139
+ tu = self.index.parse(filename)
140
+
141
+ def visit_node(node):
142
+ # Classes
143
+ if node.kind == CursorKind.CLASS_DECL:
144
+ results["Classes"] += 1
145
+
146
+ # Templates
147
+ if node.kind == CursorKind.CLASS_TEMPLATE:
148
+ results["Templates"] += 1
149
+
150
+ # Namespace
151
+ if node.kind == CursorKind.NAMESPACE:
152
+ results["Namespaces"] += 1
153
+
154
+ # Referências
155
+ if node.type.kind == TypeKind.LVALUEREFERENCE:
156
+ results["Referências"] += 1
157
+
158
+ # Métodos
159
+ if node.kind == CursorKind.CXX_METHOD:
160
+ results["Métodos"] += 1
161
+ # Virtual
162
+ if "virtual" in [token.spelling for token in node.get_tokens()]:
163
+ results["Métodos Virtuais"] += 1
164
+
165
+ # Sobrecarga de Operadores
166
+ if node.kind == CursorKind.CXX_METHOD and node.spelling.startswith("operator"):
167
+ results["Sobrecarga de Operadores"] += 1
168
+
169
+ # Membros e Encapsulamento
170
+ if node.kind == CursorKind.FIELD_DECL:
171
+ results["Atributos"] += 1
172
+ if node.access_specifier.name == "PRIVATE":
173
+ results["Membros Private"] += 1
174
+ elif node.access_specifier.name == "PROTECTED":
175
+ results["Membros Protected"] += 1
176
+
177
+ # Herança
178
+ if node.kind == CursorKind.CXX_BASE_SPECIFIER:
179
+ results["Herança"] += 1
180
+
181
+ # Análise recursiva
182
+ for child in node.get_children():
183
+ visit_node(child)
184
+
185
+ visit_node(tu.cursor)
186
+
187
+ # Análise de recursos específicos via texto
188
+ code_text = code.lower()
189
+
190
+ # STL e Recursos Modernos
191
+ stl_containers = ["vector", "list", "map", "set", "queue", "stack", "deque"]
192
+ results["Uso de STL"] = sum(code_text.count(container) for container in stl_containers)
193
+
194
+ modern_features = ["auto", "nullptr", "constexpr", "static_assert", "decltype"]
195
+ results["Recursos C++ Moderno"] = sum(code_text.count(feature) for feature in modern_features)
196
+
197
+ except Exception as e:
198
+ results["Erro"] = str(e)
199
+
200
+ return dict(results)
201
+
202
+ def process_files(files) -> List[Dict]:
203
+ """Processa múltiplos arquivos"""
204
+ analyzer = CPPSyntaxAnalyzer()
205
+ file_results = []
206
+
207
+ for file in files:
208
+ with open(file.name, 'r', encoding='utf-8') as f:
209
+ code = f.read()
210
+
211
+ syntax_results = analyzer.analyze_syntax(code, file.name)
212
+ cpp_results = analyzer.analyze_cpp_features(code, file.name)
213
+
214
+ combined_results = {**syntax_results, **cpp_results}
215
+ combined_results["Arquivo"] = file.name
216
+ file_results.append(combined_results)
217
+
218
+ return file_results
219
+ def analyze_files(files):
220
+ """Analisa os arquivos e retorna os resultados separados por categoria"""
221
+ if not files:
222
+ return [], [], [], [], [], [], [], []
223
+
224
+ results = process_files(files)
225
+
226
+ # Separar resultados por categoria
227
+ file_info = [[result["Arquivo"]] for result in results]
228
+
229
+ basic_elements = [[
230
+ result.get("Tipos Primitivos", 0),
231
+ result.get("Constantes", 0),
232
+ result.get("Variáveis Declaradas", 0)
233
+ ] for result in results]
234
+
235
+ pointers_structs = [[
236
+ result.get("Ponteiros", 0),
237
+ result.get("Ponteiros Múltiplos", 0),
238
+ result.get("Arrays", 0),
239
+ result.get("Structs", 0),
240
+ result.get("Unions", 0),
241
+ result.get("Enums", 0),
242
+ result.get("Typedefs", 0)
243
+ ] for result in results]
244
+
245
+ flow_control = [[
246
+ result.get("If/Else", 0),
247
+ result.get("Switch/Case", 0),
248
+ result.get("For Loops", 0),
249
+ result.get("While Loops", 0),
250
+ result.get("Do-While Loops", 0)
251
+ ] for result in results]
252
+
253
+ operators = [[
254
+ result.get("Aritméticos", 0),
255
+ result.get("Comparação", 0),
256
+ result.get("Lógicos", 0),
257
+ result.get("Bit a Bit", 0),
258
+ result.get("Atribuição", 0)
259
+ ] for result in results]
260
+
261
+ io_ops = [[
262
+ result.get("Funções de Entrada", 0),
263
+ result.get("Funções de Saída", 0)
264
+ ] for result in results]
265
+
266
+ memory = [[
267
+ result.get("Alocação Dinâmica (malloc/new)", 0),
268
+ result.get("Liberação de Memória (free/delete)", 0),
269
+ result.get("Realocação (realloc)", 0),
270
+ result.get("Operações de Memória", 0)
271
+ ] for result in results]
272
+
273
+ cpp_features = [[
274
+ result.get("Classes", 0),
275
+ result.get("Templates", 0),
276
+ result.get("Namespaces", 0),
277
+ result.get("Referências", 0),
278
+ result.get("Métodos", 0),
279
+ result.get("Métodos Virtuais", 0),
280
+ result.get("Sobrecarga de Operadores", 0),
281
+ result.get("Membros Private", 0),
282
+ result.get("Membros Protected", 0),
283
+ result.get("Herança", 0),
284
+ result.get("Uso de STL", 0),
285
+ result.get("Recursos C++ Moderno", 0)
286
+ ] for result in results]
287
+
288
+ return (file_info, basic_elements, pointers_structs, flow_control,
289
+ operators, io_ops, memory, cpp_features)
290
+
291
+ # Interface Gradio
292
+ with gr.Blocks(title="C/Cpp-Inspector") as demo:
293
+ gr.Markdown("# C/Cpp-Inspector: Code Analysis")
294
+ gr.Markdown("""
295
+ <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>
296
+ """)
297
+ gr.Markdown("Faça upload dos arquivos C/C++ para análise detalhada das estruturas e recursos da linguagem.")
298
+
299
+ with gr.Column():
300
+ file_input = gr.File(label="Arquivos C/C++", file_types=[".c", ".cpp", ".h", ".hpp"], file_count="multiple")
301
+ analyze_button = gr.Button("Analisar Arquivos")
302
+
303
+ gr.Markdown("## Resultados da Análise ©️/©️++")
304
+
305
+ with gr.Tabs():
306
+ with gr.TabItem("📁 Informações do Arquivo"):
307
+ output_file = gr.Dataframe(
308
+ label="Arquivo",
309
+ headers=["Arquivo"]
310
+ )
311
+
312
+ with gr.TabItem("#️⃣ Elementos Básicos"):
313
+ output_basic = gr.Dataframe(
314
+ label="Elementos Básicos",
315
+ headers=["Tipos Primitivos", "Constantes", "Variáveis Declaradas"]
316
+ )
317
+
318
+ with gr.TabItem("*️⃣ Ponteiros e Estruturas"):
319
+ output_pointers = gr.Dataframe(
320
+ label="Ponteiros e Estruturas",
321
+ headers=["Ponteiros", "Ponteiros Múltiplos", "Arrays",
322
+ "Structs", "Unions", "Enums", "Typedefs"]
323
+ )
324
+
325
+ with gr.TabItem("🔄 Controle de Fluxo"):
326
+ output_flow = gr.Dataframe(
327
+ label="Controle de Fluxo",
328
+ headers=["If/Else", "Switch/Case", "For Loops", "While Loops", "Do-While Loops"]
329
+ )
330
+
331
+ with gr.TabItem("🔣 Operadores"):
332
+ output_operators = gr.Dataframe(
333
+ label="Operadores",
334
+ headers=["Aritméticos", "Comparação", "Lógicos", "Bit a Bit", "Atribuição"]
335
+ )
336
+
337
+ with gr.TabItem("↕️ Entrada/Saída"):
338
+ output_io = gr.Dataframe(
339
+ label="Entrada/Saída",
340
+ headers=["Funções de Entrada", "Funções de Saída"]
341
+ )
342
+
343
+ with gr.TabItem("⏺️ Gerenciamento de Memória"):
344
+ output_memory = gr.Dataframe(
345
+ label="Gerenciamento de Memória",
346
+ headers=["Alocação Dinâmica (malloc/new)", "Liberação de Memória (free/delete)",
347
+ "Realocação (realloc)", "Operações de Memória"]
348
+ )
349
+
350
+ with gr.TabItem("⏭️ Recursos C++"):
351
+ output_cpp = gr.Dataframe(
352
+ label="Recursos C++",
353
+ headers=["Classes", "Templates", "Namespaces", "Referências",
354
+ "Métodos", "Métodos Virtuais", "Sobrecarga de Operadores",
355
+ "Membros Private", "Membros Protected", "Herança",
356
+ "Uso de STL", "Recursos C++ Moderno"]
357
+ )
358
+
359
+ analyze_button.click(
360
+ fn=analyze_files,
361
+ inputs=file_input,
362
+ outputs=[output_file, output_basic, output_pointers, output_flow,
363
+ output_operators, output_io, output_memory, output_cpp]
364
+ )
365
+
366
+ if __name__ == "__main__":
367
+ demo.launch()
requirements.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ gradio
2
+ libclang>=14.0.0
3
+