diff options
Diffstat (limited to 'src/zisp/io/Parser.zig')
| -rw-r--r-- | src/zisp/io/Parser.zig | 85 |
1 files changed, 33 insertions, 52 deletions
diff --git a/src/zisp/io/Parser.zig b/src/zisp/io/Parser.zig index ed55a36..dbcd6ad 100644 --- a/src/zisp/io/Parser.zig +++ b/src/zisp/io/Parser.zig @@ -1,55 +1,36 @@ -// === Syntax === -// -// See docs/parser.md and spec/syntax.bnf to understand the syntax. -// -// -// === Trampolining strategy === -// -// Instead of using recursion directly, the parser is written in a "trampoline" -// style, which ensures that parse depth is not limited by stack size. -// -// All state and context is passed around via a struct pointer. The parser has -// a main loop, which calls a function as dictated by parser.context.next, and -// the function may update the state to have another function called next. -// -// If a function wants to call a recursive subroutine, it pushes some of the -// current context onto a stack, including what function the subroutine should -// return to, and then updates the state to instruct the main loop to call one -// of the entry point subroutines. -// -// If a function wants to make the parser return, either from a subroutine or -// from the main loop, it sets the .result field, and tries to pop the saved -// context. If the context stack was empty, the main loop returns. -// -// -// === Buffering === -// -// For efficiency, call the parser on an input stream with implicit buffering. -// -// The parser does not use its own buffer, beyond one character that may be -// written back into the unread_char field, which is checked at the end to -// ensure it's nothing other than a trailing blank or comment. -// -// This lack of buffering is to ensure that the parser never reads more bytes -// from the input than what it needs to parse a datum. Consider the input: -// -// (a b c) (x y z) -// -// If we used proper buffering, like reading up to 4K bytes per read, then the -// whole stream would be consumed at once before it's parsed. Then, the parser -// would return the first datum, and the rest of the stream would be lost. The -// parser would need some way to reset the input stream's read head to the end -// of the first datum, but not all stream types may support this. -// -// Although in a scenario like this it would be wise to create a single Parser -// instance to call multiple times (in which case it could continue using its -// internal buffer from where it left), this may not always be practical. -// -// One could even have an input stream with Zisp s-expressions and other data -// intertwined, in which case this lack of buffering is also crucial, since one -// needs to alternate between calling the Zisp parser and some other parser on -// the same input stream. -// +//! +//! === Syntax === +//! +//! See docs/c1/1-parse.md to understand the implemented syntax. +//! +//! +//! === Trampolining strategy === +//! +//! Instead of using recursion directly, the parser is written in a "trampoline" +//! style, which ensures that parse depth is not limited by stack size. +//! +//! All state and context is passed around via a struct pointer. The parser has +//! a main loop, which calls a function as dictated by parser.context.next, and +//! the function may update the state to have another function called next. +//! +//! If a function wants to call a recursive subroutine, it pushes some of the +//! current context onto a stack, including what function the subroutine should +//! return to, and then updates the state to instruct the main loop to call one +//! of the entry point subroutines. +//! +//! If a function wants to make the parser return, either from a subroutine or +//! from the main loop, it sets the .result field, and tries to pop the saved +//! context. If the context stack was empty, the main loop returns. +//! +//! +//! === Buffering === +//! +//! For efficiency, call the parser on an input stream with implicit buffering. +//! +//! The parser does not use its own buffer, beyond one character that may be +//! written back into the unread_char field, which is checked at the end to +//! ensure it's nothing other than a trailing blank or comment. +//! const builtin = @import("builtin"); const std = @import("std"); |
