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)
42 ahead_[i] = self().lexer().lex();
43 curr_ = Loc(path, {1, 1});
44 }
45 ///@}
46
47 /// @name Tracker
48 /// Track Loc%ation in Source File.
49 /// Use like this:
50 /// ```
51 /// auto track = tracker();
52 /// auto foo = parse_foo();
53 /// auto bar = parse_bar();
54 /// auto foobar = new FooBar(track, foo, bar);
55 /// ```
56 ///@{
57 class Tracker {
58 public:
59 Tracker(Pos start, Loc& curr)
60 : start_(start)
61 , curr_(curr) {}
62
63 Loc loc() const { return {curr_.path, start_, curr_.finis}; }
64 Loc operator()() const { return loc(); }
65 operator Loc() const { return loc(); }
66
67 private:
68 Pos start_;
69 const Loc& curr_;
70 };
71
72 /// Factory method to build a Parser::Tracker.
73 Tracker tracker() { return {ahead().loc().begin, curr_}; }
74 Tracker tracker(Pos begin) { return {begin, curr_}; } ///< As above but start tracking at @p begin.
75 Tracker tracker(Loc begin) { return {begin.begin, curr_}; }
76 ///@}
77
78 /// @name Shift Token
79 ///@{
80 /// Get lookahead.
81 Tok ahead(size_t i = 0) const { return ahead_[i]; }
82
83 /// Invoke Lexer to retrieve next Token.
84 Tok lex() {
85 auto result = ahead();
86 curr_ = result.loc();
87 ahead_.put(self().lexer().lex());
88 return result;
89 }
90
91 /// If Parser::ahead() is a @p tag, consume and return it, otherwise yield `std::nullopt`.
92 Tok accept(Tag tag) {
93 if (tag != ahead().tag()) return {};
94 return lex();
95 }
96
97 /// Parser::lex Parser::ahead() which must be a @p tag.
98 /// Issue error with @p ctxt otherwise.
99 Tok expect(Tag tag, std::string_view ctxt) {
100 if (ahead().tag() == tag) return lex();
101 self().syntax_err(tag, ctxt);
102 return {};
103 }
104
105 /// Consume Parser::ahead which must be a @p tag; asserts otherwise.
106 Tok eat([[maybe_unused]] Tag tag) {
107 assert(tag == ahead().tag() && "internal parser error");
108 return lex();
109 }
110 ///@}
111
114};
115
116} // namespace fe
Loc operator()() const
Definition parser.h:64
Tracker(Pos start, Loc &curr)
Definition parser.h:59
Loc loc() const
Definition parser.h:63
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:74
Tracker tracker(Loc begin)
Definition parser.h:75
Tok lex()
Invoke Lexer to retrieve next Token.
Definition parser.h:84
Ring< Tok, K > ahead_
Definition parser.h:112
Loc curr_
Definition parser.h:113
Tok eat(Tag tag)
Consume Parser::ahead which must be a tag; asserts otherwise.
Definition parser.h:106
Tok expect(Tag tag, std::string_view ctxt)
Parser::lex Parser::ahead() which must be a tag.
Definition parser.h:99
Tok accept(Tag tag)
If Parser::ahead() is a tag, consume and return it, otherwise yield std::nullopt.
Definition parser.h:92
Tracker tracker()
Factory method to build a Parser::Tracker.
Definition parser.h:73
Tok ahead(size_t i=0) const
Definition parser.h:81
void init(const std::filesystem::path *path)
Definition parser.h:39
A ring buffer with N elements.
Definition ring.h:15
Definition arena.h:10
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