2025-01-25 Latest Changes
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
# AUTOGENERATED COPYRIGHT HEADER START
|
# AUTOGENERATED COPYRIGHT HEADER START
|
||||||
# Copyright (C) 2017-2024 Michael Fabian 'Xaymar' Dirks <info@xaymar.com>
|
# Copyright (C) 2017-2024 Michael Fabian 'Xaymar' Dirks <info@xaymar.com>
|
||||||
# AUTOGENERATED COPYRIGHT HEADER END
|
# AUTOGENERATED COPYRIGHT HEADER END
|
||||||
project(code_compiler
|
project(compiler
|
||||||
VERSION ${PROJECT_VERSION}
|
VERSION ${PROJECT_VERSION}
|
||||||
)
|
)
|
||||||
add_executable(${PROJECT_NAME})
|
add_executable(${PROJECT_NAME})
|
||||||
@@ -19,12 +19,6 @@ target_sources(${PROJECT_NAME} PRIVATE
|
|||||||
"source/compiler.cpp"
|
"source/compiler.cpp"
|
||||||
"source/ast/ast.hpp"
|
"source/ast/ast.hpp"
|
||||||
"source/ast/ast.cpp"
|
"source/ast/ast.cpp"
|
||||||
"source/ast/arithmetic.hpp"
|
|
||||||
"source/ast/arithmetic.cpp"
|
|
||||||
"source/ast/function.hpp"
|
|
||||||
"source/ast/function.cpp"
|
|
||||||
"source/ast/value.hpp"
|
|
||||||
"source/ast/value.cpp"
|
|
||||||
)
|
)
|
||||||
target_include_directories(${PROJECT_NAME} PRIVATE
|
target_include_directories(${PROJECT_NAME} PRIVATE
|
||||||
"${PROJECT_SOURCE_DIR}/source"
|
"${PROJECT_SOURCE_DIR}/source"
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
/// AUTOGENERATED COPYRIGHT HEADER START
|
|
||||||
// Copyright (C) 2017-2024 Michael Fabian 'Xaymar' Dirks <info@xaymar.com>
|
|
||||||
// AUTOGENERATED COPYRIGHT HEADER END
|
|
||||||
#include "arithmetic.hpp"
|
|
||||||
|
|
||||||
blitz::ast::arithmetic_expression::arithmetic_expression(expression_operator op, std::unique_ptr<expression> left, std::unique_ptr<expression> right)
|
|
||||||
: m_operator(op), m_left(std::move(left)), m_right(std::move(right)) {}
|
|
||||||
|
|
||||||
blitz::ast::arithmetic_expression::~arithmetic_expression() {}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
/// AUTOGENERATED COPYRIGHT HEADER START
|
|
||||||
// Copyright (C) 2017-2024 Michael Fabian 'Xaymar' Dirks <info@xaymar.com>
|
|
||||||
// AUTOGENERATED COPYRIGHT HEADER END
|
|
||||||
#pragma once
|
|
||||||
#include "ast.hpp"
|
|
||||||
#include "value.hpp"
|
|
||||||
|
|
||||||
namespace blitz {
|
|
||||||
namespace ast {
|
|
||||||
enum class expression_operator : int8_t {
|
|
||||||
Add, /*+*/
|
|
||||||
Subtract, /*-*/
|
|
||||||
Multiply, /***/
|
|
||||||
Divide, /*/*/
|
|
||||||
Invert, /*~*/
|
|
||||||
Power, /*^*/
|
|
||||||
Equal, /*=*/
|
|
||||||
};
|
|
||||||
|
|
||||||
class arithmetic_expression : public expression {
|
|
||||||
public:
|
|
||||||
arithmetic_expression(expression_operator op, std::unique_ptr<expression> left, std::unique_ptr<expression> right);
|
|
||||||
virtual ~arithmetic_expression();
|
|
||||||
|
|
||||||
private:
|
|
||||||
expression_operator m_operator;
|
|
||||||
std::unique_ptr<expression> m_left, m_right;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,3 +4,11 @@
|
|||||||
#include "ast.hpp"
|
#include "ast.hpp"
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
|
blitz::ast::variable::~variable() {}
|
||||||
|
|
||||||
|
blitz::ast::variable::variable(blitz::token token) : _token(token), _value(nullptr) {}
|
||||||
|
|
||||||
|
void blitz::ast::variable::set_value(std::shared_ptr<blitz::ast::expression> value)
|
||||||
|
{
|
||||||
|
_value = value;
|
||||||
|
}
|
||||||
|
|||||||
@@ -30,85 +30,34 @@
|
|||||||
|
|
||||||
namespace blitz {
|
namespace blitz {
|
||||||
namespace ast {
|
namespace ast {
|
||||||
class expression {
|
class node {
|
||||||
public:
|
public:
|
||||||
virtual ~expression() = default;
|
virtual ~node() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Values
|
class expression : public node {};
|
||||||
class value_expression : public expression {
|
|
||||||
protected:
|
class variable : public node {
|
||||||
blitz::token _token;
|
blitz::token _token;
|
||||||
|
std::shared_ptr<blitz::ast::expression> _value;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~value_expression() = default;
|
virtual ~variable();
|
||||||
value_expression(blitz::token token);
|
variable(blitz::token token);
|
||||||
|
|
||||||
|
void set_value(std::shared_ptr<blitz::ast::expression> value);
|
||||||
};
|
};
|
||||||
|
|
||||||
class integer_expression : public value_expression {
|
class call : public node {};
|
||||||
protected:
|
|
||||||
int32_t _value;
|
|
||||||
|
|
||||||
|
class local : public node {
|
||||||
public:
|
public:
|
||||||
virtual ~integer_expression() = default;
|
~local();
|
||||||
integer_expression(blitz::token token);
|
local();
|
||||||
};
|
};
|
||||||
|
|
||||||
class real_expression : public value_expression {
|
class global : public node {};
|
||||||
protected:
|
|
||||||
float _value;
|
|
||||||
|
|
||||||
public:
|
|
||||||
virtual ~real_expression() = default;
|
|
||||||
real_expression(blitz::token token);
|
|
||||||
};
|
|
||||||
|
|
||||||
class string_expression : public value_expression {
|
|
||||||
std::string _value;
|
|
||||||
|
|
||||||
public:
|
|
||||||
virtual ~string_expression() = default;
|
|
||||||
string_expression(blitz::token token);
|
|
||||||
};
|
|
||||||
|
|
||||||
/** One or more constant values
|
|
||||||
*
|
|
||||||
* Const var = Value, var2 = value
|
|
||||||
*/
|
|
||||||
class const_expression : public expression {
|
|
||||||
std::list<std::shared_ptr<variable_expression>> _values;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/** One or more local variables
|
|
||||||
*
|
|
||||||
* Local var, var2 = value, var3
|
|
||||||
*/
|
|
||||||
class local_expression : public expression {
|
|
||||||
std::list<std::shared_ptr<variable_expression>> _values;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** One or more global variables
|
|
||||||
*
|
|
||||||
* Local var, var2 = value, var3
|
|
||||||
*/
|
|
||||||
class global_expression : public expression {
|
|
||||||
std::list<std::shared_ptr<variable_expression>> _values;
|
|
||||||
};
|
|
||||||
|
|
||||||
/** A variable definition
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
class variable_expression : public expression {
|
|
||||||
blitz::token _assign;
|
|
||||||
std::string _name;
|
|
||||||
std::shared_ptr<value_expression> _value;
|
|
||||||
|
|
||||||
public:
|
|
||||||
virtual ~variable_expression() = default;
|
|
||||||
variable_expression(blitz::token token);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace ast
|
} // namespace ast
|
||||||
} // namespace blitz
|
} // namespace blitz
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
// AUTOGENERATED COPYRIGHT HEADER START
|
|
||||||
// Copyright (C) 2024 Michael Fabian 'Xaymar' Dirks <info@xaymar.com>
|
|
||||||
// AUTOGENERATED COPYRIGHT HEADER END
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
// AUTOGENERATED COPYRIGHT HEADER START
|
|
||||||
// Copyright (C) 2024 Michael Fabian 'Xaymar' Dirks <info@xaymar.com>
|
|
||||||
// AUTOGENERATED COPYRIGHT HEADER END
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
/// AUTOGENERATED COPYRIGHT HEADER START
|
|
||||||
// Copyright (C) 2024 Michael Fabian 'Xaymar' Dirks <info@xaymar.com>
|
|
||||||
// AUTOGENERATED COPYRIGHT HEADER END
|
|
||||||
#include "function.hpp"
|
|
||||||
|
|
||||||
blitz::ast::ScopeExpression::ScopeExpression() {}
|
|
||||||
|
|
||||||
blitz::ast::ScopeExpression::~ScopeExpression() {}
|
|
||||||
|
|
||||||
void blitz::ast::ScopeExpression::AddExpression(std::unique_ptr<expression> ex) {
|
|
||||||
m_expressions.push_back(std::move(ex));
|
|
||||||
}
|
|
||||||
|
|
||||||
blitz::ast::FunctionExpression::FunctionExpression(ValueType returnType,
|
|
||||||
std::string& m_name,
|
|
||||||
std::list<std::unique_ptr<VariableExpression>> parameters,
|
|
||||||
std::unique_ptr<ScopeExpression> scope)
|
|
||||||
: m_returnType(returnType), m_name(m_name), m_parameters(std::move(parameters)), m_content(std::move(scope)) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
blitz::ast::FunctionExpression::~FunctionExpression() {}
|
|
||||||
|
|
||||||
blitz::ast::CallExpression::CallExpression(std::string& name, std::list<std::unique_ptr<VariableExpression>> arguments)
|
|
||||||
: m_name(name), m_arguments(std::move(arguments)) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
blitz::ast::CallExpression::~CallExpression() {}
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
/// AUTOGENERATED COPYRIGHT HEADER START
|
|
||||||
// Copyright (C) 2024 Michael Fabian 'Xaymar' Dirks <info@xaymar.com>
|
|
||||||
// AUTOGENERATED COPYRIGHT HEADER END
|
|
||||||
#pragma once
|
|
||||||
#include "ast.hpp"
|
|
||||||
#include "value.hpp"
|
|
||||||
#include <list>
|
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace blitz {
|
|
||||||
namespace ast {
|
|
||||||
class ScopeExpression : public expression {
|
|
||||||
public:
|
|
||||||
ScopeExpression();
|
|
||||||
virtual ~ScopeExpression();
|
|
||||||
|
|
||||||
void AddExpression(std::unique_ptr<expression> ex);
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::list<std::unique_ptr<expression>> m_expressions;
|
|
||||||
};
|
|
||||||
|
|
||||||
class FunctionExpression : public ScopeExpression {
|
|
||||||
public:
|
|
||||||
FunctionExpression(ValueType returnType,
|
|
||||||
std::string& m_name,
|
|
||||||
std::list<std::unique_ptr<VariableExpression>> parameters,
|
|
||||||
std::unique_ptr<ScopeExpression> scope);
|
|
||||||
virtual ~FunctionExpression();
|
|
||||||
|
|
||||||
private:
|
|
||||||
ValueType m_returnType;
|
|
||||||
std::string m_name;
|
|
||||||
std::list<std::unique_ptr<VariableExpression>> m_parameters;
|
|
||||||
std::unique_ptr<ScopeExpression> m_content;
|
|
||||||
};
|
|
||||||
|
|
||||||
class CallExpression : public expression {
|
|
||||||
public:
|
|
||||||
CallExpression(std::string& name, std::list<std::unique_ptr<VariableExpression>> arguments);
|
|
||||||
virtual ~CallExpression();
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string m_name;
|
|
||||||
std::list<std::unique_ptr<VariableExpression>> m_arguments;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
/// AUTOGENERATED COPYRIGHT HEADER START
|
|
||||||
// Copyright (C) 2024 Michael Fabian 'Xaymar' Dirks <info@xaymar.com>
|
|
||||||
// AUTOGENERATED COPYRIGHT HEADER END
|
|
||||||
#include "value.hpp"
|
|
||||||
|
|
||||||
blitz::ast::VariableExpression::VariableExpression(std::string& name, ValueType type /*= ValueType::Number*/)
|
|
||||||
: m_name(name), m_type(type) {}
|
|
||||||
|
|
||||||
blitz::ast::VariableExpression::~VariableExpression() {}
|
|
||||||
|
|
||||||
blitz::ast::ValueType blitz::ast::VariableExpression::GetType() {
|
|
||||||
return m_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
blitz::ast::NumberExpression::NumberExpression(int32_t value) : value(value) {}
|
|
||||||
|
|
||||||
blitz::ast::NumberExpression::~NumberExpression() {}
|
|
||||||
|
|
||||||
blitz::ast::ValueType blitz::ast::NumberExpression::GetType() {
|
|
||||||
return ValueType::INTEGER;
|
|
||||||
}
|
|
||||||
|
|
||||||
blitz::ast::DecimalExpression::DecimalExpression(float_t value) : value(value) {}
|
|
||||||
|
|
||||||
blitz::ast::DecimalExpression::~DecimalExpression() {}
|
|
||||||
|
|
||||||
blitz::ast::ValueType blitz::ast::DecimalExpression::GetType() {
|
|
||||||
return ValueType::REAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
blitz::ast::StringExpression::StringExpression(std::string value) : value(value) {}
|
|
||||||
|
|
||||||
blitz::ast::StringExpression::~StringExpression() {}
|
|
||||||
|
|
||||||
blitz::ast::ValueType blitz::ast::StringExpression::GetType() {
|
|
||||||
return ValueType::STRING;
|
|
||||||
}
|
|
||||||
|
|
||||||
blitz::ast::ConstExpression::ConstExpression(std::string& name, std::unique_ptr<ValueExpression> value)
|
|
||||||
: m_name(name), m_value(std::move(value)) {}
|
|
||||||
|
|
||||||
blitz::ast::ConstExpression::~ConstExpression() {}
|
|
||||||
|
|
||||||
blitz::ast::ValueType blitz::ast::ConstExpression::GetType() {
|
|
||||||
return m_value->GetType();
|
|
||||||
}
|
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
/// AUTOGENERATED COPYRIGHT HEADER START
|
|
||||||
// Copyright (C) 2024 Michael Fabian 'Xaymar' Dirks <info@xaymar.com>
|
|
||||||
// AUTOGENERATED COPYRIGHT HEADER END
|
|
||||||
#pragma once
|
|
||||||
#include "ast.hpp"
|
|
||||||
#include "lexer.hpp"
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include <float.h>
|
|
||||||
#include <math.h>
|
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace blitz {
|
|
||||||
namespace ast {
|
|
||||||
enum class ValueType : int8_t {
|
|
||||||
UNKNOWN,
|
|
||||||
INTEGER,
|
|
||||||
REAL,
|
|
||||||
STRING,
|
|
||||||
TYPE,
|
|
||||||
};
|
|
||||||
|
|
||||||
class ValueExpression : public expression {
|
|
||||||
public:
|
|
||||||
virtual ValueType GetType() = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ConstExpression : public ValueExpression {
|
|
||||||
public:
|
|
||||||
ConstExpression(std::string& name, std::unique_ptr<ValueExpression> value);
|
|
||||||
virtual ~ConstExpression();
|
|
||||||
|
|
||||||
virtual ValueType GetType() override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string m_name;
|
|
||||||
std::unique_ptr<ValueExpression> m_value;
|
|
||||||
};
|
|
||||||
|
|
||||||
class VariableExpression : public ValueExpression {
|
|
||||||
public:
|
|
||||||
VariableExpression(std::string& name, ValueType type = ValueType::INTEGER);
|
|
||||||
virtual ~VariableExpression();
|
|
||||||
|
|
||||||
virtual ValueType GetType() override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string m_name;
|
|
||||||
ValueType m_type;
|
|
||||||
};
|
|
||||||
|
|
||||||
class NumberExpression : public ValueExpression {
|
|
||||||
public:
|
|
||||||
NumberExpression(int32_t value);
|
|
||||||
virtual ~NumberExpression();
|
|
||||||
|
|
||||||
virtual ValueType GetType() override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
int32_t value;
|
|
||||||
};
|
|
||||||
|
|
||||||
class DecimalExpression : public ValueExpression {
|
|
||||||
public:
|
|
||||||
DecimalExpression(float_t value);
|
|
||||||
virtual ~DecimalExpression();
|
|
||||||
|
|
||||||
virtual ValueType GetType() override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
float_t value;
|
|
||||||
};
|
|
||||||
|
|
||||||
class StringExpression : public ValueExpression {
|
|
||||||
public:
|
|
||||||
StringExpression(std::string value);
|
|
||||||
virtual ~StringExpression();
|
|
||||||
|
|
||||||
virtual ValueType GetType() override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string value;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
// Copyright (C) 2024 Michael Fabian 'Xaymar' Dirks <info@xaymar.com>
|
// Copyright (C) 2024 Michael Fabian 'Xaymar' Dirks <info@xaymar.com>
|
||||||
// AUTOGENERATED COPYRIGHT HEADER END
|
// AUTOGENERATED COPYRIGHT HEADER END
|
||||||
#include "error.hpp"
|
#include "error.hpp"
|
||||||
|
#include <cstdarg>
|
||||||
|
|
||||||
blitz::error::~error() {}
|
blitz::error::~error() {}
|
||||||
|
|
||||||
@@ -26,3 +27,17 @@ std::pair<uint64_t, uint64_t> const& blitz::error::at() const
|
|||||||
{
|
{
|
||||||
return _at;
|
return _at;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string blitz::format(const char* format, ...)
|
||||||
|
{
|
||||||
|
va_list arg1;
|
||||||
|
va_list arg2;
|
||||||
|
va_start(arg1, format);
|
||||||
|
va_copy(arg2, arg1);
|
||||||
|
int length = vsnprintf(nullptr, 0, format, arg1);
|
||||||
|
std::vector<char> buffer(length + 1);
|
||||||
|
vsnprintf(buffer.data(), buffer.size(), format, arg2);
|
||||||
|
va_end(arg1);
|
||||||
|
va_end(arg2);
|
||||||
|
return {buffer.data(), buffer.data() + length};
|
||||||
|
}
|
||||||
|
|||||||
@@ -24,4 +24,6 @@ namespace blitz {
|
|||||||
|
|
||||||
std::pair<uint64_t, uint64_t> const& at() const;
|
std::pair<uint64_t, uint64_t> const& at() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::string format(const char* format, ...);
|
||||||
} // namespace blitz
|
} // namespace blitz
|
||||||
|
|||||||
+26
-300
@@ -6,20 +6,6 @@
|
|||||||
#include <cstdarg>
|
#include <cstdarg>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
std::string format(const char* format, ...)
|
|
||||||
{
|
|
||||||
va_list arg1;
|
|
||||||
va_list arg2;
|
|
||||||
va_start(arg1, format);
|
|
||||||
va_copy(arg2, arg1);
|
|
||||||
int length = vsnprintf(nullptr, 0, format, arg1);
|
|
||||||
std::vector<char> buffer(length + 1);
|
|
||||||
vsnprintf(buffer.data(), buffer.size(), format, arg2);
|
|
||||||
va_end(arg1);
|
|
||||||
va_end(arg2);
|
|
||||||
return {buffer.data(), buffer.data() + length};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string blitz::token::to_string()
|
std::string blitz::token::to_string()
|
||||||
{
|
{
|
||||||
std::string name;
|
std::string name;
|
||||||
@@ -55,17 +41,27 @@ std::string blitz::token::to_string()
|
|||||||
name = "Symbol";
|
name = "Symbol";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
name = "How the fuck?!";
|
name = "Invalid";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == variant::NEWLINE || type == variant::CONTROL) {
|
if (type == variant::NEWLINE || type == variant::CONTROL) {
|
||||||
return format("%s(%llu@%llu, %d)", name.c_str(), location.first, location.second, text[0]);
|
return blitz::format("%s(%llu@%llu, %d)", name.c_str(), location.first, location.second, text[0]);
|
||||||
} else {
|
} else {
|
||||||
return format("%s(%llu@%llu, %s)", name.c_str(), location.first, location.second, text.c_str());
|
return blitz::format("%s(%llu@%llu, %s)", name.c_str(), location.first, location.second, text.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool blitz::token::operator==(variant rhs)
|
||||||
|
{
|
||||||
|
return type == rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool blitz::token::operator==(std::string const& rhs)
|
||||||
|
{
|
||||||
|
return text == rhs;
|
||||||
|
}
|
||||||
|
|
||||||
blitz::lexer::~lexer() {}
|
blitz::lexer::~lexer() {}
|
||||||
|
|
||||||
blitz::lexer::lexer(std::filesystem::path file)
|
blitz::lexer::lexer(std::filesystem::path file)
|
||||||
@@ -77,7 +73,7 @@ blitz::lexer::lexer(std::filesystem::path file)
|
|||||||
_file = file;
|
_file = file;
|
||||||
_stream = std::ifstream(_file, std::ios_base::binary); // We use binary so we can eventually support UTF-8.
|
_stream = std::ifstream(_file, std::ios_base::binary); // We use binary so we can eventually support UTF-8.
|
||||||
if (!_stream.good() || _stream.eof() || _stream.bad() || _stream.fail()) {
|
if (!_stream.good() || _stream.eof() || _stream.bad() || _stream.fail()) {
|
||||||
throw std::runtime_error(format("Reading file '%s' failed.", file.generic_string().c_str()));
|
throw std::runtime_error(blitz::format("Reading file '%s' failed.", file.generic_string().c_str()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize token storage to a default token.
|
// Initialize token storage to a default token.
|
||||||
@@ -94,6 +90,12 @@ blitz::token blitz::lexer::current()
|
|||||||
}
|
}
|
||||||
|
|
||||||
blitz::token blitz::lexer::next()
|
blitz::token blitz::lexer::next()
|
||||||
|
{
|
||||||
|
_current = peek();
|
||||||
|
return _current;
|
||||||
|
}
|
||||||
|
|
||||||
|
blitz::token blitz::lexer::peek()
|
||||||
{
|
{
|
||||||
enum class stage {
|
enum class stage {
|
||||||
DEFAULT,
|
DEFAULT,
|
||||||
@@ -204,14 +206,14 @@ blitz::token blitz::lexer::next()
|
|||||||
complete = true;
|
complete = true;
|
||||||
_stream.get();
|
_stream.get();
|
||||||
_location.second++;
|
_location.second++;
|
||||||
} else if (chr == ':') {
|
/*} else if (chr == ':') {
|
||||||
// Allows code writers to pretend it's all one line.
|
// Allows code writers to pretend it's all one line.
|
||||||
token.location = _location;
|
token.location = _location;
|
||||||
token.type = blitz::token::variant::SEPARATOR;
|
token.type = blitz::token::variant::SEPARATOR;
|
||||||
token.text = {1, char(chr)};
|
token.text = {1, char(chr)};
|
||||||
complete = true;
|
complete = true;
|
||||||
_stream.get();
|
_stream.get();
|
||||||
_location.second++;
|
_location.second++;*/
|
||||||
} else if (chr == ';') {
|
} else if (chr == ';') {
|
||||||
// A comment, which ends at the next new line.
|
// A comment, which ends at the next new line.
|
||||||
state = stage::COMMENT;
|
state = stage::COMMENT;
|
||||||
@@ -308,14 +310,14 @@ blitz::token blitz::lexer::next()
|
|||||||
token.type = blitz::token::variant::REAL;
|
token.type = blitz::token::variant::REAL;
|
||||||
} else {
|
} else {
|
||||||
token.text = buffer.str();
|
token.text = buffer.str();
|
||||||
throw blitz::error(_file, token.location, _location, format("In token %s: Expected [0-9], got '%s' instead.", token.to_string().c_str(), std::string{1, (char)chr}.c_str()));
|
throw blitz::error(_file, token.location, _location, blitz::format("In token %s: Expected [0-9], got '%s' instead.", token.to_string().c_str(), std::string{1, (char)chr}.c_str()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (issymbol(chr)) {
|
} else if (issymbol(chr)) {
|
||||||
complete = true;
|
complete = true;
|
||||||
} else {
|
} else {
|
||||||
token.text = buffer.str();
|
token.text = buffer.str();
|
||||||
throw blitz::error(_file, token.location, _location, format("In token %s: Expected [0-9.], got '%s' instead.", token.to_string().c_str(), std::string{1, (char)chr}.c_str()));
|
throw blitz::error(_file, token.location, _location, blitz::format("In token %s: Expected [0-9.], got '%s' instead.", token.to_string().c_str(), std::string{1, (char)chr}.c_str()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (complete) {
|
if (complete) {
|
||||||
@@ -331,7 +333,7 @@ blitz::token blitz::lexer::next()
|
|||||||
_location.second++;
|
_location.second++;
|
||||||
} else {
|
} else {
|
||||||
token.text = buffer.str();
|
token.text = buffer.str();
|
||||||
throw blitz::error(_file, token.location, _location, format("In token %s: Expected [a-zA-Z0-9_], got '%s' instead.", token.to_string().c_str(), std::string{1, (char)chr}.c_str()));
|
throw blitz::error(_file, token.location, _location, blitz::format("In token %s: Expected [a-zA-Z0-9_], got '%s' instead.", token.to_string().c_str(), std::string{1, (char)chr}.c_str()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (complete) {
|
if (complete) {
|
||||||
@@ -372,281 +374,5 @@ blitz::token blitz::lexer::next()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_current = token;
|
return token;
|
||||||
return _current;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
std::pair<blitz::tokentype, std::string> blitz::lexer::current() {
|
|
||||||
return _current;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<blitz::tokentype, std::string> blitz::lexer::next(std::istream& fs) {
|
|
||||||
std::stringstream buffer;
|
|
||||||
blitz::tokentype token;
|
|
||||||
|
|
||||||
enum class parserState {
|
|
||||||
DEFAULT,
|
|
||||||
TEXT,
|
|
||||||
NUMBER,
|
|
||||||
STRING,
|
|
||||||
COMMENT,
|
|
||||||
} state = parserState::DEFAULT;
|
|
||||||
|
|
||||||
while ((token == blitz::tokentype::TokenUnknown) && !fs.eof() && fs.good()) {
|
|
||||||
auto chr = fs.get();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
std::pair<blitz::lexer::token, std::string> blitz::lexer::next(std::shared_ptr<std::istream> fs) {
|
|
||||||
std::string buf;
|
|
||||||
token tkn = token::TokenUnknown;
|
|
||||||
bool haveResult = false;
|
|
||||||
|
|
||||||
// Allow "overriding" the next retrieved Token.
|
|
||||||
if (m_overrideToken != token::TokenUnknown) {
|
|
||||||
buf = m_overrideText;
|
|
||||||
tkn = m_overrideToken;
|
|
||||||
m_overrideToken = token::TokenUnknown;
|
|
||||||
haveResult = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool m_isTextMode = false;
|
|
||||||
bool m_isNumberMode = false;
|
|
||||||
bool m_isStringMode = false;
|
|
||||||
bool m_isCommentMode = false;
|
|
||||||
bool m_numberModeHasDecimal = false;
|
|
||||||
while (((fs->eof() == false) && (fs->good())) && !haveResult) {
|
|
||||||
char chr = fs->get();
|
|
||||||
|
|
||||||
if (chr == '\r' || chr == '\n') {
|
|
||||||
if (tkn != token::TokenEOF) {
|
|
||||||
m_overrideToken = token::TokenNewLine;
|
|
||||||
m_overrideText = "";
|
|
||||||
} else {
|
|
||||||
tkn = token::TokenNewLine;
|
|
||||||
buf = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
m_isStringMode = false;
|
|
||||||
m_isNumberMode = false;
|
|
||||||
m_isTextMode = false;
|
|
||||||
m_isCommentMode = false;
|
|
||||||
break;
|
|
||||||
} else if (m_isStringMode) {
|
|
||||||
if (chr == '\"') {
|
|
||||||
m_overrideToken = token::TokenDoubleQuote;
|
|
||||||
m_overrideText = chr;
|
|
||||||
m_isStringMode = false;
|
|
||||||
tkn = token::TokenQuotedText;
|
|
||||||
break;
|
|
||||||
} else if (iscntrl(chr) || !isprint(chr)) {
|
|
||||||
fs->putback(chr);
|
|
||||||
m_isStringMode = false;
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
buf += chr;
|
|
||||||
}
|
|
||||||
} else if (m_isTextMode) {
|
|
||||||
if (isalnum(chr) || (chr == '_')) {
|
|
||||||
buf += chr;
|
|
||||||
} else {
|
|
||||||
fs->putback(chr);
|
|
||||||
m_isTextMode = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else if (m_isNumberMode) {
|
|
||||||
if (isdigit(chr)) {
|
|
||||||
buf += chr;
|
|
||||||
} else if (chr == '.') {
|
|
||||||
if (m_numberModeHasDecimal == false) {
|
|
||||||
m_numberModeHasDecimal = true;
|
|
||||||
tkn = token::TokenDecimal;
|
|
||||||
buf += chr;
|
|
||||||
} else {
|
|
||||||
fs->putback(chr);
|
|
||||||
m_isNumberMode = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fs->putback(chr);
|
|
||||||
m_isNumberMode = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else if (m_isCommentMode) {
|
|
||||||
buf += chr;
|
|
||||||
tkn = token::TokenComment;
|
|
||||||
} else {
|
|
||||||
// Whitespace
|
|
||||||
if (isspace(chr))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// Control Code
|
|
||||||
if (iscntrl(chr)) {
|
|
||||||
tkn = token::TokenUnknown;
|
|
||||||
buf = chr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Special handling for + and -, due to numbers and decimals.
|
|
||||||
if (chr == '+' || chr == '-') {
|
|
||||||
char chr2 = fs->get();
|
|
||||||
if (isdigit(chr2)) {
|
|
||||||
m_isNumberMode = true;
|
|
||||||
m_numberModeHasDecimal = false;
|
|
||||||
tkn = token::TokenNumber;
|
|
||||||
buf = chr + chr2;
|
|
||||||
break;
|
|
||||||
} else if (chr2 == '.') {
|
|
||||||
m_isNumberMode = true;
|
|
||||||
m_numberModeHasDecimal = true;
|
|
||||||
tkn = token::TokenDecimal;
|
|
||||||
buf = chr + "0" + chr2;
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
fs->putback(chr2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Symbol
|
|
||||||
for (auto v : g_symbolCharacters) {
|
|
||||||
if (v.first == chr) {
|
|
||||||
tkn = v.second;
|
|
||||||
buf = v.first;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (tkn != token::TokenEOF) {
|
|
||||||
haveResult = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Strings, Text, Numbers
|
|
||||||
if (chr == ';') {
|
|
||||||
m_isCommentMode = true;
|
|
||||||
tkn = token::TokenSemicolon;
|
|
||||||
buf = chr;
|
|
||||||
break;
|
|
||||||
} else if (chr == '\"') {
|
|
||||||
m_isStringMode = true;
|
|
||||||
tkn = token::TokenDoubleQuote;
|
|
||||||
buf = chr;
|
|
||||||
break;
|
|
||||||
} else if (isalpha(chr)) {
|
|
||||||
m_isTextMode = true;
|
|
||||||
tkn = token::TokenText;
|
|
||||||
buf = chr;
|
|
||||||
} else if (isdigit(chr)) {
|
|
||||||
m_isNumberMode = true;
|
|
||||||
m_numberModeHasDecimal = false;
|
|
||||||
tkn = token::TokenNumber;
|
|
||||||
buf = chr;
|
|
||||||
} else if (chr == '.') {
|
|
||||||
m_isNumberMode = true;
|
|
||||||
m_numberModeHasDecimal = true;
|
|
||||||
tkn = token::TokenDecimal;
|
|
||||||
buf = "0" + chr;
|
|
||||||
} else {
|
|
||||||
tkn = token::TokenUnknown;
|
|
||||||
buf = chr;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert from Text into native Token.
|
|
||||||
if (tkn == token::TokenText)
|
|
||||||
tkn = to_token(tkn, buf);
|
|
||||||
|
|
||||||
return std::make_pair(tkn, buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
blitz::lexer::token blitz::lexer::to_token(token in, std::string text) {
|
|
||||||
static std::pair<const char*, token> l_textToTokenList[] = {
|
|
||||||
// Binary
|
|
||||||
{ "not", token::TokenNot },
|
|
||||||
{ "and", token::TokenAnd },
|
|
||||||
{ "or", token::TokenOr },
|
|
||||||
{ "xor", token::TokenXor },
|
|
||||||
{ "shl", token::TokenShl },
|
|
||||||
{ "shr", token::TokenShr },
|
|
||||||
{ "sal", token::TokenSal },
|
|
||||||
{ "sar", token::TokenSar },
|
|
||||||
{ "false", token::TokenFalse },
|
|
||||||
{ "true", token::TokenTrue },
|
|
||||||
|
|
||||||
// Conversion
|
|
||||||
{ "float", token::TokenFloat },
|
|
||||||
{ "string", token::TokenString },
|
|
||||||
{ "hex", token::TokenHex },
|
|
||||||
{ "int", token::TokenInt },
|
|
||||||
|
|
||||||
// Control
|
|
||||||
{ "if", token::TokenIf },
|
|
||||||
{ "then", token::TokenThen },
|
|
||||||
{ "elseif", token::TokenElseIf },
|
|
||||||
{ "else", token::TokenElse },
|
|
||||||
{ "endif", token::TokenEndIf },
|
|
||||||
{ "select", token::TokenSelect },
|
|
||||||
{ "case", token::TokenCase },
|
|
||||||
{ "default", token::TokenDefault },
|
|
||||||
{ "goto", token::TokenGoto },
|
|
||||||
{ "gosub", token::TokenGosub },
|
|
||||||
{ "return", token::TokenReturn },
|
|
||||||
{ "function", token::TokenFunction },
|
|
||||||
{ "end", token::TokenEnd },
|
|
||||||
{ "stop", token::TokenStop },
|
|
||||||
|
|
||||||
// Loop
|
|
||||||
{ "for", token::TokenFor },
|
|
||||||
{ "to", token::TokenTo },
|
|
||||||
{ "next", token::TokenNext },
|
|
||||||
{ "while", token::TokenWhile },
|
|
||||||
{ "wend", token::TokenWend },
|
|
||||||
{ "repeat", token::TokenRepeat },
|
|
||||||
{ "until", token::TokenUntil },
|
|
||||||
{ "forever", token::TokenForever },
|
|
||||||
{ "exit", token::TokenExit },
|
|
||||||
|
|
||||||
// Math
|
|
||||||
{ "abs", token::TokenAbs },
|
|
||||||
{ "sign", token::TokenSign },
|
|
||||||
{ "cos", token::TokenCos },
|
|
||||||
{ "sin", token::TokenSin },
|
|
||||||
{ "tan", token::TokenTan },
|
|
||||||
{ "acos", token::TokenACos },
|
|
||||||
{ "asin", token::TokenASin },
|
|
||||||
{ "atan", token::TokenATan },
|
|
||||||
{ "atan2", token::TokenATan2 },
|
|
||||||
{ "log", token::TokenLog },
|
|
||||||
{ "log10", token::TokenLog10 },
|
|
||||||
{ "ceil", token::TokenCeil },
|
|
||||||
{ "floor", token::TokenFloor },
|
|
||||||
{ "mod", token::TokenMod },
|
|
||||||
{ "pi", token::TokenPi },
|
|
||||||
{ "exp", token::TokenExp },
|
|
||||||
{ "sqr", token::TokenSqr },
|
|
||||||
|
|
||||||
// Variables
|
|
||||||
{ "const", token::TokenConst },
|
|
||||||
{ "global", token::TokenGlobal },
|
|
||||||
{ "local", token::TokenLocal },
|
|
||||||
|
|
||||||
// Includes
|
|
||||||
{ "include", token::TokenInclude },
|
|
||||||
};
|
|
||||||
for (auto v : l_textToTokenList) {
|
|
||||||
if (stricmp(text.c_str(), v.first)) {
|
|
||||||
return v.second;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return in;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|||||||
@@ -35,6 +35,9 @@ namespace blitz {
|
|||||||
} type;
|
} type;
|
||||||
|
|
||||||
std::string to_string();
|
std::string to_string();
|
||||||
|
|
||||||
|
bool operator==(blitz::token::variant rhs);
|
||||||
|
bool operator==(std::string const& rhs);
|
||||||
};
|
};
|
||||||
|
|
||||||
class lexer {
|
class lexer {
|
||||||
@@ -60,5 +63,11 @@ namespace blitz {
|
|||||||
* This will replace the current token.
|
* This will replace the current token.
|
||||||
*/
|
*/
|
||||||
blitz::token next();
|
blitz::token next();
|
||||||
|
|
||||||
|
/** Peek at the next token in the given stream.
|
||||||
|
*
|
||||||
|
* The current token will remain in-tact.
|
||||||
|
*/
|
||||||
|
blitz::token peek();
|
||||||
};
|
};
|
||||||
} // namespace blitz
|
} // namespace blitz
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// AUTOGENERATED COPYRIGHT HEADER START
|
// AUTOGENERATED COPYRIGHT HEADER START
|
||||||
// Copyright (C) 2017-2024 Michael Fabian 'Xaymar' Dirks <info@xaymar.com>
|
// Copyright (C) 2017-2024 Michael Fabian 'Xaymar' Dirks <info@xaymar.com>
|
||||||
// AUTOGENERATED COPYRIGHT HEADER END
|
// AUTOGENERATED COPYRIGHT HEADER END
|
||||||
|
#include <clocale>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "compiler.hpp"
|
#include "compiler.hpp"
|
||||||
#include "error.hpp"
|
#include "error.hpp"
|
||||||
@@ -8,6 +9,8 @@
|
|||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
|
std::setlocale(LC_ALL, "en_US.UTF-8");
|
||||||
|
|
||||||
std::cout << argv[1] << std::endl;
|
std::cout << argv[1] << std::endl;
|
||||||
blitz::lexer lex(argv[1]);
|
blitz::lexer lex(argv[1]);
|
||||||
|
|
||||||
@@ -32,6 +35,7 @@ int main(int argc, char** argv)
|
|||||||
case blitz::token::variant::NEWLINE:
|
case blitz::token::variant::NEWLINE:
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
std::cout << token.to_string() << " ";
|
std::cout << token.to_string() << " ";
|
||||||
break;
|
break;
|
||||||
@@ -47,7 +51,7 @@ int main(int argc, char** argv)
|
|||||||
std::cout << ex.what() << std::endl;
|
std::cout << ex.what() << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cin.get();
|
//std::cin.get();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,115 +1,112 @@
|
|||||||
/// AUTOGENERATED COPYRIGHT HEADER START
|
/// AUTOGENERATED COPYRIGHT HEADER START
|
||||||
// Copyright (C) 2024 Michael Fabian 'Xaymar' Dirks <info@xaymar.com>
|
// Copyright (C) 2024 Michael Fabian 'Xaymar' Dirks <info@xaymar.com>
|
||||||
// AUTOGENERATED COPYRIGHT HEADER END
|
// AUTOGENERATED COPYRIGHT HEADER END
|
||||||
/*
|
|
||||||
#include "parser.hpp"
|
#include "parser.hpp"
|
||||||
#include "ast/function.hpp"
|
#include <algorithm>
|
||||||
#include <iostream>
|
#include <cctype>
|
||||||
#include <vector>
|
#include <cstdarg>
|
||||||
#include <stdarg.h>
|
#include "error.hpp"
|
||||||
|
|
||||||
blitz::parser::parser(std::string file) {
|
blitz::parser::~parser() {}
|
||||||
// Try and load the file
|
|
||||||
std::shared_ptr<std::ifstream> instream = std::make_shared<std::ifstream>(file);
|
blitz::parser::parser(std::filesystem::path file) : _file(file), _lexer(), _expr()
|
||||||
if (instream->bad() || !instream->good()) {
|
{
|
||||||
throw std::ios_base::failure("Failed to open file.");
|
_lexer = std::make_shared<blitz::lexer>(file);
|
||||||
}
|
|
||||||
m_files.push(std::make_pair(file, instream));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
blitz::parser::~parser() {
|
std::shared_ptr<blitz::ast::node> blitz::parser::current()
|
||||||
while (m_files.size() > 0) {
|
{
|
||||||
std::shared_ptr<std::ifstream> file = std::dynamic_pointer_cast<std::ifstream>(m_files.top().second);
|
return _expr;
|
||||||
file->close();
|
|
||||||
m_files.pop();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<blitz::ast::expression> blitz::parser::parse() {
|
std::shared_ptr<blitz::ast::node> blitz::parser::next()
|
||||||
std::unique_ptr<ast::ScopeExpression> scope = std::make_unique<ast::ScopeExpression>();
|
{
|
||||||
|
// 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;
|
// Grab the next token to figure out what behavior we should have.
|
||||||
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() {
|
|
||||||
while (true) {
|
while (true) {
|
||||||
auto tkn = next();
|
auto token = _lexer->next();
|
||||||
log("%s", tkn.second.c_str());
|
try {
|
||||||
|
switch (token.type) {
|
||||||
switch (tkn.first) {
|
case blitz::token::variant::ENDOFFILE:
|
||||||
case blitz::lexer::tokentype::TokenNewLine:
|
// End of file means there's nothing left to parse.
|
||||||
case blitz::lexer::tokentype::TokenComment:
|
_expr.reset();
|
||||||
// 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:
|
|
||||||
return nullptr;
|
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) {
|
std::shared_ptr<blitz::ast::node> blitz::parser::try_parse(blitz::token token)
|
||||||
if (token != lexer::tokentype::TokenNumber) {
|
{
|
||||||
log_error("Unexpected Token during parsing, expected number.");
|
// ToDo: Switch to a proper Unicode library. Maybe Boost?
|
||||||
return nullptr;
|
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());
|
return nullptr;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<blitz::ast::DecimalExpression> blitz::parser::parse_decimal(blitz::lexer::tokentype token, std::string value) {
|
std::shared_ptr<blitz::ast::node> blitz::parser::try_parse_variable()
|
||||||
if (token != lexer::tokentype::TokenNumber) {
|
{
|
||||||
log_error("Unexpected Token during parsing, expected number.");
|
// Text [Symbol(=) Expression(...)] [Symbol(,) [Text [Symbol(=) Expression(...)]]]
|
||||||
return nullptr;
|
|
||||||
|
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());
|
auto node = std::make_shared<blitz::ast::variable>(label);
|
||||||
float_t parsed = strtof(value.c_str(), &endptr);
|
|
||||||
if (errno == ERANGE) {
|
auto operand = _lexer->next();
|
||||||
log_error("Number out of range.");
|
if (operand == "=") {
|
||||||
return nullptr;
|
//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;
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|||||||
@@ -3,52 +3,26 @@
|
|||||||
// AUTOGENERATED COPYRIGHT HEADER END
|
// AUTOGENERATED COPYRIGHT HEADER END
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include <memory>
|
||||||
#include "ast/ast.hpp"
|
#include "ast/ast.hpp"
|
||||||
#include "lexer.hpp"
|
#include "lexer.hpp"
|
||||||
|
|
||||||
namespace blitz {
|
namespace blitz {
|
||||||
class parser {
|
class parser {
|
||||||
std::filesystem::path _file;
|
std::filesystem::path _file;
|
||||||
|
std::shared_ptr<blitz::lexer> _lexer;
|
||||||
|
|
||||||
|
std::shared_ptr<blitz::ast::node> _expr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
~parser();
|
~parser();
|
||||||
parser(std::filesystem::path file);
|
parser(std::filesystem::path file);
|
||||||
|
|
||||||
|
std::shared_ptr<blitz::ast::node> current();
|
||||||
|
std::shared_ptr<blitz::ast::node> next();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr<blitz::ast::node> try_parse(blitz::token token);
|
||||||
|
std::shared_ptr<blitz::ast::node> try_parse_variable();
|
||||||
};
|
};
|
||||||
} // namespace blitz
|
} // namespace blitz
|
||||||
|
|
||||||
/*
|
|
||||||
#include <fstream>
|
|
||||||
#include <map>
|
|
||||||
#include <memory>
|
|
||||||
#include <stack>
|
|
||||||
#include <string>
|
|
||||||
#include "ast/value.hpp"
|
|
||||||
#include "lexer.hpp"
|
|
||||||
|
|
||||||
namespace blitz {
|
|
||||||
class parser {
|
|
||||||
public:
|
|
||||||
parser(std::string file);
|
|
||||||
~parser();
|
|
||||||
|
|
||||||
std::unique_ptr<ast::expression> parse();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void log(const char* msg, ...);
|
|
||||||
void log_error(const char* msg, ...);
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::pair<blitz::lexer::tokentype, std::string> next();
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::unique_ptr<ast::expression> parse_expression();
|
|
||||||
std::unique_ptr<ast::NumberExpression> parse_number(blitz::lexer::tokentype token, std::string value);
|
|
||||||
std::unique_ptr<ast::DecimalExpression> parse_decimal(blitz::lexer::tokentype token, std::string value);
|
|
||||||
|
|
||||||
private:
|
|
||||||
lexer m_lexer;
|
|
||||||
std::stack<std::pair<std::string, std::shared_ptr<std::istream>>> m_files;
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|||||||
Reference in New Issue
Block a user