This commit is contained in:
2023-12-23 10:50:28 +01:00
commit 2685cedba4
17 changed files with 497 additions and 0 deletions

77
.gitignore vendored Normal file
View File

@@ -0,0 +1,77 @@
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
# AWS User-specific
.idea/**/aws.xml
# Generated files
.idea/**/contentModel.xml
# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
# Gradle
.idea/**/gradle.xml
.idea/**/libraries
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/jarRepositories.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr
# CMake
cmake-build-*/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# SonarLint plugin
.idea/sonarlint/
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser

8
.idea/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

8
.idea/cmake.xml generated Normal file
View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CMakeSharedSettings">
<configurations>
<configuration PROFILE_NAME="Debug" ENABLED="true" CONFIG_NAME="Debug" GENERATION_OPTIONS="-DSANITIZE=YES" />
</configurations>
</component>
</project>

4
.idea/misc.xml generated Normal file
View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
</project>

8
.idea/modules.xml generated Normal file
View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/psil.iml" filepath="$PROJECT_DIR$/.idea/psil.iml" />
</modules>
</component>
</project>

2
.idea/psil.iml generated Normal file
View File

@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<module classpath="CMake" type="CPP_MODULE" version="4" />

27
CMakeLists.txt Normal file
View File

@@ -0,0 +1,27 @@
cmake_minimum_required(VERSION 3.27)
project(psil)
if (SANITIZE STREQUAL "YES")
message(WARNING "Enabling sanitizers!")
add_compile_options(-Wall -Wextra -pedantic -Wshadow -Wformat=2 -Wfloat-equal -D_GLIBCXX_DEBUG -Wconversion -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2)
add_compile_options(-fsanitize=address -fsanitize=undefined -fno-sanitize-recover)
add_link_options(-fsanitize=address -fsanitize=undefined -fno-sanitize-recover)
endif ()
if (CMAKE_BUILD_TYPE STREQUAL "Release")
add_compile_options(-flto)
add_link_options(-flto)
endif ()
if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
add_compile_options(-O3)
add_link_options(-O3)
endif ()
set(CMAKE_CXX_STANDARD 20)
add_subdirectory(src)
enable_testing()
add_subdirectory(test)

8
src/CMakeLists.txt Normal file
View File

@@ -0,0 +1,8 @@
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_subdirectory(vm)
add_executable(psil main.cpp)
target_link_libraries(psil PRIVATE vm)

6
src/main.cpp Normal file
View File

@@ -0,0 +1,6 @@
#include <iostream>
#include "vm/includes/VM.h"
int main() {
return 0;
}

3
src/vm/CMakeLists.txt Normal file
View File

@@ -0,0 +1,3 @@
add_library(vm src/VM.cpp src/Cell.cpp)
target_include_directories(vm PUBLIC includes)

74
src/vm/includes/Cell.h Normal file
View File

@@ -0,0 +1,74 @@
//
// Created by Stepan Usatiuk on 22.12.2023.
//
#ifndef PSIL_CELL_H
#define PSIL_CELL_H
#include <cstdint>
#include <cassert>
enum class CellType {
INT,
CONS
};
struct Cell {
explicit Cell(CellType type) : _type(type) {}
virtual ~Cell() = 0;
CellType _type;
};
struct IntCell : public Cell {
IntCell() : Cell(CellType::INT) {}
IntCell(int64_t val) : Cell(CellType::INT), _val(val) {}
int64_t _val{};
};
struct CommandCell : public IntCell {
enum class CommandNum {
NIL = 1,
LDC = 2,
LD = 3,
SEL = 4,
JOIN = 5,
LDF = 6,
AP = 7,
RET = 8,
DUM = 9,
RAP = 10,
STOP = 11,
ADD = 100,
SUB = 101,
READCHAR = 201,
PUTCHAR = 202,
END = 1000
};
CommandCell(CommandNum cmd) : IntCell(static_cast<int64_t>(cmd)) {}
CommandNum intToCmd() {
assert((_val > 0 && static_cast<CommandNum>(_val) <= CommandNum::END));
return static_cast<CommandNum>(_val);
}
};
struct ConsCell : public Cell {
ConsCell() : Cell(CellType::CONS) {}
ConsCell(Cell *car) : Cell(CellType::CONS), _car(car) {}
ConsCell(Cell *car, Cell *cdr) : Cell(CellType::CONS), _car(car), _cdr(cdr) {}
Cell *_car = nullptr;
Cell *_cdr = nullptr;
};
#endif //PSIL_CELL_H

73
src/vm/includes/VM.h Normal file
View File

