Initial commit

This commit is contained in:
2025-09-30 21:29:06 +10:00
commit 39735ed696
41 changed files with 1692 additions and 0 deletions

27
src/data/data.cpp Normal file
View File

@@ -0,0 +1,27 @@
#include "data.h"
#include <string>
#include <vector>
#include <map>
#include "../defs/defs.h"
#include "../error/error.h"
namespace data {
std::map<std::string, Value> vars;
std::map<std::string, std::vector<Instruction>> functions;
void modifyValue(std::string key, Value value) {
if (vars.find(key) != vars.end()) {
vars[key] = value;
} else {
error("Could not find variable " + key + "to modify (try defining first with let?)");
}
}
Value getValue(std::string key) {
if (vars.find(key) != vars.end()) {
return vars[key];
} else {
error("Could not find variable " + key + " to access (try defining first with let?)");
return Value();
}
}
}

13
src/data/data.h Normal file
View File

@@ -0,0 +1,13 @@
#pragma once
#include <map>
#include <string>
#include <vector>
#include "../defs/defs.h"
namespace data {
extern std::map<std::string, Value> vars;
extern std::map<std::string, std::vector<Instruction>> functions;
void modifyValue(std::string key, Value value);
Value getValue(std::string key);
}

205
src/defs/defs.cpp Normal file
View File

@@ -0,0 +1,205 @@
#include "defs.h"
#include "../error/error.h"
#include <vector>
#include <string>
#include <memory>
#include <utility>
InstructionType strToInstructionType(std::string in) {
if (in == "println") return InstructionType::Println;
else if (in == "print") return InstructionType::Print;
else if (in == "math") return InstructionType::Math;
else if (in == "let") return InstructionType::Let;
else if (in == "exit") return InstructionType::Exit;
else if (in == "if") return InstructionType::If;
else if (in == "while") return InstructionType::While;
else if (in == "compare") return InstructionType::Compare;
else if (in == "input") return InstructionType::Input;
else return InstructionType::Variable;
}
Instruction::Instruction(std::vector<std::string> toks) {
if (!toks.empty()) {
// Get type of instruction from first token
instruction = strToInstructionType(toks[0]);
if (instruction == InstructionType::Variable) {
for (std::string tok : toks) {
args.push_back(Value(tok));
}
} else {
// The rest are the args, convert them to values first
for (size_t i = 1; i < toks.size(); i++) {
args.push_back(Value(toks[i]));
}
}
} else {
error("Empty tokens!");
}
}
Instruction::Instruction(std::vector<Value> toks) {
if (!toks.empty()) {
// Check type of value in first token, then compute token
if (toks[0].valtype == ValueType::Real) {
instruction = strToInstructionType(toks[0].real);
} else {
error("Instruction should be a real");
}
if (instruction == InstructionType::Variable) {
for (const auto& tok : toks) {
args.push_back(tok);
}
} else {
// The rest are the args
for (size_t i = 1; i < toks.size(); i++) {
args.push_back(toks[i]);
}
}
} else {
error("Empty tokens!");
}
}
Value::Value(std::string stringval) : valtype(ValueType::Real), real(stringval) {}
Value::Value(Instruction instval) : valtype(ValueType::Processed), processed(std::make_unique<Instruction>(std::move(instval))) {}
Value::Value() : valtype(ValueType::Real) {}
Value::Value(InstructionGroup instgroup) : valtype(ValueType::InstructionGroup), instructionGroup(instgroup) {};
Value::Value(const Value& other) : valtype(other.valtype), real(other.real), varName(other.varName), instructionGroup(other.instructionGroup) {
if (other.processed) {
processed = std::make_unique<Instruction>(*other.processed);
}
}
Value::Value(Varname varname) : valtype(ValueType::Variable), varName(varname) {}
Varname::Varname(std::string in) : key(in.substr(1)) {}
Varname::Varname() : key("") {}
Value& Value::operator=(const Value& other) {
if (this != &other) {
valtype = other.valtype;
real = other.real;
varName = other.varName;
instructionGroup = other.instructionGroup;
if (other.processed) {
processed = std::make_unique<Instruction>(*other.processed);
} else {
processed.reset();
}
}
return *this;
}
std::string Value::toString() const {
std::string out = "Value(type: ";
switch (valtype) {
case ValueType::Real:
out += "Real, value: " + real + ")";
break;
case ValueType::Processed:
out += "Processed, value: ";
if (processed) {
out += processed->toString();
} else {
out += "null";
}
out += ")";
break;
case ValueType::InstructionGroup:
out += "InstructionGroup, contains " + std::to_string(instructionGroup.size()) + " instructions)";
break;
default:
out += "FIXME)";
break;
}
return out;
}
std::string Instruction::toString() const {
std::string out = "Instruction(type: ";
switch (instruction) {
case InstructionType::None:
out += "None";
break;
case InstructionType::Println:
out += "Println";
break;
case InstructionType::Math:
out += "Math";
break;
case InstructionType::Let:
out += "Let";
break;
case InstructionType::If:
out += "If";
break;
case InstructionType::Compare:
out += "Compare";
break;
case InstructionType::Input:
out += "Input";
break;
default:
out += "FIXME";
break;
}
out += ", args: [";
for (const auto& val : args) {
out += val.toString() + ", ";
}
out += "])";
return out;
}
std::vector<Value> split(std::string line) {
std::vector<Value> splitvals;
std::string buf;
bool instring = false;
int brackets = 0;
for (char chr : line) {
if (chr == ' ' && !instring && brackets == 0 && !buf.empty()) {
if (buf[0] == '$') {
splitvals.push_back(Value(Varname(buf)));
} else {
splitvals.push_back(Value(buf));
}
buf = "";
} else if (chr == '(' || chr == '[') {
brackets += 1;
if (brackets == 1) {
if (!buf.empty()) {
splitvals.push_back(Value(buf));
buf = "";
}
} else {
buf += chr;
}
} else if (chr == ')' || chr == ']') {
brackets -= 1;
if (brackets == 0) {
if (!buf.empty()) {
splitvals.push_back(Value(Instruction(split(buf))));
buf = "";
}
}
} else if (chr == '"') {
instring = !instring;
} else {
buf += chr;
}
}
if (!buf.empty()) {
if (buf[0] == '$') {
splitvals.push_back(Value(Varname(buf)));
} else {
splitvals.push_back(Value(buf));
}
}
return splitvals;
}
bool inReplMode = false;

