LParser Class
Public Functions
| LParser(const std::vector<LToken> & tokens) | |
| const std::vector<LError> & | errors() |
| LLayerNode | parse_file() |
Detailed Description
Build a Layers abstract syntax tree (AST) from a token stream.
Consider the following Layers text:
Host: "huntrsoftware.com"
Providing the lexer's tokens for the above as input, the parser produces a root layer node representing the whole file, holding one attribute node:
attributes = {
{ declaration = {
item = {{"Host"}} }
expression -> value -> string = "huntrsoftware.com" } }
It is not the job of the parser to resolve references or create live
data; the tree only describes the file. Converting it into live
LLayer and LAttribute objects is
called lowering, and that's handled by the loader.
The parser provides parse_file() which returns the root LLayerNode built
from the tokens provided when constructing the parser. The tokens must end
with an ENDFILE token (tokens from LLexer always do).
LLexer lexer("Host: \"huntrsoftware.com\"");
LParser parser(lexer.build_tokens());
LLayerNode root = parser.parse_file();
// `root.attributes` contains the `Host` attribute node
Call errors() to acquire the errors that were found while parsing the
tokens. The parser doesn't stop at an error; it reports it, skips ahead to
the next line or past the current block, and carries on, so a single pass
finds as many errors as it can. A tree with errors is therefore only a best
effort: it can be missing statements or hold incomplete nodes, and shouldn't
be lowered.
Parser errors that follow lexer errors are often caused by them, so consider
logging the parser's errors only when the lexer found none, like
LEngine does.
if (lexer.errors().empty())
for (const LError& parser_error : parser.errors())
Layers::log("parser: " + std::to_string(parser_error.line) + ": " +
parser_error.message);
A tree without errors is ready for a loader to lower. Lowering expands each
declaration into the layers and attributes it names, applies their values
and states, and records their base and link paths, which the engine
resolves afterward. LEngine::load_files()
lexes, parses, and lowers each file for you, skipping any file with errors.
if (lexer.errors().empty() && parser.errors().empty())
loader.lower(root);
Member Function Documentation
LParser(const std::vector<LToken> & tokens)
Construct a parser for the provided tokens, like those returned by
LLexer::build_tokens(). The tokens must end with an ENDFILE token.
const std::vector<LError> & errors()
Returns the errors that were discovered while parsing the tokens.
LLayerNode parse_file()
Parse the token stream into a root layer node representing the whole file. The root has an empty declaration; the file's top-level statements are its members.