mirror of
https://github.com/ProgramSnail/Lama.git
synced 2025-12-06 06:48:48 +00:00
234 lines
5.1 KiB
C++
234 lines
5.1 KiB
C++
#pragma once
|
|
|
|
#include <optional>
|
|
#include <string>
|
|
#include <variant>
|
|
#include <vector>
|
|
|
|
enum class Patt {
|
|
BOXED,
|
|
UNBOXED,
|
|
ARRAY,
|
|
STRING,
|
|
SEXP,
|
|
CLOSURE,
|
|
STRCMP,
|
|
};
|
|
|
|
enum class Opr {
|
|
ADD = 0, // +
|
|
SUB, // -
|
|
MULT, // *
|
|
DIV, // /
|
|
MOD, // %
|
|
LEQ, // <=
|
|
LT, // <
|
|
GT, // >
|
|
GEQ, // >=
|
|
EQ, // ==
|
|
NEQ, // !=
|
|
AND, // &&
|
|
OR, // !!
|
|
XOR, // ^ (compiler only)
|
|
CMP, // cmp (compiler only)
|
|
TEST, // test (compiler only)
|
|
};
|
|
|
|
struct ValT {
|
|
struct Global {
|
|
std::string s;
|
|
};
|
|
struct Local {
|
|
size_t n;
|
|
};
|
|
struct Arg {
|
|
size_t n;
|
|
};
|
|
struct Access {
|
|
size_t n;
|
|
};
|
|
struct Fun {
|
|
std::string s;
|
|
};
|
|
|
|
using T = std::variant<Global, Local, Arg, Access, Fun>;
|
|
|
|
T val;
|
|
|
|
template <typename U>
|
|
requires(not std::is_same_v<ValT, std::remove_reference_t<U>>)
|
|
ValT(U &&x) : val(std::forward<U>(x)) {}
|
|
|
|
template <typename U> bool is() const {
|
|
return std::holds_alternative<U>(val);
|
|
}
|
|
|
|
const T &operator*() const { return val; }
|
|
const T &operator->() const { return val; }
|
|
|
|
bool operator==(const ValT &other) const = default;
|
|
};
|
|
|
|
/* The type for local scopes tree */
|
|
struct Scope {
|
|
std::string blab;
|
|
std::string elab;
|
|
std::vector<std::pair<std::string, int>> names;
|
|
std::vector<Scope> subs;
|
|
};
|
|
|
|
// TODO: use bytecode in interpreter represientation instead
|
|
/* The type for the stack machine instructions */
|
|
struct SMInstr {
|
|
|
|
/* binary operator */
|
|
struct BINOP {
|
|
Opr opr;
|
|
};
|
|
/* put a constant on the stack */
|
|
struct CONST {
|
|
int n;
|
|
};
|
|
/* put a string on the stack */
|
|
struct STRING {
|
|
std::string str;
|
|
};
|
|
/* create an S-expression */
|
|
struct SEXP {
|
|
std::string tag;
|
|
int n;
|
|
};
|
|
/* load a variable to the stack */
|
|
struct LD {
|
|
ValT v;
|
|
};
|
|
/* load a variable address to the stack */
|
|
struct LDA {
|
|
ValT v;
|
|
};
|
|
/* store a value into a variable */
|
|
struct ST {
|
|
ValT v;
|
|
};
|
|
/* store a value into a reference */
|
|
struct STI {};
|
|
/* store a value into array/sexp/string */
|
|
struct STA {};
|
|
/* takes an element of array/string/sexp */
|
|
struct ELEM {};
|
|
/* a label */
|
|
struct LABEL {
|
|
std::string s;
|
|
};
|
|
/* a forwarded label */
|
|
struct FLABEL {
|
|
std::string s;
|
|
};
|
|
/* a scope label */
|
|
struct SLABEL {
|
|
std::string s;
|
|
};
|
|
/* unconditional jump */
|
|
struct JMP {
|
|
std::string l;
|
|
};
|
|
/* conditional jump */
|
|
struct CJMP {
|
|
std::string s;
|
|
std::string l;
|
|
};
|
|
/* begins procedure definition */
|
|
struct BEGIN {
|
|
std::string f;
|
|
int nargs;
|
|
int nlocals;
|
|
std::vector<ValT> closure;
|
|
std::vector<std::string> args;
|
|
std::vector<Scope> scopes;
|
|
};
|
|
/* end procedure definition */
|
|
struct END {};
|
|
/* create a closure */
|
|
struct CLOSURE {
|
|
std::string name;
|
|
std::vector<ValT> closure;
|
|
};
|
|
/* calls a closure */
|
|
struct CALLC {
|
|
int n;
|
|
bool tail;
|
|
};
|
|
/* calls a function/procedure */
|
|
struct CALL {
|
|
std::string fname;
|
|
int n;
|
|
bool tail;
|
|
};
|
|
/* returns from a function */
|
|
struct RET {};
|
|
/* drops the top element off */
|
|
struct DROP {};
|
|
/* duplicates the top element */
|
|
struct DUP {};
|
|
/* swaps two top elements */
|
|
struct SWAP {};
|
|
/* checks the tag and arity of S-expression */
|
|
struct TAG {
|
|
std::string tag;
|
|
int n;
|
|
};
|
|
/* checks the tag and size of array */
|
|
struct ARRAY {
|
|
int n;
|
|
};
|
|
/* checks various patterns */
|
|
struct PATT {
|
|
Patt patt;
|
|
};
|
|
/* match failure (location, leave a value */
|
|
struct FAIL {
|
|
size_t line;
|
|
size_t col;
|
|
bool val;
|
|
};
|
|
/* external definition */
|
|
struct EXTERN {
|
|
std::string name;
|
|
};
|
|
/* public definition */
|
|
struct PUBLIC {
|
|
std::string name;
|
|
};
|
|
/* import clause */
|
|
struct IMPORT {
|
|
std::string name;
|
|
};
|
|
/* line info */
|
|
struct LINE {
|
|
int n;
|
|
};
|
|
|
|
using T = std::variant<BINOP, CONST, STRING, SEXP, LD, LDA, ST, STI, STA,
|
|
ELEM, LABEL, FLABEL, SLABEL, JMP, CJMP, BEGIN, END,
|
|
CLOSURE, CALLC, CALL, RET, DROP, DUP, SWAP, TAG, ARRAY,
|
|
PATT, FAIL, EXTERN, PUBLIC, IMPORT, LINE>;
|
|
|
|
T val;
|
|
|
|
template <typename U>
|
|
requires(not std::is_same_v<SMInstr, std::remove_reference_t<U>>)
|
|
SMInstr(U &&x) : val(std::forward<U>(x)) {}
|
|
|
|
template <typename U> bool is() const {
|
|
return std::holds_alternative<U>(val);
|
|
}
|
|
|
|
const T &operator*() const { return val; }
|
|
const T &operator->() const { return val; }
|
|
|
|
bool operator==(const SMInstr &other) const = default;
|
|
};
|
|
|
|
std::vector<SMInstr> parse_sm(std::istream &in);
|
|
|
|
std::optional<SMInstr> parse_sm(std::string &line);
|