Page concepts parsers: Source version: Markbridge 0.4.2. These docs are built from the repository and may include unreleased changes. Source page: https://markbridge.dev/concepts/parsers/ # Parsers > How the four parsers work and where they differ. Each parser targets one input format but produces the same AST. They share philosophy (graceful degradation, bounded recursion) but not implementation. ## BBCode parser **Path:** `Markbridge::Parsers::BBCode::Parser` A hand-written, two-stage parser: 1. **Scanner** — streams the input and produces `TextToken`, `TagStartToken`, `TagEndToken`. Byte-offset based (`byteslice` / `byteindex` / `getbyte`, not character indices, which are O(n) on multibyte input), no regex except for character classes, minimal allocations. 2. **Parser** — consumes tokens through a `HandlerRegistry`. Each handler implements `on_open` / `on_close`. A `ParserState` tracks the node stack and enforces the max-depth limit (100). **Unique to BBCode:** closing strategies. Real-world BBCode often has mismatched tags (`[b][i]text[/b][/i]`). A `ClosingStrategy` decides how to recover: * `Strict` — auto-close only. * `Reordering` (default) — reconciles sequences of up to 5 mismatched closing tags by peeking ahead. **Handler API:** stateful. Handlers push/pop elements on the parser state stack via `on_open` / `on_close` callbacks. ## HTML parser **Path:** `Markbridge::Parsers::HTML::Parser` Thin wrapper over `Nokogiri::HTML.fragment` + a handler registry. Walks the DOM and dispatches each element to a handler. **Handler API:** stateless — an object responding to `#process(element:, parent:)`. It adds an AST node to `parent` and returns either the node to descend into, or `nil` to skip children. ```ruby class AsideHandler < Markbridge::Parsers::HTML::Handlers::BaseHandler # Descend the children straight into the parent — no AST node for