visitor/expr: initial

This commit is contained in:
Zack Buhman 2023-08-15 18:56:13 +00:00
parent 082ebc20e5
commit 97d35bfa4f
12 changed files with 196 additions and 59 deletions

View File

@ -6,6 +6,7 @@ CXX = $(TARGET)clang++
SRC = main.cpp SRC = main.cpp
SRC += lexer.cpp SRC += lexer.cpp
SRC += ast.cpp
OBJ = $(patsubst %.cpp,%.o,$(SRC)) OBJ = $(patsubst %.cpp,%.o,$(SRC))
DEP = $(patsubst %.cpp,%.d,$(SRC)) DEP = $(patsubst %.cpp,%.d,$(SRC))

31
ast.cpp Normal file
View File

@ -0,0 +1,31 @@
#include "ast.hpp"
namespace dsp {
void ast_printer_t::parenthesize(const std::string_view s, const expr_t * a) const
{
os << '(' << s << ' ';
a->accept(this);
os << ')';
}
void ast_printer_t::parenthesize(const std::string_view s, const expr_t * a, const expr_t * b) const
{
os << '(' << s << ' ';
a->accept(this);
os << ' ';
b->accept(this);
os << ')';
}
void ast_printer_t::visit(const literal_t * literal) const
{
os << std::to_string(literal->value);
}
void ast_printer_t::visit(const assign_t * expr) const
{
parenthesize((expr->name).lexeme, &(expr->value));
}
}

26
ast.hpp Normal file
View File

@ -0,0 +1,26 @@
#pragma once
#include <ostream>
#include <string_view>
#include "visitor.hpp"
#include "expr.hpp"
#include "num.hpp"
namespace dsp {
struct ast_printer_t : visitor_t<void>
{
ast_printer_t(std::ostream& os)
: os(os) {}
std::ostream& os;
void visit(const assign_t * expr) const;
void visit(const literal_t * literal) const;
void parenthesize(const std::string_view s, const expr_t * a) const;
void parenthesize(const std::string_view s, const expr_t * a, const expr_t * b) const;
};
}

View File

@ -25,7 +25,7 @@ def print_switch(d, level=0):
p(inden0 + f"case '{key.upper()}': [[fallthrough]];") p(inden0 + f"case '{key.upper()}': [[fallthrough]];")
p(inden0 + f"case '{key.lower()}':") p(inden0 + f"case '{key.lower()}':")
if terminal is not None: if terminal is not None:
p(inden1 + f"if (ix == s.length()) return {{ token::type_t::_{terminal} }};") p(inden1 + f"if (ix == s.length()) return {{ token_t::type_t::_{terminal} }};")
if children: if children:
p(inden1 + "else {") p(inden1 + "else {")
else: else:
@ -47,7 +47,7 @@ def print_keyword_func(root):
p() p()
p("struct keyword {") p("struct keyword {")
p() p()
p("inline static constexpr std::optional<enum token::type_t>") p("inline static constexpr std::optional<enum token_t::type_t>")
p("find(const std::string_view s)") p("find(const std::string_view s)")
p("{") p("{")
p(inden1 + "if (s.length() == 0) { return {}; }") p(inden1 + "if (s.length() == 0) { return {}; }")

44
expr.hpp Normal file
View File

@ -0,0 +1,44 @@
#include <string>
#include "token.hpp"
#include "visitor.hpp"
#include "num.hpp"
namespace dsp {
struct expr_t
{
virtual void accept(visitor_t<void> const * visitor) const = 0;
virtual std::string accept(visitor_t<std::string> const * visitor) const = 0;
};
template <typename T>
struct expr_accept_t : expr_t {
virtual void accept(visitor_t<void> const * visitor) const {
return visitor->visit(static_cast<const T*>(this));
}
virtual std::string accept(visitor_t<std::string> const * visitor) const
{
return visitor->visit(static_cast<const T*>(this));
}
};
struct assign_t : expr_accept_t<assign_t>
{
assign_t(token_t& name, expr_t& value)
: name(name), value(value) {}
const token_t name;
const expr_t& value;
};
struct literal_t : expr_accept_t<literal_t>
{
literal_t(num_t value)
: value(value) {}
const num_t value;
};
}

View File

