ROUP
Rust-based OpenMP Parser
Safe, fast, and comprehensive OpenMP directive parsing
What is ROUP?
ROUP is an experimental parser for OpenMP directives, written in safe Rust with C and C++ APIs. Parse OpenMP pragmas like #pragma omp parallel for
into structured data that your tools can analyze, transform, and process.
⚠️ Experimental Status: ROUP is under active development and not yet production-ready. APIs may change, and some OpenMP features are still being implemented. Use in research and experimental projects.
Perfect for:
- 🔧 Compiler research - Experiment with OpenMP parsing in compilers
- 🔍 Analysis prototypes - Build experimental linters and analyzers
- 🎓 Researchers - Study parallelization patterns and test new ideas
- 📚 Educators - Teaching tool for parallel programming concepts
Why ROUP?
🚀 Fast & Lightweight
- Microsecond parsing - Parse directives in ~500ns
- Zero-copy lexer - Minimal memory allocations
- No LLVM dependency - Standalone library, small binary size
- 16 FFI functions - Simple, focused C API
🛡️ Safe & Reliable
- 99.1% safe Rust - Memory safety guaranteed
- 352 passing tests - Comprehensive test coverage
- Fuzzing tested - Handles malformed input gracefully
- NULL-safe C API - Defensive checks at FFI boundary
📚 Comprehensive OpenMP Support
- 95 directives - From
parallel
tometadirective
- 91 clauses - Extensive OpenMP 3.0 through 6.0 coverage
- Version tracking - Know which OpenMP version introduced each feature
- Spec compliant - Follows official OpenMP specifications
🔌 Multi-Language APIs
Language | API Style | Memory Management | Status |
---|---|---|---|
Rust | Native | Automatic (ownership) | ✅ Stable |
C | Pointer-based | Manual (malloc/free pattern) | ✅ Stable |
C++ | RAII wrappers | Automatic (destructors) | ✅ Stable |
Fortran | C interop | Manual (via iso_c_binding) | ⚠️ Experimental |
Quick Example
Parse in 3 Lines (Rust)
use roup::parser::openmp;
let parser = openmp::parser();
let (_, directive) = parser.parse("#pragma omp parallel for num_threads(4)").unwrap();
// Access directive information
println!("Directive: {}", directive.name); // Output: Directive: parallel for
println!("Found {} clauses", directive.clauses.len()); // Output: Found 1 clauses
// Iterate through clauses
for clause in &directive.clauses {
println!(" Clause: {}", clause.name); // Output: Clause: num_threads
}
Parse in C
OmpDirective* dir = roup_parse("#pragma omp parallel for num_threads(4)");
printf("Clauses: %d\n", roup_directive_clause_count(dir));
roup_directive_free(dir);
Parse in C++ (with RAII)
roup::Directive dir("#pragma omp parallel for num_threads(4)");
std::cout << "Clauses: " << dir.clause_count() << "\n";
// Automatic cleanup!
Parse Fortran (Experimental)
! Free-form Fortran
directive_ptr = roup_parse_with_language("!$OMP PARALLEL PRIVATE(A)", &
ROUP_LANG_FORTRAN_FREE)
Feature Highlights
🎯 Comprehensive Coverage
Parallel Constructs - 20+ directives
parallel
- Basic parallel regionsparallel for
- Combined parallel + worksharingparallel sections
- Parallel sectionsparallel master
- Parallel master threadparallel loop
- OpenMP 5.0+ parallel loop- And more...
Work-Sharing - 10+ directives
for
/do
- Loop worksharingsections
/section
- Code sectionssingle
- Execute onceworkshare
- Fortran worksharingloop
- Generic loop construct
Tasking - 15+ directives
task
- Explicit taskstaskloop
- Loop-based taskstaskgroup
- Task synchronizationtaskwait
- Wait for taskstaskyield
- Yield to other tasks- Dependency clauses:
depend
,priority
,detach
Device Offloading - 25+ directives
target
- Offload to devicetarget data
- Device data managementtarget enter/exit data
- Data transfertarget update
- Synchronize datateams
- Multiple thread teamsdistribute
- Distribute iterations
SIMD - 10+ directives
simd
- SIMD loopsdeclare simd
- Vectorizable functionsdistribute simd
- Combined distribute + SIMD- Various alignment and vectorization clauses
Advanced (OpenMP 5.0+)
metadirective
- Context-sensitive directivesdeclare variant
- Function variantsloop
- Generic loop constructscan
- Prefix scan operationsassume
- Compiler assumptions
🔍 Rich Clause Support
92+ clause types including:
Category | Clauses |
---|---|
Data Sharing | private , shared , firstprivate , lastprivate |
Reductions | reduction(+:x) , reduction(min:y) , custom operators |
Scheduling | schedule(static) , schedule(dynamic,100) , collapse(3) |
Control | if(condition) , num_threads(8) , proc_bind(close) |
Device | map(to:x) , device(2) , defaultmap(tofrom:scalar) |
Dependencies | depend(in:x) , depend(out:y) , depend(inout:z) |
Architecture
┌──────────────────────────────────────┐
│ Your Application │
├──────────────────────────────────────┤
│ Language Bindings │
│ ├─ Rust API (native) │
│ ├─ C API (16 functions) │
│ └─ C++ API (RAII wrappers) │
├──────────────────────────────────────┤
│ Parser Layer (99.1% safe Rust) │
│ ├─ Directive Parser │
│ ├─ Clause Parser │
│ └─ Error Recovery │
├──────────────────────────────────────┤
│ Lexer (nom-based, zero-copy) │
└──────────────────────────────────────┘
Design Principles:
- Safety first - Rust ownership prevents memory bugs
- Zero-copy - Parse directly from input string
- Minimal FFI - Only ~60 lines of unsafe code (0.9%)
- Extensible - Easy to add new directives/clauses
Learn more about the architecture →
Comparison
ROUP vs LLVM/Clang
Feature | ROUP | LLVM/Clang |
---|---|---|
Purpose | OpenMP parsing only | Full C/C++ compiler |
Binary size | ~500KB | ~50MB+ |
Parse time | ~500ns - 1µs | ~10-100µs |
Dependencies | None | LLVM, Clang, libc++ |
API complexity | 16 C functions | 1000s of functions |
Learning curve | Minutes | Weeks |
Use case | Analysis, tools, IDE plugins | Compilation |
Use ROUP when:
- ✅ You only need to parse OpenMP, not compile
- ✅ You want minimal dependencies
- ✅ You need fast integration into tools
- ✅ You value simplicity and safety
Use LLVM when:
- You need full C/C++ compilation
- You're building a complete compiler
- You need LLVM IR generation
ROUP vs Custom Parser
Aspect | ROUP | Custom Parser |
---|---|---|
Development time | Minutes (add dependency) | Weeks/months |
OpenMP coverage | 120+ directives | You must implement all |
Testing | 342 tests included | You must write tests |
Maintenance | Active, updated for new OpenMP | You must maintain |
Edge cases | Handled (fuzzing tested) | Likely has bugs |
Spec compliance | Verified | Uncertain |
Verdict: Unless you have very specific needs, use ROUP.
Safety Guarantees
ROUP prioritizes safety without compromising usability:
Memory Safety
- ✅ No buffer overflows - Rust prevents at compile time
- ✅ No use-after-free - Ownership system enforces
- ✅ No double-free - Checked at FFI boundary
- ✅ No memory leaks - RAII and destructors
- ✅ No data races - Thread-safe parsing
API Safety
Rust API:
- 100% memory-safe by construction
- Impossible to trigger undefined behavior
C API:
- NULL checks before all pointer operations
- Returns safe defaults on error (-1, NULL)
- Validates UTF-8 encoding
- Documents all safety contracts
Testing
- 342 tests covering all features
- Fuzzing with random inputs
- Valgrind verified (no leaks)
- Thread sanitizer verified (no races)
- Address sanitizer verified (no memory errors)
Performance
Typical performance characteristics:
Operation | Time | Notes |
---|---|---|
Parse #pragma omp parallel | ~500ns | Simple directive |
Parse with clauses | ~800ns | num_threads(4) |
Complex directive | ~1.2µs | Multiple clauses |
Iterator creation | ~10ns | FFI overhead |
Scalability:
- ✅ Thread-safe - Parse from multiple threads
- ✅ Zero-copy - No string allocations during lexing
- ✅ Minimal allocations - ~3 allocations per directive
- ✅ Fast enough - Parsing is rarely the bottleneck
Getting Started
Choose your language:
Community
- GitHub: ouankou/roup
- Issues: Bug reports
- Discussions: Questions & ideas
- Contributing: How to contribute
License
ROUP is open source under the MIT License.
Copyright © 2024-2025 Anjia Wang
Next Steps
- 📖 Read the Getting Started guide
- 🦀 Try the Rust tutorial
- 🔧 Try the C tutorial
- 📚 Browse the API reference
- 🏗️ Learn the architecture
- ❓ Check the FAQ
Why ROUP?
For Compiler Developers
- Drop-in OpenMP/OpenACC parser component
- Well-tested, battle-hardened parsing logic
- Easy FFI integration from any language
For Tool Builders
- Analyze OpenMP code without a full compiler
- Build linters, formatters, and code analyzers
- Extract parallelization patterns from codebases
For Researchers
- Study directive usage patterns
- Prototype new directive extensions
- Educational tool for learning parallel programming
Quick Example
Rust
use roup::parser::openmp;
let parser = openmp::parser();
let input = "#pragma omp parallel for num_threads(4) private(i)";
match parser.parse(input) {
Ok((_, directive)) => {
println!("Directive: {:?}", directive.kind);
println!("Clauses: {}", directive.clauses.len());
}
Err(e) => eprintln!("Parse error: {:?}", e),
}
C
#include <stdio.h>
// Forward declarations
typedef struct OmpDirective OmpDirective;
extern OmpDirective* roup_parse(const char* input);
extern int32_t roup_directive_clause_count(const OmpDirective* dir);
extern void roup_directive_free(OmpDirective* dir);
int main() {
OmpDirective* dir = roup_parse("#pragma omp parallel for num_threads(4)");
if (dir) {
printf("Clauses: %d\n", roup_directive_clause_count(dir));
roup_directive_free(dir);
}
return 0;
}
C++
#include <iostream>
#include <memory>
struct OmpDirective;
extern "C" {
OmpDirective* roup_parse(const char* input);
int32_t roup_directive_clause_count(const OmpDirective* dir);
void roup_directive_free(OmpDirective* dir);
}
// RAII wrapper
class Directive {
OmpDirective* ptr_;
public:
explicit Directive(const char* input) : ptr_(roup_parse(input)) {}
~Directive() { if (ptr_) roup_directive_free(ptr_); }
bool valid() const { return ptr_ != nullptr; }
int clause_count() const {
return ptr_ ? roup_directive_clause_count(ptr_) : 0;
}
};
int main() {
Directive dir("#pragma omp parallel for num_threads(4)");
if (dir.valid()) {
std::cout << "Clauses: " << dir.clause_count() << "\n";
}
return 0;
}
Architecture
ROUP uses a clean, modular architecture:
┌─────────────────────────────────────────┐
│ Application Layer │
│ (Your compiler/tool/analyzer) │
└─────────────────┬───────────────────────┘
│
┌───────────┼───────────┐
│ │ │
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│ Rust API│ │ C API │ │ C++ API │
│ │ │ │ │ (RAII) │
└─────────┘ └─────────┘ └─────────┘
│ │ │
└───────────┼───────────┘
│
▼
┌────────────────┐
│ Core Parser │
│ (nom-based) │
└────────────────┘
│
┌───────────┼───────────┐
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│ Lexer │ │Directive│ │ Clause │
│ │ │ Parser │ │ Parser │
└─────────┘ └─────────┘ └─────────┘
Key Design Principles:
- Safe by default - Rust's ownership system prevents memory errors
- Zero-copy parsing - Uses string slices, not allocations
- Minimal unsafe - FFI boundary only, well-documented
- Extensible - Easy to add new directives and clauses
OpenMP Support
ROUP currently supports OpenMP 5.0+ with comprehensive coverage:
Supported Directives (15+)
parallel
- Parallel regionsfor
- Worksharing loopssections
,single
- Worksharing constructstask
,taskwait
,taskgroup
- Taskingtarget
,teams
,distribute
- Device offloadingbarrier
,critical
,atomic
- Synchronizationmetadirective
- Dynamic selection- And more...
Supported Clauses (50+)
- Data sharing:
private
,shared
,firstprivate
,lastprivate
- Parallelism control:
num_threads
,if
,proc_bind
- Worksharing:
schedule
,collapse
,nowait
- Reductions:
reduction
with 10+ operators (+, *, min, max, etc.) - Device:
map
,device
,defaultmap
- Dependencies:
depend
,in
,out
,inout
- And more...
See the OpenMP Support Matrix for the complete list.
Safety Guarantees
ROUP is built with safety as a core principle:
Metric | Value | Notes |
---|---|---|
Safe Rust | 99.1% | All core logic is safe |
Unsafe blocks | 18 | Only at FFI boundary |
Unsafe lines | ~60 | Well-documented, NULL-checked |
Memory leaks | 0 | Rust's RAII prevents leaks |
Segfaults | 0 | Ownership system prevents use-after-free |
All unsafe
code is:
- Documented with safety requirements
- NULL-checked before dereferencing
- Isolated to
src/c_api.rs
- Tested with 355+ tests
Testing
ROUP has comprehensive test coverage:
- 239 doc tests - Examples in documentation are auto-tested
- 116 integration tests - Real-world usage scenarios
- 355 total tests - All passing, zero warnings
- Cross-platform - Tested on Linux, macOS, Windows
Test categories:
- ✅ Basic directives (parallel, for, task, teams, target)
- ✅ Complex features (reductions, metadirectives, nesting)
- ✅ Edge cases (comments, whitespace, error handling)
- ✅ Roundtrip parsing (parse → format → parse)
- ✅ FFI safety (C and C++ examples)
Getting Started
Want to experiment with ROUP? Check out our tutorials:
- C++ Tutorial - Build an experimental application with C++17
- Rust API Docs - Complete API reference
Or jump straight to the code:
License
ROUP is open source under the MIT License.
Copyright © 2024-2025 Anjia Wang