2025-01-25 Latest Changes
This commit is contained in:
@@ -1,115 +1,112 @@
|
||||
/// AUTOGENERATED COPYRIGHT HEADER START
|
||||
// Copyright (C) 2024 Michael Fabian 'Xaymar' Dirks <info@xaymar.com>
|
||||
// AUTOGENERATED COPYRIGHT HEADER END
|
||||
/*
|
||||
#include "parser.hpp"
|
||||
#include "ast/function.hpp"
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <stdarg.h>
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <cstdarg>
|
||||
#include "error.hpp"
|
||||
|
||||
blitz::parser::parser(std::string file) {
|
||||
// Try and load the file
|
||||
std::shared_ptr<std::ifstream> instream = std::make_shared<std::ifstream>(file);
|
||||
if (instream->bad() || !instream->good()) {
|
||||
throw std::ios_base::failure("Failed to open file.");
|
||||
}
|
||||
m_files.push(std::make_pair(file, instream));
|
||||
blitz::parser::~parser() {}
|
||||
|
||||
blitz::parser::parser(std::filesystem::path file) : _file(file), _lexer(), _expr()
|
||||
{
|
||||
_lexer = std::make_shared<blitz::lexer>(file);
|
||||
}
|
||||
|
||||
blitz::parser::~parser() {
|
||||
while (m_files.size() > 0) {
|
||||
std::shared_ptr<std::ifstream> file = std::dynamic_pointer_cast<std::ifstream>(m_files.top().second);
|
||||
file->close();
|
||||
m_files.pop();
|
||||
}
|
||||
std::shared_ptr<blitz::ast::node> blitz::parser::current()
|
||||
{
|
||||
return _expr;
|
||||
}
|
||||
|
||||
std::unique_ptr<blitz::ast::expression> blitz::parser::parse() {
|
||||
std::unique_ptr<ast::ScopeExpression> scope = std::make_unique<ast::ScopeExpression>();
|
||||
std::shared_ptr<blitz::ast::node> blitz::parser::next()
|
||||
{
|
||||
// This should return an entire "line" of expressions in one go, i.e.:
|
||||
// 1. Local a = 1, b = a, c = b+a
|
||||
// -> Local(Variable(a, Expression(Integer(1))), Variable(b, Expresssion(Variable(a))), Variable(c, Expression(Add(Variable(b), Variable(a)))
|
||||
// 2. Include "HelloWorld.bb"
|
||||
// -> Include(String("HelloWorld.bb"))
|
||||
// 3. Function HelloWorld()
|
||||
// -> Function(HelloWorld, ...)(
|
||||
// Not quite sure if the above makes sense, we'd be returning many expressions outside of functions, but only one inside a function? Why even bother with the current/next crap then?
|
||||
// Handling Include becomes a problem too. I guess we should actually return expressions on a line by line basis, and let the "compiler" figure out scope and stuff.
|
||||
|
||||
std::unique_ptr<ast::expression> expr;
|
||||
while ((expr = std::move(parse_expression())) != nullptr) {
|
||||
scope->AddExpression(std::move(expr));
|
||||
}
|
||||
|
||||
return std::move(scope);
|
||||
}
|
||||
|
||||
void blitz::parser::log(const char* msg, ...) {
|
||||
std::vector<char> buf(65535);
|
||||
va_list val;
|
||||
va_start(val, msg);
|
||||
int rval = vsnprintf(buf.data(), buf.size(), msg, val);
|
||||
va_end(val);
|
||||
std::cout << buf.data() << '\n';
|
||||
}
|
||||
|
||||
void blitz::parser::log_error(const char* msg, ...) {
|
||||
std::vector<char> buf(65535);
|
||||
va_list val;
|
||||
va_start(val, msg);
|
||||
int rval = vsnprintf(buf.data(), buf.size(), msg, val);
|
||||
va_end(val);
|
||||
std::cerr << buf.data() << '\n';
|
||||
}
|
||||
|
||||
std::pair<blitz::lexer::tokentype, std::string> blitz::parser::next() {
|
||||
return m_lexer.next(m_files.top().second);
|
||||
}
|
||||
|
||||
std::unique_ptr<blitz::ast::expression> blitz::parser::parse_expression() {
|
||||
// Grab the next token to figure out what behavior we should have.
|
||||
while (true) {
|
||||
auto tkn = next();
|
||||
log("%s", tkn.second.c_str());
|
||||
|
||||
switch (tkn.first) {
|
||||
case blitz::lexer::tokentype::TokenNewLine:
|
||||
case blitz::lexer::tokentype::TokenComment:
|
||||
// Skip Comments, since we don't really need them for the AST.
|
||||
continue;
|
||||
case blitz::lexer::tokentype::TokenPlus:
|
||||
case blitz::lexer::tokentype::TokenMinus:
|
||||
|
||||
|
||||
default: // End Of File / Unknown
|
||||
case blitz::lexer::tokentype::TokenUnknown:
|
||||
case blitz::lexer::tokentype::TokenEOF:
|
||||
auto token = _lexer->next();
|
||||
try {
|
||||
switch (token.type) {
|
||||
case blitz::token::variant::ENDOFFILE:
|
||||
// End of file means there's nothing left to parse.
|
||||
_expr.reset();
|
||||
return nullptr;
|
||||
break;
|
||||
case blitz::token::variant::COMMENT:
|
||||
case blitz::token::variant::NEWLINE:
|
||||
case blitz::token::variant::SEPARATOR:
|
||||
// Ignore some things that aren't very useful right now.
|
||||
continue;
|
||||
case blitz::token::variant::TEXT:
|
||||
return try_parse(token);
|
||||
default:
|
||||
throw nullptr;
|
||||
}
|
||||
} catch (blitz::error const& ex) {
|
||||
throw ex;
|
||||
} catch (std::exception const& ex) {
|
||||
throw new blitz::error(_file, token.location, token.location, ex.what());
|
||||
} catch (...) {
|
||||
throw new blitz::error(_file, token.location, token.location, blitz::format("Token %s unexpected at this point.", token.to_string().c_str()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<blitz::ast::NumberExpression> blitz::parser::parse_number(blitz::lexer::tokentype token, std::string value) {
|
||||
if (token != lexer::tokentype::TokenNumber) {
|
||||
log_error("Unexpected Token during parsing, expected number.");
|
||||
return nullptr;
|
||||
std::shared_ptr<blitz::ast::node> blitz::parser::try_parse(blitz::token token)
|
||||
{
|
||||
// ToDo: Switch to a proper Unicode library. Maybe Boost?
|
||||
std::string ltext;
|
||||
std::transform(token.text.begin(), token.text.end(), ltext.begin(), [](std::string::value_type c) { return std::tolower(c); });
|
||||
|
||||
if ((ltext == "local") || (ltext == "global")) {
|
||||
// Local/Global have the same parsing, but different functionality.
|
||||
// Should be:
|
||||
// Text Text [Symbol(=) Expression] [Symbol(,) Text [Symbol(=) Expression] [Symbol(,) ...]]
|
||||
|
||||
} else if (ltext == "global") {
|
||||
// Global ...
|
||||
|
||||
} else if (ltext == "function") {
|
||||
} else if (ltext == "select") {
|
||||
} else if (ltext == "case") {
|
||||
} else if (ltext == "endselect") {
|
||||
} else if (ltext == "if") {
|
||||
} else if (ltext == "elif") {
|
||||
} else if (ltext == "endif") {
|
||||
|
||||
} else if (ltext == "end") {
|
||||
}
|
||||
|
||||
char* endptr = const_cast<char*>(value.c_str() + value.size());
|
||||
int32_t parsed = strtol(value.c_str(), &endptr, 10);
|
||||
if (errno == ERANGE) {
|
||||
log_error("Number out of range.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return std::make_unique<blitz::ast::NumberExpression>(parsed);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<blitz::ast::DecimalExpression> blitz::parser::parse_decimal(blitz::lexer::tokentype token, std::string value) {
|
||||
if (token != lexer::tokentype::TokenNumber) {
|
||||
log_error("Unexpected Token during parsing, expected number.");
|
||||
return nullptr;
|
||||
std::shared_ptr<blitz::ast::node> blitz::parser::try_parse_variable()
|
||||
{
|
||||
// Text [Symbol(=) Expression(...)] [Symbol(,) [Text [Symbol(=) Expression(...)]]]
|
||||
|
||||
auto label = _lexer->next();
|
||||
if (label != blitz::token::variant::TEXT) {
|
||||
throw new blitz::error(_file, label.location, label.location, blitz::format("Unexpected %s, expected Text.", label.to_string().c_str()));
|
||||
}
|
||||
|
||||
char* endptr = const_cast<char*>(value.c_str() + value.size());
|
||||
float_t parsed = strtof(value.c_str(), &endptr);
|
||||
if (errno == ERANGE) {
|
||||
log_error("Number out of range.");
|
||||
return nullptr;
|
||||
auto node = std::make_shared<blitz::ast::variable>(label);
|
||||
|
||||
auto operand = _lexer->next();
|
||||
if (operand == "=") {
|
||||
//node->set_value(try_parse_expression());
|
||||
} else if (operand == blitz::token::variant::NEWLINE || operand == blitz::token::variant::SEPARATOR || (operand == blitz::token::variant::SYMBOL && operand == ",")) {
|
||||
return node;
|
||||
} else {
|
||||
throw new blitz::error(_file, label.location, operand.location, blitz::format("Unexpected %s, expected Symbol(=), NewLine, Separator, or Symbol(,).", operand.to_string().c_str()));
|
||||
}
|
||||
|
||||
return std::make_unique<blitz::ast::DecimalExpression>(parsed);
|
||||
return node;
|
||||
}
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user