@ -5,7 +5,7 @@ namespace dsp {
struct keyword { struct keyword {
inline static constexpr std::optional<enum token::type_t> inline static constexpr std::optional<enum token_t::type_t>
find(const std::string_view s) find(const std::string_view s)
{ {
if (s.length() == 0) { return {}; } if (s.length() == 0) { return {}; }
@ -23,15 +23,15 @@ find(const std::string_view s)
switch (s[ix++]) { switch (s[ix++]) {
case 'H': [[fallthrough]]; case 'H': [[fallthrough]];
case 'h': case 'h':
if (ix == s.length()) return { token::type_t::_alh }; if (ix == s.length()) return { token_t::type_t::_alh };
break; break;
case 'L': [[fallthrough]]; case 'L': [[fallthrough]];
case 'l': case 'l':
if (ix == s.length()) return { token::type_t::_all }; if (ix == s.length()) return { token_t::type_t::_all };
break; break;
case 'U': [[fallthrough]]; case 'U': [[fallthrough]];
case 'u': case 'u':
if (ix == s.length()) return { token::type_t::_alu }; if (ix == s.length()) return { token_t::type_t::_alu };
break; break;
} }
} }
@ -42,7 +42,7 @@ find(const std::string_view s)
switch (s[ix++]) { switch (s[ix++]) {
case 'D': [[fallthrough]]; case 'D': [[fallthrough]];
case 'd': case 'd':
if (ix == s.length()) return { token::type_t::_and }; if (ix == s.length()) return { token_t::type_t::_and };
break; break;
} }
} }
@ -53,10 +53,10 @@ find(const std::string_view s)
switch (s[ix++]) { switch (s[ix++]) {
case 'D': [[fallthrough]]; case 'D': [[fallthrough]];
case 'd': case 'd':
if (ix == s.length()) return { token::type_t::_add }; if (ix == s.length()) return { token_t::type_t::_add };
break; break;
case '2': case '2':
if (ix == s.length()) return { token::type_t::_ad2 }; if (ix == s.length()) return { token_t::type_t::_ad2 };
break; break;
} }
} }
@ -69,32 +69,32 @@ find(const std::string_view s)
if (ix < s.length()) { if (ix < s.length()) {
switch (s[ix++]) { switch (s[ix++]) {
case '0': case '0':
if (ix == s.length()) return { token::type_t::_m0 }; if (ix == s.length()) return { token_t::type_t::_m0 };
break; break;
case '1': case '1':
if (ix == s.length()) return { token::type_t::_m1 }; if (ix == s.length()) return { token_t::type_t::_m1 };
break; break;
case '2': case '2':
if (ix == s.length()) return { token::type_t::_m2 }; if (ix == s.length()) return { token_t::type_t::_m2 };
break; break;
case '3': case '3':
if (ix == s.length()) return { token::type_t::_m3 }; if (ix == s.length()) return { token_t::type_t::_m3 };
break; break;
case 'C': [[fallthrough]]; case 'C': [[fallthrough]];
case 'c': case 'c':
if (ix < s.length()) { if (ix < s.length()) {
switch (s[ix++]) { switch (s[ix++]) {
case '0': case '0':
if (ix == s.length()) return { token::type_t::_mc0 }; if (ix == s.length()) return { token_t::type_t::_mc0 };
break; break;
case '1': case '1':
if (ix == s.length()) return { token::type_t::_mc1 }; if (ix == s.length()) return { token_t::type_t::_mc1 };
break; break;
case '2': case '2':
if (ix == s.length()) return { token::type_t::_mc2 }; if (ix == s.length()) return { token_t::type_t::_mc2 };
break; break;
case '3': case '3':
if (ix == s.length()) return { token::type_t::_mc3 }; if (ix == s.length()) return { token_t::type_t::_mc3 };
break; break;
} }
} }
@ -105,7 +105,7 @@ find(const std::string_view s)
switch (s[ix++]) { switch (s[ix++]) {
case 'L': [[fallthrough]]; case 'L': [[fallthrough]];
case 'l': case 'l':
if (ix == s.length()) return { token::type_t::_mul }; if (ix == s.length()) return { token_t::type_t::_mul };
break; break;
} }
} }
@ -116,7 +116,7 @@ find(const std::string_view s)
switch (s[ix++]) { switch (s[ix++]) {
case 'V': [[fallthrough]]; case 'V': [[fallthrough]];
case 'v': case 'v':
if (ix == s.length()) return { token::type_t::_mov }; if (ix == s.length()) return { token_t::type_t::_mov };
break; break;
} }
} }
@ -127,7 +127,7 @@ find(const std::string_view s)
switch (s[ix++]) { switch (s[ix++]) {
case 'I': [[fallthrough]]; case 'I': [[fallthrough]];
case 'i': case 'i':
if (ix == s.length()) return { token::type_t::_mvi }; if (ix == s.length()) return { token_t::type_t::_mvi };
break; break;
} }
} }
@ -145,7 +145,7 @@ find(const std::string_view s)
switch (s[ix++]) { switch (s[ix++]) {
case 'P': [[fallthrough]]; case 'P': [[fallthrough]];
case 'p': case 'p':
if (ix == s.length()) return { token::type_t::_nop }; if (ix == s.length()) return { token_t::type_t::_nop };
break; break;
} }
} }
@ -159,12 +159,12 @@ find(const std::string_view s)
switch (s[ix++]) { switch (s[ix++]) {
case 'R': [[fallthrough]]; case 'R': [[fallthrough]];
case 'r': case 'r':
if (ix == s.length()) return { token::type_t::_or }; if (ix == s.length()) return { token_t::type_t::_or };
else { else {
switch (s[ix++]) { switch (s[ix++]) {
case 'G': [[fallthrough]]; case 'G': [[fallthrough]];
case 'g': case 'g':
if (ix == s.length()) return { token::type_t::_org }; if (ix == s.length()) return { token_t::type_t::_org };
break; break;
} }
} }
@ -182,7 +182,7 @@ find(const std::string_view s)
switch (s[ix++]) { switch (s[ix++]) {
case 'R': [[fallthrough]]; case 'R': [[fallthrough]];
case 'r': case 'r':
if (ix == s.length()) return { token::type_t::_xor }; if (ix == s.length()) return { token_t::type_t::_xor };
break; break;
} }
} }
@ -200,18 +200,18 @@ find(const std::string_view s)
switch (s[ix++]) { switch (s[ix++]) {
case 'B': [[fallthrough]]; case 'B': [[fallthrough]];
case 'b': case 'b':
if (ix == s.length()) return { token::type_t::_sub }; if (ix == s.length()) return { token_t::type_t::_sub };
break; break;
} }
} }
break; break;
case 'R': [[fallthrough]]; case 'R': [[fallthrough]];
case 'r': case 'r':
if (ix == s.length()) return { token::type_t::_sr }; if (ix == s.length()) return { token_t::type_t::_sr };
break; break;
case 'L': [[fallthrough]]; case 'L': [[fallthrough]];
case 'l': case 'l':
if (ix == s.length()) return { token::type_t::_sl }; if (ix == s.length()) return { token_t::type_t::_sl };
break; break;
} }
} }
@ -222,15 +222,15 @@ find(const std::string_view s)
switch (s[ix++]) { switch (s[ix++]) {
case 'R': [[fallthrough]]; case 'R': [[fallthrough]];
case 'r': case 'r':
if (ix == s.length()) return { token::type_t::_rr }; if (ix == s.length()) return { token_t::type_t::_rr };
break; break;
case 'L': [[fallthrough]]; case 'L': [[fallthrough]];
case 'l': case 'l':
if (ix == s.length()) return { token::type_t::_rl }; if (ix == s.length()) return { token_t::type_t::_rl };
else { else {
switch (s[ix++]) { switch (s[ix++]) {
case '8': case '8':
if (ix == s.length()) return { token::type_t::_rl8 }; if (ix == s.length()) return { token_t::type_t::_rl8 };
break; break;
} }
} }
@ -248,7 +248,7 @@ find(const std::string_view s)
switch (s[ix++]) { switch (s[ix++]) {
case 'R': [[fallthrough]]; case 'R': [[fallthrough]];
case 'r': case 'r':
if (ix == s.length()) return { token::type_t::_clr }; if (ix == s.length()) return { token_t::type_t::_clr };
break; break;
} }
} }
@ -266,12 +266,12 @@ find(const std::string_view s)
switch (s[ix++]) { switch (s[ix++]) {
case 'A': [[fallthrough]]; case 'A': [[fallthrough]];
case 'a': case 'a':
if (ix == s.length()) return { token::type_t::_dma }; if (ix == s.length()) return { token_t::type_t::_dma };
else { else {
switch (s[ix++]) { switch (s[ix++]) {
case 'H': [[fallthrough]]; case 'H': [[fallthrough]];
case 'h': case 'h':
if (ix == s.length()) return { token::type_t::_dmah }; if (ix == s.length()) return { token_t::type_t::_dmah };
break; break;
} }
} }
@ -292,7 +292,7 @@ find(const std::string_view s)
switch (s[ix++]) { switch (s[ix++]) {
case 'P': [[fallthrough]]; case 'P': [[fallthrough]];
case 'p': case 'p':
if (ix == s.length()) return { token::type_t::_jmp }; if (ix == s.length()) return { token_t::type_t::_jmp };
break; break;
} }
} }
@ -310,7 +310,7 @@ find(const std::string_view s)
switch (s[ix++]) { switch (s[ix++]) {
case 'M': [[fallthrough]]; case 'M': [[fallthrough]];
case 'm': case 'm':
if (ix == s.length()) return { token::type_t::_btm }; if (ix == s.length()) return { token_t::type_t::_btm };
break; break;
} }
} }
@ -328,7 +328,7 @@ find(const std::string_view s)
switch (s[ix++]) { switch (s[ix++]) {
case 'S': [[fallthrough]]; case 'S': [[fallthrough]];
case 's': case 's':
if (ix == s.length()) return { token::type_t::_lps }; if (ix == s.length()) return { token_t::type_t::_lps };
break; break;
} }
} }
@ -346,16 +346,16 @@ find(const std::string_view s)
switch (s[ix++]) { switch (s[ix++]) {
case 'D': [[fallthrough]]; case 'D': [[fallthrough]];
case 'd': case 'd':
if (ix == s.length()) return { token::type_t::_end }; if (ix == s.length()) return { token_t::type_t::_end };
else { else {
switch (s[ix++]) { switch (s[ix++]) {
case 'I': [[fallthrough]]; case 'I': [[fallthrough]];
case 'i': case 'i':
if (ix == s.length()) return { token::type_t::_endi }; if (ix == s.length()) return { token_t::type_t::_endi };
break; break;
case 'S': [[fallthrough]]; case 'S': [[fallthrough]];
case 's': case 's':
if (ix == s.length()) return { token::type_t::_ends }; if (ix == s.length()) return { token_t::type_t::_ends };
break; break;
} }
} }
@ -369,7 +369,7 @@ find(const std::string_view s)
switch (s[ix++]) { switch (s[ix++]) {
case 'U': [[fallthrough]]; case 'U': [[fallthrough]];
case 'u': case 'u':
if (ix == s.length()) return { token::type_t::_equ }; if (ix == s.length()) return { token_t::type_t::_equ };
break; break;
} }
} }

