Basic lexer
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
#include "furc/front/lexer.hpp"
|
||||
|
||||
#include <cctype>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace furc::front {
|
||||
|
||||
lexer::lexer(std::string_view filename, std::string_view content)
|
||||
: m_filename(filename), m_content(content) {}
|
||||
|
||||
token lexer::next_token() {
|
||||
skip_spaces();
|
||||
|
||||
location location = current_location();
|
||||
|
||||
char ch = get();
|
||||
switch (ch) {
|
||||
case '(': return create_token(location, token_t::Lparen, m_content.substr(m_cursor++, 1));
|
||||
case ')': return create_token(location, token_t::Rparen, m_content.substr(m_cursor++, 1));
|
||||
case '{': return create_token(location, token_t::Lbrace, m_content.substr(m_cursor++, 1));
|
||||
case '}': return create_token(location, token_t::Rbrace, m_content.substr(m_cursor++, 1));
|
||||
case '[': return create_token(location, token_t::Lbracket, m_content.substr(m_cursor++, 1));
|
||||
case ']': return create_token(location, token_t::Rbracket, m_content.substr(m_cursor++, 1));
|
||||
case ';': return create_token(location, token_t::Semicolon, m_content.substr(m_cursor++, 1));
|
||||
case ':': return create_token(location, token_t::Colon, m_content.substr(m_cursor++, 1));
|
||||
case std::char_traits<char>::eof(): return create_token(location, token_t::None);
|
||||
default: {
|
||||
if (std::isdigit(ch) != 0) {}
|
||||
|
||||
if (std::isalnum(ch) != 0 || ch == '_') {
|
||||
std::size_t start = m_cursor++;
|
||||
while (std::isalnum(get()) != 0 || get() == '_')
|
||||
next();
|
||||
|
||||
std::string_view value = m_content.substr(start, m_cursor - start);
|
||||
|
||||
static std::unordered_map<std::string_view, keyword_token> s_keywords = {
|
||||
{ "func", keyword_token::Func },
|
||||
{ "return", keyword_token::Return },
|
||||
};
|
||||
|
||||
if (auto it = s_keywords.find(value); it != s_keywords.end())
|
||||
return create_token(location, it->second, value);
|
||||
return create_token(location, token_t::Identifier, value);
|
||||
}
|
||||
|
||||
return create_token(location, error_token::UnexpectedCharacter, m_content.substr(m_cursor, 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void lexer::next() {
|
||||
if (m_cursor >= m_content.size()) return;
|
||||
char ch = get();
|
||||
++m_cursor;
|
||||
if (ch == '\n') {
|
||||
++m_row;
|
||||
m_lineStart = m_cursor;
|
||||
}
|
||||
}
|
||||
|
||||
char lexer::get(std::size_t offset) const {
|
||||
if (m_cursor + offset < m_content.size()) return m_content[m_cursor + offset];
|
||||
return std::char_traits<char>::eof();
|
||||
}
|
||||
|
||||
void lexer::skip_spaces() {
|
||||
while (std::isspace(get()) != 0)
|
||||
next();
|
||||
}
|
||||
|
||||
location lexer::current_location() {
|
||||
return { m_filename, m_row, m_cursor - m_lineStart };
|
||||
}
|
||||
|
||||
} // namespace furc::front
|
||||
@@ -0,0 +1,15 @@
|
||||
#include "furc/front/lexer.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
int main(void) {
|
||||
furc::front::lexer lexer("<TEMP>", "func main() {\n return 0;\n}");
|
||||
|
||||
furc::front::token token = {};
|
||||
while (!furc::front::is_token_type_empty((token = lexer.next_token()).type)) {
|
||||
std::cout << token << '\n';
|
||||
}
|
||||
if (token.type == furc::front::token_t::Error) std::cout << token << '\n';
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user