Skip to content

Compilation Pipeline

The AXSLC compiler processes shader source through four distinct phases:

Phase Details

Phase 1: Tokenizer

The tokenizer (Tokenizer class) performs lexical analysis, converting the raw source text into a stream of tokens. It handles:

  • Keywords (@version, @stage, in, out, uniform, etc.)
  • Identifiers and type names
  • Literals (integers, floats, booleans)
  • Operators and punctuation
  • Comments (line and block)
  • Source location tracking for error reporting

Phase 2: Parser

The parser (Parser class) consumes tokens and builds an Abstract Syntax Tree. Key features:

  • Pratt parsing for expressions with proper precedence
  • Flat AST using integer node IDs instead of pointers
  • Tracks declared identifiers to distinguish variables from function calls
  • Produces a Program struct with separate lists for globals and per-stage items

Phase 3: Linker

The linker (Linker class) performs several critical tasks and produces a LinkResult struct containing the merged AST, uniform usage map, and any errors:

Include Resolution

Recursively loads and parses @include files, merging their AST nodes into the main program. Only global declarations are merged; stage blocks are not.

Symbol Table Construction

Builds a complete symbol table of all declared names (functions, structs, uniforms, buffers) from both globals and stages.

Uniform Usage Scanning

Analyzes each stage's function bodies to determine which global uniforms are actually referenced. This enables per-stage dead-code elimination.

Identifier Validation

Validates all identifier references:

  • Reports unresolved function calls
  • Checks field access and array subscript base expressions
  • Ensures all referenced names are declared

LinkResult Structure

The linker returns a LinkResult struct containing:

  • all_nodes: Merged flat AST from main file and all includes
  • uniform_usage: Map of stage to set of used uniform names
  • errors: Vector of error messages

Phase 4: Emitter

The emitter (OpenGLGLSLEmitter class) generates final GLSL code for each stage:

The emitter also handles:

  • Layout qualifier generation from annotations
  • Uniform shadowing (stage-local overrides of globals)
  • Expression parenthesization
  • Clean formatting of float literals

The Compiler API

The Compiler class orchestrates all four phases and is the only public API:

cpp
struct CompileResult {
    std::map<StageKind, std::string> stages;
    std::vector<std::string> errors;
};

class Compiler {
public:
    CompileResult compile(
        const std::string& source,
        const std::string& filename = "",
        const std::string& base_path = ""
    );
};

Usage:

cpp
Compiler compiler;
auto result = compiler.compile(source, "shader.axsl", "./");

if (!result.errors.empty()) {
    for (const auto& error : result.errors) {
        std::cerr << error << std::endl;
    }
    return 1;
}

// Write output files
for (const auto& [stage, code] : result.stages) {
    // Write code to appropriate file
}