uploaded current state of stacat

This commit is contained in:
2025-06-14 00:29:53 +02:00
parent e1824fc79c
commit 69bff131db
17 changed files with 643 additions and 0 deletions

50
Makefile Normal file
View File

@@ -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)

20
README.md Normal file
View File

@@ -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**

25
doc/de_DE.md Normal file
View File

@@ -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?

25
doc/en_EN.md Normal file
View File

@@ -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

25
doc/zh_CN.md Normal file
View File

@@ -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

33
notes.md Normal file
View File

@@ -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 >^+>+^*>^+^+^+*

7
src/config.h Normal file
View File

@@ -0,0 +1,7 @@
#ifndef CONFIG_H
#define CONFIG_H
#define DEBUG true
#define STACAT_VERSION "1.0.0"
#endif

View File

@@ -0,0 +1,89 @@
#include <iostream>
#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<size_t>();
this->ostream = list<char>();
// 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;
}

View File

@@ -0,0 +1,55 @@
#ifndef INTERPRETER_H
#define INTERPRETER_H
#include <iostream>
#include <list>
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<size_t> stack;
std::list<char> 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

View File

@@ -0,0 +1,46 @@
#include <iostream>
#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");
}

79
src/main.cpp Normal file
View File

@@ -0,0 +1,79 @@
#include <iostream>
#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;
}
}

25
src/main.h Normal file
View File

@@ -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

76
src/output.cpp Normal file
View File

@@ -0,0 +1,76 @@
#include <iostream>
#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";
}
}
}

31
src/output.h Normal file
View File

@@ -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

36
src/utils/readfile.cpp Normal file
View File

@@ -0,0 +1,36 @@
#include <iostream>
#include <fstream>
#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;
}
}

9
src/utils/readfile.h Normal file
View File

@@ -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

12
src/utils/utils.h Normal file
View File

@@ -0,0 +1,12 @@
#ifndef UTILS_H
#define UTILS_H
#include <fstream>
namespace utils {
// readfile.cpp
std::string readfile(const char* filename);
bool checkfile(std::ifstream& file);
}
#endif