FE 0.9.2
Header-only C++ frontend library
Loading...
Searching...
No Matches
parser.h
Go to the documentation of this file.
1#pragma once
2
3#include "fe/loc.h"
4#include "fe/ring.h"
5
6namespace fe {
7
8/// The blueprint for a [recursive descent](https://en.wikipedia.org/wiki/Recursive_descent_parser)/
9/// [ascent parser](https://en.wikipedia.org/wiki/Recursive_ascent_parser) using a @p K lookahead of `Tok`ens.
10/// Parser::accept and Parser::expect indicate failure by constructing a @p Tok%en with its default constructor.
11/// Hence, @p Tok must be default-constructible *and* testable as a `bool` (to check for that failure):
12/// ```
13/// class Tok {
14/// public:
15/// enum class Tag {
16/// Nil,
17/// // ...
18/// };
19/// Tok() {} // default constructor yields the "failure" token
20/// // ...
21/// explicit operator bool() const { return tag_ != Tag::Nil; }
22/// // ...
23/// };
24///
25/// // Your Parser:
26/// if (auto tok = accept(Tok::Tag::My_Tag)) {
27/// do_something(tok);
28/// }
29/// ```
30template<class Tok, class Tag, size_t K, class S>
31requires std::is_default_constructible_v<Tok>
32 && (std::is_convertible_v<Tok, bool> || std::is_constructible_v<bool, Tok>)
33class Parser {
34private:
35 S& self() { return *static_cast<S*>(this); }
36 const S& self() const { return *static_cast<const S*>(this); }
37
38protected:
39 /// @name Construction
40 ///@{
41 void init(const std::filesystem::path* path) {
42 ahead_.reset();
43 for (size_t i = 0; i != K; ++i)
44 ahead_[i] = self().lexer().lex();
45 curr_ = Loc(path, {1, 1});
46 }
47 ///@}
48
49 /// @name Tracker
50 /// Track Loc%ation in the source file.
51 /// Use like this:
52 /// ```
53 /// auto track = tracker();
54 /// auto foo = parse_foo();
55 /// auto bar = parse_bar();
56 /// auto foobar = new FooBar(track, foo, bar);
57 /// ```
58 ///@{
59 class Tracker {
60 public:
61 Tracker(Pos start, Loc& curr)
62 : start_(start)
63 , curr_(curr) {}
64
65 Loc loc() const { return {curr_.path, start_, curr_.finis}; }
66 Loc operator()() const { return loc(); }
67 operator Loc() const { return loc(); }
68
69 private:
70 Pos start_;
71 const Loc& curr_;
72 };
73
74 /// Factory method to build a Parser::Tracker.
75 Tracker tracker() { return {ahead().loc().begin, curr_}; }
76 Tracker tracker(Pos begin) { return {begin, curr_}; } ///< As above but start tracking at @p begin.
77 Tracker tracker(Loc begin) { return {begin.begin, curr_}; }
78 ///@}
79
80 /// @name Shift Token
81 ///@{
82 /// Get lookahead.
83 Tok ahead(size_t i = 0) const { return ahead_[i]; }
84
85 /// Invoke Lexer to retrieve next Token.
86 Tok lex() {
87 auto result = ahead();
88 curr_ = result.loc();
89 ahead_.put(self().lexer().lex());
90 return result;
91 }
92
93 /// If Parser::ahead() is a @p tag, consume and return it, otherwise yield `std::nullopt`.
94 Tok accept(Tag tag) {
95 if (tag != ahead().tag()) return {};
96 return lex();
97 }
98
99 /// Parser::lex Parser::ahead() which must be a @p tag.
100 /// Issue error with @p ctxt otherwise.
101 Tok expect(Tag tag, std::string_view ctxt) {
102 if (ahead().tag() == tag) return lex();
103 self().syntax_err(tag, ctxt);
104 return {};
105 }
106
107 /// Consume Parser::ahead which must be a @p tag; asserts otherwise.
108 Tok eat([[maybe_unused]] Tag tag) {
109 assert(tag == ahead().tag() && "internal parser error");
110 return lex();
111 }
112 ///@}
113
116};
117
118} // namespace fe
Loc operator()() const
Definition parser.h:66
Tracker(Pos start, Loc &curr)
Definition parser.h:61
Loc loc() const
Definition parser.h:65
The blueprint for a recursive descent/ ascent parser using a K lookahead of Tokens.
Definition parser.h:33
Tracker tracker(Pos begin)
As above but start tracking at begin.
Definition parser.h:76
Tracker tracker(Loc begin)
Definition parser.h:77
Tok lex()
Invoke Lexer to retrieve next Token.
Definition parser.h:86
Ring< Tok, K > ahead_
Definition parser.h:114
Loc curr_
Definition parser.h:115
Tok eat(Tag tag)
Consume Parser::ahead which must be a tag; asserts otherwise.
Definition parser.h:108
Tok expect(Tag tag, std::string_view ctxt)
Parser::lex Parser::ahead() which must be a tag.
Definition parser.h:101
Tok accept(Tag tag)
If Parser::ahead() is a tag, consume and return it, otherwise yield std::nullopt.
Definition parser.h:94
Tracker tracker()
Factory method to build a Parser::Tracker.
Definition parser.h:75
Tok ahead(size_t i=0) const
Definition parser.h:83
void init(const std::filesystem::path *path)
Definition parser.h:41
A ring buffer with N elements.
Definition ring.h:15
Definition arena.h:13
Location in a File.
Definition loc.h:35
Pos begin
Definition loc.h:58
Position in a source file; pass around as value.
Definition loc.h:10