55
src/defs/defs.h Normal file
View File

@@ -0,0 +1,55 @@
#pragma once
#include <vector>
#include <string>
#include <memory>
enum class InstructionType {
None, Print, Println, Math, Let, Variable, Exit, If, While, Input, Compare
};
enum class ValueType {
Real, Processed, Variable, InstructionGroup
};
struct Instruction;
typedef std::vector<Instruction> InstructionGroup;
struct Varname {
std::string key;
Varname(std::string in);
Varname();
};
struct Value {
ValueType valtype = ValueType::Real;
std::unique_ptr<Instruction> processed;
std::string real = "";
InstructionGroup instructionGroup;
std::string toString() const;
Varname varName = Varname();
Value(std::string stringval);
Value(Instruction instval);
Value(InstructionGroup instgroup);
Value(Varname var);
Value();
Value(const Value& other);
Value& operator=(const Value& other);
Value(Value&& other) = default;
Value& operator=(Value&& other) = default;
};
struct Instruction {
InstructionType instruction = InstructionType::None;
std::vector<Value> args;
std::string toString() const;
Instruction() = default;
Instruction(std::vector<std::string> toks);
Instruction(std::vector<Value> toks);
};
std::vector<Value> split(std::string in);
InstructionType strToInstructionType(std::string in);
extern bool inReplMode;

11
src/error/error.cpp Normal file
View File

@@ -0,0 +1,11 @@
#include "error.h"
#include "../defs/defs.h"
#include <iostream>
#include <string>
void error(std::string err) {
std::cout << "Error: " << err << std::endl;
if (!inReplMode) {
exit(1);
}
}

6
src/error/error.h Normal file
View File

@@ -0,0 +1,6 @@
#pragma once
#include <iostream>
#include <string>
void error(std::string err);

80
src/executor/executor.cpp Normal file
View File

@@ -0,0 +1,80 @@
#include "executor.h"
#include "../defs/defs.h"
#include "../data/data.h"
#include "../error/error.h"
#include "../vars/vars.h"
#include "../modules/println/println.h"
#include "../modules/print/print.h"
#include "../modules/math/math.h"
#include "../modules/let/let.h"
#include "../modules/exit/exit.h"
#include "../modules/if/if.h"
#include "../modules/while/while.h"
#include "../modules/compare/compare.h"
#include "../modules/input/input.h"
Value execute(Instruction inst) {
// Special cases that need to manage their own argument evaluation
if (inst.instruction == InstructionType::Let) {
return modules::let(inst.args);
}
if (inst.instruction == InstructionType::If) {
return modules::ifs(inst.args);
}
if (inst.instruction == InstructionType::While) {
return modules::whiles(inst.args);
}
// For all other instructions, evaluate the arguments first
size_t i = 0;
while (i < inst.args.size()) {
bool evaluated = false;
if (inst.args[i].valtype == ValueType::Processed) {
if (inst.args[i].processed) {
inst.args[i] = execute(*inst.args[i].processed);
evaluated = true;
}
} else if (inst.args[i].valtype == ValueType::Variable) {
inst.args[i] = data::getValue(inst.args[i].varName.key);
evaluated = true;
}
if (!evaluated) {
i++;
}
}
// Then, execute the instruction with the evaluated arguments
switch (inst.instruction) {
case InstructionType::Print:
return modules::print(inst.args);
break;
case InstructionType::Println:
return modules::println(inst.args);
break;
case InstructionType::Math:
return modules::math(inst.args);
break;
case InstructionType::Compare:
return modules::compare(inst.args);
break;
case InstructionType::Input:
return modules::input(inst.args);
break;
case InstructionType::Exit:
return modules::exit(inst.args);
break;
case InstructionType::Variable:
if (inst.args.size() > 2 && inst.args[1].valtype == ValueType::Real && inst.args[1].real == "=") {
return varmod(inst.args);
} else {
error("Unknown instruction or variable");
return Value("");
}
break;
default:
// Note: 'If' and 'Let' are already handled.
error("Unknown instruction");
return Value("");
}
}

5
src/executor/executor.h Normal file
View File

@@ -0,0 +1,5 @@
#pragma once
#include "../defs/defs.h"
Value execute(Instruction inst);

18
src/filerun/filerun.cpp Normal file
View File

@@ -0,0 +1,18 @@
#include "filerun.h"
#include "../parser/parser.h"
#include "../executor/executor.h"
#include <fstream>
void execFile(std::string filename) {
std::string program;
std::ifstream file(filename);
std::string buf;
while (getline(file, buf)) {
program += buf + "\n";
}
file.close();
std::vector<Instruction> parsed = parse(program);
for (Instruction inst : parsed) {
execute(inst);
}
}

5
src/filerun/filerun.h Normal file
View File

@@ -0,0 +1,5 @@
#pragma once
#include <string>
void execFile(std::string filename);

22
src/main.cpp Normal file
View File

@@ -0,0 +1,22 @@
#include "filerun/filerun.h"
#include "repl/repl.h"
#include <iostream>
#include <string.h>
int main(int argc, char** argv) {
if (argc < 2) {
repl();
} else {
for (int i = 0; i < argc; i++) {
if (strcmp(argv[i], "-h") || strcmp(argv[i], "--help")) {
std::cout << "Kyn programming language" << std::endl;
std::cout << "Usage: " << argv[0] << " (filename).kyn" << std::endl;
std::cout << "Kyn is licensed to you under the Mozilla Public License v2.0" << std::endl;
std::cout << "See the code at https://chookspace.com/max/kyn" << std::endl;
exit(0);
}
}
execFile(argv[1]);
}
}

View File

@@ -0,0 +1,45 @@
#include "compare.h"
#include "../../error/error.h"
#include "../math/math.h"
Value modules::compare(std::vector<Value> values) {
if (values.size() != 3) {
error("Compare instruction requires 3 arguments (e.g., compare 5 == 10)");
return Value("0");
}
if (values[0].valtype != ValueType::Real || values[1].valtype != ValueType::Real || values[2].valtype != ValueType::Real) {
error("Compare arguments must be real values for now");
return Value("0");
}
std::string op = values[1].real;
if (mathstuff::strisdigit(values[0].real) && mathstuff::strisdigit(values[2].real)) {
int lhs = std::stoi(values[0].real);
int rhs = std::stoi(values[2].real);
bool result = false;
if (op == "==") result = (lhs == rhs);
else if (op == "!=") result = (lhs != rhs);
else if (op == ">") result = (lhs > rhs);
else if (op == "<") result = (lhs < rhs);
else if (op == ">=") result = (lhs >= rhs);
else if (op == "<=") result = (lhs <= rhs);
else {
error("Unknown comparison operator: " + op);
}
return Value(result ? "1" : "0");
} else {
std::string lhs = values[0].real;
std::string rhs = values[2].real;
bool result = false;
if (op == "==") result = (lhs == rhs);
else if (op == "!=") result = (lhs != rhs);
else {
error("Unknown comparison operator: " + op);
}
return Value(result ? "1" : "0");
}
}

View File

@@ -0,0 +1,8 @@
#pragma once
#include "../../defs/defs.h"
#include <vector>
namespace modules {
Value compare(std::vector<Value> values);
}

12
src/modules/exit/exit.cpp Normal file
View File

@@ -0,0 +1,12 @@
#include "exit.h"
#include "../../defs/defs.h"
#include <vector>
#include "../math/math.h"
Value modules::exit(std::vector<Value> args) {
if (args.size() > 0 && args[0].valtype == ValueType::Real && mathstuff::strisdigit(args[0].real)) {
std::exit(stoi(args[0].real));
} else {
std::exit(0);
}
}

8
src/modules/exit/exit.h Normal file
View File

@@ -0,0 +1,8 @@
#pragma once
#include "../../defs/defs.h"
#include <vector>
namespace modules {
Value exit(std::vector<Value> args);
}

47
src/modules/if/if.cpp Normal file
View File

@@ -0,0 +1,47 @@
#include "if.h"
#include "../../executor/executor.h"
#include "../../error/error.h"
Value modules::ifs(std::vector<Value> args) {
if (args.size() < 2) {
error("Syntax error: 'if' statement requires a condition and a body");
return Value();
}
if (args[0].valtype != ValueType::Processed) {
error("Syntax error: 'if' condition must be an instruction");
return Value();
}
if (args[1].valtype != ValueType::InstructionGroup) {
error("Syntax error: 'if' body must be an instruction group");
return Value();
}
Value condition_result = execute(*args[0].processed);
bool is_true = false;
if (condition_result.valtype == ValueType::Real) {
if (condition_result.real != "0" && condition_result.real != "false" && !condition_result.real.empty()) {
is_true = true;
}
}
Value return_val;
if (is_true) {
for (const auto& inst : args[1].instructionGroup) {
return_val = execute(inst);
}
} else {
if (args.size() > 2) {
if (args[2].valtype == ValueType::InstructionGroup) {
for (const auto& inst : args[2].instructionGroup) {
return_val = execute(inst);
}
} else {
error("Syntax error: 'else' body must be an instruction group");
}
}
}
return return_val;
}

8
src/modules/if/if.h Normal file
View File

@@ -0,0 +1,8 @@
#pragma once
#include "../../defs/defs.h"
#include <vector>
namespace modules {
Value ifs(std::vector<Value> args);
}

View File

@@ -0,0 +1,11 @@
#include "input.h"
#include "../../defs/defs.h"
#include <vector>
#include <string>
#include <iostream>
Value modules::input(std::vector<Value> args) {
std::string userin;
std::getline(std::cin, userin);
return Value(userin);
}

View File

@@ -0,0 +1,8 @@
#pragma once
#include "../../defs/defs.h"
#include <vector>
namespace modules {
Value input(std::vector<Value> args);
}

33
src/modules/let/let.cpp Normal file
View File

@@ -0,0 +1,33 @@
#include "let.h"
#include "../../data/data.h"
#include "../../defs/defs.h"
#include "../../error/error.h"
#include <map>
#include <string>
Value modules::let(std::vector<Value> values) {
std::string varName;
if (values.size() > 0) {
if (values[0].valtype == ValueType::Real) {
varName = values[0].real;
} else {
error("FIXME unprocessed processed (in let module)");
}
if (values.size() > 1) {
if (values[1].valtype == ValueType::Real && values[1].real == "=") {
if (values.size() > 2) {
data::vars[varName] = values[2];
} else {
error("Expecting value after token '=' (in let module)");
}
} else {
error("Expecting token '=' (in let module)");
}
} else {
data::vars[varName] = Value("");
}
} else {
error("Expecting variable name (in let module)");
}
return Value("");
}

8
src/modules/let/let.h Normal file
View File

@@ -0,0 +1,8 @@
#pragma once
#include "../../data/data.h"
#include "../../defs/defs.h"
namespace modules {
Value let(std::vector<Value> values);
}

139
src/modules/math/math.cpp Normal file
View File

@@ -0,0 +1,139 @@
#include "math.h"
#include "../../defs/defs.h"
#include "../../error/error.h"
#include <vector>
mathstuff::Part::Part(int in) {
num = in;
}
mathstuff::Part::Part(mathstuff::Operators in) {
isOperator = true;
op = in;
}
bool mathstuff::strisdigit(std::string in) {
for (char c : in) {
if (!isdigit(c)) return false;
}
return true;
}
Value modules::math(std::vector<Value> values) {
std::vector<mathstuff::Part> expression;
for (Value value : values) {
if (value.valtype == ValueType::Real) {
if (value.real == "+") {
expression.push_back(mathstuff::Part(mathstuff::Operators::Add));
} else if (value.real == "-") {
expression.push_back(mathstuff::Part(mathstuff::Operators::Subtract));
} else if (value.real == "*") {
expression.push_back(mathstuff::Part(mathstuff::Operators::Multiply));
} else if (value.real == "/") {
expression.push_back(mathstuff::Part(mathstuff::Operators::Divide));
} else if (value.real == "^") {
expression.push_back(mathstuff::Part(mathstuff::Operators::Power));
} else if (value.real == "%") {
expression.push_back(mathstuff::Part(mathstuff::Operators::Mod));
} else {
if (mathstuff::strisdigit(value.real)) {
expression.push_back(mathstuff::Part(std::stoi(value.real)));
} else {
error("Expected an integer or operator (in math module)");
}
}
} else {
error("FIXME unprocessed process (in math module)");
}
}
// Power
size_t i = 0;
while (i < expression.size()) {
if (expression[i].isOperator && expression[i].op == mathstuff::Operators::Power) {
if (i >= expression.size() || expression[i + 1].isOperator) {
error("Expecting number after * (in math module)");
}
if (i == 0 || expression[i - 1].isOperator) {
error("Expecting number after * (in math module)");
}
expression[i] = mathstuff::Part(expression[i - 1].num * expression[i + 1].num);
expression.erase(std::next(expression.begin(), i + 1));
expression.erase(std::next(expression.begin(), i - 1));
}
i++;
}
// Modulo
i = 0;
while (i < expression.size()) {
if (expression[i].isOperator && expression[i].op == mathstuff::Operators::Mod) {
if (i >= expression.size() || expression[i + 1].isOperator) {
error("Expecting number after % (in math module)");
}
if (i == 0 || expression[i - 1].isOperator) {
error("Expecting number after % (in math module)");
}
expression[i] = mathstuff::Part(expression[i - 1].num % expression[i + 1].num);
expression.erase(std::next(expression.begin(), i + 1));
expression.erase(std::next(expression.begin(), i - 1));
}
i++;
}
// Multiplication + Division
i = 0;
while (i < expression.size()) {
if (expression[i].isOperator && expression[i].op == mathstuff::Operators::Multiply) {
if (i >= expression.size() || expression[i + 1].isOperator) {
error("Expecting number after * (in math module)");
}
if (i == 0 || expression[i - 1].isOperator) {
error("Expecting number after * (in math module)");
}
expression[i] = mathstuff::Part(expression[i - 1].num * expression[i + 1].num);
expression.erase(std::next(expression.begin(), i + 1));
expression.erase(std::next(expression.begin(), i - 1));
} else if (expression[i].isOperator && expression[i].op == mathstuff::Operators::Divide) {
if (i >= expression.size() || expression[i].isOperator) {
error("Expecting number after / (in math module)");
}
if (i == 0 || expression[i].isOperator) {
error("Expecting number after / (in math module)");
}
expression[i] = mathstuff::Part(expression[i - 1].num / expression[i + 1].num);
expression.erase(std::next(expression.begin(), i + 1));
expression.erase(std::next(expression.begin(), i - 1));
}
i++;
}
// Addition + Subtraction
i = 0;
while (i < expression.size()) {
if (expression[i].isOperator && expression[i].op == mathstuff::Operators::Add) {
if (i >= expression.size() || expression[i + 1].isOperator) {
error("Expecting number after + (in math module)");
}
if (i == 0 || expression[i - 1].isOperator) {
error("Expecting number after + (in math module)");
}
expression[i] = mathstuff::Part(expression[i - 1].num + expression[i + 1].num);
expression.erase(std::next(expression.begin(), i + 1));
expression.erase(std::next(expression.begin(), i - 1));
} else if (expression[i].isOperator && expression[i].op == mathstuff::Operators::Subtract) {
if (i >= expression.size() || expression[i].isOperator) {
error("Expecting number after - (in math module)");
}
if (i == 0 || expression[i].isOperator) {
error("Expecting number after - (in math module)");
}
expression[i] = mathstuff::Part(expression[i - 1].num - expression[i + 1].num);
expression.erase(std::next(expression.begin(), i + 1));
expression.erase(std::next(expression.begin(), i - 1));
}
i++;
}
return Value(std::to_string(expression[0].num));
}

24
src/modules/math/math.h Normal file
View File

@@ -0,0 +1,24 @@
#pragma once
#include "../../defs/defs.h"
#include <vector>
namespace mathstuff {
enum class Operators {
Add, Subtract, Multiply, Divide, Mod, Power, None
};
bool strisdigit(std::string in);
struct Part {
Part(int in);
Part(Operators in);
bool isOperator = false;
int num = 0;
Operators op = Operators::None;
};
}
namespace modules {
Value math(std::vector<Value> values);
}

View File

@@ -0,0 +1,17 @@
#include "print.h"
#include "../../defs/defs.h"
#include "../../error/error.h"
#include <vector>
#include <iostream>
#include <string>
Value modules::print(std::vector<Value> values) {
for (Value value : values) {
if (value.valtype == ValueType::Real) {
std::cout << value.real << " ";
} else {
error("FIXME unprocessed processed (in print module)");
}
}
return Value("");
}

View File

@@ -0,0 +1,8 @@
#pragma once
#include "../../defs/defs.h"
#include <vector>
namespace modules {
Value print(std::vector<Value> values);
}

View File

@@ -0,0 +1,18 @@
#include "println.h"
#include "../../defs/defs.h"
#include "../../error/error.h"
#include <vector>
#include <iostream>
#include <string>
Value modules::println(std::vector<Value> values) {
for (Value value : values) {
if (value.valtype == ValueType::Real) {
std::cout << value.real << " ";
} else {
error("FIXME unprocessed processed (in println module)");
}
}
std::cout << "\n";
return Value("");
}

View File

@@ -0,0 +1,8 @@
#pragma once
#include "../../defs/defs.h"
#include <vector>
namespace modules {
Value println(std::vector<Value> values);
}

View File

@@ -0,0 +1,45 @@
#include "while.h"
#include "../../executor/executor.h"
#include "../../error/error.h"
Value modules::whiles(std::vector<Value> args) {
if (args.size() < 2) {
error("Syntax error: 'while' statement requires a condition and a body");
return Value();
}
if (args[0].valtype != ValueType::Processed) {
error("Syntax error: 'while' condition must be an instruction");
return Value();
}
if (args[1].valtype != ValueType::InstructionGroup) {
error("Syntax error: 'while' body must be an instruction group");
return Value();
}
Value condition_result = execute(*args[0].processed);
bool is_true = false;
if (condition_result.valtype == ValueType::Real) {
if (condition_result.real != "0" && condition_result.real != "false" && !condition_result.real.empty()) {
is_true = true;
}
}
Value return_val;
while (is_true) {
for (const auto& inst : args[1].instructionGroup) {
return_val = execute(inst);
}
condition_result = execute(*args[0].processed);
is_true = false;
if (condition_result.valtype == ValueType::Real) {
if (condition_result.real != "0" && condition_result.real != "false" && !condition_result.real.empty()) {
is_true = true;
}
}
}
return return_val;
}

View File

@@ -0,0 +1,8 @@
#pragma once
#include "../../defs/defs.h"
#include <vector>
namespace modules {
Value whiles(std::vector<Value> args);
}

145
src/parser/parser.cpp Normal file
View File

@@ -0,0 +1,145 @@
#include "parser.h"
#include "../error/error.h"
#include <string>
#include <vector>
// Helper to trim whitespace
std::string trim(const std::string& str) {
size_t first = str.find_first_not_of(" \t\n\r");
if (std::string::npos == first) {
return str;
}
size_t last = str.find_last_not_of(" \t\n\r");
return str.substr(first, (last - first + 1));
}
std::vector<Instruction> parse(std::string program) {
std::vector<Instruction> instructions;
std::vector<std::string> lines;
std::string buf;
int blockTracker = 0;
for (char chr : program) {
if (chr == '{') {
blockTracker++;
} else if (chr == '}') {
if (blockTracker > 0) {
blockTracker--;
} else {
error("Expected opening '{' to match closing '}'");
}
}
if ((chr == '\n' || chr == ';') && blockTracker == 0) {
if (!buf.empty()) {
lines.push_back(buf);
buf.clear();
}
} else {
buf.push_back(chr);
}
}
if (blockTracker != 0) {
error("Expected closing '}' to match opening '{'");
}
if (!buf.empty()) {
lines.push_back(buf);
}
for (std::string line : lines) {
line = trim(line);
if (line.empty()) {
continue;
}
if (line.rfind("if", 0) == 0) {
Instruction if_inst;
if_inst.instruction = InstructionType::If;
size_t block_start = line.find('{');
if (block_start == std::string::npos) {
error("Expected '{' for if statement");
continue;
}
// 1. Condition
std::string condition_str = line.substr(2, block_start - 2);
if_inst.args.push_back(Value(Instruction(split(trim(condition_str)))));
// 2. Find 'then' block
size_t block_end = 0;
int brace_level = 0;
for (size_t i = block_start; i < line.length(); ++i) {
if (line[i] == '{') brace_level++;
else if (line[i] == '}') brace_level--;
if (brace_level == 0) {
block_end = i;
break;
}
}
if (block_end == 0) {
error("Mismatched braces in if statement");
continue;
}
std::string then_content = line.substr(block_start + 1, block_end - block_start - 1);
if_inst.args.push_back(Value(parse(then_content))); // Recursive call
// 3. Else block (optional)
std::string remaining_line = trim(line.substr(block_end + 1));
if (remaining_line.rfind("else", 0) == 0) {
size_t else_block_start = remaining_line.find('{');
if (else_block_start == std::string::npos) {
error("Expected '{' for else statement");
continue;
}
size_t else_block_end = remaining_line.find_last_of('}');
if (else_block_end == std::string::npos) {
error("Expected '}' for else statement");
continue;
}
std::string else_content = remaining_line.substr(else_block_start + 1, else_block_end - else_block_start - 1);
if_inst.args.push_back(Value(parse(else_content)));
}
instructions.push_back(if_inst);
} else if (line.rfind("while", 0) == 0) {
Instruction while_inst;
while_inst.instruction = InstructionType::While;
size_t block_start = line.find('{');
if (block_start == std::string::npos) {
error("Expected '{' for while statement");
continue;
}
// 1. Condition
std::string condition_str = line.substr(5, block_start - 5);
while_inst.args.push_back(Value(Instruction(split(trim(condition_str)))));
// 2. Find 'then' block
size_t block_end = 0;
int brace_level = 0;
for (size_t i = block_start; i < line.length(); ++i) {
if (line[i] == '{') brace_level++;
else if (line[i] == '}') brace_level--;
if (brace_level == 0) {
block_end = i;
break;
}
}
if (block_end == 0) {
error("Mismatched braces in while statement");
continue;
}
std::string then_content = line.substr(block_start + 1, block_end - block_start - 1);
while_inst.args.push_back(Value(parse(then_content))); // Recursive call
instructions.push_back(while_inst);
} else {
instructions.push_back(Instruction(split(line)));
}
}
return instructions;
}

7
src/parser/parser.h Normal file
View File

@@ -0,0 +1,7 @@
#pragma once
#include <vector>
#include <string>
#include "../defs/defs.h"
std::vector<Instruction> parse(std::string lines);

21
src/repl/repl.cpp Normal file
View File

@@ -0,0 +1,21 @@
#include "repl.h"
#include "../executor/executor.h"
#include "../parser/parser.h"
#include "../defs/defs.h"
#include <iostream>
#include <string>
void repl() {
inReplMode = true;
std::cout << "Kyn REPL v0.0.1" << std::endl;
std::cout << "Type 'exit' to exit" << std::endl;
std::string buf;
while (true) {
std::cout << "kyn> ";
getline(std::cin, buf);
std::vector<Instruction> parsed = parse(buf);
for (Instruction inst : parsed) {
execute(inst);
}
}
}

1
src/repl/repl.h Normal file
View File

@@ -0,0 +1 @@
void repl();

22
src/vars/vars.cpp Normal file
View File

@@ -0,0 +1,22 @@
#include "vars.h"
#include "../data/data.h"
#include "../defs/defs.h"
#include "../error/error.h"
#include <vector>
#include <string>
Value varmod(std::vector<Value> args) {
if (args.size() < 3) {
error("Not enough args to reassign variable");
}
if (args[1].real != "=") {
error("Expecting '=' token");
}
if (args[0].valtype == ValueType::Real) {
data::modifyValue(args[0].real, args[2]);
} else {
error("Invalid variable name for assignment");
}
return Value("");
}

6
src/vars/vars.h Normal file
View File

@@ -0,0 +1,6 @@
#pragma once
#include "../defs/defs.h"
#include <vector>
Value varmod(std::vector<Value> args);