1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84//! # VirtuC Compiler Library
//!
//! This is the main library crate for the `virtuc` compiler, a Rust-based compiler
//! for a minimal subset of the C programming language. The compiler supports only
//! primitives (int, float), for loops, if-elseif-else statements, and functions.
//!
//! ## Architecture
//!
//! The compiler follows a standard compilation pipeline:
//! 1. **Lexing**: Source code โ Tokens
//! 2. **Parsing**: Tokens โ Abstract Syntax Tree (AST)
//! 3. **Semantic Analysis**: AST validation and type checking
//! 4. **Code Generation**: AST โ LLVM Intermediate Representation (IR)
//! 5. **Execution**: IR โ Native executable
pub mod ast;
pub mod codegen;
pub mod error;
pub mod header_registry;
pub mod lexer;
pub mod parser;
pub mod semantic;
use std::fs;
use std::path::Path;
use std::process::Command;
/// Compiles a C subset source string to an executable at the specified output path.
///
/// # Arguments
///
/// * `source` - The source code string.
/// * `output` - The path where the executable should be written.
///
/// # Returns
///
/// * `Result<(), Box<dyn std::error::Error>>` - Ok if compilation succeeds, Err otherwise.
pub fn compile(source: &str, output: &Path) -> Result<(), Box<dyn std::error::Error>> {
// Lexical analysis
let tokens = lexer::lex(source)?;
// Parsing
let ast = parser::parse(&tokens)?;
// Semantic analysis
let errors = semantic::analyze(&ast);
if !errors.is_empty() {
let error_msg = errors
.iter()
.map(|e| e.to_string())
.collect::<Vec<_>>()
.join("\n");
return Err(format!("Semantic errors:\n{}", error_msg).into());
}
// Code generation
let ir = codegen::generate_ir(&ast)?;
// Write IR to temporary file
// Use output path with .ll extension
let ir_file = output.with_extension("ll");
fs::write(&ir_file, &ir)?;
// Compile IR to executable using clang
let status = Command::new("clang")
.args([
ir_file.to_str().unwrap(),
"-o",
output.to_str().unwrap(),
"-lc",
"-Wno-override-module",
])
.status()?;
if !status.success() {
return Err("Compilation failed".into());
}
// Clean up IR file
let _ = fs::remove_file(ir_file);
Ok(())
}