avciTheProgrammer commited on
Commit
0425e1e
·
verified ·
1 Parent(s): 7dde54b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +132 -14
app.py CHANGED
@@ -5,10 +5,12 @@ import subprocess
5
  import os
6
  import tempfile
7
  import shutil
 
 
8
 
9
- app = FastAPI(title="C Compiler API")
10
 
11
- # Configure CORS - allows any frontend to call this API
12
  app.add_middleware(
13
  CORSMiddleware,
14
  allow_origins=["*"],
@@ -21,36 +23,99 @@ class CodeRequest(BaseModel):
21
  code: str
22
  filename: str = "main.c"
23
  compiler: str = "gcc" # gcc, clang, or pclint
 
 
 
 
 
 
 
 
24
 
25
  class CompileResponse(BaseModel):
26
  success: bool
27
  output: str
28
  errors: str
29
  executable_output: str = ""
 
30
 
31
  @app.get("/")
32
  def read_root():
33
  """API information endpoint"""
34
  return {
35
  "message": "C Compiler API is running",
 
36
  "endpoints": {
37
  "/compile": "POST - Compile C code",
38
  "/health": "GET - Health check",
39
  "/docs": "GET - API documentation"
40
  },
41
- "supported_compilers": ["gcc", "clang", "pclint"]
 
 
 
 
 
 
42
  }
43
 
44
  @app.get("/health")
45
  def health_check():
46
  """Health check endpoint"""
47
- return {"status": "healthy", "service": "C Compiler API"}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
 
49
  @app.post("/compile", response_model=CompileResponse)
50
  async def compile_code(request: CodeRequest):
51
  """
52
  Compile and execute C code
53
 
 
 
 
 
 
54
  Example request:
55
  {
56
  "code": "#include <stdio.h>\\nint main() { printf(\\"Hello\\\\n\\"); return 0; }",
@@ -59,10 +124,11 @@ async def compile_code(request: CodeRequest):
59
  }
60
  """
61
  try:
62
- # Create a temporary directory for this compilation
63
  temp_dir = tempfile.mkdtemp()
64
  source_file = os.path.join(temp_dir, request.filename)
65
  output_file = os.path.join(temp_dir, "output")
 
66
 
67
  # Write the code to a file
68
  with open(source_file, 'w') as f:
@@ -72,39 +138,90 @@ async def compile_code(request: CodeRequest):
72
  compile_errors = ""
73
  executable_output = ""
74
  success = False
 
75
 
76
  if request.compiler == "pclint":
77
- # PC-Lint specific handling (using splint as alternative)
 
 
 
78
  try:
 
79
  result = subprocess.run(
80
- ["splint", source_file],
81
  capture_output=True,
82
  text=True,
83
  timeout=10,
84
  cwd=temp_dir
85
  )
86
- compile_output = result.stdout
87
  compile_errors = result.stderr
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
  success = result.returncode == 0
 
89
  except FileNotFoundError:
90
- # If splint not available, fall back to gcc with warnings
91
  result = subprocess.run(
92
- ["gcc", "-Wall", "-Wextra", "-pedantic", "-fsyntax-only", source_file],
 
 
 
 
 
 
 
93
  capture_output=True,
94
  text=True,
95
  timeout=10,
96
  cwd=temp_dir
97
  )
98
- compile_output = "Using GCC static analysis (PC-Lint not available)\n" + result.stdout
99
  compile_errors = result.stderr
100
  success = result.returncode == 0
 
 
 
 
 
 
 
 
 
 
 
 
 
101
  else:
102
  # Standard GCC or Clang compilation
103
  compiler_cmd = request.compiler if request.compiler in ["gcc", "clang"] else "gcc"
104
 
 
 
 
 
 
 
 
 
 
 
105
  # Compile the code
106
  compile_result = subprocess.run(
107
- [compiler_cmd, source_file, "-o", output_file, "-Wall"],
108
  capture_output=True,
109
  text=True,
110
  timeout=10,
@@ -114,7 +231,7 @@ async def compile_code(request: CodeRequest):
114
  compile_output = compile_result.stdout
115
  compile_errors = compile_result.stderr
116
 
117
- # If compilation successful, try to run the executable
118
  if compile_result.returncode == 0:
119
  success = True
120
  try:
@@ -140,7 +257,8 @@ async def compile_code(request: CodeRequest):
140
  success=success,
141
  output=compile_output,
142
  errors=compile_errors,
143
- executable_output=executable_output
 
144
  )
145
 
146
  except subprocess.TimeoutExpired:
 
5
  import os
6
  import tempfile
7
  import shutil
8
+ from typing import Optional, List, Dict
9
+ import xml.etree.ElementTree as ET
10
 
11
+ app = FastAPI(title="C Compiler API - PC-Lint Compatible")
12
 
13
+ # Configure CORS
14
  app.add_middleware(
15
  CORSMiddleware,
16
  allow_origins=["*"],
 
23
  code: str
24
  filename: str = "main.c"
25
  compiler: str = "gcc" # gcc, clang, or pclint
26
+ standards: Optional[List[str]] = None # For MISRA standards
27
+
28
+ class LintMessage(BaseModel):
29
+ file: str
30
+ line: int
31
+ type: str
32
+ code: str
33
+ desc: str
34
 
35
  class CompileResponse(BaseModel):
36
  success: bool
37
  output: str
38
  errors: str
39
  executable_output: str = ""
40
+ messages: Optional[List[LintMessage]] = None # For PC-lint XML output
41
 
42
  @app.get("/")
43
  def read_root():
44
  """API information endpoint"""
45
  return {
46
  "message": "C Compiler API is running",
47
+ "version": "2.0",
48
  "endpoints": {
49
  "/compile": "POST - Compile C code",
50
  "/health": "GET - Health check",
51
  "/docs": "GET - API documentation"
52
  },
53
+ "supported_compilers": ["gcc", "clang", "pclint"],
54
+ "features": [
55
+ "Standard C compilation",
56
+ "PC-lint static analysis",
57
+ "MISRA C/C++ checking",
58
+ "XML output parsing"
59
+ ]
60
  }
61
 
62
  @app.get("/health")
63
  def health_check():
64
  """Health check endpoint"""
65
+ # Check if compilers are available
66
+ compilers_status = {}
67
+ for compiler in ["gcc", "clang", "splint"]:
68
+ try:
69
+ result = subprocess.run(
70
+ [compiler, "--version"],
71
+ capture_output=True,
72
+ timeout=2
73
+ )
74
+ compilers_status[compiler] = "available" if result.returncode == 0 else "not available"
75
+ except:
76
+ compilers_status[compiler] = "not available"
77
+
78
+ return {
79
+ "status": "healthy",
80
+ "service": "C Compiler API",
81
+ "compilers": compilers_status
82
+ }
83
+
84
+ def parse_xml_lint_output(xml_file: str) -> List[Dict]:
85
+ """Parse PC-lint XML output format"""
86
+ messages = []
87
+
88
+ try:
89
+ if not os.path.exists(xml_file) or os.path.getsize(xml_file) == 0:
90
+ return messages
91
+
92
+ tree = ET.parse(xml_file)
93
+ root = tree.getroot()
94
+
95
+ # Parse messages from XML
96
+ for msg in root.findall('.//message'):
97
+ messages.append({
98
+ "file": msg.find('file').text if msg.find('file') is not None else "",
99
+ "line": int(msg.find('line').text) if msg.find('line') is not None and msg.find('line').text else 0,
100
+ "type": msg.find('type').text if msg.find('type') is not None else "unknown",
101
+ "code": msg.find('code').text if msg.find('code') is not None else "",
102
+ "desc": msg.find('desc').text if msg.find('desc') is not None else ""
103
+ })
104
+ except Exception as e:
105
+ print(f"XML parsing error: {e}")
106
+
107
+ return messages
108
 
109
  @app.post("/compile", response_model=CompileResponse)
110
  async def compile_code(request: CodeRequest):
111
  """
112
  Compile and execute C code
113
 
114
+ Supports:
115
+ - gcc: Standard GNU C compiler
116
+ - clang: LLVM C compiler
117
+ - pclint: PC-lint Plus static analysis (using splint alternative)
118
+
119
  Example request:
120
  {
121
  "code": "#include <stdio.h>\\nint main() { printf(\\"Hello\\\\n\\"); return 0; }",
 
124
  }
125
  """
126
  try:
127
+ # Create a temporary directory
128
  temp_dir = tempfile.mkdtemp()
129
  source_file = os.path.join(temp_dir, request.filename)
130
  output_file = os.path.join(temp_dir, "output")
131
+ xml_output = os.path.join(temp_dir, "lint_report.xml")
132
 
133
  # Write the code to a file
134
  with open(source_file, 'w') as f:
 
138
  compile_errors = ""
139
  executable_output = ""
140
  success = False
141
+ lint_messages = None
142
 
143
  if request.compiler == "pclint":
144
+ # PC-lint static analysis
145
+ # Note: Using splint as PC-lint alternative (PC-lint is proprietary)
146
+ # If you have PC-lint, modify this section to use: pclp64 or lint-nt
147
+
148
  try:
149
+ # Try using splint first (open-source alternative)
150
  result = subprocess.run(
151
+ ["splint", "+quiet", source_file],
152
  capture_output=True,
153
  text=True,
154
  timeout=10,
155
  cwd=temp_dir
156
  )
157
+ compile_output = "PC-lint analysis (using Splint alternative)\n" + result.stdout
158
  compile_errors = result.stderr
159
+
160
+ # Parse output into structured messages
161
+ lint_messages = []
162
+ for line in (result.stdout + result.stderr).split('\n'):
163
+ if line.strip() and ':' in line:
164
+ parts = line.split(':', 3)
165
+ if len(parts) >= 3:
166
+ lint_messages.append({
167
+ "file": parts[0] if len(parts) > 0 else "",
168
+ "line": int(parts[1]) if len(parts) > 1 and parts[1].isdigit() else 0,
169
+ "type": "warning",
170
+ "code": "",
171
+ "desc": parts[-1].strip() if len(parts) > 2 else ""
172
+ })
173
+
174
  success = result.returncode == 0
175
+
176
  except FileNotFoundError:
177
+ # Fallback to GCC with strict warnings (MISRA-like)
178
  result = subprocess.run(
179
+ [
180
+ "gcc",
181
+ "-Wall", "-Wextra", "-pedantic",
182
+ "-Wconversion", "-Wshadow",
183
+ "-Wstrict-prototypes",
184
+ "-fsyntax-only",
185
+ source_file
186
+ ],
187
  capture_output=True,
188
  text=True,
189
  timeout=10,
190
  cwd=temp_dir
191
  )
192
+ compile_output = "PC-lint not available. Using GCC with strict warnings.\n" + result.stdout
193
  compile_errors = result.stderr
194
  success = result.returncode == 0
195
+
196
+ # Parse GCC warnings into messages
197
+ lint_messages = []
198
+ for line in compile_errors.split('\n'):
199
+ if ':' in line and ('warning' in line or 'error' in line):
200
+ lint_messages.append({
201
+ "file": source_file,
202
+ "line": 0,
203
+ "type": "warning" if "warning" in line else "error",
204
+ "code": "",
205
+ "desc": line.strip()
206
+ })
207
+
208
  else:
209
  # Standard GCC or Clang compilation
210
  compiler_cmd = request.compiler if request.compiler in ["gcc", "clang"] else "gcc"
211
 
212
+ # Additional flags for MISRA-like checking
213
+ extra_flags = ["-Wall", "-Wextra"]
214
+ if request.standards and "misra" in str(request.standards).lower():
215
+ extra_flags.extend([
216
+ "-pedantic",
217
+ "-Wconversion",
218
+ "-Wshadow",
219
+ "-Wstrict-prototypes"
220
+ ])
221
+
222
  # Compile the code
223
  compile_result = subprocess.run(
224
+ [compiler_cmd, source_file, "-o", output_file] + extra_flags,
225
  capture_output=True,
226
  text=True,
227
  timeout=10,
 
231
  compile_output = compile_result.stdout
232
  compile_errors = compile_result.stderr
233
 
234
+ # If compilation successful, run the executable
235
  if compile_result.returncode == 0:
236
  success = True
237
  try:
 
257
  success=success,
258
  output=compile_output,
259
  errors=compile_errors,
260
+ executable_output=executable_output,
261
+ messages=lint_messages
262
  )
263
 
264
  except subprocess.TimeoutExpired: