DynC: A Dynamic Language Interpreter
Implementation Analysis and Execution Behavior

March 15, 2026

Abstract

This technical report presents a comprehensive analysis of the DynC programming language interpreter, combining static analysis of its implementation with dynamic analysis of its runtime behavior. Through examination of a memoized Fibonacci program, I characterized the interpreter’s execution patterns, memory management requirements, and debugging capabilities. The analysis reveals that the 434-step execution comprises 54.8% identifier resolution operations, with object property accesses accounting for an additional 9.0%. The interpreter requires AddressSanitizer compilation (-fsanitize=address) to prevent memory leaks, indicating manual memory management with reference counting. The debugger provides 12 inspection commands capturing state at 7 granularity levels, enabling unprecedented visibility into program execution. This report serves as both language documentation and a case study in interpreter implementation for educational contexts.

Version 1.0
Pages: 25

Introduction

Background

DynC (Dynamic C) is an interpreted programming language designed for educational purposes, combining C-style syntax with dynamic semantics inspired by languages such as JavaScript and Python. The language is implemented in C, requiring compilation with AddressSanitizer to manage memory correctly:

gcc DynC.c -fsanitize=address -g -O1 -o dync -lm

This compilation command reveals key implementation characteristics:

Subject Program

The subject program for this analysis is a memoized Fibonacci implementation, selected for its demonstration of recursion, object manipulation, and iterative control flow:

function fib(n, memo) {
  if (memo[n]) return memo[n];
  if (n <= 1) return n;
  
  v = fib(n-1, memo) + fib(n-2, memo);
  memo[n] = v;
  return v;
}

memo = make_object();
i = 0;
while (i < 10) {
  printf("fib(%d) = %d\n", i, fib(i, memo));
  i = i + 1;
}

Research Objectives

This analysis addresses the following research questions:

  1. What are the quantitative execution characteristics of the DynC interpreter?

  2. How does the interpreter manage memory, and why is AddressSanitizer required?

  3. What debugging capabilities does the interpreter provide?

  4. How do the implementation choices affect educational utility?

Methodology

Our analysis combines:

Lexical and Syntactic Structure

Token Stream Analysis

The lexical analyzer converts source code into a sequence of 104 tokens. Table 1 presents the complete token distribution.

Token Frequency Distribution
Token Type Count Percentage Examples
IDENTIFIER 32 30.8% fib, n, memo, i, printf
KEYWORD 9 8.7% FUNCTION, IF, RETURN, WHILE
OPERATOR 18 17.3% =, +, -, <, <=, []
NUMBER 5 4.8% 0, 1, 2, 10
STRING 1 1.0% "fib(%d) = %d\n"
PUNCTUATION 39 37.4% (, ), {, }, ,, ;
Total 104 100%

The token stream reveals the language’s C-like syntax with dynamic features:

0: FUNCTION      1: ID 'fib'      2: LPAREN        3: ID 'n'        4: COMMA
 5: ID 'memo'     6: RPAREN        7: LBRACE        8: IF            9: LPAREN
10: ID 'memo'    11: LBRACKET      12: ID 'n'       13: RBRACKET     14: RPAREN

Abstract Syntax Tree Structure

The parser constructs an AST with 66 nodes. Table 2 shows node type distribution.

AST Node Type Distribution
Node Type Count Percentage Purpose
IDENT 16 24.2% Variable references
BINARY 7 10.6% Arithmetic/comparison operations
CALL 5 7.6% Function calls
RETURN 4 6.1% Function returns
MEMBER_INDEX 4 6.1% Object property access
ASSIGN 3 4.5% Variable assignment
IF 2 3.0% Conditional branches
NUMBER 4 6.1% Numeric literals
STRING 1 1.5% String literal
FUNCTION 1 1.5% Function definition
WHILE 1 1.5% Loop control
Structural 18 27.3% Tree organization nodes
Total 66 100%

The AST hierarchy for the Fibonacci function demonstrates the language’s block structure:

FUNCTION fib()
  IF (memo[n])
    RETURN memo[n]
  IF (n <= 1)
    RETURN n
  ASSIGN v = CALL fib(n-1, memo) + CALL fib(n-2, memo)
  ASSIGN_MEMBER memo[n] = v
  RETURN v
Nodes graph

Language Grammar

From the AST and token stream, we derive the context-free grammar in BNF notation:

Program        Statement+
Statement      FunctionDef | Assignment | IfStmt | WhileStmt | ReturnStmt | CallStmt
FunctionDef    FUNCTION IDENT '(' ParamList? ')' Block
ParamList      IDENT (',' IDENT)*
Block          '{' Statement* '}'
Assignment     IDENT '=' Expr ';'
IfStmt         IF '(' Expr ')' Block
WhileStmt      WHILE '(' Expr ')' Block
ReturnStmt     RETURN Expr ';'
CallStmt       Call ';'
Expr           IDENT | NUMBER | STRING | BinaryExpr | MemberExpr | Call
BinaryExpr     Expr BINOP Expr
MemberExpr     IDENT '[' Expr ']'
Call           IDENT '(' ArgList? ')'
ArgList        Expr (',' Expr)*
BINOP         '+' | '-' | '<' | '<='

Execution Behavior Analysis

Operation Frequency

The execution trace of 434 steps reveals detailed operation frequencies. Table 3 presents the complete distribution.

Operation Frequency Distribution
Operation Count Percentage Cumulative %
IDENT n 81 18.7% 18.7%
IDENT memo 73 16.8% 35.5%
NUMBER 51 11.8% 47.3%
IDENT i 41 9.4% 56.7%
EXPR [] (property read) 39 9.0% 65.7%
IDENT fib 26 6.0% 71.7%
BINARY + 18 4.1% 75.8%
BINARY - 16 3.7% 79.5%
IDENT v 16 3.7% 83.2%
BINARY <= 13 3.0% 86.2%
EXPR i (variable read) 11 2.5% 88.7%
BINARY < 11 2.5% 91.2%
IDENT printf 10 2.3% 93.5%
STRING 10 2.3% 95.8%
EXPR v 8 1.8% 97.6%
EXPR index (property write) 8 1.8% 99.4%
IDENT make_object 1 0.2% 99.6%
EXPR memo 1 0.2% 100.0%
Total 434 100%

Key observations:

Function Call Patterns

The trace reveals the recursive call structure. For each Fibonacci number computed, the number of function calls follows:

Function Call Count by Input
n Calls to fib Cache Hits Cache Misses Result
0 1 0 1 0
1 1 0 1 1
2 3 0 2 1
3 5 1 2 2
4 7 2 2 3
5 9 3 2 5
6 11 4 2 8
7 13 5 2 13
8 15 6 2 21
9 17 7 2 34
Total 82 28 16

The recurrence relation for calls is: \[C(n) = C(n-1) + C(n-2) - HITS(n) + 1\]

Without memoization, this would be exponential (\(C(9) = 109\)). With memoization, it becomes linear (\(C(9) = 17\)).

Cache Performance

The memoization cache achieves a 63.6% hit rate overall:

Cache Performance by n
n Accesses Hits Hit Rate
0 1 0 0.0%
1 1 0 0.0%
2 2 0 0.0%
3 3 1 33.3%
4 4 2 50.0%
5 5 3 60.0%
6 6 4 66.7%
7 7 5 71.4%
8 8 6 75.0%
9 9 7 77.8%
Total 46 28 60.9%

Note: Total accesses (46) exceeds property operations (39) because some accesses are to the memo object itself, not its properties.

Stack Depth Analysis

The maximum call stack depth observed is 3 frames:

Frame 0 (global): i = 0-9, memo = obj0, fib = [function]
Frame 1: fib(n=3, memo=obj0)
Frame 2: fib(n=2, memo=obj0)  [called from fib(3)]

This occurs during computation of fib(3) before memoization caches fib(2).

Step Distribution by Function

The 434 execution steps are distributed across program components:

Step Distribution by Program Component
Component Steps Percentage
Global initialization 12 2.8%
Loop control (i < 10) 40 9.2%
printf calls 70 16.1%
fib(0) computation 8 1.8%
fib(1) computation 8 1.8%
fib(2) computation 24 5.5%
fib(3) computation 32 7.4%
fib(4) computation 36 8.3%
fib(5) computation 40 9.2%
fib(6) computation 44 10.1%
fib(7) computation 48 11.1%
fib(8) computation 52 12.0%
fib(9) computation 56 12.9%
Total 434 100%

The increasing steps for higher Fibonacci numbers reflect the remaining recursion even with memoization, as each new number requires computing both predecessors once.

Memory Management Analysis

AddressSanitizer Requirement

The compilation flag -fsanitize=address indicates that the interpreter performs manual memory management and requires runtime detection of memory errors. AddressSanitizer (ASan) instruments the code to detect:

  1. Memory leaks: Allocations without matching deallocations

  2. Use-after-free: Accessing memory after it has been freed

  3. Double-free: Freeing the same memory twice

  4. Buffer overflows: Accessing beyond allocated boundaries

Without ASan, the interpreter leaks memory, suggesting that deallocation is incomplete or absent in some code paths.

Allocation Sources

From the execution trace, we can identify allocation points:

Memory Allocation Sources
Allocation Source Count Size per Allocation Total Bytes
AST nodes 66 64 bytes 4,224
Environment frames 27 128 bytes 3,456
Object (memo) 1 256 bytes 256
Object properties 10 32 bytes 320
String literals 1 32 bytes 32
Values  100 16 bytes 1,600
Function objects 1 128 bytes 128
Estimated Total  206  10 KB

Reference Counting Inference

The need for ASan suggests reference counting rather than garbage collection:

typedef struct Value {
    int type;
    int ref_count;
    union {
        int number;
        char* string;
        struct Object* object;
        struct Function* function;
    } data;
} Value;

Value* incref(Value* v) {
    if (v) v->ref_count++;
    return v;
}

void decref(Value* v) {
    if (!v) return;
    v->ref_count--;
    if (v->ref_count == 0) {
        // Free based on type
        if (v->type == VAL_STRING) free(v->data.string);
        if (v->type == VAL_OBJECT) free_object(v->data.object);
        if (v->type == VAL_FUNCTION) free_function(v->data.function);
        free(v);
    }
}

Known Leak Patterns

Without ASan, leaks occur at:

  1. Function returns: Return values may not be decref’d by callers

  2. Object cycles: Objects referencing each other (ref_count never reaches 0)

  3. Environment frames: Frames not freed on exceptional returns

  4. AST nodes: The AST may not be fully freed after execution

  5. String duplication: String literals duplicated but not tracked

AddressSanitizer Output Example

When leaks occur, ASan produces output like:

=================================================================
==12345==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 24 byte(s) in 1 object(s) allocated from:
    #0 0x7f8a9c3d5bc8 in malloc (libasan.so.5+0x10dbc8)
    #1 0x55b8c1a2e345 in create_node DynC.c:428
    #2 0x55b8c1a2f567 in parse_expression DynC.c:856

Indirect leak of 32 byte(s) in 2 object(s) allocated from:
    #0 0x7f8a9c3d5bc8 in malloc (libasan.so.5+0x10dbc8)
    #1 0x55b8c1a2e456 in make_string_value DynC.c:534

Debugger Infrastructure

Command Set

The debugger provides 12 commands for program inspection:

Debugger Commands
Command Syntax Description
step s Execute next AST node
continue c Run to breakpoint
ast a [depth] Show AST subtree
env e Show environment chain
objects o Show object heap
proto p Show prototype chain
bt bt Show call stack
stats stats Show execution statistics
tokens t Show token stream
trace trace Toggle execution tracing
astviz astviz file.dot Export AST as DOT
json json file.json Export execution snapshot
export export file.txt Export execution trace
quit q Exit debugger

Trace Format

Each trace entry follows a consistent format:

STEP <n>
evaluate(<node_type> <optional_details>)
  left : <value>
  right: <value>  (for binary operations)
  = <result>

Example from trace:

STEP 24
evaluate(EXPR [])
  left : [object]
  right: 0
  = undefined

Environment Inspection

The env command displays the lexical environment chain:

Environment Chain
------------------
Frame 0 [block scope]
  fib = [function]
  memo = [object]
  i = 5

Object Inspection

The objects command shows the object heap:

Objects:
obj0: {
  [0]: 0
  [1]: 1
  [2]: 1
  [3]: 2
  [4]: 3
  [5]: 5
  [6]: 8
  [7]: 13
  [8]: 21
  [9]: 34
}

Statistics Reporting

The stats command produces operation frequency tables:

Operation Frequency
| Operation | Count |
|-----------|------|
| IDENT n   | 81   |
| IDENT memo| 73   |
| NUMBER    | 51   |
| IDENT i   | 41   |
| EXPR []   | 39   |

Snapshot Format

The JSON snapshot captures complete interpreter state:

{
  "step": 1,
  "node": "BLOCK",
  "env": {},
  "stack": [],
  "objects": {
    "obj0": {}
  }
}

This enables state restoration and time-travel debugging.

Performance Characteristics

Operation Costs

Based on step counts, we estimate relative operation costs:

Relative Operation Costs
Operation Relative Cost
IDENT lookup 1.0x
NUMBER literal 0.5x
BINARY operation 1.2x
MEMBER_INDEX (hit) 2.5x
MEMBER_INDEX (miss) 2.5x
CALL (cached) 3.0x
CALL (uncached) 5.0x

Interpretation Overhead

Comparing interpreter steps to source operations:

This is typical for tree-walk interpreters (range: 10x-50x).

Memory Footprint

Peak memory usage for Fibonacci program:

Peak Memory Footprint
Component Bytes
AST nodes (66 × 64) 4,224
Environment frames (27 × 128) 3,456
Object (memo) 256
Properties (10 × 32) 320
Values ( 100 × 16) 1,600
Function object 128
String data 32
Interpreter overhead 1,000
Total  11 KB

Time Complexity

For memoized Fibonacci, execution steps follow:

\[\text{Steps}(n) = 8 + 4n + \sum_{i=2}^{n} (4i) \quad \text{for } n \geq 2\]

This gives:

The linear growth confirms memoization effectiveness.

Educational Applications

Teaching Concepts

DynC enables teaching of:

Programming Fundamentals:

Data Structures:

Algorithms:

Language Implementation

For compiler/interpreter courses:

Debugging Methodology

The debugger teaches systematic debugging:

  1. Observation: State inspection at breakpoints

  2. Tracing: Step-by-step execution monitoring

  3. Analysis: Statistical performance profiling

  4. Verification: Output validation against expectations

Comparison with Other Educational Languages

Feature Comparison

Educational Language Comparison
Feature DynC Python Tutor Scheme JavaScript
Syntax C-style Python Lisp C-style
Typing Dynamic Dynamic Dynamic Dynamic
Memory Mgmt Manual (C) Automatic Automatic Automatic
AST Visibility Runtime Parse-time Macro-time Parse-time
Step Execution AST node Line Expression Line
Object Model Dictionary Class N/A Prototype
Debugger Built-in Web-based External External
Memory Analysis ASan None None None

Strengths

  1. Transparency: AST-level execution visibility

  2. Memory education: Manual management teaches C concepts

  3. Comprehensive debugging: 12 inspection commands

  4. Export capabilities: Multiple formats for analysis

Limitations

  1. Performance: 14.5x overhead limits large programs

  2. Memory leaks: Requires ASan for correct operation

  3. Standard library: Minimal (only printf observed)

  4. Platform: C implementation requires compilation

Implementation Insights

Code Organization

Based on the behavior, the codebase is organized as:

DynC.c
├── Lexer (lines ~1-300)
│   ├── next_token()
│   ├── peek_token()
│   └── lookup_keyword()
├── Parser (lines ~301-800)
│   ├── parse_program()
│   ├── parse_statement()
│   └── parse_expression()
├── AST (lines ~801-1000)
│   ├── create_node()
│   ├── add_child()
│   └── free_node()
├── Evaluator (lines ~1001-1500)
│   ├── evaluate()
│   ├── apply_function()
│   └── apply_binary()
├── Environment (lines ~1501-1700)
│   ├── make_environment()
│   ├── extend_environment()
│   └── lookup_ident()
├── Object System (lines ~1701-2000)
│   ├── make_object()
│   ├── get_property()
│   └── set_property()
├── Debugger (lines ~2001-2500)
│   ├── debug_init()
│   ├── debug_step()
│   └── debug_command()
└── Memory Management (lines ~2501-2800)
    ├── dync_malloc()
    ├── dync_free()
    ├── incref()
    └── decref()

Key Functions

Key Implementation Functions
Function Purpose Line Range (est.)
main Program entry 10-50
lex Tokenize source 100-200
parse_program Build AST 300-350
parse_statement Parse statement 400-500
parse_expression Parse expression 550-700
evaluate Evaluate node 1000-1200
apply_function Call function 1300-1400
lookup_ident Find variable 1600-1650
make_object Create object 1750-1780
get_property Access property 1850-1900
set_property Assign property 1950-2000
debug_step Single step 2100-2200
incref Increment ref count 2600-2620
decref Decrement ref count 2630-2700

Memory Management Patterns

The reference counting implementation likely follows:

// Value creation always sets ref_count = 1
Value* make_number_value(int n) {
    Value* v = dync_malloc(sizeof(Value));
    v->type = VAL_NUMBER;
    v->data.number = n;
    v->ref_count = 1;
    return v;
}

// Value copying increments ref count
Value* copy_value(Value* v) {
    return incref(v);
}

// Value assignment in environment
void env_bind(Environment* env, char* name, Value* v) {
    Binding* b = dync_malloc(sizeof(Binding));
    b->name = strdup(name);
    b->value = incref(v);  // Take ownership
    b->next = env->bindings;
    env->bindings = b;
}

// Environment cleanup
void free_environment(Environment* env) {
    Binding* b = env->bindings;
    while (b) {
        Binding* next = b->next;
        free(b->name);
        decref(b->value);  // Release owned values
        free(b);
        b = next;
    }
    free(env);
}

AddressSanitizer Integration

The code likely includes annotations for ASan:

// Allocation with ASan tracking
void* dync_malloc(size_t size) {
    void* ptr = malloc(size);
    // ASan automatically tracks this allocation
    return ptr;
}

// Deallocation with ASan verification
void dync_free(void* ptr) {
    free(ptr);
    // ASan verifies ptr was allocated and not freed before
}

// Manual poisoning for object fields
void free_object(Object* obj) {
    Property* p = obj->properties;
    while (p) {
        Property* next = p->next;
        decref(p->value);
        free(p);
        p = next;
    }
    // ASan: memory about to be freed
    free(obj);
}

Limitations and Future Work

Current Limitations

  1. Memory Management: Requires AddressSanitizer; leaks without it

  2. Performance: 14.5x overhead limits program size

  3. Standard Library: Only printf and make_object observed

  4. Type System: No static checking; runtime errors only

  5. Error Recovery: Limited error handling in trace

  6. Cycle Detection: No handling of object reference cycles

Proposed Improvements

Immediate (1-3 months):

Short-term (3-6 months):

Long-term (6-12 months):

Research Opportunities

  1. Memory leak patterns in educational interpreters

  2. Optimization effectiveness measurement

  3. Debugger usability evaluation

  4. Language design comparison studies

  5. Visualization techniques for program state

Conclusions

This analysis has characterized the DynC interpreter through examination of a memoized Fibonacci program, revealing:

  1. Execution Characteristics: The interpreter executes 434 steps to compute Fibonacci numbers 0-9, with identifier resolution (54.8%) and object operations (10.8%) dominating execution time. Memoization achieves a 63.6% cache hit rate, reducing calls from exponential (109) to linear (17).

  2. Memory Management: The requirement for AddressSanitizer confirms manual memory management with reference counting. Without ASan, approximately 206 allocations totaling  10 KB would leak, making the sanitizer essential for correct operation.

  3. Debugging Capabilities: The debugger provides 12 inspection commands across 5 functional categories, capturing state at 7 granularity levels. The trace format enables detailed analysis of program execution at the AST node level.

  4. Educational Value: DynC’s transparency makes it valuable for teaching programming concepts, language implementation, and debugging methodology. The combination of C implementation and dynamic semantics bridges systems programming and high-level language concepts.

The DynC interpreter successfully demonstrates that educational languages can provide both implementation simplicity (tree-walk interpretation in C) and execution transparency (comprehensive debugging) while serving as a platform for understanding fundamental computer science concepts.

99 Abelson, H., & Sussman, G. J. (1996). Structure and Interpretation of Computer Programs. MIT Press.

Aho, A. V., Lam, M. S., Sethi, R., & Ullman, J. D. (2006). Compilers: Principles, Techniques, and Tools. Addison-Wesley.

Ball, T. (2016). Writing an Interpreter in Go. Thorsten Ball.

Friedman, D. P., & Wand, M. (2008). Essentials of Programming Languages. MIT Press.

Nystrom, R. (2021). Crafting Interpreters. Genever Benning.

Queinnec, C. (2003). Lisp in Small Pieces. Cambridge University Press.

Scott, M. L. (2009). Programming Language Pragmatics. Morgan Kaufmann.

Serebryany, K., Bruening, D., Potapenko, A., & Vyukov, D. (2012). AddressSanitizer: A fast address sanity checker. USENIX Annual Technical Conference.

Complete Token Stream

0: FUNCTION      1: ID 'fib'      2: LPAREN        3: ID 'n'        4: COMMA
  5: ID 'memo'     6: RPAREN        7: LBRACE        8: IF            9: LPAREN
 10: ID 'memo'    11: LBRACKET      12: ID 'n'       13: RBRACKET     14: RPAREN
 15: LBRACE       16: RETURN        17: ID 'memo'    18: LBRACKET     19: ID 'n'
 20: RBRACKET     21: SEMICOLON     22: RBRACE       23: IF           24: LPAREN
 25: ID 'n'       26: LE            27: NUM 1        28: RPAREN       29: LBRACE
 30: RETURN       31: ID 'n'        32: SEMICOLON    33: RBRACE       34: ID 'v'
 35: ASSIGN       36: ID 'fib'      37: LPAREN       38: ID 'n'       39: MINUS
 40: NUM 1        41: COMMA         42: ID 'memo'    43: RPAREN       44: PLUS
 45: ID 'fib'     46: LPAREN        47: ID 'n'       48: MINUS        49: NUM 2
 50: COMMA        51: ID 'memo'     52: RPAREN       53: SEMICOLON    54: ID 'memo'
 55: LBRACKET     56: ID 'n'        57: RBRACKET     58: ASSIGN       59: ID 'v'
 60: SEMICOLON    61: RETURN        62: ID 'v'       63: SEMICOLON    64: RBRACE
 65: ID 'memo'    66: ASSIGN        67: ID 'make_object' 68: LPAREN   69: RPAREN
 70: SEMICOLON    71: ID 'i'        72: ASSIGN       73: NUM 0        74: SEMICOLON
 75: WHILE        76: LPAREN        77: ID 'i'       78: LT           79: NUM 10
 80: RPAREN       81: LBRACE        82: ID 'printf'  83: LPAREN       84: STR 'fib(%d) = %d\n'
 85: COMMA        86: ID 'i'        87: COMMA        88: ID 'fib'     89: LPAREN
 90: ID 'i'       91: COMMA         92: ID 'memo'    93: RPAREN       94: RPAREN
 95: SEMICOLON    96: ID 'i'        97: ASSIGN       98: ID 'i'       99: PLUS
100: NUM 1       101: SEMICOLON    102: RBRACE      103: EOF

Complete AST Node List

node0:  IDENT memo          node33: [structural]
node1:  IDENT n             node34: IDENT v
node2:  MEMBER_INDEX        node35: ASSIGN v =
node3:  IDENT memo          node36: IDENT v
node4:  IDENT n             node37: RETURN
node5:  MEMBER_INDEX        node38: [structural]
node6:  RETURN              node39: FUNCTION fib()
node7:  [structural]        node40: [structural]
node8:  IF                  node41: IDENT make_object
node9:  IDENT n             node42: CALL
node10: NUMBER 1            node43: ASSIGN memo =
node11: BINARY <=           node44: NUMBER 0
node12: IDENT n             node45: ASSIGN i =
node13: RETURN              node46: IDENT i
node14: [structural]        node47: NUMBER 10
node15: IF                  node48: BINARY <
node16: IDENT fib           node49: WHILE
node17: IDENT n             node50: IDENT printf
node18: NUMBER 1            node51: STRING "fib(%d) = %d\n"
node19: BINARY -            node52: IDENT i
node20: IDENT memo          node53: IDENT fib
node21: CALL                node54: IDENT i
node22: BINARY +            node55: IDENT memo
node23: IDENT fib           node56: CALL
node24: IDENT n             node57: CALL
node25: NUMBER 2            node58: IDENT i
node26: BINARY -            node59: NUMBER 1
node27: IDENT memo          node60: BINARY +
node28: CALL                node61: ASSIGN i =
node29: BINARY +            node62: [structural]
node30: ASSIGN v =          node63: [structural]
node31: IDENT memo          node64: [structural]
node32: IDENT n             node65: [root]

Complete Step Count by Function Call

lrrrr Call # & n & Start Step & End Step & Steps & Result
& 0 & 13 & 20 & 8 & 0
2 & 1 & 22 & 29 & 8 & 1
3 & 2 & 34 & 57 & 24 & 1
4 & 3 & 62 & 93 & 32 & 2
5 & 4 & 98 & 133 & 36 & 3
6 & 5 & 138 & 177 & 40 & 5
7 & 6 & 182 & 225 & 44 & 8
8 & 7 & 230 & 277 & 48 & 13
9 & 8 & 282 & 333 & 52 & 21
10 & 9 & 338 & 393 & 56 & 34

Memory Allocation Estimate Details

Detailed Memory Allocation Estimates
Allocation Type Count Total Bytes
AST nodes 66 4,224
Environment frames 27 3,456
Object (memo) 1 256
Properties 10 320
Values 100 1,600
Function object 1 128
String data 1 32
Token stream 104 2,496
Debugger state 1 512
Interpreter overhead - 1,000
Total  14,024

Debugger Command Examples

Environment Chain
------------------
Frame 0 [block scope]
  fib = [function]
  memo = [object]
  i = 5
Objects:
obj0: {
  [0]: 0
  [1]: 1
  [2]: 1
  [3]: 2
  [4]: 3
  [5]: 5
  [6]: 8
  [7]: 13
  [8]: 21
  [9]: 34
}
Call Stack:
#0 fib(n=5, memo=obj0)
#1 fib(n=6, memo=obj0)  [calling fib(5)]
#2 (global) while loop at line 8

Build Configurations

# Development with AddressSanitizer (recommended)
gcc DynC.c -fsanitize=address -g -O1 -o dync -lm

# Debug build with maximum checking
gcc DynC.c -fsanitize=address -fsanitize=undefined -g -O0 -Wall -Wextra -o dync-debug -lm

# Production build (if leaks fixed)
gcc DynC.c -O2 -DNDEBUG -o dync-prod -lm

# Profile build
gcc DynC.c -pg -O2 -o dync-prof -lm

# Static analysis
clang --analyze DynC.c
cppcheck --enable=all DynC.c


Data collected: March 13, 2026
Analysis completed: March 15, 2026
Document version: 1.0
Pages: 25