@@ -0,0 +1,73 @@
//
// Created by Stepan Usatiuk on 22.12.2023.
//
#ifndef PSIL_VM_H
#define PSIL_VM_H
#include <vector>
#include<utility>
#include <iostream>
#include "Cell.h"
class VM {
public:
VM(std::istream &instream = std::cin, std::ostream &outstream = std::cout);
void run();
void step();
// template<typename T>
// void appendCommand(T cell) {
// push(_c, makeCell<T>(std::move(cell)));
// }
template<typename T>
void appendCommand(T *cell) {
push(_c, cell);
}
template<typename CT, typename... Args>
CT *makeCell(Args... args) {
return static_cast<CT *>(_cells.emplace_back(new CT(std::forward<Args>(args)...)));
}
Cell *car(ConsCell *cell) {
return cell->_car;
}
Cell *cdr(ConsCell *cell) {
return cell->_cdr;
}
ConsCell *cons(Cell *car, Cell *cdr) {
return dynamic_cast<ConsCell *>(makeCell<ConsCell>(car, cdr));
}
Cell *pop(ConsCell *&what) {
Cell *ret = what->_car;
what = dynamic_cast<ConsCell *>(cdr(what));
return ret;
}
Cell *push(ConsCell *&what, Cell *toAppend) {
what = cons(toAppend, what);
return what;
}
private:
std::vector<Cell *> _cells;
ConsCell *_s = nullptr;
ConsCell *_e = nullptr;
ConsCell *_c = nullptr;
ConsCell *_d = nullptr;
bool _stop = false;
std::istream &_instream;
std::ostream &_outstream;
};
#endif //PSIL_VM_H

7
src/vm/src/Cell.cpp Normal file
View File

@@ -0,0 +1,7 @@
//
// Created by Stepan Usatiuk on 22.12.2023.
//
#include "../includes/Cell.h"
Cell::~Cell() = default;

101
src/vm/src/VM.cpp Normal file
View File

@@ -0,0 +1,101 @@
//
// Created by Stepan Usatiuk on 22.12.2023.
//
#include "../includes/VM.h"
#include <utility>
#include <iostream>
void VM::run() {
while (!_stop) step();
}
void VM::step() {
CommandCell *popped = dynamic_cast<CommandCell *>(pop(_c));
switch (popped->intToCmd()) {
case CommandCell::CommandNum::NIL: {
push(_s, nullptr);
break;
}
case CommandCell::CommandNum::LDC: {
IntCell *popped2 = dynamic_cast<IntCell *>(pop(_c));
push(_s, popped2);
break;
}
case CommandCell::CommandNum::LD: {
ConsCell *popped2 = dynamic_cast<ConsCell *>(pop(_c));
int64_t frame = dynamic_cast<IntCell *>(popped2->_car)->_val;
int64_t arg = dynamic_cast<IntCell *>(popped2->_cdr)->_val;
// todo
break;
}
case CommandCell::CommandNum::SEL: {
IntCell *popped2 = dynamic_cast<IntCell *>(pop(_s));
ConsCell *ct = dynamic_cast<ConsCell *>(pop(_c));
ConsCell *cf = dynamic_cast<ConsCell *>(pop(_c));
ConsCell *ret = _c;
push(_d, ret);
if (popped2->_val > 0) {
_c = ct;
} else {
_c = cf;
}
break;
}
case CommandCell::CommandNum::JOIN: {
ConsCell *ret = dynamic_cast<ConsCell *>(pop(_d));
_c = ret;
break;
}
case CommandCell::CommandNum::LDF: {
break;
}
case CommandCell::CommandNum::AP: {
break;
}
case CommandCell::CommandNum::RET: {
break;
}
case CommandCell::CommandNum::DUM: {
break;
}
case CommandCell::CommandNum::RAP: {
break;
}
case CommandCell::CommandNum::STOP: {
_stop = true;
break;
}
case CommandCell::CommandNum::ADD: {
break;
}
case CommandCell::CommandNum::SUB: {
break;
}
case CommandCell::CommandNum::END: {
break;
}
case CommandCell::CommandNum::READCHAR:
char c;
_instream >> c;
push(_s, makeCell<IntCell>(c));
break;
case CommandCell::CommandNum::PUTCHAR:
IntCell *popped2 = dynamic_cast<IntCell *>(pop(_s));
_outstream << (char) popped2->_val;
break;
}
}
VM::VM(std::istream &instream, std::ostream &outstream) : _instream(instream), _outstream(outstream) {
_s = dynamic_cast<ConsCell *>(makeCell<ConsCell>(nullptr));
_e = dynamic_cast<ConsCell *>(makeCell<ConsCell>(nullptr));
_c = dynamic_cast<ConsCell *>(makeCell<ConsCell>(nullptr));
_d = dynamic_cast<ConsCell *>(makeCell<ConsCell>(nullptr));
}

