From 69bff131db3a42805c73b30282a7786aadc86f92 Mon Sep 17 00:00:00 2001 From: Void Date: Sat, 14 Jun 2025 00:29:53 +0200 Subject: [PATCH] uploaded current state of stacat --- Makefile | 50 ++++++++++++++++++ README.md | 20 ++++++++ doc/de_DE.md | 25 +++++++++ doc/en_EN.md | 25 +++++++++ doc/zh_CN.md | 25 +++++++++ notes.md | 33 ++++++++++++ src/config.h | 7 +++ src/interpreter/interpreter.cpp | 89 +++++++++++++++++++++++++++++++++ src/interpreter/interpreter.h | 55 ++++++++++++++++++++ src/interpreter/operations.cpp | 46 +++++++++++++++++ src/main.cpp | 79 +++++++++++++++++++++++++++++ src/main.h | 25 +++++++++ src/output.cpp | 76 ++++++++++++++++++++++++++++ src/output.h | 31 ++++++++++++ src/utils/readfile.cpp | 36 +++++++++++++ src/utils/readfile.h | 9 ++++ src/utils/utils.h | 12 +++++ 17 files changed, 643 insertions(+) create mode 100644 Makefile create mode 100644 README.md create mode 100644 doc/de_DE.md create mode 100644 doc/en_EN.md create mode 100644 doc/zh_CN.md create mode 100644 notes.md create mode 100644 src/config.h create mode 100644 src/interpreter/interpreter.cpp create mode 100644 src/interpreter/interpreter.h create mode 100644 src/interpreter/operations.cpp create mode 100644 src/main.cpp create mode 100644 src/main.h create mode 100644 src/output.cpp create mode 100644 src/output.h create mode 100644 src/utils/readfile.cpp create mode 100644 src/utils/readfile.h create mode 100644 src/utils/utils.h diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..88c82f9 --- /dev/null +++ b/Makefile @@ -0,0 +1,50 @@ +# Makefile for stacat project +# Void (c) 2024 +# Version 1.0.0 + +# Compiler flags +CFLAGS = -std=c++23 -Wall # -Wextra -Werror -pedantic -g +# -std=c99 +# Directories +SRC_DIR = ./src +OBJ_DIR = ./obj +BUILD_DIR = ./build + +# Executable name +TARGET = $(BUILD_DIR)/stacat + +# Find all .c files recursively in SRC_DIR +SRC_FILES = $(shell find $(SRC_DIR) -type f -name '*.cpp') + +# Create corresponding .o paths in OBJ_DIR with the same structure +OBJ_FILES = $(patsubst $(SRC_DIR)/%.cpp, $(OBJ_DIR)/%.o, $(SRC_FILES)) + +# Default rule +all: $(OBJ_DIR) $(BUILD_DIR) $(TARGET) + +# Create obj directory if not exists +$(OBJ_DIR): + @echo "Creating obj directory:" + mkdir -p $(OBJ_DIR) + @echo "Creating subdirectories in obj:" + @find $(SRC_DIR) -type d | sed "s@$(SRC_DIR)@$(OBJ_DIR)@" | xargs mkdir -p + +# Create build directory if not exists +$(BUILD_DIR): + @echo "Creating build directory:" + mkdir -p $(BUILD_DIR) + +# Compile each .c to .o in corresponding obj structure +$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp + @echo "Compiling $< to $@" + g++ $(CFLAGS) -c $< -o $@ + +# Link object files to create the final executable +$(TARGET): $(OBJ_FILES) + @echo "Linking object files to create the executable:" + g++ $(CFLAGS) $^ -o $(TARGET) + +# Clean rule +clean: + @echo "Cleaning all build files:" + rm -rf $(OBJ_DIR) $(TARGET) diff --git a/README.md b/README.md new file mode 100644 index 0000000..567c389 --- /dev/null +++ b/README.md @@ -0,0 +1,20 @@ +# Stacat Version 1.0.0 + +## Languages 语言 +Select your Language below | Wähle deine Sprache | __你的语言了。 + +|Language|Accuracy| +|-----------|-----| +|[English]()|100% | +|[Deutsch]()|100% | +|[中文]() |90% | + +## About the Project +This project was firstly made together with a friend from university. We used to make it one year ago, but we never managed to finish it. + +> [!NOTE] +> There is also a tiny easter egg inside this program. + +Back then it was made in C and I still love C/C++ in such a way that I thought it would be nice to implement this language. I decided to use C++ to make the program look way simpler (I mean it is really simple). + +**Void** diff --git a/doc/de_DE.md b/doc/de_DE.md new file mode 100644 index 0000000..d6da90c --- /dev/null +++ b/doc/de_DE.md @@ -0,0 +1,25 @@ +# Stacat Version 1.0.0 + +## Table of contents +1. [What is Stacat]() +2. [The Syntax of Stacat]() + - [The ">" operator]() + - [The "^" operator]() + - [The "+" operator]() + - [The "-" operator]() + - [The "*" operator]() +3. [Explanation of Errors]() +4. [Ruleset of Stacat]() + - [Repitions]() + - [Stack out of Bounds]() +5. [Why did I call it Stacat?]() + +## Was ist Stacat? + +## Erklärung der Syntax von Stacat + +## Erklärung der Fehlersyntax + +## Regelwerk der Sprache + +## Wieso habe ich die Sprache Stacat genannt? \ No newline at end of file diff --git a/doc/en_EN.md b/doc/en_EN.md new file mode 100644 index 0000000..57bc6f5 --- /dev/null +++ b/doc/en_EN.md @@ -0,0 +1,25 @@ +# Stacat Version 1.0.0 + +## Table of contents +1. [What is Stacat]() +2. [The Syntax of Stacat]() + - [The ">" operator]() + - [The "^" operator]() + - [The "+" operator]() + - [The "-" operator]() + - [The "*" operator]() +3. [Explanation of Errors]() +4. [Ruleset of Stacat]() + - [Repitions]() + - [Stack out of Bounds]() +5. [Why did I call it Stacat?]() + +## What is Stacat + +## The Syntax of Stacat + +## Explanation of Errors + +## Ruleset of Stacat + +## Why did I call it Stacat \ No newline at end of file diff --git a/doc/zh_CN.md b/doc/zh_CN.md new file mode 100644 index 0000000..25548e9 --- /dev/null +++ b/doc/zh_CN.md @@ -0,0 +1,25 @@ +# Stacat Version 1.0.0 + +## Table of contents +1. [Stacat就是什么?]() +2. [The Syntax of Stacat]() + - [The ">" operator]() + - [The "^" operator]() + - [The "+" operator]() + - [The "-" operator]() + - [The "*" operator]() +3. [Explanation of Errors]() +4. [Ruleset of Stacat]() + - [Repitions]() + - [Stack out of Bounds]() +5. [为什么我叫了它Stacat?]() + +## Stacat就是什么? + +## The Syntax of Stacat + +## Explanation of Errors + +## Ruleset of Stacat + +## 为什么我叫了它Stacat? \ No newline at end of file diff --git a/notes.md b/notes.md new file mode 100644 index 0000000..16561c7 --- /dev/null +++ b/notes.md @@ -0,0 +1,33 @@ + + +Syntax: +>: pushes 1 onto the stack +^: clones the current value onto the stack + ++: pops the stack twice and pushes the sum onto the stack +-: pops the stack twice and pushes the difference onto the stack +*: pops the stack twice and pushes the product onto the stack + +#: pops the stack and repeats the next operation n times + +!: pops the stack and outputs n as an ASCII character to the standard output +?: pushes the next character from the standard input onto the stack + +_: start line comment + +Präprozessorbefehle?! "A()" + +Unused: " $ & ' ( ) , . : ; = @ [ \ ] ` { | } + +Number examples: +1 > +2 >^+ +3 >^+>+ +4 >^+^+ +5 >^+^+>+ +6 >^+^>+* +7 >^+^>+*>+ +8 >^+^+^+ +9 >^+>+^* +10 >^+>+^*>+ +72 >^+>+^*>^+^+^+* \ No newline at end of file diff --git a/src/config.h b/src/config.h new file mode 100644 index 0000000..7dd52c5 --- /dev/null +++ b/src/config.h @@ -0,0 +1,7 @@ +#ifndef CONFIG_H +#define CONFIG_H + +#define DEBUG true +#define STACAT_VERSION "1.0.0" + +#endif \ No newline at end of file diff --git a/src/interpreter/interpreter.cpp b/src/interpreter/interpreter.cpp new file mode 100644 index 0000000..906d3c9 --- /dev/null +++ b/src/interpreter/interpreter.cpp @@ -0,0 +1,89 @@ +#include + +#include "interpreter.h" +#include "../output.h" + +using namespace std; +using namespace debug; +using namespace error; + +Interpreter::Interpreter(string data, string filename) { + // interpreter data + this->data = data; + this->stack = list(); + this->ostream = list(); + + // interpreter states + this->comment = false; + this->filename = filename; + this->line = 1; + this->column = 1; + this->before_command = 0; +} + +void Interpreter::run() { + // run interpreter + for (char command : this->data) { + this->interpret(command); + } + this->ostream.reverse(); + + // clear stack + this->stack.clear(); +} + +void Interpreter::interpret(char command) { + // evaluate command + switch (command) { + case '>': + this->push(); + break; + case '^': + this->clone(); + break; + case '+': + this->add(); + break; + case '-': + this->sub(); + break; + case '*': + this->mul(); + break; + case '!': + if (!this->comment) { + this->print(); + } + break; + case '?': + this->input(); + break; + case ' ': + break; + case '\n': + this->line++; + this->column = 1; + this->comment = false; + break; + case '\t': + this->column += 4; + break; + case '_': + this->comment = !this->comment; + break; + default: + if (!this->comment) { + throwError(UNKNOWN_INSTRUCTION, this->filename, this->line, this->column, command, __LINE__, __FILE__); + exit(EXIT_FAILURE); + } + break; + } +} + +string Interpreter::getostream() { + string output = ""; + for (char c : this->ostream) { + output += c; + } + return output; +} \ No newline at end of file diff --git a/src/interpreter/interpreter.h b/src/interpreter/interpreter.h new file mode 100644 index 0000000..359a050 --- /dev/null +++ b/src/interpreter/interpreter.h @@ -0,0 +1,55 @@ +#ifndef INTERPRETER_H +#define INTERPRETER_H + +#include +#include + +class Interpreter { + public: + // constructor + Interpreter(std::string data, std::string filename); + + // methods + void run(); + std::string getostream(); + + private: + // interpreter data + std::string data; + std::list stack; + std::list ostream; + + // interpreter states + bool comment; + std::string filename; + int line; + int column; + char before_command; + + // methods + void interpret(char command); + + void push(); + void clone(); + void add(); + void sub(); + void mul(); + + void print(); + void input(); +}; + +class Function { + public: + // constructor + Function(std::string name, std::string data); + + // methods + void run(); + private: + // function data + std::string name; + std::string data; +}; + +#endif \ No newline at end of file diff --git a/src/interpreter/operations.cpp b/src/interpreter/operations.cpp new file mode 100644 index 0000000..b593144 --- /dev/null +++ b/src/interpreter/operations.cpp @@ -0,0 +1,46 @@ +#include + +#include "interpreter.h" +#include "../output.h" + +using namespace std; +using namespace debug; +using namespace error; + +void Interpreter::push() { + this->stack.push_back(1); + this->column++; +} + +void Interpreter::clone() { + this->stack.push_back(this->stack.back()); + this->column++; +} + +void Interpreter::add() { + long long value = this->stack.back(); + this->stack.pop_back(); + this->stack.back() += value; +} + +void Interpreter::sub() { + long long value = this->stack.back(); + this->stack.pop_back(); + this->stack.back() -= value; +} + +void Interpreter::mul() { + long long value = this->stack.back(); + this->stack.pop_back(); + this->stack.back() *= value; +} + +void Interpreter::print() { + this->ostream.push_back(this->stack.back()); + this->stack.pop_back(); + this->column++; +} + +void Interpreter::input() { + log("Inputting"); +} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..cae96d3 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,79 @@ +#include + +#include "config.h" +#include "main.h" +#include "output.h" +#include "interpreter/interpreter.h" +#include "utils/utils.h" + +using namespace std; +using namespace debug; +using namespace error; + +int main(int argc, char* argv[]) { + // check arguments + program::checkargs(argc, argv); + // read arguments + ProgramMode mode = program::readargs(argc, argv); + // check interpreter mode + switch (mode) { + case FILE_INTERPRETER: + log("Running file interpreter"); + program::run(argv[1]); + break; + case CONSOLE_INTERPRETER: + log("Running console interpreter"); + program::run(); + break; + case MANUAL: + log("Displaying manual"); + program::man(); + break; + } + exit(EXIT_SUCCESS); +} + +namespace program { + + void run(char* filename) { + // prepare interpreter + string data = utils::readfile(filename); + Interpreter interpreter(data, filename); + + // run interpreter + interpreter.run(); + + // get output + string ostream = interpreter.getostream(); + program::outputconsole(ostream); + } + + void run() { + Interpreter interpreter("data", "console"); + interpreter.run(); + } + + void checkargs(int argc, char* argv[]) { + if (argc < 2) { + throwError(WRONG_ARGUMENT_COUNT, "Not enough arguments", __LINE__, __FILE__); + } + else if (argc > 2) { + throwError(WRONG_ARGUMENT_COUNT, "Too many arguments", __LINE__, __FILE__); + } + return; + } + + ProgramMode readargs(int argc, char* argv[]) { + log("Reading arguments"); + return FILE_INTERPRETER; + } + + void outputconsole(string ostream) { + cout << ostream << endl; + } + + void man() { + log("Displaying manual"); + cout << "Usage: stacat [filename]" << endl; + } +} \ No newline at end of file diff --git a/src/main.h b/src/main.h new file mode 100644 index 0000000..8e822c4 --- /dev/null +++ b/src/main.h @@ -0,0 +1,25 @@ +#ifndef MAIN_H +#define MAIN_H + +#include "config.h" + +int main(int argc, char* argv[]); + +typedef enum ProgramMode { + FILE_INTERPRETER, + CONSOLE_INTERPRETER, + MANUAL +} ProgramMode; + +namespace program { + // main.cpp + void run(char* filename); + void run(); + void checkargs(int argc, char* argv[]); + ProgramMode readargs(int argc, char* argv[]); + void outputconsole(std::string ostream); + + void man(); +} + +#endif \ No newline at end of file diff --git a/src/output.cpp b/src/output.cpp new file mode 100644 index 0000000..8127b36 --- /dev/null +++ b/src/output.cpp @@ -0,0 +1,76 @@ +#include + +#include "config.h" +#include "output.h" + +using namespace std; + +namespace debug { + + void log(string message) { + if (DEBUG) { + cerr << "(\033[1;33mDEBUG\033[0m)\033[1;34mLOG\033[0m: " << message << endl; + } + } + + void log(string message, int line) { + if (DEBUG) { + cerr << "(\033[1;33mDEBUG\033[0m)\033[1;34mLOG\033[0m: " << message << " at line " << line << endl; + } + } + + void log(string message, int line, int column, int codeLine) { + if (DEBUG) { + cerr << "(\033[1;33mDEBUG\033[0m)\033[1;34mLOG\033[0m: " << message << " at line " << line << " at column " << column << " at code line " << codeLine << endl; + } + } +} + +namespace error { + + void throwError(RuntimeError error, const string message, int line, const string file) { + string errorMessage = getRuntimeError(error); + if (DEBUG) { + cerr << "(\033[1;33mDEBUG\033[0m)\033[1;31mERROR\033[0m: " << errorMessage << " at file '" << file << "' at line " << line << endl; + } + else { + cerr << "\033[1;31mERROR\033[0m: " << errorMessage << endl; + } + } + + string getRuntimeError(RuntimeError error) { + switch (error) { + case WRONG_ARGUMENT_COUNT: + return "Wrong argument count"; + case WRONG_FILE_EXTENSION: + return "Wrong file extension"; + case FILE_NOT_FOUND: + return "File not found"; + case FILE_READ_ERROR: + return "File read error"; + case FILE_EMPTY_ERROR: + return "File empty error"; + } + } + + void throwError(InterpreterError error, const string file, const int line, const int column, const char instruction, const int codeline, const string sourcefile) { + string errorMessage = getInterpreterError(error); + if (DEBUG) { + cerr << "\033[1;35m" << file << ":l" << line << ":c" << column << "\033[0m\033[1;35m '" << instruction << "':\033[0m \033[1;31mERROR\033[0m " << "I DOAN UNDERSTAND DIS! (at line " << codeline << " at file '" << sourcefile << "')" << endl; + } + else { + cerr << "\033[1;35m" << file << ":l" << line << ":c" << column << "\033[0m\033[1;35m '" << instruction << "':\033[0m \033[1;31mERROR\033[0m " << "I DOAN UNDERSTAND DIS! " << endl; + } + } + + string getInterpreterError(InterpreterError error) { + switch (error) { + case UNKNOWN_INSTRUCTION: + return "Unknown instruction"; + case POINTER_OUT_OF_BOUNDS: + return "Pointer out of bounds"; + case INVALID_VALUE: + return "Invalid value"; + } + } +} \ No newline at end of file diff --git a/src/output.h b/src/output.h new file mode 100644 index 0000000..8817432 --- /dev/null +++ b/src/output.h @@ -0,0 +1,31 @@ +#ifndef ERROR_H +#define ERROR_H + +typedef enum RuntimeError { + WRONG_ARGUMENT_COUNT, + WRONG_FILE_EXTENSION, + FILE_NOT_FOUND, + FILE_READ_ERROR, + FILE_EMPTY_ERROR +} RuntimeError; + +typedef enum InterpreterError { + UNKNOWN_INSTRUCTION, + POINTER_OUT_OF_BOUNDS, + INVALID_VALUE +} InterpreterError; + +namespace debug { + void log(std::string message); + void log(std::string message, int line); + void log(std::string message, int line, int column, int codeLine); +} + +namespace error { + void throwError(RuntimeError error, const std::string message, int line, const std::string file); + std::string getRuntimeError(RuntimeError error); + void throwError(InterpreterError error, const std::string file, const int line, const int column, const char instruction, const int codeline, const std::string sourcefile); + std::string getInterpreterError(InterpreterError error); +} + +#endif \ No newline at end of file diff --git a/src/utils/readfile.cpp b/src/utils/readfile.cpp new file mode 100644 index 0000000..562e6fa --- /dev/null +++ b/src/utils/readfile.cpp @@ -0,0 +1,36 @@ +#include +#include + +#include "readfile.h" +#include "utils.h" +#include "../output.h" + +using namespace std; +using namespace debug; +using namespace error; + +namespace utils { + + string readfile(const char* filename) { + ifstream file(filename); + if (!checkfile(file)) { + exit(EXIT_FAILURE); + } + string data, line; + while (getline(file, line)) { + data += line; + data += '\n'; + } + data.pop_back(); + file.close(); + return data; + } + + bool checkfile(ifstream& file) { + if (!file.is_open()) { + throwError(FILE_NOT_FOUND, "File not found", __LINE__, __FILE__); + return false; + } + return true; + } +} diff --git a/src/utils/readfile.h b/src/utils/readfile.h new file mode 100644 index 0000000..8c99fd0 --- /dev/null +++ b/src/utils/readfile.h @@ -0,0 +1,9 @@ +#ifndef READFILE_H +#define READFILE_H + +#define FILE_EXTENSION ".scat" + +#define MAX_FILE_LENGTH 0x0FFFFFFFUL +#define MAX_FILE_NAME_LENGTH 256 + +#endif \ No newline at end of file diff --git a/src/utils/utils.h b/src/utils/utils.h new file mode 100644 index 0000000..b3b13e6 --- /dev/null +++ b/src/utils/utils.h @@ -0,0 +1,12 @@ +#ifndef UTILS_H +#define UTILS_H + +#include + +namespace utils { + // readfile.cpp + std::string readfile(const char* filename); + bool checkfile(std::ifstream& file); +} + +#endif \ No newline at end of file