feat: Implement compiler and virtual machine for Fig language
- Added Compiler class with methods for compiling programs, statements, and expressions. - Introduced Proto structure to hold compiled bytecode and constants. - Implemented expression compilation including literals, identifiers, and infix expressions. - Developed statement compilation for variable declarations and expression statements. - Created a VM class to execute compiled bytecode with support for arithmetic and comparison operations. - Added Object and Value classes for handling different data types and memory management. - Implemented String and Struct objects for enhanced data representation. - Established a parser for parsing variable declarations and statements. - Included tests for the VM and object representations.
This commit is contained in:
@@ -14,4 +14,5 @@
|
|||||||
#include <Ast/Expr/LiteralExpr.hpp>
|
#include <Ast/Expr/LiteralExpr.hpp>
|
||||||
#include <Ast/Expr/PrefixExpr.hpp>
|
#include <Ast/Expr/PrefixExpr.hpp>
|
||||||
|
|
||||||
|
#include <Ast/Stmt/ExprStmt.hpp>
|
||||||
#include <Ast/Stmt/VarDecl.hpp>
|
#include <Ast/Stmt/VarDecl.hpp>
|
||||||
@@ -16,29 +16,33 @@ namespace Fig
|
|||||||
enum class AstType : std::uint8_t
|
enum class AstType : std::uint8_t
|
||||||
{
|
{
|
||||||
AstNode, // 基类
|
AstNode, // 基类
|
||||||
|
Program, // 程序
|
||||||
Expr, // 表达式
|
Expr, // 表达式
|
||||||
Stmt, // 语句
|
Stmt, // 语句
|
||||||
|
|
||||||
/* Expressions */
|
/* Expressions */
|
||||||
IdentiExpr, // 标识符表达式
|
IdentiExpr, // 标识符表达式
|
||||||
LiteralExpr, // 字面量表达式
|
LiteralExpr, // 字面量表达式
|
||||||
PrefixExpr, // 一元 前缀表达式
|
PrefixExpr, // 一元 前缀表达式
|
||||||
InfixExpr, // 二元 中缀表达式
|
InfixExpr, // 二元 中缀表达式
|
||||||
|
|
||||||
IndexExpr, // 后缀表达式,索引
|
IndexExpr, // 后缀表达式,索引
|
||||||
CallExpr, // 后缀表达式,函数调用
|
CallExpr, // 后缀表达式,函数调用
|
||||||
|
|
||||||
/* Statements */
|
/* Statements */
|
||||||
VarDecl,
|
ExprStmt, // 表达式语句,如 println(1)
|
||||||
|
VarDecl, // 变量声明
|
||||||
};
|
};
|
||||||
struct AstNode
|
struct AstNode
|
||||||
{
|
{
|
||||||
AstType type = AstType::AstNode;
|
AstType type = AstType::AstNode;
|
||||||
SourceLocation location;
|
SourceLocation location;
|
||||||
|
|
||||||
virtual String toString() const = 0;
|
virtual String toString() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Program;
|
||||||
|
|
||||||
struct Expr : public AstNode
|
struct Expr : public AstNode
|
||||||
{
|
{
|
||||||
Expr()
|
Expr()
|
||||||
@@ -55,6 +59,31 @@ namespace Fig
|
|||||||
type = AstType::Stmt;
|
type = AstType::Stmt;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Program final : public AstNode
|
||||||
|
{
|
||||||
|
DynArray<Stmt *> nodes;
|
||||||
|
|
||||||
|
Program()
|
||||||
|
{
|
||||||
|
type = AstType::Program;
|
||||||
|
}
|
||||||
|
|
||||||
|
Program(DynArray<Stmt *> _nodes)
|
||||||
|
{
|
||||||
|
type = AstType::Program;
|
||||||
|
nodes = std::move(_nodes);
|
||||||
|
if (!_nodes.empty())
|
||||||
|
{
|
||||||
|
location = std::move(_nodes.back()->location);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual String toString() const override
|
||||||
|
{
|
||||||
|
return "Program";
|
||||||
|
}
|
||||||
|
};
|
||||||
}; // namespace Fig
|
}; // namespace Fig
|
||||||
|
|
||||||
namespace std
|
namespace std
|
||||||
@@ -73,4 +102,4 @@ namespace std
|
|||||||
return std::format_to(ctx.out(), "{}", _node->toString().toStdString());
|
return std::format_to(ctx.out(), "{}", _node->toString().toStdString());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
}; // namespace std
|
||||||
@@ -20,6 +20,8 @@ namespace Fig
|
|||||||
Negate, // 取反 -
|
Negate, // 取反 -
|
||||||
Not, // 逻辑非 ! / not
|
Not, // 逻辑非 ! / not
|
||||||
AddressOf, // 取引用 &
|
AddressOf, // 取引用 &
|
||||||
|
|
||||||
|
Count // 哨兵,(int) Count 获得运算符数量(注意,enum必须从 0 开始且不中断)
|
||||||
};
|
};
|
||||||
enum class BinaryOperator : std::uint8_t
|
enum class BinaryOperator : std::uint8_t
|
||||||
{
|
{
|
||||||
@@ -43,13 +45,13 @@ namespace Fig
|
|||||||
|
|
||||||
Power, // 幂运算 **
|
Power, // 幂运算 **
|
||||||
|
|
||||||
Assign, // 赋值(修改) =
|
Assign, // 赋值(修改) =
|
||||||
AddAssign, // +=
|
AddAssign, // +=
|
||||||
SubAssign, // -=
|
SubAssign, // -=
|
||||||
MultiplyAssign, // *=
|
MultiplyAssign, // *=
|
||||||
DivideAssign, // /=
|
DivideAssign, // /=
|
||||||
ModuloAssign, // %=
|
ModuloAssign, // %=
|
||||||
BitXorAssign, // ^=
|
BitXorAssign, // ^=
|
||||||
|
|
||||||
// 位运算
|
// 位运算
|
||||||
BitAnd, // 按位与 &
|
BitAnd, // 按位与 &
|
||||||
@@ -60,14 +62,22 @@ namespace Fig
|
|||||||
|
|
||||||
// 成员访问
|
// 成员访问
|
||||||
MemberAccess, // .
|
MemberAccess, // .
|
||||||
|
|
||||||
|
Count // 哨兵,(int) Count 获得运算符数量(注意,enum必须从 0 开始且不中断)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
constexpr unsigned int GetOperatorsSize()
|
||||||
|
{
|
||||||
|
// 获取全部运算符的数量
|
||||||
|
return static_cast<std::uint8_t>(UnaryOperator::Count) + static_cast<std::uint8_t>(BinaryOperator::Count);
|
||||||
|
}
|
||||||
|
|
||||||
using BindingPower = unsigned int;
|
using BindingPower = unsigned int;
|
||||||
|
|
||||||
HashMap<TokenType, UnaryOperator> &GetUnaryOpMap();
|
HashMap<TokenType, UnaryOperator> &GetUnaryOpMap();
|
||||||
HashMap<TokenType, BinaryOperator> &GetBinaryOpMap();
|
HashMap<TokenType, BinaryOperator> &GetBinaryOpMap();
|
||||||
|
|
||||||
HashMap<UnaryOperator, BindingPower> &GetUnaryOpBindingPowerMap();
|
HashMap<UnaryOperator, BindingPower> &GetUnaryOpBindingPowerMap();
|
||||||
HashMap<BinaryOperator, BindingPower> &GetBinaryOpBindingPowerMap();
|
HashMap<BinaryOperator, BindingPower> &GetBinaryOpBindingPowerMap();
|
||||||
|
|
||||||
BindingPower GetUnaryOpRBp(UnaryOperator);
|
BindingPower GetUnaryOpRBp(UnaryOperator);
|
||||||
@@ -77,6 +87,6 @@ namespace Fig
|
|||||||
|
|
||||||
bool IsTokenOp(TokenType type, bool binary = true);
|
bool IsTokenOp(TokenType type, bool binary = true);
|
||||||
|
|
||||||
UnaryOperator TokenToUnaryOp(const Token &);
|
UnaryOperator TokenToUnaryOp(const Token &);
|
||||||
BinaryOperator TokenToBinaryOp(const Token &);
|
BinaryOperator TokenToBinaryOp(const Token &);
|
||||||
}; // namespace Fig
|
}; // namespace Fig
|
||||||
35
src/Ast/Stmt/ExprStmt.hpp
Normal file
35
src/Ast/Stmt/ExprStmt.hpp
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
/*!
|
||||||
|
@file src/Ast/Stmt/ExprStmt.hpp
|
||||||
|
@brief ExprStmt定义
|
||||||
|
@author PuqiAR (im@puqiar.top)
|
||||||
|
@date 2026-02-19
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Ast/Base.hpp>
|
||||||
|
|
||||||
|
namespace Fig
|
||||||
|
{
|
||||||
|
struct ExprStmt final : public Stmt
|
||||||
|
{
|
||||||
|
Expr *expr;
|
||||||
|
|
||||||
|
ExprStmt()
|
||||||
|
{
|
||||||
|
type = AstType::ExprStmt;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExprStmt(Expr *_expr) :
|
||||||
|
expr(_expr)
|
||||||
|
{
|
||||||
|
type = AstType::ExprStmt;
|
||||||
|
location = _expr->location;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual String toString() const override
|
||||||
|
{
|
||||||
|
return std::format("<ExprStmt: {}>", expr->toString());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -23,12 +23,13 @@ namespace Fig
|
|||||||
type = AstType::VarDecl;
|
type = AstType::VarDecl;
|
||||||
}
|
}
|
||||||
|
|
||||||
VarDecl(String _name, Expr *_typeSpecifier, Expr *_initExpr, SourceLocation _location) :
|
VarDecl(bool _isPublic, String _name, Expr *_typeSpecifier, Expr *_initExpr, SourceLocation _location) :
|
||||||
name(std::move(_name)),
|
name(std::move(_name)),
|
||||||
typeSpecifier(_typeSpecifier),
|
typeSpecifier(_typeSpecifier),
|
||||||
initExpr(_initExpr) // location 指向关键字 var/const位置
|
initExpr(_initExpr) // location 指向关键字 var/const位置
|
||||||
{
|
{
|
||||||
type = AstType::VarDecl;
|
type = AstType::VarDecl;
|
||||||
|
isPublic = _isPublic;
|
||||||
location = std::move(_location);
|
location = std::move(_location);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,28 +2,60 @@
|
|||||||
@file src/Bytecode/Bytecode.hpp
|
@file src/Bytecode/Bytecode.hpp
|
||||||
@brief 字节码Bytecode定义
|
@brief 字节码Bytecode定义
|
||||||
@author PuqiAR (im@puqiar.top)
|
@author PuqiAR (im@puqiar.top)
|
||||||
@date 2026-02-17
|
@date 2026-02-18
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
namespace Fig
|
namespace Fig
|
||||||
{
|
{
|
||||||
using OpCodeType = uint8_t;
|
|
||||||
|
|
||||||
enum class OpCode : OpCodeType
|
// 定长 32-bit
|
||||||
|
using Instruction = std::uint32_t;
|
||||||
|
|
||||||
|
enum class OpCode : std::uint8_t
|
||||||
{
|
{
|
||||||
LoadConst, // dst, const id
|
Exit, // 结束运行
|
||||||
LoadLocal, // dst, slot id
|
LoadK, // iABx 模式: R[A] = Constants[Bx]
|
||||||
StoreLocal, // slot, src(reg)
|
Return, // iA 模式: 返回 R[A] 的值
|
||||||
|
|
||||||
LoadLocalRef, // dst, slot
|
Mov, // iABx: R[A] = R[Bx]
|
||||||
LoadRef, // dst, refReg
|
Add, // iABC: R[A] = R[B] + R[C]
|
||||||
StoreRef, // refReg, srcReg
|
Sub, // iABC: R[A] = R[B] - R[C]
|
||||||
|
Mul, // iABC: R[A] = R[B] * R[C]
|
||||||
|
Div, // iABC: R[A] = R[B] / R[C]
|
||||||
|
Mod, // iABC: R[A] = R[B] % R[C]
|
||||||
|
BitXor, // iABC: R[A] = R[B] ^ R[C]
|
||||||
|
|
||||||
Add, // dst, a, b
|
Equal, // iABC: R[A] = R[B] == R[C]
|
||||||
Move, // dst, src
|
NotEqual, // iABC: R[A] = R[B] != R[C]
|
||||||
|
Greater, // iABC: R[A] = R[B] > R[C]
|
||||||
|
Less, // iABC: R[A] = R[B] < R[C]
|
||||||
|
GreaterEqual, // iABC: R[A] = R[B] >= R[C]
|
||||||
|
LessEqual, // iABC: R[A] = R[B] <= R[C]
|
||||||
|
|
||||||
|
Count, // 哨兵
|
||||||
};
|
};
|
||||||
}; // namespace Fig
|
|
||||||
|
namespace Op
|
||||||
|
{
|
||||||
|
// [OpCode: 8] [A: 8] [Bx: 16]
|
||||||
|
[[nodiscard]] inline constexpr Instruction iABx(OpCode op, std::uint8_t a, std::uint16_t bx)
|
||||||
|
{
|
||||||
|
return static_cast<std::uint32_t>(op) | (static_cast<std::uint32_t>(a) << 8)
|
||||||
|
| (static_cast<std::uint32_t>(bx) << 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
// [OpCode: 8] [A: 8] [B: 8] [C: 8]
|
||||||
|
[[nodiscard]] inline constexpr Instruction iABC(OpCode op, std::uint8_t a, std::uint8_t b, std::uint8_t c)
|
||||||
|
{
|
||||||
|
return static_cast<std::uint32_t>(op) | (static_cast<std::uint32_t>(a) << 8)
|
||||||
|
| (static_cast<std::uint32_t>(b) << 16) | (static_cast<std::uint32_t>(c) << 24);
|
||||||
|
}
|
||||||
|
} // namespace Op
|
||||||
|
} // namespace Fig
|
||||||
58
src/Compiler/CompileTest.cpp
Normal file
58
src/Compiler/CompileTest.cpp
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
#include <Lexer/Lexer.hpp>
|
||||||
|
#include <Parser/Parser.hpp>
|
||||||
|
#include <Deps/Deps.hpp>
|
||||||
|
#include <Core/Core.hpp>
|
||||||
|
#include <SourceManager/SourceManager.hpp>
|
||||||
|
#include <Compiler/Compiler.hpp>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <print>
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
using namespace Fig;
|
||||||
|
|
||||||
|
String fileName = "test.fig";
|
||||||
|
String filePath = "T:/Files/Maker/Code/MyCodingLanguage/The Fig Project/Fig/test.fig";
|
||||||
|
|
||||||
|
SourceManager manager(filePath);
|
||||||
|
manager.Read();
|
||||||
|
|
||||||
|
if (!manager.read)
|
||||||
|
{
|
||||||
|
std::cerr << "Couldn't read file";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Lexer lexer(manager.GetSource(), fileName);
|
||||||
|
Parser parser(lexer, manager, fileName);
|
||||||
|
|
||||||
|
const auto &program_result = parser.Parse();
|
||||||
|
if (!program_result)
|
||||||
|
{
|
||||||
|
ReportError(program_result.error(), manager);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
Program *program = *program_result;
|
||||||
|
|
||||||
|
Compiler compiler(fileName, manager);
|
||||||
|
const auto &proto_result = compiler.Compile(program);
|
||||||
|
if (!proto_result)
|
||||||
|
{
|
||||||
|
ReportError(proto_result.error(), manager);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Proto *proto = *proto_result;
|
||||||
|
|
||||||
|
std::cout << "=== Constant Pool ===" << '\n';
|
||||||
|
for (size_t i = 0; i < proto->constants.size(); ++i)
|
||||||
|
{
|
||||||
|
std::print("[{}] {}\n", i, proto->constants[i].ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
DumpCode(proto->code);
|
||||||
|
|
||||||
|
std::cout << "\nMax Stack Size: " << (int) proto->maxStack << std::endl;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
28
src/Compiler/Compiler.cpp
Normal file
28
src/Compiler/Compiler.cpp
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
/*!
|
||||||
|
@file src/Compiler/Compiler.cpp
|
||||||
|
@brief 编译器实现
|
||||||
|
@author PuqiAR (im@puqiar.top)
|
||||||
|
@date 2026-02-18
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Compiler/Compiler.hpp>
|
||||||
|
|
||||||
|
namespace Fig
|
||||||
|
{
|
||||||
|
Result<Proto *, Error> Compiler::Compile(Program *program)
|
||||||
|
{
|
||||||
|
current->proto = new Proto();
|
||||||
|
current->freeReg = 0;
|
||||||
|
|
||||||
|
for (Stmt *stmt : program->nodes)
|
||||||
|
{
|
||||||
|
const auto &result = CompileStmt(static_cast<Stmt *>(stmt));
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
return std::unexpected(result.error());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Emit(Op::iABC(OpCode::Exit, 0, 0, 0)); // 一定要退出,这是虚拟机退出信号,否则ub
|
||||||
|
return current->proto;
|
||||||
|
}
|
||||||
|
}; // namespace Fig
|
||||||
305
src/Compiler/Compiler.hpp
Normal file
305
src/Compiler/Compiler.hpp
Normal file
@@ -0,0 +1,305 @@
|
|||||||
|
/*!
|
||||||
|
@file src/Compiler/Compiler.hpp
|
||||||
|
@brief 编译器定义
|
||||||
|
@author PuqiAR (im@puqiar.top)
|
||||||
|
@date 2026-02-19
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Ast/Ast.hpp>
|
||||||
|
#include <Bytecode/Bytecode.hpp>
|
||||||
|
#include <Deps/Deps.hpp>
|
||||||
|
#include <Error/Error.hpp>
|
||||||
|
#include <Object/Object.hpp>
|
||||||
|
#include <SourceManager/SourceManager.hpp>
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
namespace Fig
|
||||||
|
{
|
||||||
|
// 编译产物
|
||||||
|
struct Proto
|
||||||
|
{
|
||||||
|
DynArray<Instruction> code;
|
||||||
|
DynArray<Value> constants;
|
||||||
|
std::uint8_t maxStack = 0; // 函数运行所需寄存器数量
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LocalVar
|
||||||
|
{
|
||||||
|
bool isPublic; // 是否向上级/同级其他域公开
|
||||||
|
String name;
|
||||||
|
std::uint8_t reg; // 寄存器(相对 frame base 的寄存器 id)
|
||||||
|
int depth; // 作用域深度
|
||||||
|
};
|
||||||
|
|
||||||
|
// 任何跨函数、跨模块的编译,都压入弹出这个 State
|
||||||
|
struct FuncState
|
||||||
|
{
|
||||||
|
String name;
|
||||||
|
FuncState *enclosing = nullptr; // 指向外层状态 (支持闭包)
|
||||||
|
Proto *proto = nullptr;
|
||||||
|
|
||||||
|
std::uint8_t freeReg = 0;
|
||||||
|
int scopeDepth = 0;
|
||||||
|
DynArray<LocalVar> locals;
|
||||||
|
|
||||||
|
FuncState(String _name, FuncState *enc = nullptr) : name(std::move(_name)), enclosing(enc)
|
||||||
|
{
|
||||||
|
proto = new Proto();
|
||||||
|
}
|
||||||
|
// 注意:这里不 delete proto,因为 proto 是要作为编译产物吐出去的
|
||||||
|
};
|
||||||
|
|
||||||
|
class Compiler
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
String fileName;
|
||||||
|
|
||||||
|
SourceManager &manager;
|
||||||
|
FuncState *current = nullptr; // 永远指向当前正在编译的上下文
|
||||||
|
public:
|
||||||
|
Compiler(String _fileName, SourceManager &_manager) : fileName(std::move(_fileName)), manager(_manager)
|
||||||
|
{
|
||||||
|
// 初始化顶级作用域
|
||||||
|
current = new FuncState("global", nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
~Compiler()
|
||||||
|
{
|
||||||
|
// 内存清理 (如果有异常中断)
|
||||||
|
while (current != nullptr)
|
||||||
|
{
|
||||||
|
FuncState *prev = current->enclosing;
|
||||||
|
delete current;
|
||||||
|
current = prev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<Proto *, Error> Compile(Program *program);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void PushState(String _name)
|
||||||
|
{
|
||||||
|
current = new FuncState(std::move(_name));
|
||||||
|
}
|
||||||
|
|
||||||
|
Proto *PopState()
|
||||||
|
{
|
||||||
|
FuncState *oldState = current;
|
||||||
|
Proto *finishedProto = oldState->proto;
|
||||||
|
|
||||||
|
current = oldState->enclosing;
|
||||||
|
delete oldState;
|
||||||
|
|
||||||
|
return finishedProto;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uint8_t AllocReg()
|
||||||
|
{
|
||||||
|
if (current->freeReg >= 250)
|
||||||
|
{
|
||||||
|
assert(false && "Register overflow!");
|
||||||
|
}
|
||||||
|
std::uint8_t reg = current->freeReg++;
|
||||||
|
if (current->freeReg > current->proto->maxStack)
|
||||||
|
{
|
||||||
|
current->proto->maxStack = current->freeReg;
|
||||||
|
}
|
||||||
|
return reg;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FreeReg(std::uint8_t reg)
|
||||||
|
{
|
||||||
|
// 如果这个寄存器被局部变量使用,不释放直接 Return
|
||||||
|
for (const auto &local : current->locals)
|
||||||
|
{
|
||||||
|
if (local.reg == reg)
|
||||||
|
{
|
||||||
|
return; // 拒绝释放,保护局部变量生命周期
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果它是纯粹的临时计算结果),释放
|
||||||
|
if (reg == current->freeReg - 1)
|
||||||
|
{
|
||||||
|
current->freeReg--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void Emit(Instruction inst)
|
||||||
|
{
|
||||||
|
current->proto->code.push_back(inst);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uint16_t AddConstant(Value v)
|
||||||
|
{
|
||||||
|
// TODO: 查重
|
||||||
|
current->proto->constants.push_back(v);
|
||||||
|
return static_cast<std::uint16_t>(current->proto->constants.size() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BeginScope()
|
||||||
|
{
|
||||||
|
current->scopeDepth++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EndScope()
|
||||||
|
{
|
||||||
|
current->scopeDepth--;
|
||||||
|
while (!current->locals.empty() && current->locals.back().depth > current->scopeDepth)
|
||||||
|
{
|
||||||
|
FreeReg(current->locals.back().reg);
|
||||||
|
current->locals.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HasLocalInCurrentScope(const String &name)
|
||||||
|
{
|
||||||
|
// 逆向查重
|
||||||
|
for (auto it = current->locals.rbegin(); it != current->locals.rend(); ++it)
|
||||||
|
{
|
||||||
|
if (it->depth < current->scopeDepth)
|
||||||
|
break; // 已经超出了当前深度,提前阻断
|
||||||
|
if (it->name == name)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HasLocal(const String &name)
|
||||||
|
{
|
||||||
|
for (auto it = current->locals.rbegin(); it != current->locals.rend(); ++it)
|
||||||
|
{
|
||||||
|
if (it->name == name)
|
||||||
|
{
|
||||||
|
if (it->depth == current->scopeDepth)
|
||||||
|
{
|
||||||
|
return true; // 同级不管 public直接捕获
|
||||||
|
}
|
||||||
|
else if (it->isPublic)
|
||||||
|
{
|
||||||
|
return true; // 不同级变量 public才能被捕捉
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uint8_t ResolveLocal(const String &name)
|
||||||
|
{
|
||||||
|
// 变量遮蔽: 永远先使用同级已有的变量, 所以逆向遍历
|
||||||
|
for (auto it = current->locals.rbegin(); it != current->locals.rend(); ++it)
|
||||||
|
{
|
||||||
|
if (it->name == name)
|
||||||
|
{
|
||||||
|
if (it->depth < current->scopeDepth && !it->isPublic)
|
||||||
|
{
|
||||||
|
assert(false && "ResolveLocal: Attempt to access a private variable from an outer scope!");
|
||||||
|
}
|
||||||
|
|
||||||
|
return it->reg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果在本 Frame 没找到,那就是外层函数的变量 (闭包 Upvalue) 或者全局变量 (Global)。
|
||||||
|
assert(false && "ResolveLocal: Variable not found in current frame (Upvalue/Global not implemented yet)!");
|
||||||
|
return UINT8_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uint8_t DeclareLocal(bool isPublic, const String &name)
|
||||||
|
{
|
||||||
|
std::uint8_t reg = AllocReg();
|
||||||
|
current->locals.push_back(LocalVar{isPublic, name, reg, current->scopeDepth});
|
||||||
|
return reg;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uint8_t DeclareLocal(bool isPublic, const String &name, std::uint8_t reg)
|
||||||
|
{
|
||||||
|
current->locals.push_back(LocalVar{isPublic, name, reg, current->scopeDepth});
|
||||||
|
return reg;
|
||||||
|
}
|
||||||
|
|
||||||
|
SourceLocation makeSourceLocation(AstNode *node)
|
||||||
|
{
|
||||||
|
SourceLocation location = node->location; // copy
|
||||||
|
location.functionName = current->name;
|
||||||
|
location.fileName = fileName;
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result<std::uint8_t, Error> CompileIdentiExpr(IdentiExpr *);
|
||||||
|
Result<std::uint8_t, Error> CompileLiteral(LiteralExpr *);
|
||||||
|
|
||||||
|
Result<std::uint8_t, Error> CompileAssignment(InfixExpr *); // 编译赋值,由 CompileInfixExpr调用
|
||||||
|
Result<std::uint8_t, Error> CompileInfixExpr(InfixExpr *);
|
||||||
|
|
||||||
|
Result<std::uint8_t, Error> CompileLeftValue(Expr *); // 左值对象,可以是变量、结构体字段或模块对象
|
||||||
|
|
||||||
|
Result<std::uint8_t, Error> CompileExpr(Expr *);
|
||||||
|
|
||||||
|
Result<void, Error> CompileVarDecl(VarDecl *);
|
||||||
|
Result<void, Error> CompileStmt(Stmt *);
|
||||||
|
};
|
||||||
|
|
||||||
|
inline void DisassembleInstruction(Instruction inst, std::size_t index)
|
||||||
|
{
|
||||||
|
// 提取OpCode (低 8 位)
|
||||||
|
auto op = static_cast<OpCode>(inst & 0xFF);
|
||||||
|
|
||||||
|
std::string_view opName = magic_enum::enum_name(op);
|
||||||
|
|
||||||
|
// 所有指令至少都有 A 操作数 (8~15 位)
|
||||||
|
std::uint8_t a = (inst >> 8) & 0xFF;
|
||||||
|
|
||||||
|
// 地址补零,指令名左对齐占 10 字符
|
||||||
|
std::cout << std::format("{:04d} {:<10} ", index, opName);
|
||||||
|
|
||||||
|
switch (op)
|
||||||
|
{
|
||||||
|
case OpCode::Mov: {
|
||||||
|
// iABx 模式
|
||||||
|
std::uint16_t bx = (inst >> 16) & 0xFFFF;
|
||||||
|
std::cout << std::format("R{:<3} R[{}]", a, bx);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case OpCode::LoadK: {
|
||||||
|
// iABx 模式:解析 Bx (16~31 位)
|
||||||
|
std::uint16_t bx = (inst >> 16) & 0xFFFF;
|
||||||
|
std::cout << std::format("R{:<3} K[{}]", a, bx);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case OpCode::Add:
|
||||||
|
case OpCode::Sub:
|
||||||
|
case OpCode::Mul:
|
||||||
|
case OpCode::Div:
|
||||||
|
case OpCode::Mod: {
|
||||||
|
// iABC 模式:解析 B (16~23 位) 和 C (24~31 位)
|
||||||
|
std::uint8_t b = (inst >> 16) & 0xFF;
|
||||||
|
std::uint8_t c = (inst >> 24) & 0xFF;
|
||||||
|
std::cout << std::format("R{:<3} R{:<3} R{}", a, b, c);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case OpCode::Return: {
|
||||||
|
// iA 模式:只用到了 A
|
||||||
|
std::cout << std::format("R{}", a);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
std::cout << "?";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::cout << '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void DumpCode(const DynArray<Instruction> &code)
|
||||||
|
{
|
||||||
|
std::cout << "=== Bytecode ===\n";
|
||||||
|
for (std::size_t i = 0; i < code.size(); ++i)
|
||||||
|
{
|
||||||
|
DisassembleInstruction(code[i], i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}; // namespace Fig
|
||||||
215
src/Compiler/ExprCompiler.cpp
Normal file
215
src/Compiler/ExprCompiler.cpp
Normal file
@@ -0,0 +1,215 @@
|
|||||||
|
/*!
|
||||||
|
@file src/Compiler/ExprCompiler.cpp
|
||||||
|
@brief 编译器实现(表达式部分)
|
||||||
|
@author PuqiAR (im@puqiar.top)
|
||||||
|
@date 2026-02-19
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Compiler/Compiler.hpp>
|
||||||
|
|
||||||
|
namespace Fig
|
||||||
|
{
|
||||||
|
Result<std::uint8_t, Error> Compiler::CompileIdentiExpr(IdentiExpr *ie)
|
||||||
|
{
|
||||||
|
if (!HasLocal(ie->name))
|
||||||
|
{
|
||||||
|
return std::unexpected(Error(ErrorType::UseUndeclaredIdentifier,
|
||||||
|
std::format("`{}` has not been defined", ie->name),
|
||||||
|
"none",
|
||||||
|
makeSourceLocation(ie)));
|
||||||
|
}
|
||||||
|
return ResolveLocal(ie->name);
|
||||||
|
}
|
||||||
|
Result<std::uint8_t, Error> Compiler::CompileLiteral(LiteralExpr *lit) // 编译字面量, 负责转换 token -> Value
|
||||||
|
{
|
||||||
|
const Token &token = lit->token;
|
||||||
|
String lexeme = manager.GetSub(token.index, token.length);
|
||||||
|
|
||||||
|
if (!token.isLiteral())
|
||||||
|
{
|
||||||
|
assert(false && "CompileLiteral: token is not literal");
|
||||||
|
}
|
||||||
|
|
||||||
|
Value v;
|
||||||
|
|
||||||
|
if (token.type == TokenType::LiteralNull)
|
||||||
|
{
|
||||||
|
v = Value::GetNullInstance();
|
||||||
|
}
|
||||||
|
else if (token.type == TokenType::LiteralTrue)
|
||||||
|
{
|
||||||
|
v = Value::GetTrueInstance();
|
||||||
|
}
|
||||||
|
else if (token.type == TokenType::LiteralFalse)
|
||||||
|
{
|
||||||
|
v = Value::GetFalseInstance();
|
||||||
|
}
|
||||||
|
else if (token.type == TokenType::LiteralNumber)
|
||||||
|
{
|
||||||
|
// TODO: 更换为无异常手写数字解析版本
|
||||||
|
if (lexeme.contains(U'.'))
|
||||||
|
{
|
||||||
|
// 非整数
|
||||||
|
double d = std::stod(lexeme.toStdString());
|
||||||
|
v = Value::FromDouble(d);
|
||||||
|
}
|
||||||
|
std::int32_t i = std::stoi(lexeme.toStdString());
|
||||||
|
v = Value::FromInt(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert("false" && "CompileLiteral: unsupport literal");
|
||||||
|
v = Value::GetNullInstance();
|
||||||
|
|
||||||
|
std::uint8_t targetReg = AllocReg();
|
||||||
|
std::uint16_t kIndex = AddConstant(v);
|
||||||
|
|
||||||
|
Emit(Op::iABx(OpCode::LoadK, targetReg, kIndex));
|
||||||
|
return targetReg;
|
||||||
|
}
|
||||||
|
Result<std::uint8_t, Error> Compiler::CompileAssignment(InfixExpr *infix) // 编译赋值,由 CompileInfixExpr调用
|
||||||
|
{
|
||||||
|
// op必须为 =
|
||||||
|
const auto &_lhsReg = CompileLeftValue(infix->left); // 必须为左值对象
|
||||||
|
if (!_lhsReg)
|
||||||
|
{
|
||||||
|
return _lhsReg;
|
||||||
|
}
|
||||||
|
std::uint8_t lhsReg = *_lhsReg;
|
||||||
|
|
||||||
|
const auto &_rhsReg = CompileExpr(infix->right);
|
||||||
|
std::uint8_t rhsReg = *_rhsReg;
|
||||||
|
|
||||||
|
FreeReg(rhsReg);
|
||||||
|
switch (infix->op)
|
||||||
|
{
|
||||||
|
case BinaryOperator::Assign: {
|
||||||
|
Emit(Op::iABx(OpCode::Mov, lhsReg, rhsReg)); // lhsReg = rhsReg
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BinaryOperator::AddAssign: {
|
||||||
|
Emit(Op::iABC(OpCode::Add, lhsReg, lhsReg, rhsReg)); // lhsReg = lhsReg + rhsReg
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BinaryOperator::SubAssign: {
|
||||||
|
Emit(Op::iABC(OpCode::Sub, lhsReg, lhsReg, rhsReg)); // lhsReg = lhsReg - rhsReg
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BinaryOperator::MultiplyAssign: {
|
||||||
|
Emit(Op::iABC(OpCode::Mul, lhsReg, lhsReg, rhsReg)); // lhsReg = lhsReg * rhsReg
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BinaryOperator::DivideAssign: {
|
||||||
|
Emit(Op::iABC(OpCode::Div, lhsReg, lhsReg, rhsReg)); // lhsReg = lhsReg / rhsReg
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BinaryOperator::ModuloAssign: {
|
||||||
|
Emit(Op::iABC(OpCode::Mod, lhsReg, lhsReg, rhsReg)); // lhsReg = lhsReg % rhsReg
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BinaryOperator::BitXorAssign: {
|
||||||
|
Emit(Op::iABC(OpCode::BitXor, lhsReg, lhsReg, rhsReg)); // lhsReg = lhsReg ^ rhsReg
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
assert(false && "CompileAssignment: op unsupported yet");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lhsReg; // 返回赋值的结果,支持连续赋值
|
||||||
|
}
|
||||||
|
Result<std::uint8_t, Error> Compiler::CompileInfixExpr(
|
||||||
|
InfixExpr *infix) // 编译中缀表达式,返回一个存放结果的寄存器 ID
|
||||||
|
{
|
||||||
|
if (infix->op >= BinaryOperator::Assign && infix->op <= BinaryOperator::BitXorAssign)
|
||||||
|
{
|
||||||
|
return CompileAssignment(infix);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto &_lhsReg = CompileExpr(infix->left);
|
||||||
|
if (!_lhsReg)
|
||||||
|
{
|
||||||
|
return _lhsReg;
|
||||||
|
}
|
||||||
|
std::uint8_t lhsReg = *_lhsReg;
|
||||||
|
const auto &_rhsReg = CompileExpr(infix->right);
|
||||||
|
if (!_rhsReg)
|
||||||
|
{
|
||||||
|
return _rhsReg;
|
||||||
|
}
|
||||||
|
std::uint8_t rhsReg = *_rhsReg;
|
||||||
|
|
||||||
|
FreeReg(rhsReg);
|
||||||
|
FreeReg(lhsReg);
|
||||||
|
|
||||||
|
std::uint8_t resultReg = AllocReg();
|
||||||
|
switch (infix->op)
|
||||||
|
{
|
||||||
|
case BinaryOperator::Add: {
|
||||||
|
Emit(Op::iABC(OpCode::Add, resultReg, lhsReg, rhsReg));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case BinaryOperator::Subtract: {
|
||||||
|
Emit(Op::iABC(OpCode::Sub, resultReg, lhsReg, rhsReg));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case BinaryOperator::Multiply: {
|
||||||
|
Emit(Op::iABC(OpCode::Mul, resultReg, lhsReg, rhsReg));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case BinaryOperator::Divide: {
|
||||||
|
Emit(Op::iABC(OpCode::Div, resultReg, lhsReg, rhsReg));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case BinaryOperator::Modulo: {
|
||||||
|
Emit(Op::iABC(OpCode::Mod, resultReg, lhsReg, rhsReg));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default: assert(false && "CompileInfixExpr: op unsupported yet");
|
||||||
|
}
|
||||||
|
return resultReg;
|
||||||
|
}
|
||||||
|
Result<std::uint8_t, Error> Compiler::CompileLeftValue(Expr *expr) // 左值对象,可以是变量、结构体字段或模块对象
|
||||||
|
{
|
||||||
|
switch (expr->type)
|
||||||
|
{
|
||||||
|
case AstType::IdentiExpr: return CompileIdentiExpr(static_cast<IdentiExpr *>(expr));
|
||||||
|
|
||||||
|
default:
|
||||||
|
return std::unexpected(Error(ErrorType::NotAnLvalue,
|
||||||
|
std::format("`{}` is not a lvalue, expect a valid lvalue", expr->toString()),
|
||||||
|
"none",
|
||||||
|
makeSourceLocation(expr)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Result<std::uint8_t, Error> Compiler::CompileExpr(Expr *expr) // 编译表达式,必定返回一个存放结果的寄存器 ID
|
||||||
|
{
|
||||||
|
switch (expr->type)
|
||||||
|
{
|
||||||
|
case AstType::Stmt:
|
||||||
|
case AstType::Expr:
|
||||||
|
case AstType::AstNode: assert(false && "CompileExpr: bad node type"); break;
|
||||||
|
|
||||||
|
case AstType::IdentiExpr: {
|
||||||
|
return CompileLeftValue(expr); // 左值直接转换成右值
|
||||||
|
}
|
||||||
|
case AstType::LiteralExpr: {
|
||||||
|
LiteralExpr *lit = static_cast<LiteralExpr *>(expr);
|
||||||
|
|
||||||
|
const auto &result = CompileLiteral(lit);
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
return std::unexpected(result.error());
|
||||||
|
}
|
||||||
|
std::uint8_t targetReg = *result;
|
||||||
|
return targetReg;
|
||||||
|
}
|
||||||
|
case AstType::InfixExpr: {
|
||||||
|
return CompileInfixExpr(static_cast<InfixExpr *>(expr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace Fig
|
||||||
58
src/Compiler/StmtCompiler.cpp
Normal file
58
src/Compiler/StmtCompiler.cpp
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
/*!
|
||||||
|
@file src/Compiler/StmtCompiler.cpp
|
||||||
|
@brief 编译器实现(语句部分)
|
||||||
|
@author PuqiAR (im@puqiar.top)
|
||||||
|
@date 2026-02-19
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Compiler/Compiler.hpp>
|
||||||
|
|
||||||
|
namespace Fig
|
||||||
|
{
|
||||||
|
Result<void, Error> Compiler::CompileVarDecl(VarDecl *varDecl)
|
||||||
|
{
|
||||||
|
const String &name = varDecl->name;
|
||||||
|
if (HasLocalInCurrentScope(name))
|
||||||
|
{
|
||||||
|
return std::unexpected(Error(ErrorType::RedeclarationError,
|
||||||
|
std::format("variable `{}` has already defined in this scope", name),
|
||||||
|
"change its name",
|
||||||
|
makeSourceLocation(varDecl)));
|
||||||
|
}
|
||||||
|
std::uint8_t varReg;
|
||||||
|
if (varDecl->initExpr)
|
||||||
|
{
|
||||||
|
const auto &result = CompileExpr(varDecl->initExpr);
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
return std::unexpected(result.error());
|
||||||
|
}
|
||||||
|
std::uint8_t resultReg = *result;
|
||||||
|
varReg = resultReg; // 复用临时计算结果寄存器
|
||||||
|
DeclareLocal(varDecl->isPublic, name, varReg);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
varReg = DeclareLocal(varDecl->isPublic, name);
|
||||||
|
}
|
||||||
|
return Result<void, Error>();
|
||||||
|
}
|
||||||
|
Result<void, Error> Compiler::CompileStmt(Stmt *stmt) // 编译语句
|
||||||
|
{
|
||||||
|
if (stmt->type == AstType::ExprStmt)
|
||||||
|
{
|
||||||
|
ExprStmt *exprStmt = static_cast<ExprStmt *>(stmt);
|
||||||
|
Expr *expr = exprStmt->expr;
|
||||||
|
const auto &result = CompileExpr(expr);
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
return std::unexpected(result.error());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (stmt->type == AstType::VarDecl)
|
||||||
|
{
|
||||||
|
return CompileVarDecl(static_cast<VarDecl *>(stmt));
|
||||||
|
}
|
||||||
|
return Result<void, Error>();
|
||||||
|
}
|
||||||
|
}; // namespace Fig
|
||||||
@@ -52,7 +52,10 @@ namespace Fig
|
|||||||
case ExpectedExpression: return "ExpectedExpression";
|
case ExpectedExpression: return "ExpectedExpression";
|
||||||
case SyntaxError: return "SyntaxError";
|
case SyntaxError: return "SyntaxError";
|
||||||
|
|
||||||
// default: return "Some one forgot to add case to `ErrorTypeToString`";
|
case RedeclarationError: return "RedeclarationError";
|
||||||
|
case UseUndeclaredIdentifier: return "UseUndeclaredIdentifier";
|
||||||
|
case NotAnLvalue: return "NotAnLvalue";
|
||||||
|
// default: return "Some one forgot to add case to `ErrorTypeToString`";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,6 +41,11 @@ namespace Fig
|
|||||||
// parser errors
|
// parser errors
|
||||||
ExpectedExpression,
|
ExpectedExpression,
|
||||||
SyntaxError,
|
SyntaxError,
|
||||||
|
|
||||||
|
// compiler errors
|
||||||
|
RedeclarationError,
|
||||||
|
UseUndeclaredIdentifier,
|
||||||
|
NotAnLvalue
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *ErrorTypeToString(ErrorType type);
|
const char *ErrorTypeToString(ErrorType type);
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ namespace Fig
|
|||||||
|
|
||||||
Result<Token, Error> Lexer::scanMultilineComments()
|
Result<Token, Error> Lexer::scanMultilineComments()
|
||||||
{
|
{
|
||||||
Token tok(rd.currentIndex(), 2, TokenType::Comments);
|
Token tok(rd.currentIndex(), 2, TokenType::Comments);
|
||||||
SourcePosition startPos = rd.currentPosition();
|
SourcePosition startPos = rd.currentPosition();
|
||||||
rd.skip(2); // 跳过 / *
|
rd.skip(2); // 跳过 / *
|
||||||
while (true)
|
while (true)
|
||||||
@@ -43,9 +43,9 @@ namespace Fig
|
|||||||
if (rd.isAtEnd())
|
if (rd.isAtEnd())
|
||||||
{
|
{
|
||||||
return std::unexpected(Error(ErrorType::UnterminatedComments,
|
return std::unexpected(Error(ErrorType::UnterminatedComments,
|
||||||
"unterminated multiline comments",
|
"unterminated multiline comments",
|
||||||
"insert '*/'",
|
"insert '*/'",
|
||||||
makeSourceLocation(startPos)));
|
makeSourceLocation(startPos)));
|
||||||
}
|
}
|
||||||
if (rd.current() == U'*' && rd.peekIf() == U'/')
|
if (rd.current() == U'*' && rd.peekIf() == U'/')
|
||||||
{
|
{
|
||||||
@@ -60,7 +60,7 @@ namespace Fig
|
|||||||
|
|
||||||
Result<Token, Error> Lexer::scanIdentifierOrKeyword()
|
Result<Token, Error> Lexer::scanIdentifierOrKeyword()
|
||||||
{
|
{
|
||||||
Token tok(rd.currentIndex(), 1, TokenType::Identifier);
|
Token tok(rd.currentIndex(), 1, TokenType::Identifier);
|
||||||
String value; // 用于判断是标识符还是关键字
|
String value; // 用于判断是标识符还是关键字
|
||||||
value.push_back(rd.produce()); // 加入第一个
|
value.push_back(rd.produce()); // 加入第一个
|
||||||
|
|
||||||
@@ -135,15 +135,60 @@ namespace Fig
|
|||||||
rd.next();
|
rd.next();
|
||||||
} while (!rd.isAtEnd());
|
} while (!rd.isAtEnd());
|
||||||
|
|
||||||
// 科学计数法
|
// 下划线表示法(1_000_000)
|
||||||
while (!rd.isAtEnd() && state == State::ScanDec
|
while (!rd.isAtEnd() && state == State::ScanDec && (rd.current() == U'_' || CharUtils::isDigit(rd.current())))
|
||||||
&& (rd.current() == U'e' || rd.current() == U'E' || rd.current() == U'_' || rd.current() == U'+'
|
|
||||||
|| rd.current() == U'-' || CharUtils::isDigit(rd.current())))
|
|
||||||
{
|
{
|
||||||
tok.length++;
|
tok.length++;
|
||||||
rd.next();
|
rd.next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 小数点
|
||||||
|
if (rd.currentIf() == U'.')
|
||||||
|
{
|
||||||
|
tok.length++;
|
||||||
|
rd.next();
|
||||||
|
|
||||||
|
if (!CharUtils::isDigit(rd.currentIf()))
|
||||||
|
{
|
||||||
|
return std::unexpected(Error(ErrorType::InvalidNumberLiteral,
|
||||||
|
"need matissa",
|
||||||
|
"insert matissa",
|
||||||
|
makeSourceLocation(rd.currentPosition())));
|
||||||
|
}
|
||||||
|
while (!rd.isAtEnd() && CharUtils::isDigit(rd.current()))
|
||||||
|
{
|
||||||
|
tok.length++;
|
||||||
|
rd.next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 科学计数法
|
||||||
|
if (rd.currentIf() == U'e')
|
||||||
|
{
|
||||||
|
tok.length++;
|
||||||
|
char32_t peek = rd.peekIf();
|
||||||
|
if (peek == U'+' || peek == U'-') // ae+b, ae-b
|
||||||
|
{
|
||||||
|
tok.length++;
|
||||||
|
rd.skip(2); // consume `e`, +/-
|
||||||
|
}
|
||||||
|
else if (CharUtils::isDigit(peek)) // aeb 情况
|
||||||
|
{
|
||||||
|
rd.next(); // `e`
|
||||||
|
}
|
||||||
|
if (!CharUtils::isDigit(rd.currentIf()))
|
||||||
|
{
|
||||||
|
return std::unexpected(Error(ErrorType::InvalidNumberLiteral,
|
||||||
|
"need exponent for scientific notation",
|
||||||
|
"insert exponent",
|
||||||
|
makeSourceLocation(rd.currentPosition())));
|
||||||
|
}
|
||||||
|
while (!rd.isAtEnd() && CharUtils::isDigit(rd.current()))
|
||||||
|
{
|
||||||
|
tok.length++;
|
||||||
|
rd.next();
|
||||||
|
}
|
||||||
|
}
|
||||||
return tok;
|
return tok;
|
||||||
}
|
}
|
||||||
Result<Token, Error> Lexer::scanStringLiteral()
|
Result<Token, Error> Lexer::scanStringLiteral()
|
||||||
@@ -152,31 +197,29 @@ namespace Fig
|
|||||||
|
|
||||||
SourcePosition startPos = rd.currentPosition();
|
SourcePosition startPos = rd.currentPosition();
|
||||||
|
|
||||||
|
|
||||||
Token tok(rd.currentIndex(), 1, TokenType::LiteralString); // "
|
Token tok(rd.currentIndex(), 1, TokenType::LiteralString); // "
|
||||||
rd.next(); // skip " / '
|
rd.next(); // skip " / '
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
if (state == State::ScanStringDQ && rd.current() == U'"')
|
if (state == State::ScanStringDQ && rd.current() == U'"')
|
||||||
{
|
{
|
||||||
tok.length ++;
|
tok.length++;
|
||||||
rd.next(); // skip '"'
|
rd.next(); // skip '"'
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if (state == State::ScanStringSQ && rd.current() == U'\'')
|
else if (state == State::ScanStringSQ && rd.current() == U'\'')
|
||||||
{
|
{
|
||||||
tok.length ++;
|
tok.length++;
|
||||||
rd.next(); // skip `'`
|
rd.next(); // skip `'`
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if (rd.isAtEnd())
|
else if (rd.isAtEnd())
|
||||||
{
|
{
|
||||||
return std::unexpected(
|
return std::unexpected(Error(ErrorType::UnterminatedString,
|
||||||
Error(ErrorType::UnterminatedString,
|
"unterminated string literal",
|
||||||
"unterminated string literal",
|
std::format("insert '{}'", String((state == State::ScanStringDQ ? "\"" : "'"))),
|
||||||
std::format("insert '{}'", String((state == State::ScanStringDQ ? "\"" : "'"))),
|
makeSourceLocation(startPos)));
|
||||||
makeSourceLocation(startPos)));
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -220,9 +263,9 @@ namespace Fig
|
|||||||
if (!Token::punctMap.contains(sym))
|
if (!Token::punctMap.contains(sym))
|
||||||
{
|
{
|
||||||
return std::unexpected(Error(ErrorType::InvalidSymbol,
|
return std::unexpected(Error(ErrorType::InvalidSymbol,
|
||||||
std::format("invalid symbol `{}`", sym),
|
std::format("invalid symbol `{}`", sym),
|
||||||
"correct it",
|
"correct it",
|
||||||
makeSourceLocation(rd.currentPosition())));
|
makeSourceLocation(rd.currentPosition())));
|
||||||
}
|
}
|
||||||
tok.type = Token::punctMap.at(sym);
|
tok.type = Token::punctMap.at(sym);
|
||||||
return tok;
|
return tok;
|
||||||
@@ -276,8 +319,7 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return std::unexpected(Error(
|
return std::unexpected(Error(ErrorType::InvalidCharacter,
|
||||||
ErrorType::InvalidCharacter,
|
|
||||||
std::format("invalid character '{}' (U+{})", String(rd.current()), static_cast<int>(rd.current())),
|
std::format("invalid character '{}' (U+{})", String(rd.current()), static_cast<int>(rd.current())),
|
||||||
"correct it",
|
"correct it",
|
||||||
makeSourceLocation(rd.currentPosition())));
|
makeSourceLocation(rd.currentPosition())));
|
||||||
|
|||||||
13
src/Object/Object.cpp
Normal file
13
src/Object/Object.cpp
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
/*!
|
||||||
|
@file src/Object/Object.hpp
|
||||||
|
@brief 值表示实现 (NaN Boxing) 和 堆对象函数的实现
|
||||||
|
@author PuqiAR (im@puqiar.top)
|
||||||
|
@date 2026-02-19
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Object/ObjectBase.hpp>
|
||||||
|
|
||||||
|
namespace Fig
|
||||||
|
{
|
||||||
|
|
||||||
|
}; // namespace Fig
|
||||||
12
src/Object/Object.hpp
Normal file
12
src/Object/Object.hpp
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
/*!
|
||||||
|
@file src/Object/Object.hpp
|
||||||
|
@brief 值系统总文件
|
||||||
|
@author PuqiAR (im@puqiar.top)
|
||||||
|
@date 2026-02-19
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Object/ObjectBase.hpp>
|
||||||
|
#include <Object/String.hpp>
|
||||||
|
#include <Object/Struct.hpp>
|
||||||
237
src/Object/ObjectBase.hpp
Normal file
237
src/Object/ObjectBase.hpp
Normal file
@@ -0,0 +1,237 @@
|
|||||||
|
/*!
|
||||||
|
@file src/Object/ObjectBase.hpp
|
||||||
|
@brief 值表示定义 (NaN Boxing) uint64
|
||||||
|
@author PuqiAR (im@puqiar.top)
|
||||||
|
@date 2026-02-19
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <bit>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include <Deps/Deps.hpp>
|
||||||
|
|
||||||
|
namespace Fig
|
||||||
|
{
|
||||||
|
|
||||||
|
struct Object; // 前置声明
|
||||||
|
|
||||||
|
/*
|
||||||
|
正常来说直接 Value = std::uint64_t会更快
|
||||||
|
但是这样会带来隐式转换的问题
|
||||||
|
|
||||||
|
因此我们封装成一个类,这样速度不会损失很多。
|
||||||
|
(release模式编译器会直接优化, 速度和uint64_t直接表示一样快)
|
||||||
|
*/
|
||||||
|
class Value
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
std::uint64_t v_; // 唯一的物理成员 sizeof(Value) 永远是 8 字节。
|
||||||
|
|
||||||
|
// --- 私有掩码常量 ---
|
||||||
|
static constexpr std::uint64_t QNAN_MASK = 0x7ffc000000000000;
|
||||||
|
static constexpr std::uint64_t SIGN_BIT = 0x8000000000000000;
|
||||||
|
|
||||||
|
// 专门给 Int32 预留的高位 Tag
|
||||||
|
static constexpr std::uint32_t INT_TAG_HIGH = 0x7FFD0000;
|
||||||
|
|
||||||
|
// 基础原语 Tag
|
||||||
|
static constexpr std::uint64_t TAG_NULL = 1;
|
||||||
|
static constexpr std::uint64_t TAG_FALSE = 2;
|
||||||
|
static constexpr std::uint64_t TAG_TRUE = 3;
|
||||||
|
|
||||||
|
// 私有底层构造:仅供内部组装使用
|
||||||
|
constexpr explicit Value(uint64_t raw) : v_(raw) {}
|
||||||
|
|
||||||
|
public:
|
||||||
|
// 默认构造为 Null,保证未初始化变量也是安全的
|
||||||
|
constexpr Value()
|
||||||
|
{
|
||||||
|
*this = GetNullInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] static constexpr Value FromDouble(double d)
|
||||||
|
{
|
||||||
|
uint64_t raw = std::bit_cast<uint64_t>(d);
|
||||||
|
// 清洗非法的 NaN
|
||||||
|
if ((raw & QNAN_MASK) == QNAN_MASK)
|
||||||
|
return Value(QNAN_MASK);
|
||||||
|
return Value(raw);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] static constexpr Value FromInt(std::int32_t i)
|
||||||
|
{
|
||||||
|
// 移位构造,彻底阻断符号扩展漏洞
|
||||||
|
return Value((static_cast<uint64_t>(INT_TAG_HIGH) << 32) | static_cast<uint32_t>(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] static constexpr Value &GetTrueInstance()
|
||||||
|
{
|
||||||
|
static Value trueInstance(QNAN_MASK | TAG_TRUE);
|
||||||
|
return trueInstance;
|
||||||
|
}
|
||||||
|
[[nodiscard]] static constexpr Value &GetFalseInstance()
|
||||||
|
{
|
||||||
|
static Value falseInstance(QNAN_MASK | TAG_FALSE);
|
||||||
|
return falseInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] static constexpr Value &FromBool(bool b)
|
||||||
|
{
|
||||||
|
return (b ? GetTrueInstance() : GetFalseInstance());
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] static constexpr Value &GetNullInstance()
|
||||||
|
{
|
||||||
|
static Value nullInstance(QNAN_MASK | TAG_NULL);
|
||||||
|
return nullInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] static Value FromObject(Object *ptr)
|
||||||
|
{
|
||||||
|
return Value(reinterpret_cast<uint64_t>(ptr) | SIGN_BIT | QNAN_MASK);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 类型检查 (Is)
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr bool IsDouble() const
|
||||||
|
{
|
||||||
|
return (v_ & QNAN_MASK) != QNAN_MASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr bool IsInt() const
|
||||||
|
{
|
||||||
|
// 安全的高 32 位移位判定
|
||||||
|
return static_cast<uint32_t>(v_ >> 32) == INT_TAG_HIGH;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr bool IsNumber() const
|
||||||
|
{
|
||||||
|
return IsDouble() || IsInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr bool IsObject() const
|
||||||
|
{
|
||||||
|
return (v_ & (SIGN_BIT | QNAN_MASK)) == (SIGN_BIT | QNAN_MASK);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr bool IsNull() const
|
||||||
|
{
|
||||||
|
return v_ == (QNAN_MASK | TAG_NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr bool IsBool() const
|
||||||
|
{
|
||||||
|
return (v_ | 1) == (QNAN_MASK | TAG_TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提取数据 (Unbox / As)
|
||||||
|
[[nodiscard]] constexpr double AsDouble() const
|
||||||
|
{
|
||||||
|
return std::bit_cast<double>(v_);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr int32_t AsInt() const
|
||||||
|
{
|
||||||
|
return static_cast<int32_t>(v_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 核心辅助:泛型数字提取。算术指令可以直接用这个,免去手写 if 分支
|
||||||
|
// 若不是 int/double 会导致非常恐怖的问题
|
||||||
|
[[nodiscard]] constexpr double CastToDouble() const
|
||||||
|
{
|
||||||
|
return IsInt() ? static_cast<double>(AsInt()) : AsDouble();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr bool AsBool() const
|
||||||
|
{
|
||||||
|
return v_ == (QNAN_MASK | TAG_TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] struct Object *AsObject() const
|
||||||
|
{
|
||||||
|
return reinterpret_cast<struct Object *>(v_ & ~(SIGN_BIT | QNAN_MASK));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重载
|
||||||
|
|
||||||
|
// 暴露原生值用于硬核位运算或 Hash 计算
|
||||||
|
[[nodiscard]] constexpr uint64_t Raw() const
|
||||||
|
{
|
||||||
|
return v_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 让 VM 的 OP_EQ 指令极简:`if (RA == RB)`
|
||||||
|
[[nodiscard]] constexpr bool operator==(const Value &other) const
|
||||||
|
{
|
||||||
|
// IEEE 754 规定浮点数有 +0.0 == -0.0 的特殊规则
|
||||||
|
if (IsDouble() && other.IsDouble())
|
||||||
|
{
|
||||||
|
return AsDouble() == other.AsDouble();
|
||||||
|
}
|
||||||
|
// 直接比较 64 位整数内存
|
||||||
|
return v_ == other.v_;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr bool operator!=(const Value &other) const
|
||||||
|
{
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 类函数
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
constexpr String ToString() const
|
||||||
|
{
|
||||||
|
if (IsNull())
|
||||||
|
{
|
||||||
|
return "null";
|
||||||
|
}
|
||||||
|
else if (IsInt())
|
||||||
|
{
|
||||||
|
return std::to_string(AsInt());
|
||||||
|
}
|
||||||
|
else if (IsDouble())
|
||||||
|
{
|
||||||
|
return std::format("{}", AsDouble());
|
||||||
|
}
|
||||||
|
else if (IsBool())
|
||||||
|
{
|
||||||
|
return (AsBool() ? "true" : "false");
|
||||||
|
}
|
||||||
|
else if (IsObject())
|
||||||
|
{
|
||||||
|
return "Object"; // TODO: 分派
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return "Unknow";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
C风格继承 + 手动分发
|
||||||
|
禁止任何 virtual 达到最高效率
|
||||||
|
*/
|
||||||
|
enum class ObjectType : uint8_t
|
||||||
|
{
|
||||||
|
String,
|
||||||
|
Function,
|
||||||
|
Struct,
|
||||||
|
Instance,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Struct /* : public Object */; // 结构体基类的定义,前向声明
|
||||||
|
|
||||||
|
// Total 24 bytes size
|
||||||
|
struct Object
|
||||||
|
{
|
||||||
|
Object *next; // 8 bytes: gc链表
|
||||||
|
Struct *klass; // 8 bytes: 一切皆对象,父类指针
|
||||||
|
ObjectType type; // 1 byte : 类型
|
||||||
|
bool isMarked = false; // 1 byte : gc标记
|
||||||
|
// + 6 bytes padding
|
||||||
|
};
|
||||||
|
} // namespace Fig
|
||||||
20
src/Object/ObjectTest.cpp
Normal file
20
src/Object/ObjectTest.cpp
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#include <Object/ObjectBase.hpp>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <iostream>
|
||||||
|
#include <cmath>
|
||||||
|
#include <numbers>
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
using namespace Fig;
|
||||||
|
|
||||||
|
Value null;
|
||||||
|
Value d = Value::FromDouble(-std::numbers::pi);
|
||||||
|
Value i = Value::FromInt(-2143242);
|
||||||
|
Value b = Value::FromBool(false);
|
||||||
|
|
||||||
|
std::cout << null.ToString() << '\n';
|
||||||
|
std::cout << d.ToString() << '\n';
|
||||||
|
std::cout << i.ToString() << '\n';
|
||||||
|
std::cout << b.ToString() << '\n';
|
||||||
|
}
|
||||||
29
src/Object/String.hpp
Normal file
29
src/Object/String.hpp
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
/*!
|
||||||
|
@file src/Object/String.hpp
|
||||||
|
@brief 字符串对象标识
|
||||||
|
@author PuqiAR (im@puqiar.top)
|
||||||
|
@date 2026-02-19
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Object/ObjectBase.hpp>
|
||||||
|
|
||||||
|
namespace Fig
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
// Total 24 bytes size
|
||||||
|
struct Object
|
||||||
|
{
|
||||||
|
Object *next; // 8 bytes: gc链表
|
||||||
|
Struct *klass; // 8 bytes: 一切皆对象,父类指针
|
||||||
|
ObjectType type; // 1 byte : 类型
|
||||||
|
bool isMarked = false; // 1 byte : gc标记
|
||||||
|
// + 6 bytes padding
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
struct StringObject final : public Object
|
||||||
|
{
|
||||||
|
String data; // 40 bytes
|
||||||
|
};
|
||||||
|
};
|
||||||
54
src/Object/Struct.hpp
Normal file
54
src/Object/Struct.hpp
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
/*!
|
||||||
|
@file src/Object/Struct.hpp
|
||||||
|
@brief 结构体类型 Struct定义
|
||||||
|
@author PuqiAR (im@puqiar.top)
|
||||||
|
@date 2026-02-19
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Ast/Operator.hpp>
|
||||||
|
#include <Object/ObjectBase.hpp>
|
||||||
|
|
||||||
|
namespace Fig
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
// Total 24 bytes size
|
||||||
|
struct Object
|
||||||
|
{
|
||||||
|
Object *next; // 8 bytes: gc链表
|
||||||
|
Struct *klass; // 8 bytes: 一切皆对象,父类指针
|
||||||
|
ObjectType type; // 1 byte : 类型
|
||||||
|
bool isMarked = false; // 1 byte : gc标记
|
||||||
|
// + 6 bytes padding
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
struct StructObject final : public Object
|
||||||
|
{
|
||||||
|
String name; // 元信息(仅供调试/打印/反射)
|
||||||
|
|
||||||
|
// 内存布局信息
|
||||||
|
std::uint8_t fieldCount;
|
||||||
|
Object *operators[GetOperatorsSize()];
|
||||||
|
/*
|
||||||
|
运算符重载,nullptr代表无重载
|
||||||
|
一般为 NativeFunction / Function
|
||||||
|
|
||||||
|
排列:
|
||||||
|
[unary operators ]( binary operators]
|
||||||
|
0 - UnaryOperators::Count BinaryOperators::Count
|
||||||
|
*/
|
||||||
|
|
||||||
|
Object *GetUnaryOperator(UnaryOperator _op)
|
||||||
|
{
|
||||||
|
std::uint8_t idx = static_cast<std::uint8_t>(_op);
|
||||||
|
return operators[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
Object *GetBinaryOperator(BinaryOperator _op)
|
||||||
|
{
|
||||||
|
std::uint16_t idx = static_cast<std::uint8_t>(UnaryOperator::Count) + static_cast<std::uint8_t>(_op);
|
||||||
|
return operators[idx];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}; // namespace Fig
|
||||||
@@ -13,7 +13,7 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
state = State::ParsingLiteralExpr;
|
state = State::ParsingLiteralExpr;
|
||||||
const Token &literal_token = consumeToken();
|
const Token &literal_token = consumeToken();
|
||||||
LiteralExpr *node = new LiteralExpr(literal_token, makeSourcelocation(literal_token));
|
LiteralExpr *node = new LiteralExpr(literal_token, makeSourceLocation(literal_token));
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
Result<IdentiExpr *, Error> Parser::parseIdentiExpr() // 当前token为Identifier调用
|
Result<IdentiExpr *, Error> Parser::parseIdentiExpr() // 当前token为Identifier调用
|
||||||
@@ -21,7 +21,7 @@ namespace Fig
|
|||||||
state = State::ParsingIdentiExpr;
|
state = State::ParsingIdentiExpr;
|
||||||
const Token &identifier = consumeToken();
|
const Token &identifier = consumeToken();
|
||||||
IdentiExpr *node =
|
IdentiExpr *node =
|
||||||
new IdentiExpr(srcManager.GetSub(identifier.index, identifier.length), makeSourcelocation(identifier));
|
new IdentiExpr(srcManager.GetSub(identifier.index, identifier.length), makeSourceLocation(identifier));
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ namespace Fig
|
|||||||
if (currentToken().type != TokenType::RightBracket) // `]`
|
if (currentToken().type != TokenType::RightBracket) // `]`
|
||||||
{
|
{
|
||||||
return std::unexpected(
|
return std::unexpected(
|
||||||
Error(ErrorType::SyntaxError, "unclosed brackets", "insert `]`", makeSourcelocation(lbracket_token)));
|
Error(ErrorType::SyntaxError, "unclosed brackets", "insert `]`", makeSourceLocation(lbracket_token)));
|
||||||
}
|
}
|
||||||
consumeToken(); // consume `]`
|
consumeToken(); // consume `]`
|
||||||
|
|
||||||
@@ -104,7 +104,7 @@ namespace Fig
|
|||||||
return std::unexpected(Error(ErrorType::SyntaxError,
|
return std::unexpected(Error(ErrorType::SyntaxError,
|
||||||
"fn call has unclosed parenthese",
|
"fn call has unclosed parenthese",
|
||||||
"insert `)`",
|
"insert `)`",
|
||||||
makeSourcelocation(lparen_token)));
|
makeSourceLocation(lparen_token)));
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto &arg_result = parseExpression();
|
const auto &arg_result = parseExpression();
|
||||||
@@ -124,7 +124,7 @@ namespace Fig
|
|||||||
return std::unexpected(Error(ErrorType::SyntaxError,
|
return std::unexpected(Error(ErrorType::SyntaxError,
|
||||||
"expected `,` or `)` in argument list",
|
"expected `,` or `)` in argument list",
|
||||||
"insert `,`",
|
"insert `,`",
|
||||||
makeSourcelocation(currentToken())));
|
makeSourceLocation(currentToken())));
|
||||||
}
|
}
|
||||||
|
|
||||||
consumeToken(); // consume `,`
|
consumeToken(); // consume `,`
|
||||||
@@ -158,7 +158,7 @@ namespace Fig
|
|||||||
return terminators.contains(token.type);
|
return terminators.contains(token.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<Expr *, Error> Parser::parseExpression(BindingPower rbp)
|
Result<Expr *, Error> Parser::parseExpression(BindingPower rbp, TokenType stop, TokenType stop2)
|
||||||
{
|
{
|
||||||
Expr *lhs = nullptr;
|
Expr *lhs = nullptr;
|
||||||
Token token = currentToken();
|
Token token = currentToken();
|
||||||
@@ -202,7 +202,7 @@ namespace Fig
|
|||||||
if (rparen_token.type != TokenType::RightParen)
|
if (rparen_token.type != TokenType::RightParen)
|
||||||
{
|
{
|
||||||
return std::unexpected(Error(
|
return std::unexpected(Error(
|
||||||
ErrorType::SyntaxError, "unclosed parenthese", "insert `)`", makeSourcelocation(lparen_token)));
|
ErrorType::SyntaxError, "unclosed parenthese", "insert `)`", makeSourceLocation(lparen_token)));
|
||||||
}
|
}
|
||||||
lhs = *expr_result;
|
lhs = *expr_result;
|
||||||
}
|
}
|
||||||
@@ -212,7 +212,7 @@ namespace Fig
|
|||||||
return std::unexpected(Error(ErrorType::ExpectedExpression,
|
return std::unexpected(Error(ErrorType::ExpectedExpression,
|
||||||
"expected expression",
|
"expected expression",
|
||||||
"insert expressions",
|
"insert expressions",
|
||||||
makeSourcelocation(prevToken())));
|
makeSourceLocation(prevToken())));
|
||||||
}
|
}
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
@@ -222,6 +222,10 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (token.type == stop || token.type == stop2)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (IsTokenOp(token.type /* isBinary = true */)) // 是否为二元运算符
|
if (IsTokenOp(token.type /* isBinary = true */)) // 是否为二元运算符
|
||||||
{
|
{
|
||||||
@@ -266,7 +270,7 @@ namespace Fig
|
|||||||
return std::unexpected(Error(ErrorType::ExpectedExpression,
|
return std::unexpected(Error(ErrorType::ExpectedExpression,
|
||||||
"expression unexpectedly ended",
|
"expression unexpectedly ended",
|
||||||
"insert expressions",
|
"insert expressions",
|
||||||
makeSourcelocation(token)));
|
makeSourceLocation(token)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return lhs;
|
return lhs;
|
||||||
|
|||||||
@@ -10,9 +10,18 @@
|
|||||||
|
|
||||||
namespace Fig
|
namespace Fig
|
||||||
{
|
{
|
||||||
DynArray<AstNode *> Parser::parseAll()
|
Result<Program *, Error> Parser::Parse()
|
||||||
{
|
{
|
||||||
DynArray<AstNode *> nodes;
|
Program *program = new Program;
|
||||||
return nodes;
|
while (!isEOF)
|
||||||
|
{
|
||||||
|
const auto &result = parseStatement();
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
return std::unexpected(result.error());
|
||||||
|
}
|
||||||
|
program->nodes.push_back(*result);
|
||||||
|
}
|
||||||
|
return program;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -111,6 +111,38 @@ namespace Fig
|
|||||||
return current;
|
return current;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool match(TokenType type)
|
||||||
|
{
|
||||||
|
if (currentToken().type == type)
|
||||||
|
{
|
||||||
|
consumeToken();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Error makeUnexpectTokenError(const String &stmtType, const String &expect, const Token &tokenGot, std::source_location loc = std::source_location::current())
|
||||||
|
{
|
||||||
|
return Error(
|
||||||
|
ErrorType::SyntaxError,
|
||||||
|
std::format("expect '{}' in {}, got `{}`", expect, stmtType, magic_enum::enum_name(tokenGot.type)),
|
||||||
|
"none",
|
||||||
|
makeSourceLocation(tokenGot),
|
||||||
|
loc
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Error makeExpectSemicolonError(std::source_location loc = std::source_location::current())
|
||||||
|
{
|
||||||
|
return Error(
|
||||||
|
ErrorType::SyntaxError,
|
||||||
|
"expect ';' after statement",
|
||||||
|
"insert ';'",
|
||||||
|
makeSourceLocation(currentToken()),
|
||||||
|
loc
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum class State : std::uint8_t
|
enum class State : std::uint8_t
|
||||||
{
|
{
|
||||||
@@ -125,6 +157,8 @@ namespace Fig
|
|||||||
ParsingIndexExpr,
|
ParsingIndexExpr,
|
||||||
ParsingCallExpr,
|
ParsingCallExpr,
|
||||||
|
|
||||||
|
ParsingVarDecl,
|
||||||
|
|
||||||
} state;
|
} state;
|
||||||
|
|
||||||
Parser(Lexer &_lexer, SourceManager &_srcManager, String _fileName) :
|
Parser(Lexer &_lexer, SourceManager &_srcManager, String _fileName) :
|
||||||
@@ -134,37 +168,36 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SourceLocation makeSourcelocation(const Token &tok)
|
SourceLocation makeSourceLocation(const Token &tok)
|
||||||
{
|
{
|
||||||
auto [line, column] = srcManager.GetLineColumn(tok.index);
|
auto [line, column] = srcManager.GetLineColumn(tok.index);
|
||||||
return SourceLocation(
|
return SourceLocation(SourcePosition(line, column, tok.length),
|
||||||
SourcePosition(
|
fileName,
|
||||||
line,
|
"[internal parser]",
|
||||||
column,
|
magic_enum::enum_name(state).data());
|
||||||
tok.length
|
|
||||||
), fileName, "[internal parser]", magic_enum::enum_name(state).data());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Expressions */
|
/* Expressions */
|
||||||
Result<LiteralExpr *, Error> parseLiteralExpr(); // 当前token为literal时调用
|
Result<LiteralExpr *, Error> parseLiteralExpr(); // 当前token为literal时调用
|
||||||
Result<IdentiExpr *, Error> parseIdentiExpr(); // 当前token为Identifier调用
|
Result<IdentiExpr *, Error> parseIdentiExpr(); // 当前token为Identifier调用
|
||||||
|
|
||||||
Result<InfixExpr *, Error> parseInfixExpr(Expr *); // 由 parseExpression递归调用, 当前token为op
|
Result<InfixExpr *, Error> parseInfixExpr(Expr *); // 由 parseExpression递归调用, 当前token为op
|
||||||
Result<PrefixExpr *, Error> parsePrefixExpr(); // 由 parseExpression递归调用, 当前token为op
|
Result<PrefixExpr *, Error> parsePrefixExpr(); // 由 parseExpression递归调用, 当前token为op
|
||||||
|
|
||||||
Result<IndexExpr *, Error> parseIndexExpr(Expr *); // 由 parseExpression调用, 当前token为 `[`
|
Result<IndexExpr *, Error> parseIndexExpr(Expr *); // 由 parseExpression调用, 当前token为 `[`
|
||||||
Result<CallExpr *, Error> parseCallExpr(Expr *); // 由 parseExpression调用, 当前token为 `(`
|
Result<CallExpr *, Error> parseCallExpr(Expr *); // 由 parseExpression调用, 当前token为 `(`
|
||||||
|
|
||||||
std::unordered_set<TokenType> getTerminators(); // 返回固定的终止符
|
std::unordered_set<TokenType> getTerminators(); // 返回固定的终止符
|
||||||
bool shouldTerminate(); // 判断是否终结
|
bool shouldTerminate(); // 判断是否终结
|
||||||
|
|
||||||
// Result<Expr *, Error> parseExpression(BindingPower = 0);
|
Result<Expr *, Error> parseExpression(BindingPower = 0, TokenType stop = TokenType::Semicolon, TokenType stop2 = TokenType::Semicolon);
|
||||||
|
|
||||||
/* Statements */
|
/* Statements */
|
||||||
|
Result<VarDecl *, Error> parseVarDecl(bool); // 由 parseStatement调用, 当前token为 var
|
||||||
|
|
||||||
|
Result<Stmt *, Error> parseStatement();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
Result<Program *, Error> Parse();
|
||||||
Result<Expr *, Error> parseExpression(BindingPower = 0);
|
|
||||||
DynArray<AstNode *> parseAll();
|
|
||||||
};
|
};
|
||||||
}; // namespace Fig
|
}; // namespace Fig
|
||||||
@@ -18,12 +18,15 @@ int main()
|
|||||||
|
|
||||||
Lexer lexer(source, fileName);
|
Lexer lexer(source, fileName);
|
||||||
Parser parser(lexer, srcManager, fileName);
|
Parser parser(lexer, srcManager, fileName);
|
||||||
const auto &result = parser.parseExpression();
|
const auto &result = parser.Parse();
|
||||||
if (!result)
|
if (!result)
|
||||||
{
|
{
|
||||||
ReportError(result.error(), srcManager);
|
ReportError(result.error(), srcManager);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
Expr *expr = *result;
|
Program *program = *result;
|
||||||
std::cout << expr->toString() << '\n';
|
for (Stmt *stmt : program->nodes)
|
||||||
|
{
|
||||||
|
std::cout << stmt->toString() << '\n';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
82
src/Parser/StmtParser.cpp
Normal file
82
src/Parser/StmtParser.cpp
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
/*!
|
||||||
|
@file src/Parser/StmtParser.hpp
|
||||||
|
@brief 语法分析器(Pratt + 手动递归下降) 语句解析实现
|
||||||
|
@author PuqiAR (im@puqiar.top)
|
||||||
|
@date 2026-02-19
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Parser/Parser.hpp>
|
||||||
|
|
||||||
|
namespace Fig
|
||||||
|
{
|
||||||
|
Result<VarDecl *, Error> Parser::parseVarDecl(bool isPublic) // 由 parseStatement调用, 当前token为 var
|
||||||
|
{
|
||||||
|
state = State::ParsingVarDecl;
|
||||||
|
|
||||||
|
SourceLocation location = makeSourceLocation(consumeToken()); // consume `var`
|
||||||
|
|
||||||
|
if (currentToken().type != TokenType::Identifier)
|
||||||
|
{
|
||||||
|
return std::unexpected(makeUnexpectTokenError("VarDecl", "var name", currentToken()));
|
||||||
|
}
|
||||||
|
const String &name = srcManager.GetSub(currentToken().index, currentToken().length);
|
||||||
|
consumeToken(); // consume name
|
||||||
|
|
||||||
|
Expr *typeSpeicifer = nullptr;
|
||||||
|
if (match(TokenType::Colon)) // `:`
|
||||||
|
{
|
||||||
|
const auto &result = parseExpression(0, TokenType::Assign);
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
return std::unexpected(result.error());
|
||||||
|
}
|
||||||
|
typeSpeicifer = *result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expr *initExpr = nullptr;
|
||||||
|
if (match(TokenType::Assign))
|
||||||
|
{
|
||||||
|
const auto &result = parseExpression();
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
return std::unexpected(result.error());
|
||||||
|
}
|
||||||
|
initExpr = *result;
|
||||||
|
}
|
||||||
|
if (!match(TokenType::Semicolon))
|
||||||
|
{
|
||||||
|
makeExpectSemicolonError();
|
||||||
|
}
|
||||||
|
VarDecl *varDecl = new VarDecl(isPublic, name, typeSpeicifer, initExpr, location);
|
||||||
|
return varDecl;
|
||||||
|
}
|
||||||
|
Result<Stmt *, Error> Parser::parseStatement()
|
||||||
|
{
|
||||||
|
if (currentToken().type == TokenType::Public)
|
||||||
|
{
|
||||||
|
consumeToken(); // consume `public`
|
||||||
|
if (currentToken().type == TokenType::Variable)
|
||||||
|
{
|
||||||
|
return parseVarDecl(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (currentToken().type == TokenType::Variable)
|
||||||
|
{
|
||||||
|
return parseVarDecl(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const auto &expr_result = parseExpression(0);
|
||||||
|
if (!expr_result)
|
||||||
|
{
|
||||||
|
return std::unexpected(expr_result.error());
|
||||||
|
}
|
||||||
|
ExprStmt *exprStmt = new ExprStmt(*expr_result);
|
||||||
|
if (!match(TokenType::Semicolon))
|
||||||
|
{
|
||||||
|
return std::unexpected(makeExpectSemicolonError());
|
||||||
|
}
|
||||||
|
return exprStmt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}; // namespace Fig
|
||||||
@@ -7,8 +7,9 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <Deps/Deps.hpp>
|
|
||||||
#include <Core/SourceLocations.hpp>
|
#include <Core/SourceLocations.hpp>
|
||||||
|
#include <Deps/Deps.hpp>
|
||||||
|
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
@@ -17,8 +18,8 @@ namespace Fig
|
|||||||
class SourceManager
|
class SourceManager
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
String filePath;
|
String filePath;
|
||||||
String source;
|
String source;
|
||||||
std::vector<String> lines;
|
std::vector<String> lines;
|
||||||
std::vector<size_t> lineStartIndex; // 每行在整个源字符串中的起始 index
|
std::vector<size_t> lineStartIndex; // 每行在整个源字符串中的起始 index
|
||||||
|
|
||||||
@@ -45,7 +46,7 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool read = false;
|
bool read = false;
|
||||||
String &Read()
|
String &Read()
|
||||||
{
|
{
|
||||||
std::fstream fs(filePath.toStdString());
|
std::fstream fs(filePath.toStdString());
|
||||||
@@ -73,7 +74,10 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
|
|
||||||
SourceManager() {}
|
SourceManager() {}
|
||||||
SourceManager(String _path) { filePath = std::move(_path); }
|
SourceManager(String _path)
|
||||||
|
{
|
||||||
|
filePath = std::move(_path);
|
||||||
|
}
|
||||||
|
|
||||||
bool HasLine(int64_t _line) const
|
bool HasLine(int64_t _line) const
|
||||||
{
|
{
|
||||||
@@ -127,4 +131,4 @@ namespace Fig
|
|||||||
return {line + 1, column};
|
return {line + 1, column};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
}; // namespace Fig
|
||||||
127
src/VM/VM.cpp
Normal file
127
src/VM/VM.cpp
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
/*!
|
||||||
|
@file src/VM/VM.hpp
|
||||||
|
@brief 虚拟机核心执行引擎实现
|
||||||
|
@author PuqiAR (im@puqiar.top)
|
||||||
|
@date 2026-02-19
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <VM/VM.hpp>
|
||||||
|
|
||||||
|
#define BINARY_ARITHMETIC_OP(opCode, op) \
|
||||||
|
case OpCode::opCode: { \
|
||||||
|
std::uint8_t b = decodeB(inst); \
|
||||||
|
std::uint8_t c = decodeC(inst); \
|
||||||
|
Value lhs = registers[b]; \
|
||||||
|
Value rhs = registers[c]; \
|
||||||
|
if (lhs.IsInt() && rhs.IsInt()) [[likely]] \
|
||||||
|
{ \
|
||||||
|
registers[a] = Value::FromInt(lhs.AsInt() op rhs.AsInt()); \
|
||||||
|
} \
|
||||||
|
else if (lhs.IsDouble() && rhs.IsDouble()) [[likely]] \
|
||||||
|
{ \
|
||||||
|
registers[a] = Value::FromDouble(lhs.AsDouble() op rhs.AsDouble()); \
|
||||||
|
} \
|
||||||
|
/* 隐式类型提升:Int 与 Double 混合运算 */ \
|
||||||
|
else if (lhs.IsInt() && rhs.IsDouble()) [[likely]] \
|
||||||
|
{ \
|
||||||
|
registers[a] = Value::FromDouble(lhs.AsInt() op rhs.AsDouble()); \
|
||||||
|
} \
|
||||||
|
else if (lhs.IsDouble() && rhs.IsInt()) [[likely]] \
|
||||||
|
{ \
|
||||||
|
registers[a] = Value::FromDouble(lhs.AsDouble() op rhs.AsInt()); \
|
||||||
|
} \
|
||||||
|
else \
|
||||||
|
{ \
|
||||||
|
assert(false && "VM Runtime Error: Unsupported types for arithmetic operation"); \
|
||||||
|
} \
|
||||||
|
break; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BINARY_COMPARE_OP(opCode, op) \
|
||||||
|
case OpCode::opCode: { \
|
||||||
|
std::uint8_t b = decodeB(inst); \
|
||||||
|
std::uint8_t c = decodeC(inst); \
|
||||||
|
Value lhs = registers[b]; \
|
||||||
|
Value rhs = registers[c]; \
|
||||||
|
if (lhs.IsInt() && rhs.IsInt()) [[likely]] \
|
||||||
|
{ \
|
||||||
|
registers[a] = (lhs.AsInt() op rhs.AsInt()) ? Value::GetTrueInstance() : Value::GetFalseInstance(); \
|
||||||
|
} \
|
||||||
|
else if (lhs.IsDouble() && rhs.IsDouble()) [[likely]] \
|
||||||
|
{ \
|
||||||
|
registers[a] = (lhs.AsDouble() op rhs.AsDouble()) ? Value::GetTrueInstance() : Value::GetFalseInstance(); \
|
||||||
|
} \
|
||||||
|
else if (lhs.IsInt() && rhs.IsDouble()) [[likely]] \
|
||||||
|
{ \
|
||||||
|
registers[a] = (lhs.AsInt() op rhs.AsDouble()) ? Value::GetTrueInstance() : Value::GetFalseInstance(); \
|
||||||
|
} \
|
||||||
|
else if (lhs.IsDouble() && rhs.IsInt()) [[likely]] \
|
||||||
|
{ \
|
||||||
|
registers[a] = (lhs.AsDouble() op rhs.AsInt()) ? Value::GetTrueInstance() : Value::GetFalseInstance(); \
|
||||||
|
} \
|
||||||
|
else \
|
||||||
|
{ \
|
||||||
|
/* TODO: 非数字比较 */ \
|
||||||
|
assert(false && "VM Runtime Error: Unsupported types for comparison"); \
|
||||||
|
} \
|
||||||
|
break; \
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Fig
|
||||||
|
{
|
||||||
|
Result<Value, Error> VM::Execute(Proto *proto)
|
||||||
|
{
|
||||||
|
// 指令指针 (Instruction Pointer / PC) 和 常量池指针
|
||||||
|
const Instruction *ip = proto->code.data();
|
||||||
|
const Value *k = proto->constants.data();
|
||||||
|
|
||||||
|
// 核心解释器循环 (The Dispatch Loop)
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
// 取指并递增指针
|
||||||
|
Instruction inst = *ip++;
|
||||||
|
|
||||||
|
// 解码 OpCode 和 A 操作数
|
||||||
|
OpCode op = decodeOpCode(inst);
|
||||||
|
std::uint8_t a = decodeA(inst);
|
||||||
|
switch (op)
|
||||||
|
{
|
||||||
|
case OpCode::Exit: {
|
||||||
|
return Value::GetNullInstance();
|
||||||
|
}
|
||||||
|
case OpCode::LoadK: {
|
||||||
|
std::uint16_t bx = decodeBx(inst);
|
||||||
|
registers[a] = k[bx]; // constants
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case OpCode::Mov: {
|
||||||
|
std::uint16_t bx = decodeBx(inst);
|
||||||
|
registers[a] = registers[bx];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
BINARY_ARITHMETIC_OP(Add, +);
|
||||||
|
BINARY_ARITHMETIC_OP(Sub, -);
|
||||||
|
BINARY_ARITHMETIC_OP(Mul, *);
|
||||||
|
BINARY_ARITHMETIC_OP(Div, /);
|
||||||
|
|
||||||
|
BINARY_COMPARE_OP(Equal, ==);
|
||||||
|
BINARY_COMPARE_OP(NotEqual, !=);
|
||||||
|
BINARY_COMPARE_OP(Greater, >);
|
||||||
|
BINARY_COMPARE_OP(Less, <);
|
||||||
|
BINARY_COMPARE_OP(GreaterEqual, >=);
|
||||||
|
BINARY_COMPARE_OP(LessEqual, <=);
|
||||||
|
|
||||||
|
case OpCode::Return: {
|
||||||
|
return registers[a];
|
||||||
|
}
|
||||||
|
|
||||||
|
default: {
|
||||||
|
assert(false && "VM: Unknown OpCode encountered!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Value::GetNullInstance();
|
||||||
|
}
|
||||||
|
}; // namespace Fig
|
||||||
75
src/VM/VM.hpp
Normal file
75
src/VM/VM.hpp
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
/*!
|
||||||
|
@file src/VM/VM.hpp
|
||||||
|
@brief 虚拟机核心执行引擎
|
||||||
|
@author PuqiAR (im@puqiar.top)
|
||||||
|
@date 2026-02-19
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Compiler/Compiler.hpp>
|
||||||
|
#include <Object/Object.hpp>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#include <iostream> // debug
|
||||||
|
#include <print>
|
||||||
|
|
||||||
|
namespace Fig
|
||||||
|
{
|
||||||
|
class VM
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
static constexpr unsigned int MAX_REGISTERS = 1024;
|
||||||
|
|
||||||
|
// 一次性分配
|
||||||
|
Value registers[MAX_REGISTERS];
|
||||||
|
|
||||||
|
public:
|
||||||
|
VM()
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < MAX_REGISTERS; ++i)
|
||||||
|
{
|
||||||
|
registers[i] = Value::GetNullInstance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
inline OpCode decodeOpCode(Instruction inst)
|
||||||
|
{
|
||||||
|
return static_cast<OpCode>(inst & 0xFF);
|
||||||
|
}
|
||||||
|
inline std::uint8_t decodeA(Instruction inst)
|
||||||
|
{
|
||||||
|
return (inst >> 8) & 0xFF;
|
||||||
|
}
|
||||||
|
inline std::uint16_t decodeBx(Instruction inst)
|
||||||
|
{
|
||||||
|
return (inst >> 16) & 0xFFFF;
|
||||||
|
}
|
||||||
|
inline std::uint8_t decodeB(Instruction inst)
|
||||||
|
{
|
||||||
|
return (inst >> 16) & 0xFF;
|
||||||
|
}
|
||||||
|
inline std::uint8_t decodeC(Instruction inst)
|
||||||
|
{
|
||||||
|
return (inst >> 24) & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
// 执行入口:接收 Proto
|
||||||
|
Result<Value, Error> Execute(Proto *proto);
|
||||||
|
|
||||||
|
inline void PrintRegisters()
|
||||||
|
{
|
||||||
|
std::cout << "=== Registers ===" << '\n';
|
||||||
|
for (unsigned int i = 0; i < MAX_REGISTERS; ++i)
|
||||||
|
{
|
||||||
|
Value &v = registers[i];
|
||||||
|
if (!v.IsNull())
|
||||||
|
{
|
||||||
|
std::println("[{}] {}", i, v.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace Fig
|
||||||
5
src/VM/__VMTest.cpp
Normal file
5
src/VM/__VMTest.cpp
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
/*
|
||||||
|
哈哈!
|
||||||
|
VM的测试?
|
||||||
|
就是main.cpp啦!全流程执行!
|
||||||
|
*/
|
||||||
67
src/main.cpp
67
src/main.cpp
@@ -1,4 +1,71 @@
|
|||||||
|
#include <Compiler/Compiler.hpp>
|
||||||
|
#include <Core/Core.hpp>
|
||||||
|
#include <Deps/Deps.hpp>
|
||||||
|
#include <Lexer/Lexer.hpp>
|
||||||
|
#include <Parser/Parser.hpp>
|
||||||
|
#include <SourceManager/SourceManager.hpp>
|
||||||
|
#include <VM/VM.hpp>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <print>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
|
using namespace Fig;
|
||||||
|
|
||||||
|
String fileName = "test.fig";
|
||||||
|
String filePath = "T:/Files/Maker/Code/MyCodingLanguage/The Fig Project/Fig/test.fig";
|
||||||
|
|
||||||
|
SourceManager manager(filePath);
|
||||||
|
manager.Read();
|
||||||
|
|
||||||
|
if (!manager.read)
|
||||||
|
{
|
||||||
|
std::cerr << "Couldn't read file";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Lexer lexer(manager.GetSource(), fileName);
|
||||||
|
Parser parser(lexer, manager, fileName);
|
||||||
|
|
||||||
|
const auto &program_result = parser.Parse();
|
||||||
|
if (!program_result)
|
||||||
|
{
|
||||||
|
ReportError(program_result.error(), manager);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
Program *program = *program_result;
|
||||||
|
|
||||||
|
Compiler compiler(fileName, manager);
|
||||||
|
const auto &proto_result = compiler.Compile(program);
|
||||||
|
if (!proto_result)
|
||||||
|
{
|
||||||
|
ReportError(proto_result.error(), manager);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Proto *proto = *proto_result;
|
||||||
|
|
||||||
|
std::cout << "=== Constant Pool ===" << '\n';
|
||||||
|
for (size_t i = 0; i < proto->constants.size(); ++i)
|
||||||
|
{
|
||||||
|
std::print("[{}] {}\n", i, proto->constants[i].ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
DumpCode(proto->code);
|
||||||
|
|
||||||
|
std::cout << "\nMax Stack Size: " << (int) proto->maxStack << std::endl;
|
||||||
|
|
||||||
|
VM vm;
|
||||||
|
|
||||||
|
const auto &result_ = vm.Execute(proto);
|
||||||
|
if (!result_)
|
||||||
|
{
|
||||||
|
ReportError(result_.error(), manager);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
Value result = *result_;
|
||||||
|
std::cout << "result: " << result.ToString() << "\n";
|
||||||
|
vm.PrintRegisters();
|
||||||
}
|
}
|
||||||
32
xmake.lua
32
xmake.lua
@@ -44,10 +44,34 @@ target("ParserTest")
|
|||||||
|
|
||||||
add_files("src/Ast/Operator.cpp")
|
add_files("src/Ast/Operator.cpp")
|
||||||
add_files("src/Parser/ExprParser.cpp")
|
add_files("src/Parser/ExprParser.cpp")
|
||||||
|
add_files("src/Parser/StmtParser.cpp")
|
||||||
add_files("src/Parser/Parser.cpp")
|
add_files("src/Parser/Parser.cpp")
|
||||||
|
|
||||||
add_files("src/Parser/ParserTest.cpp")
|
add_files("src/Parser/ParserTest.cpp")
|
||||||
|
|
||||||
|
target("ObjectTest")
|
||||||
|
add_files("src/Object/Object.cpp")
|
||||||
|
add_files("src/Object/ObjectTest.cpp")
|
||||||
|
|
||||||
|
target("CompilerTest")
|
||||||
|
add_files("src/Core/*.cpp")
|
||||||
|
add_files("src/Token/Token.cpp")
|
||||||
|
add_files("src/Error/Error.cpp")
|
||||||
|
add_files("src/Lexer/Lexer.cpp")
|
||||||
|
|
||||||
|
add_files("src/Ast/Operator.cpp")
|
||||||
|
add_files("src/Parser/ExprParser.cpp")
|
||||||
|
add_files("src/Parser/StmtParser.cpp")
|
||||||
|
add_files("src/Parser/Parser.cpp")
|
||||||
|
|
||||||
|
add_files("src/Object/Object.cpp")
|
||||||
|
|
||||||
|
add_files("src/Compiler/ExprCompiler.cpp")
|
||||||
|
add_files("src/Compiler/StmtCompiler.cpp")
|
||||||
|
add_files("src/Compiler/Compiler.cpp")
|
||||||
|
|
||||||
|
add_files("src/Compiler/CompileTest.cpp")
|
||||||
|
|
||||||
target("Fig")
|
target("Fig")
|
||||||
add_files("src/Core/*.cpp")
|
add_files("src/Core/*.cpp")
|
||||||
add_files("src/Token/Token.cpp")
|
add_files("src/Token/Token.cpp")
|
||||||
@@ -56,6 +80,14 @@ target("Fig")
|
|||||||
|
|
||||||
add_files("src/Ast/Operator.cpp")
|
add_files("src/Ast/Operator.cpp")
|
||||||
add_files("src/Parser/ExprParser.cpp")
|
add_files("src/Parser/ExprParser.cpp")
|
||||||
|
add_files("src/Parser/StmtParser.cpp")
|
||||||
add_files("src/Parser/Parser.cpp")
|
add_files("src/Parser/Parser.cpp")
|
||||||
|
|
||||||
|
add_files("src/Object/Object.cpp")
|
||||||
|
|
||||||
|
add_files("src/Compiler/ExprCompiler.cpp")
|
||||||
|
add_files("src/Compiler/StmtCompiler.cpp")
|
||||||
|
add_files("src/Compiler/Compiler.cpp")
|
||||||
|
|
||||||
|
add_files("src/VM/VM.cpp")
|
||||||
add_files("src/main.cpp")
|
add_files("src/main.cpp")
|
||||||
Reference in New Issue
Block a user