13
test/CMakeLists.txt Normal file
View File

@@ -0,0 +1,13 @@
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
include(FetchContent)
FetchContent_Declare(
googletest
URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip
)
# For Windows: Prevent overriding the parent project's compiler/linker settings
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)
add_subdirectory(vm)

12
test/vm/CMakeLists.txt Normal file
View File

@@ -0,0 +1,12 @@
add_executable(
VMTest
VMTest.cpp
)
target_link_libraries(
VMTest
vm
GTest::gtest_main
)
include(GoogleTest)
gtest_discover_tests(VMTest)

66
test/vm/VMTest.cpp Normal file
View File

@@ -0,0 +1,66 @@
#include <gtest/gtest.h>
#include "VM.h"
TEST(VMTest, BasicHello) {
std::stringstream ssin;
std::stringstream ssout;
{
VM vm(ssin, ssout);
vm.appendCommand(vm.makeCell<CommandCell>(CommandCell::CommandNum::STOP));
vm.appendCommand(vm.makeCell<CommandCell>(CommandCell::CommandNum::PUTCHAR));
vm.appendCommand(vm.makeCell<IntCell>('h'));
vm.appendCommand(vm.makeCell<CommandCell>(CommandCell::CommandNum::LDC));
vm.appendCommand(vm.makeCell<CommandCell>(CommandCell::CommandNum::NIL));
vm.run();
}
ssout.flush();
EXPECT_EQ(ssout.str(), "h");
}
TEST(VMTest, SelTest) {
std::stringstream ssin;
std::stringstream ssout;
{
VM vm(ssin, ssout);
vm.appendCommand(vm.makeCell<CommandCell>(CommandCell::CommandNum::STOP));
// True branch true test
ConsCell *tbtt = vm.makeCell<ConsCell>(vm.makeCell<CommandCell>(CommandCell::CommandNum::JOIN));
vm.push(tbtt, vm.makeCell<CommandCell>(CommandCell::CommandNum::PUTCHAR));
vm.push(tbtt, vm.makeCell<IntCell>('1'));
vm.push(tbtt, vm.makeCell<CommandCell>(CommandCell::CommandNum::LDC));
// False branch true test
ConsCell *fbtt = vm.makeCell<ConsCell>(vm.makeCell<CommandCell>(CommandCell::CommandNum::JOIN));
vm.push(fbtt, vm.makeCell<CommandCell>(CommandCell::CommandNum::PUTCHAR));
vm.push(fbtt, vm.makeCell<IntCell>('2'));
vm.push(fbtt, vm.makeCell<CommandCell>(CommandCell::CommandNum::LDC));
// True branch false test
ConsCell *tbft = vm.makeCell<ConsCell>(vm.makeCell<CommandCell>(CommandCell::CommandNum::JOIN));
vm.push(tbft, vm.makeCell<CommandCell>(CommandCell::CommandNum::PUTCHAR));
vm.push(tbft, vm.makeCell<IntCell>('3'));
vm.push(tbft, vm.makeCell<CommandCell>(CommandCell::CommandNum::LDC));
// False branch false test
ConsCell *fbft = vm.makeCell<ConsCell>(vm.makeCell<CommandCell>(CommandCell::CommandNum::JOIN));
vm.push(fbft, vm.makeCell<CommandCell>(CommandCell::CommandNum::PUTCHAR));
vm.push(fbft, vm.makeCell<IntCell>('4'));
vm.push(fbft, vm.makeCell<CommandCell>(CommandCell::CommandNum::LDC));
vm.appendCommand(fbft);
vm.appendCommand(tbft);
vm.appendCommand(vm.makeCell<CommandCell>(CommandCell::CommandNum::SEL));
vm.appendCommand(vm.makeCell<IntCell>(0));
vm.appendCommand(vm.makeCell<CommandCell>(CommandCell::CommandNum::LDC));
vm.appendCommand(fbtt);
vm.appendCommand(tbtt);
vm.appendCommand(vm.makeCell<CommandCell>(CommandCell::CommandNum::SEL));
vm.appendCommand(vm.makeCell<IntCell>(1));
vm.appendCommand(vm.makeCell<CommandCell>(CommandCell::CommandNum::LDC));
vm.run();
}
ssout.flush();
EXPECT_EQ(ssout.str(), "14");
}