NotPlusPlus is a small interpreter for a strict subset of real C++. It accepts ordinary .cpp source files, parses and type-checks supported constructs, lowers them to an internal IR, and executes int main() directly without producing native code.
The project is intentionally narrow. Supported C++ works with predictable semantics; unsupported C++ is rejected with targeted diagnostics instead of being silently reinterpreted.
This repository already includes:
- A Rust library crate plus the
nppCLI binary - A front-end pipeline for lexing, parsing, semantic analysis, IR lowering, and interpretation
- Built-in output functions
print(int)andprint(bool) - Debug modes for dumping tokens, AST, semantic analysis, IR, and execution traces
- Integration and snapshot tests covering lexer, parser, semantics, runtime, diagnostics, and CLI behavior
The authoritative design lives in docs/design.md. The test workflow and layering policy live in docs/tdd.md.
NotPlusPlus currently supports a deliberately small, explicit subset:
- Single-file programs with function declarations and definitions
- Exactly one entry point with the signature
int main() - Scalar types
int,bool, andvoid - Fixed-size one-dimensional arrays
- Integer and boolean literals
- Identifier references, parenthesized expressions, function calls, and array indexing
- Unary operators
+,-,! - Binary arithmetic
+,-,*,/,% - Comparisons
<,<=,>,>=,==,!= - Logical operators
&&,||with short-circuit behavior - Assignment
=and compound assignment+=,-=,*=,/=,%= - Statements: declaration, expression, block,
if,if/else,while,for,return,break,continue - Implicit
return 0;at the end ofmain
Runtime checks currently report errors for:
- Division by zero
- Integer overflow
- Uninitialized reads
- Missing return values from non-
voidfunctions - Exceeded call-depth limits
- Array bounds violations
Examples of constructs that are intentionally rejected today:
- Preprocessor directives such as
#include std::coutand stream insertion- Namespaces
- Pointers and references
- Classes, structs, templates, and dynamic allocation
- String literals and floating-point types
constand other storage/type qualifiers++and--- Complex declarators such as multi-declarator statements
If a feature is not listed as supported, assume it is outside the current subset.
Build and run the interpreter with Cargo:
cargo run -- tests/fixtures/integration/for_loop_end_to_end.cppThat fixture program is:
int main() {
int sum = 0;
for (int i = 1; i <= 4; i += 1) {
sum += i;
}
print(sum);
return 0;
}Expected output:
10
You can also run one of the curated examples in examples:
examples/limit_deep_recursion.cppexamples/limit_array_shadowing.cppexamples/limit_complex_lvalues.cpp
usage: npp [--dump-tokens|--dump-ast|--dump-sema|--dump-ir|--trace-exec] [--no-color] [--max-call-depth=N] <file>
Options:
--dump-tokens: lex and print the token stream--dump-ast: parse and print the AST--dump-sema: run semantic analysis and print the analyzed program--dump-ir: lower to IR and print the executable representation--trace-exec: execute the program and emit a statement-level trace to stderr--no-color: render diagnostics without ANSI color codes--max-call-depth=N: override the runtime recursion/call-depth limit; default is256
Only one debug mode can be selected at a time.
Example:
cargo run -- --trace-exec tests/fixtures/cli/basic.cppThat prints program output to stdout and a trace like this to stderr:
trace:
enter main
stmt main at tests/fixtures/cli/basic.cpp:6:5
enter add at tests/fixtures/cli/basic.cpp:6:17
stmt add at tests/fixtures/cli/basic.cpp:2:5
return add => 5
stmt main at tests/fixtures/cli/basic.cpp:7:5
stmt main at tests/fixtures/cli/basic.cpp:8:5
return main => 0
The interpreter distinguishes between compile-time failures and runtime failures:
0: successful execution2: compile failure3: runtime failure4: CLI or internal failure
Diagnostics include source locations, stable project-specific error codes, and stack traces for runtime failures when available.
Common commands:
cargo test --all-targets
cargo test runtime_allows_implicit_zero_return_from_main
cargo run -- --dump-ir tests/fixtures/runtime/arithmetic.cpp
cargo fmt
cargo fmt --checkRepository layout:
src: implementationtests: integration and snapshot testsexamples: small standalone example programsdocs: design and workflow notes
See LICENSE.