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 = 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
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.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
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 {
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
15
lexer.cpp
15
lexer.cpp
@ -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;
|
||||||
|
@ -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();
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
16
main.cpp
16
main.cpp
@ -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]);
|
||||||
|
13
token.hpp
13
token.hpp
@ -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
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