Last active
October 14, 2022 14:25
-
-
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 :)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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 file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Note: The makefile is for windows so you may need to modify it for it to be able to run on Linux.