Defined in header <cparse/Cursor.hh>
class Cursor;
Cursor is a read-only position in an std::istream. On top of what the standard stream cursor gives you, it adds three things:
- Line and column tracking that updates automatically on every read.
- A save/restore mechanism for cheap backtracking without seeking manually.
- Safe variants of
getandpeekthat return an EOF sentinel'\032'(^Z) instead of throwing when the stream cannot be read.
Grammars almost never construct a Cursor directly — Parser::parse() does that for the outermost file, and Parser::pushCursor() does it for nested inputs. But grammars call cursor methods on every character consumed, so the interface matters.
Member types
| Member type | Definition |
|---|---|
stream_type | std::istream |
Member functions
| (constructor) | constructs the cursor |
| (destructor) | destroys the cursor (virtual) |
| operator= | assigns from another cursor |
| operator== | compares two cursors for equality |
Position management
| rewind | seeks to start of stream and resets line/column |
| store | records the current position for later restore |
| restore | seeks back to a previously stored position |
| safeRestore | restore with exception-mask handling for post-EOF recovery |
| isValid | checks whether the stream is set and not in eof/bad state |
Reading
| get | consumes and returns the next character; throws at EOF |
| safeGet | as get, but returns EOF sentinel instead of throwing |
| peek | inspects the next character without consuming; throws at EOF |
| safePeek | as peek, but returns EOF sentinel instead of throwing |
Location accessors
| getLocation | returns the shared filename pointer |
| getFilename | returns the filename by reference |
| getLineNumber | returns the current one-based line number |
| getColumnNumber | returns the current one-based column number |
Notes
The stream is held via std::shared_ptr. Copies of a Cursor share the same underlying stream, so store() / restore() cannot "undo" a get() on the stream itself — they only reset the recorded position and seek the underlying stream back. This is fine for files but may be surprising for non-seekable streams.
Move construction and move assignment are deleted. The rationale is that Parser::storeCursor() returns a Cursor const& (aliasing the parser's own cursor) and callers who need an independent snapshot must make an explicit copy — which move-elision would silently break.
The destructor is virtual. The class is not final, though it is not currently subclassed inside cparse.
Example
#include <cparse/Cursor.hh>
#include <iostream>
#include <sstream>
int main()
{
auto ss = std::make_shared<std::istringstream>("hello\nworld");
fedem::parser::Cursor c("<memory>", ss);
while (c.isValid())
{
auto ch = c.safeGet();
if (ch == '\032') break;
std::cout << ch;
}
std::cout << "\nreached line " << c.getLineNumber()
<< ", column " << c.getColumnNumber() << '\n';
}
Output:
hello
world
reached line 2, column 5
See also
- Parser — the abstract driver that owns and drives Cursor instances.
- Getting Started — how a grammar consumes a Cursor.