View File

@ -124,24 +124,24 @@ const std::string_view lexer_t::lexeme()
} }
template <typename T> template <typename T>
token lexer_t::_number() token_t lexer_t::_number()
{ {
while (T::pred(peek())) advance(); while (T::pred(peek())) advance();
return {pos, token::number, lexeme(), T::template parse<num_t>(lexeme())}; return {pos, token_t::number, lexeme(), T::template parse<num_t>(lexeme())};
} }
token lexer_t::_identifier() token_t lexer_t::_identifier()
{ {
while (alpha_numeric_p(peek())) advance(); while (alpha_numeric_p(peek())) advance();
std::optional<enum token::type_t> keyword = keyword::find(lexeme()); std::optional<enum token_t::type_t> keyword = keyword::find(lexeme());
if (keyword) return {pos, *keyword, lexeme()}; if (keyword) return {pos, *keyword, lexeme()};
else return {pos, token::identifier, lexeme()}; else return {pos, token_t::identifier, lexeme()};
} }
std::optional<token> lexer_t::scan_token() std::optional<token_t> lexer_t::scan_token()
{ {
using enum token::type_t; using enum token_t::type_t;
if (at_end_p()) if (at_end_p())
return {{pos, eof, ""}}; return {{pos, eof, ""}};
@ -163,6 +163,7 @@ std::optional<token> lexer_t::scan_token()
case '&': return {{pos, ampersand, lexeme()}}; case '&': return {{pos, ampersand, lexeme()}};
case '|': return {{pos, bar, lexeme()}}; case '|': return {{pos, bar, lexeme()}};
case '^': return {{pos, carot, lexeme()}}; case '^': return {{pos, carot, lexeme()}};
case '=': return {{pos, equal, lexeme()}};
case '<': case '<':
if (match('<')) return {{pos, left_shift, lexeme()}}; if (match('<')) return {{pos, left_shift, lexeme()}};
break; break;

View File

@ -19,7 +19,7 @@ struct lexer_t {
: source(source), start_ix(0), current_ix(0), pos{ .line = 1, .col = 0 } : source(source), start_ix(0), current_ix(0), pos{ .line = 1, .col = 0 }
{ } { }
std::optional<token> scan_token(); std::optional<token_t> scan_token();
private: private:
bool at_end_p(); bool at_end_p();
@ -33,9 +33,9 @@ private:
const std::string_view lexeme(); const std::string_view lexeme();
template <typename T> template <typename T>
token _number(); token_t _number();
token _identifier(); token_t _identifier();
}; };
} }

