diff --git a/src/main.cpp b/src/main.cpp index e59c42c..b7d53df 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,21 +4,28 @@ #include "Parser.h" #include "VM.h" -int main() { - Handle repl; - { - Parser parser; - parser.loadStr("(READ EVAL PRINT STOP)"); - repl = parser.parseExpr(); - } - - while (true) { +int main(int argc, char *argv[]) { + try { + Handle repl; + { + Parser parser; + parser.loadStr("(READ EVAL PRINT STOP)"); + repl = parser.parseExpr(); + } VM vm; - std::cout << std::endl; - vm.loadControl(repl); - vm.run(); - std::cout << std::endl; - } + while (true) { + std::cout << std::endl; + vm.loadControl(repl); + vm.run(); + std::cout << std::endl; + } + } catch (const std::exception &e) { + std::cerr << "\nUncaught exception: " << e.what() << std::endl; + return -1; + } catch (...) { + std::cerr << "Crash!" << std::endl; + return -1; + } return 0; } diff --git a/src/vm/include/Command.h b/src/vm/include/Command.h new file mode 100644 index 0000000..4c79d53 --- /dev/null +++ b/src/vm/include/Command.h @@ -0,0 +1,49 @@ +// +// Created by stepus53 on 3.1.24. +// + +#ifndef PSIL_COMMAND_H +#define PSIL_COMMAND_H + +#include + +#include "Cell.h" + +namespace Command { + enum Command : CellValType { + NIL = 1, + LDC = 2, + LD = 3, + SEL = 4, + JOIN = 5, + LDF = 6, + AP = 7, + RET = 8, + DUM = 9, + RAP = 10, + STOP = 11, + + ATOM = 12, + ADD = 13, + SUB = 14, + + READCHAR = 15, + PUTCHAR = 16, + PUTNUM = 17, + + EVAL = 18, + PRINT = 19, + READ = 20, + + CONS = 21, + }; + + static inline std::unordered_map str_to_cmd{ + {"NIL", 1}, {"LDC", 2}, {"LD", 3}, {"SEL", 4}, {"JOIN", 5}, {"LDF", 6}, {"AP", 7}, + {"RET", 8}, {"DUM", 9}, {"RAP", 10}, {"STOP", 11}, {"ATOM", 12}, {"ADD", 13}, {"SUB", 14}, + {"READCHAR", 15}, {"PUTCHAR", 16}, {"PUTNUM", 17}, {"EVAL", 18}, {"PRINT", 19}, {"READ", 20}, {"CONS", 21}, + }; +};// namespace Command + + +#endif//PSIL_COMMAND_H diff --git a/src/vm/include/VM.h b/src/vm/include/VM.h index ff33b12..6eb9577 100644 --- a/src/vm/include/VM.h +++ b/src/vm/include/VM.h @@ -19,7 +19,10 @@ public: void run(); - void loadControl(const Handle &h) { _c = h; } + void loadControl(const Handle &h) { + _c = h; + _stop = false; + } void step(); @@ -32,32 +35,6 @@ private: std::istream &_instream; std::ostream &_outstream; - - Handle NIL = Handle::makeStrCell("NIL"); - Handle LDC = Handle::makeStrCell("LDC"); - Handle LD = Handle::makeStrCell("LD"); - Handle SEL = Handle::makeStrCell("SEL"); - Handle JOIN = Handle::makeStrCell("JOIN"); - Handle LDF = Handle::makeStrCell("LDF"); - Handle AP = Handle::makeStrCell("AP"); - Handle RET = Handle::makeStrCell("RET"); - Handle DUM = Handle::makeStrCell("DUM"); - Handle RAP = Handle::makeStrCell("RAP"); - Handle STOP = Handle::makeStrCell("STOP"); - - Handle ATOM = Handle::makeStrCell("ATOM"); - Handle ADD = Handle::makeStrCell("ADD"); - Handle SUB = Handle::makeStrCell("SUB"); - - Handle READCHAR = Handle::makeStrCell("READCHAR"); - Handle PUTCHAR = Handle::makeStrCell("PUTCHAR"); - Handle PUTNUM = Handle::makeStrCell("PUTNUM"); - - Handle EVAL = Handle::makeStrCell("EVAL"); - Handle PRINT = Handle::makeStrCell("PRINT"); - Handle READ = Handle::makeStrCell("READ"); - - Handle CONS = Handle::makeStrCell("CONS"); }; #endif//PSIL_VM_H diff --git a/src/vm/src/Compiler.cpp b/src/vm/src/Compiler.cpp index e6c6849..05524d3 100644 --- a/src/vm/src/Compiler.cpp +++ b/src/vm/src/Compiler.cpp @@ -4,9 +4,13 @@ #include "Compiler.h" +#include "Command.h" + #include #include +using namespace Command; + Handle Compiler::compile(Handle src, Handle fake_env, Handle suffix) { Handle out; @@ -21,10 +25,10 @@ Handle Compiler::compile(Handle src, Handle fake_env, Handle suffix) { std::function compileArgsList = [&](Handle args, Handle env) { Handle out; - out.append(Handle("NIL")); + out.append(Handle(NIL)); while (!args.null()) { out.splice(compile(args.car(), env)); - out.append(Handle("CONS")); + out.append(Handle(CONS)); args = args.cdr(); } return out; @@ -33,18 +37,18 @@ Handle Compiler::compile(Handle src, Handle fake_env, Handle suffix) { Handle expr = src; if (expr.null()) { - out.append(Handle("NIL")); + out.append(Handle(NIL)); } else if (expr.atom()) { if (expr.type() == CellType::NUMATOM) { - out.append(Handle("LDC")); + out.append(Handle(LDC)); out.append(expr); } else if (expr.type() == CellType::STRATOM) { Handle idx = findIndex(expr, fake_env); if (idx == nullptr) { - out.append(Handle("LDC")); + out.append(Handle(LDC)); out.append(expr); } else { - out.append(Handle("LD")); + out.append(Handle(LD)); out.append(idx); } } @@ -54,17 +58,17 @@ Handle Compiler::compile(Handle src, Handle fake_env, Handle suffix) { if (car.atom()) { if (car.strval() == "+") { out.splice(compileArgsRaw(cdr)); - out.append(Handle("ADD")); + out.append(Handle(ADD)); } else if (car.strval() == "read") { - out.append(Handle("READ")); + out.append(Handle(READ)); } else if (car.strval() == "lambda") { - out.append(Handle("LDF")); - out.append(compile(cdr.cdr().car(), Handle::cons(cdr.car(), fake_env), Handle("RET"))); + out.append(Handle(LDF)); + out.append(compile(cdr.cdr().car(), Handle::cons(cdr.car(), fake_env), Handle(RET))); } else if (car.strval() == "if") { out.splice(compile(cdr.car(), fake_env)); - out.append(Handle("SEL")); - out.append(compile(cdr.cdr().car(), fake_env, Handle("JOIN"))); - out.append(compile(cdr.cdr().cdr().car(), fake_env, Handle("JOIN"))); + out.append(Handle(SEL)); + out.append(compile(cdr.cdr().car(), fake_env, Handle(JOIN))); + out.append(compile(cdr.cdr().cdr().car(), fake_env, Handle(JOIN))); } else if (car.strval() == "let" || car.strval() == "letrec") { std::vector> argBody; @@ -85,26 +89,26 @@ Handle Compiler::compile(Handle src, Handle fake_env, Handle suffix) { Handle newenv = Handle::cons(argNames, fake_env); if (car.strval() == "let") out.splice(compileArgsList(argBodies, fake_env)); else if (car.strval() == "letrec") { - out.append(Handle("DUM")); + out.append(Handle(DUM)); out.splice(compileArgsList(argBodies, newenv)); } - out.append(Handle("LDF")); - out.append(compile(body, newenv, Handle("RET"))); - if (car.strval() == "let") out.append(Handle("AP")); + out.append(Handle(LDF)); + out.append(compile(body, newenv, Handle(RET))); + if (car.strval() == "let") out.append(Handle(AP)); else - out.append(Handle("RAP")); + out.append(Handle(RAP)); } else { out.splice(compileArgsList(cdr, fake_env)); - out.append(Handle("LD")); + out.append(Handle(LD)); Handle idx = findIndex(car, fake_env); out.append(idx); - out.append(Handle("AP")); + out.append(Handle(AP)); } } else { out.splice(compileArgsList(cdr, fake_env)); - out.splice(compile(car, fake_env, Handle("AP"))); + out.splice(compile(car, fake_env, Handle(AP))); } } out.splice(suffix); diff --git a/src/vm/src/VM.cpp b/src/vm/src/VM.cpp index eca5dc4..4768177 100644 --- a/src/vm/src/VM.cpp +++ b/src/vm/src/VM.cpp @@ -6,10 +6,12 @@ #include #include +#include "Command.h" #include "Compiler.h" #include "Parser.h" #include "VM.h" +using namespace Command; VM::VM(std::istream &instream, std::ostream &outstream) : _instream(instream), _outstream(outstream) {} @@ -19,13 +21,15 @@ void VM::run() { void VM::step() { Handle poppedH = _c.pop(); - if (poppedH == NIL) { + // as to not complicate parser for tests... + CellValType poppedCmd = poppedH.type() == CellType::STRATOM ? str_to_cmd.at(poppedH.strval()) : poppedH.val(); + if (poppedCmd == NIL) { _s.push(nullptr); - } else if (poppedH == LDC) { + } else if (poppedCmd == LDC) { _s.push(_c.pop()); - } else if (poppedH == ATOM) { + } else if (poppedCmd == ATOM) { _s.push(_c.pop().atom() ? 1 : 0); - } else if (poppedH == LD) { + } else if (poppedCmd == LD) { Handle poppedH2 = _c.pop(); int64_t frame = poppedH2.car().val(); @@ -43,7 +47,7 @@ void VM::step() { for (int i = 1; i < arg; i++) { curArg = curArg.cdr(); } _s.push(curArg.car()); - } else if (poppedH == SEL) { + } else if (poppedCmd == SEL) { Handle popped2H = _s.pop(); Handle ct = _c.pop(); @@ -55,11 +59,11 @@ void VM::step() { } else { _c = cf; } - } else if (poppedH == JOIN) { + } else if (poppedCmd == JOIN) { _c = _d.pop(); - } else if (poppedH == LDF) { + } else if (poppedCmd == LDF) { _s.push(Handle::cons(_c.pop(), _e)); - } else if (poppedH == AP) { + } else if (poppedCmd == AP) { Handle closureH = _s.pop(); Handle argsH = _s.pop(); @@ -71,7 +75,7 @@ void VM::step() { _c = closureH.car(); _e = closureH.cdr(); _e.push(argsH); - } else if (poppedH == RET) { + } else if (poppedCmd == RET) { Handle c = _d.pop(); Handle e = _d.pop(); Handle s = _d.pop(); @@ -83,9 +87,9 @@ void VM::step() { _s = s; _s.push(ret); - } else if (poppedH == DUM) { + } else if (poppedCmd == DUM) { _e.push(nullptr); - } else if (poppedH == RAP) { + } else if (poppedCmd == RAP) { Handle closureH = _s.pop(); Handle argsH = _s.pop(); @@ -104,26 +108,26 @@ void VM::step() { _e.push(argsH); fnEnv.setcar(argsH); - } else if (poppedH == STOP) { + } else if (poppedCmd == STOP) { _stop = true; - } else if (poppedH == ADD) { + } else if (poppedCmd == ADD) { _s.push(_s.pop().val() + _s.pop().val()); - } else if (poppedH == SUB) { + } else if (poppedCmd == SUB) { assert(false); - } else if (poppedH == CONS) { + } else if (poppedCmd == CONS) { Handle h1 = _s.pop(); Handle h2 = _s.pop(); _s.push(Handle::cons(h1, h2)); - } else if (poppedH == READCHAR) { + } else if (poppedCmd == READCHAR) { char c; _instream >> c; _s.push(Handle::makeNumCell(c)); - } else if (poppedH == PUTCHAR) { + } else if (poppedCmd == PUTCHAR) { _outstream << (char) _s.pop().val(); - } else if (poppedH == PUTNUM) { + } else if (poppedCmd == PUTNUM) { _outstream << _s.pop().val(); - } else if (poppedH == EVAL) { + } else if (poppedCmd == EVAL) { Handle code = _s.pop(); Handle newc = Compiler::compile(code, nullptr); Logger::log( @@ -136,9 +140,9 @@ void VM::step() { Logger::DEBUG); newc.splice(_c); _c = newc; - } else if (poppedH == PRINT) { + } else if (poppedCmd == PRINT) { _outstream << _s.pop(); - } else if (poppedH == READ) { + } else if (poppedCmd == READ) { std::string read; std::getline(_instream, read); Parser parser; diff --git a/test/vm/VMTest.cpp b/test/vm/VMTest.cpp index be450fd..769b994 100644 --- a/test/vm/VMTest.cpp +++ b/test/vm/VMTest.cpp @@ -1,7 +1,9 @@ #include +#include "Command.h" #include "VM.h" +using namespace Command; TEST(VMTest, BasicHello) { std::stringstream ssin; std::stringstream ssout; @@ -9,11 +11,11 @@ TEST(VMTest, BasicHello) { VM vm(ssin, ssout); Handle newc(Handle::cons(nullptr, nullptr)); - newc.append(Handle::makeStrCell("NIL")); - newc.append(Handle::makeStrCell("LDC")); + newc.append(Handle::makeNumCell(NIL)); + newc.append(Handle::makeNumCell(LDC)); newc.append(Handle::makeNumCell('h')); - newc.append(Handle::makeStrCell("PUTCHAR")); - newc.append(Handle::makeStrCell("STOP")); + newc.append(Handle::makeNumCell(PUTCHAR)); + newc.append(Handle::makeNumCell(STOP)); vm.loadControl(newc); vm.run(); }