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