View File

@ -4,6 +4,7 @@
#include "lexer.hpp" #include "lexer.hpp"
#include "token.hpp" #include "token.hpp"
#include "ast.hpp"
namespace dsp { namespace dsp {
@ -11,15 +12,25 @@ bool had_error = false;
} }
static void print()
{
dsp::literal_t l(56);
std::string_view s("asdf");
dsp::token_t t({0, 0}, dsp::token_t::identifier, s);
dsp::assign_t a(t, l);
dsp::ast_printer_t p(std::cout);
p.visit(&a);
}
static void run(std::string source) static void run(std::string source)
{ {
using namespace dsp; using namespace dsp;
std::string_view buf {source}; std::string_view buf {source};
lexer_t lexer {buf}; lexer_t lexer {buf};
while (std::optional<token> token_o = lexer.scan_token()) { while (std::optional<token_t> token_o = lexer.scan_token()) {
std::cout << *token_o << std::endl; std::cout << *token_o << std::endl;
if (token_o->type == token::type_t::eof) { if (token_o->type == token_t::type_t::eof) {
break; break;
} }
} }
@ -56,6 +67,7 @@ static int run_file(char const * const filename)
int main(const int argc, char const * const argv[]) int main(const int argc, char const * const argv[])
{ {
print();
switch (argc) { switch (argc) {
case 1: run_prompt(); return dsp::had_error; case 1: run_prompt(); return dsp::had_error;
case 2: return run_file(argv[1]); case 2: return run_file(argv[1]);

View File

@ -16,8 +16,9 @@ struct token_pos_t {
int col; int col;
}; };
template <typename N>
struct token_t { struct token_t {
using num_type = num_t;
enum type_t { enum type_t {
left_paren, left_paren,
right_paren, right_paren,
@ -86,7 +87,7 @@ struct token_t {
eof, eof,
}; };
using literal_t = std::variant<std::monostate, N>; using literal_t = std::variant<std::monostate, num_type>;
const token_pos_t pos; const token_pos_t pos;
const type_t type; const type_t type;
@ -95,7 +96,7 @@ struct token_t {
token_t() = delete; token_t() = delete;
constexpr token_t(token_pos_t pos, type_t type, const std::string_view lexeme, N number) constexpr token_t(token_pos_t pos, type_t type, const std::string_view lexeme, num_type number)
: pos(pos), type(type), lexeme(lexeme), literal(number) : pos(pos), type(type), lexeme(lexeme), literal(number)
{ } { }
@ -103,7 +104,7 @@ struct token_t {
: pos(pos), type(type), lexeme(lexeme), literal() : pos(pos), type(type), lexeme(lexeme), literal()
{ } { }
friend std::ostream& operator<<(std::ostream& os, const enum token_t<N>::type_t type) friend std::ostream& operator<<(std::ostream& os, const enum token_t::type_t type)
{ {
switch (type) { switch (type) {
case left_paren : return os << "LEFT_PAREN"; case left_paren : return os << "LEFT_PAREN";
@ -179,7 +180,7 @@ struct token_t {
{ {
os << token.type << ' ' << token.lexeme; os << token.type << ' ' << token.lexeme;
if (auto* v = std::get_if<N>(&token.literal)) { if (auto* v = std::get_if<num_type>(&token.literal)) {
os << '/' << *v; os << '/' << *v;
} else { // std::monostate } else { // std::monostate
} }
@ -189,6 +190,4 @@ struct token_t {
}; };
using token = dsp::token_t<num_t>;
} }

8
visitable.hpp Normal file
View File

@ -0,0 +1,8 @@
#pragma once
namespace dsp {
struct assign_t;
struct literal_t;
}

15
visitor.hpp Normal file
View File

@ -0,0 +1,15 @@
#pragma once
#include "visitable.hpp"
#include "num.hpp"
namespace dsp {
template <typename T>
struct visitor_t
{
virtual T visit(const assign_t * expr) const = 0;
virtual T visit(const literal_t * expr) const = 0;
};
}