visitor/expr: initial
This commit is contained in:
parent
082ebc20e5
commit
97d35bfa4f
1
Makefile
1
Makefile
@ -6,6 +6,7 @@ CXX = $(TARGET)clang++
|
||||
|
||||
SRC = main.cpp
|
||||
SRC += lexer.cpp
|
||||
SRC += ast.cpp
|
||||
OBJ = $(patsubst %.cpp,%.o,$(SRC))
|
||||
DEP = $(patsubst %.cpp,%.d,$(SRC))
|
||||
|
||||
|
31
ast.cpp
Normal file
31
ast.cpp
Normal 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
26
ast.hpp
Normal 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;
|
||||
};
|
||||
|
||||
}
|
@ -25,7 +25,7 @@ def print_switch(d, level=0):
|
||||
p(inden0 + f"case '{key.upper()}': [[fallthrough]];")
|
||||
p(inden0 + f"case '{key.lower()}':")
|
||||
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:
|
||||
p(inden1 + "else {")
|
||||
else:
|
||||
@ -47,7 +47,7 @@ def print_keyword_func(root):
|
||||
p()
|
||||
p("struct keyword {")
|
||||
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("{")
|
||||
p(inden1 + "if (s.length() == 0) { return {}; }")
|
||||
|
44
expr.hpp
Normal file
44
expr.hpp
Normal 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;
|
||||
};
|
||||
|
||||
}
|
76
keyword.hpp
76
keyword.hpp
@ -5,7 +5,7 @@ namespace dsp {
|
||||
|
||||
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)
|
||||
{
|
||||
if (s.length() == 0) { return {}; }
|
||||
@ -23,15 +23,15 @@ find(const std::string_view s)
|
||||
switch (s[ix++]) {
|
||||
case 'H': [[fallthrough]];
|
||||
case 'h':
|
||||
if (ix == s.length()) return { token::type_t::_alh };
|
||||
if (ix == s.length()) return { token_t::type_t::_alh };
|
||||
break;
|
||||
case 'L': [[fallthrough]];
|
||||
case 'l':
|
||||
if (ix == s.length()) return { token::type_t::_all };
|
||||
if (ix == s.length()) return { token_t::type_t::_all };
|
||||
break;
|
||||
case 'U': [[fallthrough]];
|
||||
case 'u':
|
||||
if (ix == s.length()) return { token::type_t::_alu };
|
||||
if (ix == s.length()) return { token_t::type_t::_alu };
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -42,7 +42,7 @@ find(const std::string_view s)
|
||||
switch (s[ix++]) {
|
||||
case 'D': [[fallthrough]];
|
||||
case 'd':
|
||||
if (ix == s.length()) return { token::type_t::_and };
|
||||
if (ix == s.length()) return { token_t::type_t::_and };
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -53,10 +53,10 @@ find(const std::string_view s)
|
||||
switch (s[ix++]) {
|
||||
case 'D': [[fallthrough]];
|
||||
case 'd':
|
||||
if (ix == s.length()) return { token::type_t::_add };
|
||||
if (ix == s.length()) return { token_t::type_t::_add };
|
||||
break;
|
||||
case '2':
|
||||
if (ix == s.length()) return { token::type_t::_ad2 };
|
||||
if (ix == s.length()) return { token_t::type_t::_ad2 };
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -69,32 +69,32 @@ find(const std::string_view s)
|
||||
if (ix < s.length()) {
|
||||
switch (s[ix++]) {
|
||||
case '0':
|
||||
if (ix == s.length()) return { token::type_t::_m0 };
|
||||
if (ix == s.length()) return { token_t::type_t::_m0 };
|
||||
break;
|
||||
case '1':
|
||||
if (ix == s.length()) return { token::type_t::_m1 };
|
||||
if (ix == s.length()) return { token_t::type_t::_m1 };
|
||||
break;
|
||||
case '2':
|
||||
if (ix == s.length()) return { token::type_t::_m2 };
|
||||
if (ix == s.length()) return { token_t::type_t::_m2 };
|
||||
break;
|
||||
case '3':
|
||||
if (ix == s.length()) return { token::type_t::_m3 };
|
||||
if (ix == s.length()) return { token_t::type_t::_m3 };
|
||||
break;
|
||||
case 'C': [[fallthrough]];
|
||||
case 'c':
|
||||
if (ix < s.length()) {
|
||||
switch (s[ix++]) {
|
||||
case '0':
|
||||
if (ix == s.length()) return { token::type_t::_mc0 };
|
||||
if (ix == s.length()) return { token_t::type_t::_mc0 };
|
||||
break;
|
||||
case '1':
|
||||
if (ix == s.length()) return { token::type_t::_mc1 };
|
||||
if (ix == s.length()) return { token_t::type_t::_mc1 };
|
||||
break;
|
||||
case '2':
|
||||
if (ix == s.length()) return { token::type_t::_mc2 };
|
||||
if (ix == s.length()) return { token_t::type_t::_mc2 };
|
||||
break;
|
||||
case '3':
|
||||
if (ix == s.length()) return { token::type_t::_mc3 };
|
||||
if (ix == s.length()) return { token_t::type_t::_mc3 };
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -105,7 +105,7 @@ find(const std::string_view s)
|
||||
switch (s[ix++]) {
|
||||
case 'L': [[fallthrough]];
|
||||
case 'l':
|
||||
if (ix == s.length()) return { token::type_t::_mul };
|
||||
if (ix == s.length()) return { token_t::type_t::_mul };
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -116,7 +116,7 @@ find(const std::string_view s)
|
||||
switch (s[ix++]) {
|
||||
case 'V': [[fallthrough]];
|
||||
case 'v':
|
||||
if (ix == s.length()) return { token::type_t::_mov };
|
||||
if (ix == s.length()) return { token_t::type_t::_mov };
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -127,7 +127,7 @@ find(const std::string_view s)
|
||||
switch (s[ix++]) {
|
||||
case 'I': [[fallthrough]];
|
||||
case 'i':
|
||||
if (ix == s.length()) return { token::type_t::_mvi };
|
||||
if (ix == s.length()) return { token_t::type_t::_mvi };
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -145,7 +145,7 @@ find(const std::string_view s)
|
||||
switch (s[ix++]) {
|
||||
case 'P': [[fallthrough]];
|
||||
case 'p':
|
||||
if (ix == s.length()) return { token::type_t::_nop };
|
||||
if (ix == s.length()) return { token_t::type_t::_nop };
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -159,12 +159,12 @@ find(const std::string_view s)
|
||||
switch (s[ix++]) {
|
||||
case 'R': [[fallthrough]];
|
||||
case 'r':
|
||||
if (ix == s.length()) return { token::type_t::_or };
|
||||
if (ix == s.length()) return { token_t::type_t::_or };
|
||||
else {
|
||||
switch (s[ix++]) {
|
||||
case 'G': [[fallthrough]];
|
||||
case 'g':
|
||||
if (ix == s.length()) return { token::type_t::_org };
|
||||
if (ix == s.length()) return { token_t::type_t::_org };
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -182,7 +182,7 @@ find(const std::string_view s)
|
||||
switch (s[ix++]) {
|
||||
case 'R': [[fallthrough]];
|
||||
case 'r':
|
||||
if (ix == s.length()) return { token::type_t::_xor };
|
||||
if (ix == s.length()) return { token_t::type_t::_xor };
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -200,18 +200,18 @@ find(const std::string_view s)
|
||||
switch (s[ix++]) {
|
||||
case 'B': [[fallthrough]];
|
||||
case 'b':
|
||||
if (ix == s.length()) return { token::type_t::_sub };
|
||||
if (ix == s.length()) return { token_t::type_t::_sub };
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'R': [[fallthrough]];
|
||||
case 'r':
|
||||
if (ix == s.length()) return { token::type_t::_sr };
|
||||
if (ix == s.length()) return { token_t::type_t::_sr };
|
||||
break;
|
||||
case 'L': [[fallthrough]];
|
||||
case 'l':
|
||||
if (ix == s.length()) return { token::type_t::_sl };
|
||||
if (ix == s.length()) return { token_t::type_t::_sl };
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -222,15 +222,15 @@ find(const std::string_view s)
|
||||
switch (s[ix++]) {
|
||||
case 'R': [[fallthrough]];
|
||||
case 'r':
|
||||
if (ix == s.length()) return { token::type_t::_rr };
|
||||
if (ix == s.length()) return { token_t::type_t::_rr };
|
||||
break;
|
||||
case 'L': [[fallthrough]];
|
||||
case 'l':
|
||||
if (ix == s.length()) return { token::type_t::_rl };
|
||||
if (ix == s.length()) return { token_t::type_t::_rl };
|
||||
else {
|
||||
switch (s[ix++]) {
|
||||
case '8':
|
||||
if (ix == s.length()) return { token::type_t::_rl8 };
|
||||
if (ix == s.length()) return { token_t::type_t::_rl8 };
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -248,7 +248,7 @@ find(const std::string_view s)
|
||||
switch (s[ix++]) {
|
||||
case 'R': [[fallthrough]];
|
||||
case 'r':
|
||||
if (ix == s.length()) return { token::type_t::_clr };
|
||||
if (ix == s.length()) return { token_t::type_t::_clr };
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -266,12 +266,12 @@ find(const std::string_view s)
|
||||
switch (s[ix++]) {
|
||||
case 'A': [[fallthrough]];
|
||||
case 'a':
|
||||
if (ix == s.length()) return { token::type_t::_dma };
|
||||
if (ix == s.length()) return { token_t::type_t::_dma };
|
||||
else {
|
||||
switch (s[ix++]) {
|
||||
case 'H': [[fallthrough]];
|
||||
case 'h':
|
||||
if (ix == s.length()) return { token::type_t::_dmah };
|
||||
if (ix == s.length()) return { token_t::type_t::_dmah };
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -292,7 +292,7 @@ find(const std::string_view s)
|
||||
switch (s[ix++]) {
|
||||
case 'P': [[fallthrough]];
|
||||
case 'p':
|
||||
if (ix == s.length()) return { token::type_t::_jmp };
|
||||
if (ix == s.length()) return { token_t::type_t::_jmp };
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -310,7 +310,7 @@ find(const std::string_view s)
|
||||
switch (s[ix++]) {
|
||||
case 'M': [[fallthrough]];
|
||||
case 'm':
|
||||
if (ix == s.length()) return { token::type_t::_btm };
|
||||
if (ix == s.length()) return { token_t::type_t::_btm };
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -328,7 +328,7 @@ find(const std::string_view s)
|
||||
switch (s[ix++]) {
|
||||
case 'S': [[fallthrough]];
|
||||
case 's':
|
||||
if (ix == s.length()) return { token::type_t::_lps };
|
||||
if (ix == s.length()) return { token_t::type_t::_lps };
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -346,16 +346,16 @@ find(const std::string_view s)
|
||||
switch (s[ix++]) {
|
||||
case 'D': [[fallthrough]];
|
||||
case 'd':
|
||||
if (ix == s.length()) return { token::type_t::_end };
|
||||
if (ix == s.length()) return { token_t::type_t::_end };
|
||||
else {
|
||||
switch (s[ix++]) {
|
||||
case 'I': [[fallthrough]];
|
||||
case 'i':
|
||||
if (ix == s.length()) return { token::type_t::_endi };
|
||||
if (ix == s.length()) return { token_t::type_t::_endi };
|
||||
break;
|
||||
case 'S': [[fallthrough]];
|
||||
case 's':
|
||||
if (ix == s.length()) return { token::type_t::_ends };
|
||||
if (ix == s.length()) return { token_t::type_t::_ends };
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -369,7 +369,7 @@ find(const std::string_view s)
|
||||
switch (s[ix++]) {
|
||||
case 'U': [[fallthrough]];
|
||||
case 'u':
|
||||
if (ix == s.length()) return { token::type_t::_equ };
|
||||
if (ix == s.length()) return { token_t::type_t::_equ };
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
15
lexer.cpp
15
lexer.cpp
@ -124,24 +124,24 @@ const std::string_view lexer_t::lexeme()
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
token lexer_t::_number()
|
||||
token_t lexer_t::_number()
|
||||
{
|
||||
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();
|
||||
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()};
|
||||
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())
|
||||
return {{pos, eof, ""}};
|
||||
@ -163,6 +163,7 @@ std::optional<token> lexer_t::scan_token()
|
||||
case '&': return {{pos, ampersand, lexeme()}};
|
||||
case '|': return {{pos, bar, lexeme()}};
|
||||
case '^': return {{pos, carot, lexeme()}};
|
||||
case '=': return {{pos, equal, lexeme()}};
|
||||
case '<':
|
||||
if (match('<')) return {{pos, left_shift, lexeme()}};
|
||||
break;
|
||||
|
@ -19,7 +19,7 @@ struct lexer_t {
|
||||
: 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:
|
||||
bool at_end_p();
|
||||
@ -33,9 +33,9 @@ private:
|
||||
const std::string_view lexeme();
|
||||
|
||||
template <typename T>
|
||||
token _number();
|
||||
token_t _number();
|
||||
|
||||
token _identifier();
|
||||
token_t _identifier();
|
||||
};
|
||||
|
||||
}
|
||||
|
16
main.cpp
16
main.cpp
@ -4,6 +4,7 @@
|
||||
|
||||
#include "lexer.hpp"
|
||||
#include "token.hpp"
|
||||
#include "ast.hpp"
|
||||
|
||||
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)
|
||||
{
|
||||
using namespace dsp;
|
||||
|
||||
std::string_view buf {source};
|
||||
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;
|
||||
if (token_o->type == token::type_t::eof) {
|
||||
if (token_o->type == token_t::type_t::eof) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -56,6 +67,7 @@ static int run_file(char const * const filename)
|
||||
|
||||
int main(const int argc, char const * const argv[])
|
||||
{
|
||||
print();
|
||||
switch (argc) {
|
||||
case 1: run_prompt(); return dsp::had_error;
|
||||
case 2: return run_file(argv[1]);
|
||||
|
13
token.hpp
13
token.hpp
@ -16,8 +16,9 @@ struct token_pos_t {
|
||||
int col;
|
||||
};
|
||||
|
||||
template <typename N>
|
||||
struct token_t {
|
||||
using num_type = num_t;
|
||||
|
||||
enum type_t {
|
||||
left_paren,
|
||||
right_paren,
|
||||
@ -86,7 +87,7 @@ struct token_t {
|
||||
eof,
|
||||
};
|
||||
|
||||
using literal_t = std::variant<std::monostate, N>;
|
||||
using literal_t = std::variant<std::monostate, num_type>;
|
||||
|
||||
const token_pos_t pos;
|
||||
const type_t type;
|
||||
@ -95,7 +96,7 @@ struct token_t {
|
||||
|
||||
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)
|
||||
{ }
|
||||
|
||||
@ -103,7 +104,7 @@ struct token_t {
|
||||
: 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) {
|
||||
case left_paren : return os << "LEFT_PAREN";
|
||||
@ -179,7 +180,7 @@ struct token_t {
|
||||
{
|
||||
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;
|
||||
} else { // std::monostate
|
||||
}
|
||||
@ -189,6 +190,4 @@ struct token_t {
|
||||
|
||||
};
|
||||
|
||||
using token = dsp::token_t<num_t>;
|
||||
|
||||
}
|
||||
|
8
visitable.hpp
Normal file
8
visitable.hpp
Normal file
@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
namespace dsp {
|
||||
|
||||
struct assign_t;
|
||||
struct literal_t;
|
||||
|
||||
}
|
15
visitor.hpp
Normal file
15
visitor.hpp
Normal 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;
|
||||
};
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user