ROUP
Rust-based OpenMP & OpenACC Parser
Safe, fast, and comprehensive directive parsing
What is ROUP?
ROUP is an experimental parser for OpenMP and OpenACC directives, written in safe Rust with C, C++, and Fortran bindings. Parse pragmas like #pragma omp parallel for or !$acc parallel 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
- Zero-copy lexer and hand-written parsers
- Standalone library (no LLVM/ANTLR dependencies)
- Compatibility shims for ompparser and accparser
🛡️ Safe & Reliable
- Memory safety guaranteed except for the narrow FFI boundary
- Extensive automated tests plus OpenMP_VV/OpenACCV-V validation and compat ctests
- NULL-safe C API with defensive checks
📚 Comprehensive Directive Support
- OpenMP 3.0–6.0 directives, clauses, combined forms, and metadirectives
- OpenACC 3.4 directives, clauses, aliases, and end-paired constructs
- Canonical keyword handling and clause alias preservation
- Interactive parser debugger (
roup_debug) for OpenMP/OpenACC (C and Fortran sentinels)
🔌 Multi-Language APIs
| Language | API Style | Memory Management | Status |
|---|---|---|---|
| Rust | Native | Automatic (ownership) | ✅ |
| C | Pointer-based | Manual (malloc/free pattern) | ✅ |
| C++ | RAII wrappers | Automatic (destructors) | ✅ |
| Fortran | C interop | Manual (via iso_c_binding) | ✅ (via C API) |
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
! 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) |
Complete clause reference → | 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
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:
reductionwith 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
All unsafe code is isolated to the FFI boundary (src/c_api.rs), documented with safety requirements, and NULL-checked before dereferencing.
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