Skip to content

Instantly share code, notes, and snippets.

@yeppiidev
Last active October 14, 2022 14:25
Show Gist options
  • Save yeppiidev/09528f684384b85d315e9221f690763e to your computer and use it in GitHub Desktop.
Save yeppiidev/09528f684384b85d315e9221f690763e to your computer and use it in GitHub Desktop.
A REPL-based language that somewhat works. Feel free to extend this to create your own language :)
#include <iostream>
#include <iterator>
#include <map>
#include <memory>
#include <sstream>
#include <stdexcept>
#include <string>
// Defines for making the code look clean
#define FUNC_TYPE_ARGS bool (*)(std::string, std::string, std::string)
// Constants
int REVISION_ID = 1;
// Variables/states
bool m_running = true;
// Helper function
template <typename... Args>
std::string string_format(const std::string& format, Args... args)
{
int size_s = std::snprintf(nullptr, 0, format.c_str(), args...) + 1; // Extra space for '\0'
if (size_s <= 0) {
throw std::runtime_error("Error during formatting.");
}
auto size = static_cast<size_t>(size_s);
auto buf = std::make_unique<char[]>(size);
std::snprintf(buf.get(), size, format.c_str(), args...);
return std::string(buf.get(), buf.get() + size - 1); // We don't want the '\0' inside
}
// Token map: funcs and stuff stored here
std::map<std::string, FUNC_TYPE_ARGS> m_functionMap;
void initialize_token_map()
{
// Used to get an ASCII character from STDIN and store it in the current stack cell
auto mfunc_inchar = [](std::string arg1, std::string arg2, std::string arg3) {
std::cout << "InChar invoked\n";
return true;
};
// Used to output the ASCII value in the current stack cell to STDOUT
auto mfunc_outchar = [](std::string arg1, std::string arg2, std::string arg3) {
std::cout << arg1;
return true;
};
// Finally, add the decleared function to the function map
m_functionMap.insert(std::pair<std::string, FUNC_TYPE_ARGS>("inchar", mfunc_inchar));
m_functionMap.insert(std::pair<std::string, FUNC_TYPE_ARGS>("outchar", mfunc_outchar));
}
int main(int argc, char* argv[])
{
std::cout << string_format("Dynamic Dummy Language (rev-%d)\n", REVISION_ID);
// Add the tokens and initialize them
initialize_token_map();
while (m_running) {
// Here are the lexed tokens from the REPL stored
std::string tokens[4];
// Print the prompt
std::cout << "\n$ > ";
std::string input;
std::getline(std::cin, input);
// Split the input
std::stringstream ssin(input);
// Tokenize the string by a ' ' (space)
for (int i = 0; ssin.good() && i < 4; ++i) {
ssin >> tokens[i];
}
// Check if the line starts with a `!quit'. If so, exit the REPL
if (input.rfind("q", 0) == 0) {
// Quit the interpreter
m_running = false;
break;
}
// Loop through each function in the function map
std::map<std::string, FUNC_TYPE_ARGS>::iterator it = m_functionMap.find(tokens[0]);
if (it != m_functionMap.end()) {
// Check the arguments and store them in a variable
auto arg1 = tokens[1] == "" ? "nil" : "";
auto arg2 = tokens[2] == "" ? "nil" : "";
auto arg3 = tokens[3] == "" ? "nil" : "";
// Execute the function and if it returns true, exit the loop
if (it->second(arg1, arg2, arg3)) {
continue;
}
} else {
// If the token isnt in the function map, throw an error
std::cout << string_format("SyntaxError: '%s' is undefined\n", input.c_str());
}
for (auto const& function : m_functionMap) {
// Check if the first token equals to the current function
if (tokens[0] == function.first) {
} else if (tokens[0] == "") {
// Ignore whitespace
continue;
} else {
// If the token isnt in the function map, throw an error
std::cout << string_format("SyntaxError: '%s' is undefined\n", input.c_str());
}
}
}
return 0;
}
# This makefile is made to run on Windows,
# you may need to modify it before running on Linux.
ifeq ($(OS),Windows_NT)
RM = del /Q /F
CP = copy /Y
ifdef ComSpec
SHELL := $(ComSpec)
endif
ifdef COMSPEC
SHELL := $(COMSPEC)
endif
else
RM = rm -rf
CP = cp -f
endif
all: clean main.exe run
clean:
-$(RM) main.exe
run:
@main.exe
main.exe:
g++ main.cxx -o main.exe -O3 -std=c++17
@yeppiidev
Copy link
Author

yeppiidev commented Jun 19, 2022

Note: The makefile is for windows so you may need to modify it for it to be able to run on Linux.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment