# Location

`Position`/`Location` (`location.h`, no separate `.cpp` - `location.cpp` is empty) are Bison-flavored source-position/-range types, shaped to match what a generated Bison C++ parser expects for `%locations`/`api.location.type`, extended with a link back to the [`FileStack`](filestack.md) currently being scanned. Their job is to be cheap to update token-by-token during lexing and then convert, once, into the simulator's own compact [`Loc`](sourceloc.md) via `.loc()`.

## `Position`

A point in a source: a `filename` pointer, 1-based `line`/`column`, a byte `offset`, and a `fileStack`/`fileStackPosition` pair identifying which entry of which `FileStack` this position belongs to. `lines(count)` advances the line and resets the column to 1; `columns(count)` advances both column and `offset`; both clamp their result to a minimum of 1 via the private `add_()` helper, so a position can never go negative even from a pathological call.

`loc()` converts to a `Loc` using only `fileStack->id()`, `fileStackPosition`, `line`, and `offset` - `column` and `filename` are dropped. `Loc` doesn't need `column`: [File Access](filesystem.md)'s `getLineByOffset()` recomputes it on demand from the stored offset whenever a location is actually displayed. `filename` is essentially vestigial: it exists to support the generic Bison-style `operator<<` further down (which prints a plain filename directly), but the simulator's real diagnostic path is `Loc::toString()`, which resolves file names through the [`FileStack`](filestack.md) instead and never reads `Position::filename` at all.

## `Location`

A `begin`/`end` `Position` pair. `step()` collapses the range to a zero-width point at `end` - the standard Bison convention of "step" before scanning the next token, so `begin` catches up to wherever the previous token left off. `columns(count)`/`lines(count)` extend only `end`. This pairing (`step()` then `columns()`) is exactly what the [lexer](dfllexer.md)'s `YY_USER_ACTION` macro runs after every matched token: `loc->step(); loc->columns(yyleng);`.

`loc()` converts to a `Loc` using only `begin` - the simulator's `Loc` is a single point, not a range, so a token/rule's start is all that survives the conversion.

## Streaming output

The `operator<<` overloads for `Position` and `Location` reproduce GNU Bison's default location-formatting convention (`file:line.col`, or `file:line.col-line.col` when a range spans more than one point). They exist for compatibility with generated-parser conventions and ad hoc debugging rather than being the simulator's actual error-formatting path - that is `Loc::toString()` (see [Source Location Tracking](sourceloc.md)), reached only after a `Location`/`Position` has already been converted to a `Loc`.
