Compare commits
1 Commits
master
...
diamondnet
| Author | SHA1 | Date | |
|---|---|---|---|
| 945f70d756 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,2 @@
|
|||||||
ground
|
ground
|
||||||
Bobfile
|
Bobfile
|
||||||
build
|
|
||||||
5
Bobfile
Normal file
5
Bobfile
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
compiler "g++";
|
||||||
|
binary "ground";
|
||||||
|
source "src/main.cpp";
|
||||||
|
flag "Ofast";
|
||||||
|
compile;
|
||||||
22
Makefile
22
Makefile
@@ -1,22 +0,0 @@
|
|||||||
CXX = g++
|
|
||||||
CXXFLAGS = -O3 -Isrc -Wall -Wextra -std=c++17
|
|
||||||
|
|
||||||
BUILD_DIR = build
|
|
||||||
SRCS = $(shell find src -name '*.cpp')
|
|
||||||
VPATH = $(sort $(dir $(SRCS)))
|
|
||||||
OBJS = $(addprefix $(BUILD_DIR)/, $(notdir $(SRCS:.cpp=.o)))
|
|
||||||
TARGET = ground
|
|
||||||
|
|
||||||
all: $(TARGET)
|
|
||||||
|
|
||||||
$(TARGET): $(OBJS)
|
|
||||||
$(CXX) $(CXXFLAGS) -o $(TARGET) $(OBJS)
|
|
||||||
|
|
||||||
$(BUILD_DIR)/%.o: %.cpp
|
|
||||||
@mkdir -p $(BUILD_DIR)
|
|
||||||
$(CXX) $(CXXFLAGS) -c $< -o $@
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -rf $(BUILD_DIR) $(TARGET)
|
|
||||||
|
|
||||||
.PHONY: all clean
|
|
||||||
10
README.md
10
README.md
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
## What is Ground?
|
## What is Ground?
|
||||||
|
|
||||||
Ground is an interpreter which processes and interprets Ground instructions. It is quite fast, and the syntax is simple.
|
Ground is a sigma interpreter which processes and interprets Ground instructions. It is quite fast, and the syntax is simple.
|
||||||
|
|
||||||
## What are the main features of Ground?
|
## What are the main features of Ground?
|
||||||
|
|
||||||
@@ -13,7 +13,13 @@ Ground is an interpreter which processes and interprets Ground instructions. It
|
|||||||
|
|
||||||
## How do I get started?
|
## How do I get started?
|
||||||
|
|
||||||
Clone the repo and compile with `make`.
|
Clone the repo and compile with your favourite C++ compiler:
|
||||||
|
|
||||||
|
```
|
||||||
|
g++ src/main.cpp -std=c++17 -O3 -o ground
|
||||||
|
```
|
||||||
|
|
||||||
|
(You can omit the -std flag on systems which default to the latest standard, and the -O3 flag if you're fine with a slightly slower interpreter.)
|
||||||
|
|
||||||
Run a Ground program:
|
Run a Ground program:
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,12 @@ and jump to that (setting labels will be discussed below):
|
|||||||
jump %myLabel
|
jump %myLabel
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Reference a list (a list reference) with an asterisk:
|
||||||
|
|
||||||
|
```
|
||||||
|
setlist *myList $value1 $value2 # and so on
|
||||||
|
```
|
||||||
|
|
||||||
Add comments with a `#`:
|
Add comments with a `#`:
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -122,31 +128,31 @@ Note: You can also replace &var1 with a list or line reference to check if it al
|
|||||||
|
|
||||||
Allows you to initialize a list.
|
Allows you to initialize a list.
|
||||||
|
|
||||||
Usage: `setlist &list $value1 $value2 $value3...`
|
Usage: `setlist *list $value1 $value2 $value3...`
|
||||||
|
|
||||||
#### setlistat
|
#### setlistat
|
||||||
|
|
||||||
Sets a list item at an index. The item at the index must already exist. Lists are index 0.
|
Sets a list item at an index. The item at the index must already exist. Lists are index 0.
|
||||||
|
|
||||||
Usage: `setlistat &list $intvalue $value`
|
Usage: `setlistat *list $intvalue $value`
|
||||||
|
|
||||||
#### getlistat
|
#### getlistat
|
||||||
|
|
||||||
Gets a list item at an index, and puts it in the variable provided. The item at the index must already exist. Lists are index 0.
|
Gets a list item at an index, and puts it in the variable provided. The item at the index must already exist. Lists are index 0.
|
||||||
|
|
||||||
Usage: `getlistat &list $intvalue &var`
|
Usage: `getlistat *list $intvalue &var`
|
||||||
|
|
||||||
#### getlistsize
|
#### getlistsize
|
||||||
|
|
||||||
Gets the size of a list and puts it in the variable provided.
|
Gets the size of a list and puts it in the variable provided.
|
||||||
|
|
||||||
Usage: `getlistsize &list &var`
|
Usage: `getlistsize *list &var`
|
||||||
|
|
||||||
#### listappend
|
#### listappend
|
||||||
|
|
||||||
Appends an item to a list.
|
Appends an item to a list.
|
||||||
|
|
||||||
Usage: `listappend &list $var`
|
Usage: `listappend *list $var`
|
||||||
|
|
||||||
### String Operations
|
### String Operations
|
||||||
|
|
||||||
|
|||||||
Submodule libraries updated: 5e7de482e7...52e95e987f
@@ -1,170 +0,0 @@
|
|||||||
#include "compiler.h"
|
|
||||||
#include "../main.h"
|
|
||||||
#include <vector>
|
|
||||||
#include <iostream>
|
|
||||||
#include <llvm-c/TargetMachine.h>
|
|
||||||
|
|
||||||
void error(std::string in) {
|
|
||||||
std::cout << "Compiler error:" << in << std::endl;
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
GroundCompiler::GroundCompiler(const std::string& moduleName) {
|
|
||||||
context = std::make_unique<llvm::LLVMContext>();
|
|
||||||
module = std::make_unique<llvm::Module>(moduleName, *context);
|
|
||||||
builder = std::make_unique<llvm::IRBuilder<>>(*context);
|
|
||||||
|
|
||||||
llvm::InitializeNativeTarget();
|
|
||||||
llvm::InitializeNativeTargetAsmPrinter();
|
|
||||||
llvm::InitializeNativeTargetAsmParser();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GroundCompiler::createMainFunction() {
|
|
||||||
llvm::FunctionType* mainType = llvm::FunctionType::get(
|
|
||||||
llvm::Type::getInt32Ty(*context), false
|
|
||||||
);
|
|
||||||
|
|
||||||
currentFunction = llvm::Function::Create(
|
|
||||||
mainType, llvm::Function::ExternalLinkage, "main", module.get()
|
|
||||||
);
|
|
||||||
|
|
||||||
llvm::BasicBlock* entry = llvm::BasicBlock::Create(
|
|
||||||
*context, "entry", currentFunction
|
|
||||||
);
|
|
||||||
builder -> SetInsertPoint(entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
llvm::Function* GroundCompiler::getPrintfFunction() {
|
|
||||||
llvm::Function* printfFunc = module->getFunction("printf");
|
|
||||||
if (!printfFunc) {
|
|
||||||
llvm::FunctionType* printfType = llvm::FunctionType::get(
|
|
||||||
llvm::Type::getInt32Ty(*context),
|
|
||||||
//llvm::Type::getInt8PtrTy(*context),
|
|
||||||
true
|
|
||||||
);
|
|
||||||
printfFunc = llvm::Function::Create(
|
|
||||||
printfType,
|
|
||||||
llvm::Function::ExternalLinkage,
|
|
||||||
"printf",
|
|
||||||
module.get()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return printfFunc;
|
|
||||||
}
|
|
||||||
|
|
||||||
llvm::AllocaInst* GroundCompiler::createVariable(const std::string& name, llvm::Type* type) {
|
|
||||||
if (namedVals.find(name) != namedVals.end()) {
|
|
||||||
return namedVals[name];
|
|
||||||
}
|
|
||||||
|
|
||||||
llvm::IRBuilder<> tmpBuilder(
|
|
||||||
¤tFunction -> getEntryBlock(),
|
|
||||||
currentFunction -> getEntryBlock().begin()
|
|
||||||
);
|
|
||||||
llvm::AllocaInst* alloca = tmpBuilder.CreateAlloca(type, nullptr, name);
|
|
||||||
namedVals[name] = alloca;
|
|
||||||
return alloca;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GroundCompiler::compileInstruction(const Instruction& inst) {
|
|
||||||
switch (inst.inst) {
|
|
||||||
case Instructions::Set:
|
|
||||||
{
|
|
||||||
if (inst.args.size() < 2) break;
|
|
||||||
|
|
||||||
const Direct& varRef = std::get<Direct>(inst.args[0]);
|
|
||||||
const Literal& value = std::get<Literal>(inst.args[1]);
|
|
||||||
|
|
||||||
llvm::Value* val = nullptr;
|
|
||||||
llvm::Type* type = nullptr;
|
|
||||||
|
|
||||||
if (std::holds_alternative<int>(value.val)) {
|
|
||||||
int intVal = std::get<int>(value.val);
|
|
||||||
val = llvm::ConstantInt::get(*context, llvm::APInt(32, intVal, true));
|
|
||||||
type = llvm::Type::getInt32Ty(*context);
|
|
||||||
} else {
|
|
||||||
error("Unsupported type at present");
|
|
||||||
}
|
|
||||||
|
|
||||||
llvm::AllocaInst* variable = createVariable(varRef.varName, type);
|
|
||||||
builder->CreateStore(val, variable);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
error("For now, only set instruction is supported in compiler");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GroundCompiler::createBasicBlocks(const std::vector<Instruction>& instructions) {
|
|
||||||
for (size_t i = 0; i < instructions.size(); i++) {
|
|
||||||
llvm::BasicBlock* bb = llvm::BasicBlock::Create(
|
|
||||||
*context, "line_" + std::to_string(i), currentFunction
|
|
||||||
);
|
|
||||||
lineBlocks[i] = bb;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GroundCompiler::compile(const std::vector<Instruction>& instructions) {
|
|
||||||
createMainFunction();
|
|
||||||
createBasicBlocks(instructions);
|
|
||||||
|
|
||||||
for (const auto& inst : instructions) {
|
|
||||||
compileInstruction(inst);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string errorStr;
|
|
||||||
llvm::raw_string_ostream errorStream(errorStr);
|
|
||||||
if (llvm::verifyModule(*module, &errorStream)) {
|
|
||||||
error("Module verification error" + errorStr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GroundCompiler::writeObjectFile(const std::string& filename) {
|
|
||||||
char* targetTripleCStr = LLVMGetDefaultTargetTriple();
|
|
||||||
std::string targetTriple(targetTripleCStr);
|
|
||||||
LLVMDisposeErrorMessage(targetTripleCStr);
|
|
||||||
module -> setTargetTriple(targetTriple);
|
|
||||||
std::string error;
|
|
||||||
const llvm::Target* target = llvm::TargetRegistry::lookupTarget(targetTriple, error);
|
|
||||||
|
|
||||||
if (!target) {
|
|
||||||
llvm::errs() << "Target Error: " << error;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
llvm::TargetOptions opt;
|
|
||||||
llvm::TargetMachine* targetMachine = target -> createTargetMachine(
|
|
||||||
targetTriple, "generic", "", opt, llvm::Reloc::PIC_
|
|
||||||
);
|
|
||||||
|
|
||||||
module -> setDataLayout(targetMachine -> createDataLayout());
|
|
||||||
|
|
||||||
std::error_code ec;
|
|
||||||
llvm::raw_fd_ostream dest(filename, ec, llvm::sys::fs::OF_None);
|
|
||||||
|
|
||||||
if (ec) {
|
|
||||||
llvm::errs() << "Couldn't open file, error: " << ec.message();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
llvm::legacy::PassManager pass;
|
|
||||||
if (targetMachine -> addPassesToEmitFile(pass, dest, nullptr, llvm::CodeGenFileType::ObjectFile)) {
|
|
||||||
llvm::errs() << "Target machine cannot emit object file";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
pass.run(*module);
|
|
||||||
dest.flush();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GroundCompiler::printIR() {
|
|
||||||
module->print(llvm::outs(), nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void compile(std::vector<Instruction> instructions) {
|
|
||||||
std::cout << "gonna compile some crap" << std::endl;
|
|
||||||
GroundCompiler compiler("cool_program");
|
|
||||||
compiler.compile(instructions);
|
|
||||||
compiler.printIR();
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <vector>
|
|
||||||
#include <memory>
|
|
||||||
#include <map>
|
|
||||||
#include <string>
|
|
||||||
#include <llvm/IR/LLVMContext.h>
|
|
||||||
#include <llvm/IR/Module.h>
|
|
||||||
#include <llvm/IR/IRBuilder.h>
|
|
||||||
#include <llvm/IR/Verifier.h>
|
|
||||||
#include <llvm/Support/TargetSelect.h>
|
|
||||||
#include <llvm/Target/TargetMachine.h>
|
|
||||||
#include <llvm/Target/TargetOptions.h>
|
|
||||||
#include <llvm/MC/TargetRegistry.h>
|
|
||||||
#include <llvm/Support/FileSystem.h>
|
|
||||||
#include <llvm/Support/raw_ostream.h>
|
|
||||||
#include <llvm/IR/LegacyPassManager.h>
|
|
||||||
//#include <llvm/Support/Host.h>
|
|
||||||
#include "../main.h"
|
|
||||||
|
|
||||||
void error(std::string in);
|
|
||||||
|
|
||||||
// class to make llvming around easier
|
|
||||||
class GroundCompiler {
|
|
||||||
private:
|
|
||||||
std::unique_ptr<llvm::LLVMContext> context;
|
|
||||||
std::unique_ptr<llvm::Module> module;
|
|
||||||
std::unique_ptr<llvm::IRBuilder<>> builder;
|
|
||||||
|
|
||||||
std::map<std::string, llvm::AllocaInst*> namedVals;
|
|
||||||
|
|
||||||
llvm::Function* currentFunction;
|
|
||||||
|
|
||||||
std::map<int, llvm::BasicBlock*> lineBlocks;
|
|
||||||
public:
|
|
||||||
GroundCompiler(const std::string& moduleName);
|
|
||||||
void createMainFunction();
|
|
||||||
llvm::Function* getPrintfFunction();
|
|
||||||
llvm::AllocaInst* createVariable(const std::string& name, llvm::Type* type);
|
|
||||||
void compileInstruction(const Instruction& inst);
|
|
||||||
void createBasicBlocks(const std::vector<Instruction>& instructions);
|
|
||||||
void compile(const std::vector<Instruction>& instructions);
|
|
||||||
bool writeObjectFile(const std::string& filename);
|
|
||||||
void printIR();
|
|
||||||
};
|
|
||||||
|
|
||||||
void compile(std::vector<Instruction> instructions);
|
|
||||||
|
|
||||||
@@ -1,244 +0,0 @@
|
|||||||
#include "data.h"
|
|
||||||
#include "../main.h"
|
|
||||||
#include "../error/error.h"
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include <map>
|
|
||||||
#include <stack>
|
|
||||||
|
|
||||||
/*
|
|
||||||
labelStack stack
|
|
||||||
Allows each function to hold it's own set of labels
|
|
||||||
*/
|
|
||||||
std::stack<std::map<std::string, int>> labelStack;
|
|
||||||
|
|
||||||
/*
|
|
||||||
variables map
|
|
||||||
Contains all variables made while running the program. See also Literal struct.
|
|
||||||
*/
|
|
||||||
std::map<std::string, Literal> variables;
|
|
||||||
|
|
||||||
/*
|
|
||||||
functions map
|
|
||||||
Contains the code of functions and types of their values
|
|
||||||
*/
|
|
||||||
std::map<std::string, Function> functions;
|
|
||||||
|
|
||||||
/*
|
|
||||||
structs map
|
|
||||||
Contains structs (see the Struct struct for more info)
|
|
||||||
*/
|
|
||||||
std::map<std::string, Struct> structs;
|
|
||||||
|
|
||||||
/*
|
|
||||||
fnArgs vector
|
|
||||||
Containst the arguments to be passed to a function
|
|
||||||
*/
|
|
||||||
std::vector<Literal> fnArgs;
|
|
||||||
|
|
||||||
// External library functions and other things
|
|
||||||
|
|
||||||
// Handle to loaded libraries
|
|
||||||
std::map<std::string, void*> loadedLibraries;
|
|
||||||
|
|
||||||
// Map of function name to function pointer
|
|
||||||
std::map<std::string, void*> externalFunctions;
|
|
||||||
|
|
||||||
// Libraries currently imported
|
|
||||||
std::vector<std::string> libraries;
|
|
||||||
|
|
||||||
// Conversion functions
|
|
||||||
GroundValue literalToGroundValue(const Literal& lit) {
|
|
||||||
GroundValue gv;
|
|
||||||
if (std::holds_alternative<int>(lit.val)) {
|
|
||||||
gv.type = GROUND_INT;
|
|
||||||
gv.data.int_val = std::get<int>(lit.val);
|
|
||||||
} else if (std::holds_alternative<double>(lit.val)) {
|
|
||||||
gv.type = GROUND_DOUBLE;
|
|
||||||
gv.data.double_val = std::get<double>(lit.val);
|
|
||||||
} else if (std::holds_alternative<bool>(lit.val)) {
|
|
||||||
gv.type = GROUND_BOOL;
|
|
||||||
gv.data.bool_val = std::get<bool>(lit.val) ? 1 : 0;
|
|
||||||
} else if (std::holds_alternative<std::string>(lit.val)) {
|
|
||||||
gv.type = GROUND_STRING;
|
|
||||||
gv.data.string_val = const_cast<char*>(std::get<std::string>(lit.val).c_str());
|
|
||||||
} else if (std::holds_alternative<char>(lit.val)) {
|
|
||||||
gv.type = GROUND_CHAR;
|
|
||||||
gv.data.char_val = std::get<char>(lit.val);
|
|
||||||
}
|
|
||||||
return gv;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
catches stackmap
|
|
||||||
This stores all catches in a scope, to catch errors before they happen.
|
|
||||||
*/
|
|
||||||
std::stack<std::map<std::string, Direct>> catches;
|
|
||||||
|
|
||||||
Literal groundValueToLiteral(const GroundValue& gv) {
|
|
||||||
Literal lit;
|
|
||||||
switch (gv.type) {
|
|
||||||
case GROUND_INT:
|
|
||||||
lit.val = gv.data.int_val;
|
|
||||||
break;
|
|
||||||
case GROUND_DOUBLE:
|
|
||||||
lit.val = gv.data.double_val;
|
|
||||||
break;
|
|
||||||
case GROUND_BOOL:
|
|
||||||
lit.val = (gv.data.bool_val != 0);
|
|
||||||
break;
|
|
||||||
case GROUND_STRING:
|
|
||||||
lit.val = std::string(gv.data.string_val);
|
|
||||||
break;
|
|
||||||
case GROUND_CHAR:
|
|
||||||
lit.val = gv.data.char_val;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return lit;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
is* functions
|
|
||||||
These functions determine if a string value can be converted into a different type.
|
|
||||||
*/
|
|
||||||
|
|
||||||
bool isInt(std::string in) {
|
|
||||||
try {
|
|
||||||
std::stoi(in);
|
|
||||||
if (std::stod(in) != std::stoi(in)) return false;
|
|
||||||
return true;
|
|
||||||
} catch (...) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isDouble(std::string in) {
|
|
||||||
try {
|
|
||||||
std::stod(in);
|
|
||||||
return true;
|
|
||||||
} catch (...) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isBool(std::string in) {
|
|
||||||
if (in == "true" || in == "false") return true;
|
|
||||||
else return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isString(std::string in) {
|
|
||||||
if (in.size() >= 2 && in[0] == '"' && in[in.size() - 1] == '"') return true;
|
|
||||||
else return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isChar(std::string in) {
|
|
||||||
if (in.size() == 3 && in[0] == '\'' && in[in.size() - 1] == '\'') return true;
|
|
||||||
else return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isValue(std::string in) {
|
|
||||||
if (in.size() >= 1 && in[0] == '$') return true;
|
|
||||||
else return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isDirect(std::string in) {
|
|
||||||
if (in.size() >= 1 && in[0] == '&') return true;
|
|
||||||
else return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isLine(std::string in) {
|
|
||||||
if (in.size() >= 1 && in[0] == '%') return true;
|
|
||||||
else return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isLabel(std::string in) {
|
|
||||||
if (in.size() >= 1 && in[0] == '@') return true;
|
|
||||||
else return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isType(std::string in) {
|
|
||||||
if (in.size() > 1 && in[0] == '-') return true;
|
|
||||||
else return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isFunction(std::string in) {
|
|
||||||
if (in.size() >= 1 && in[0] == '!') return true;
|
|
||||||
else return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isReferencingStruct(std::string in) {
|
|
||||||
return in.find('.') != std::string::npos;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
getType function
|
|
||||||
This function determines the type of a value inside a string based on the is*
|
|
||||||
functions above. Returns a type from the Types enum class.
|
|
||||||
*/
|
|
||||||
Types getType(std::string in) {
|
|
||||||
if (isInt(in)) return Types::Int;
|
|
||||||
if (isDouble(in)) return Types::Double;
|
|
||||||
if (isBool(in)) return Types::Bool;
|
|
||||||
if (isString(in)) return Types::String;
|
|
||||||
if (isChar(in)) return Types::Char;
|
|
||||||
if (isValue(in)) return Types::Value;
|
|
||||||
if (isDirect(in)) return Types::Direct;
|
|
||||||
if (isLine(in)) return Types::Line;
|
|
||||||
if (isLabel(in)) return Types::Label;
|
|
||||||
if (isType(in)) return Types::Type;
|
|
||||||
if (isFunction(in)) return Types::Function;
|
|
||||||
error("Could not determine type of \"" + in + "\"");
|
|
||||||
return Types::Int;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
getLitType function
|
|
||||||
This function determines the type of a value inside a Literal based on the
|
|
||||||
holds_alternative() function. Returns a type from the Types enum class.
|
|
||||||
*/
|
|
||||||
Types getLitType(Literal in) {
|
|
||||||
if (std::holds_alternative<int>(in.val)) return Types::Int;
|
|
||||||
if (std::holds_alternative<double>(in.val)) return Types::Double;
|
|
||||||
if (std::holds_alternative<bool>(in.val)) return Types::Bool;
|
|
||||||
if (std::holds_alternative<std::string>(in.val)) return Types::String;
|
|
||||||
if (std::holds_alternative<char>(in.val)) return Types::Char;
|
|
||||||
if (std::holds_alternative<List>(in.val)) return Types::List;
|
|
||||||
return Types::Other;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
setVal function
|
|
||||||
This function sets the value of a variable (whether in a struct or not).
|
|
||||||
*/
|
|
||||||
void setVal(std::string varName, Literal value) {
|
|
||||||
if (isReferencingStruct(varName)) {
|
|
||||||
std::string structName;
|
|
||||||
std::string varInStruct;
|
|
||||||
|
|
||||||
size_t dotPos = varName.find('.'); // Use size_t
|
|
||||||
if (dotPos != std::string::npos) {
|
|
||||||
structName = varName.substr(0, dotPos);
|
|
||||||
varInStruct = varName.substr(dotPos + 1);
|
|
||||||
if (variables.find(structName) != variables.end()) {
|
|
||||||
if (std::holds_alternative<Struct>(variables[structName].val)) {
|
|
||||||
Struct structVal = std::get<Struct>(variables[structName].val);
|
|
||||||
if (structVal.values.find(varInStruct) != structVal.values.end()) {
|
|
||||||
structVal.values[varInStruct] = value;
|
|
||||||
variables[structName].val = structVal; // Write back the modified struct
|
|
||||||
} else {
|
|
||||||
error("Could not find property '" + varInStruct + "' in struct '" + structName + "'");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
error("Variable '" + structName + "' is not a struct");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
error("Could not find struct '" + structName + "'");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
error("Invalid struct member access syntax");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Handle regular variables (both existing and new)
|
|
||||||
variables[varName] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "../main.h"
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
#include <map>
|
|
||||||
#include <stack>
|
|
||||||
|
|
||||||
/*
|
|
||||||
functions map
|
|
||||||
Contains the code of functions and types of their values
|
|
||||||
*/
|
|
||||||
extern std::map<std::string, Function> functions;
|
|
||||||
|
|
||||||
/*
|
|
||||||
structs map
|
|
||||||
Contains structs (see the Struct struct for more info)
|
|
||||||
*/
|
|
||||||
extern std::map<std::string, Struct> structs;
|
|
||||||
|
|
||||||
/*
|
|
||||||
fnArgs vector
|
|
||||||
Containst the arguments to be passed to a function
|
|
||||||
*/
|
|
||||||
extern std::vector<Literal> fnArgs;
|
|
||||||
|
|
||||||
// External library functions and other things
|
|
||||||
|
|
||||||
// Handle to loaded libraries
|
|
||||||
extern std::map<std::string, void*> loadedLibraries;
|
|
||||||
|
|
||||||
// Map of function name to function pointer
|
|
||||||
extern std::map<std::string, void*> externalFunctions;
|
|
||||||
|
|
||||||
// Libraries currently imported
|
|
||||||
extern std::vector<std::string> libraries;
|
|
||||||
|
|
||||||
// catches stackmap
|
|
||||||
extern std::stack<std::map<std::string, Direct>> catches;
|
|
||||||
|
|
||||||
// labelStack stack
|
|
||||||
extern std::stack<std::map<std::string, int>> labelStack;
|
|
||||||
|
|
||||||
// variables map
|
|
||||||
extern std::map<std::string, Literal> variables;
|
|
||||||
|
|
||||||
GroundValue literalToGroundValue(const Literal& lit);
|
|
||||||
Literal groundValueToLiteral(const GroundValue& gv);
|
|
||||||
void setVal(std::string varName, Literal value);
|
|
||||||
|
|
||||||
bool isInt(std::string in);
|
|
||||||
bool isDouble(std::string in);
|
|
||||||
bool isBool(std::string in);
|
|
||||||
bool isString(std::string in);
|
|
||||||
bool isChar(std::string in);
|
|
||||||
bool isValue(std::string in);
|
|
||||||
bool isDirect(std::string in);
|
|
||||||
bool isLine(std::string in);
|
|
||||||
bool isLabel(std::string in);
|
|
||||||
bool isType(std::string in);
|
|
||||||
bool isFunction(std::string in);
|
|
||||||
bool isReferencingStruct(std::string in);
|
|
||||||
|
|
||||||
Types getType(std::string in);
|
|
||||||
Types getLitType(Literal in);
|
|
||||||
|
|
||||||
void setVal(std::string varName, Literal value);
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
#include <iostream>
|
|
||||||
#include <cstdlib>
|
|
||||||
#include "error.h"
|
|
||||||
#include "../data/data.h"
|
|
||||||
#include "../main.h"
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
/*
|
|
||||||
error function
|
|
||||||
Takes a string (which is a debug message) and prints it to the console, letting the
|
|
||||||
user know what went wrong with the program.
|
|
||||||
*/
|
|
||||||
Literal error(string in, string errCode, int exitc) {
|
|
||||||
Error retError;
|
|
||||||
retError.code = errCode;
|
|
||||||
retError.pops = 0;
|
|
||||||
while (catches.size() > 0) {
|
|
||||||
if (catches.top().find(errCode) != catches.top().end()) {
|
|
||||||
Literal tmpLit;
|
|
||||||
tmpLit.val = false;
|
|
||||||
setVal(catches.top()[errCode].varName, tmpLit);
|
|
||||||
retError.reporter = catches.top()[errCode].varName;
|
|
||||||
Literal tmpLit2;
|
|
||||||
tmpLit2.val = retError;
|
|
||||||
return tmpLit2;
|
|
||||||
} else {
|
|
||||||
catches.pop();
|
|
||||||
retError.pops ++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cout << "\033[31m" + errCode + ": \033[39m" << in << endl;
|
|
||||||
exit(exitc);
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "../main.h"
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
Literal error(std::string in, std::string errCode = "syntaxError", int exitc = 1);
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include "../main.h"
|
|
||||||
|
|
||||||
void preProcessLabels(std::vector<Instruction> instructions);
|
|
||||||
Literal exec(std::vector<Instruction> in, bool executingFunction = false);
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
#include "lexer.h"
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
/*
|
|
||||||
lexer function
|
|
||||||
This function takes the raw text from the file and splits it into a format
|
|
||||||
that the parser can understand.
|
|
||||||
*/
|
|
||||||
|
|
||||||
vector<vector<string>> lexer(string in) {
|
|
||||||
vector<vector<string>> out;
|
|
||||||
vector<string> line;
|
|
||||||
string buf;
|
|
||||||
bool procString = false;
|
|
||||||
bool procChar = false;
|
|
||||||
bool isComment = false;
|
|
||||||
|
|
||||||
for (char i : in) {
|
|
||||||
switch (i) {
|
|
||||||
case '"':
|
|
||||||
if (!isComment) {
|
|
||||||
if (procChar) {
|
|
||||||
buf.push_back(i);
|
|
||||||
} else {
|
|
||||||
procString = !procString;
|
|
||||||
buf.push_back(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case '\'':
|
|
||||||
if (!isComment) {
|
|
||||||
if (procString) {
|
|
||||||
buf.push_back(i);
|
|
||||||
} else {
|
|
||||||
procChar = !procChar;
|
|
||||||
buf.push_back(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case '\n':
|
|
||||||
if (!procString && !procChar) {
|
|
||||||
if (!buf.empty()) line.push_back(buf);
|
|
||||||
out.push_back(line);
|
|
||||||
buf.clear();
|
|
||||||
line.clear();
|
|
||||||
isComment = false;
|
|
||||||
} else {
|
|
||||||
if (!isComment) buf.push_back(i);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case '#':
|
|
||||||
if (!procString && !procChar) {
|
|
||||||
isComment = true;
|
|
||||||
if (!buf.empty()) line.push_back(buf);
|
|
||||||
out.push_back(line);
|
|
||||||
buf.clear();
|
|
||||||
line.clear();
|
|
||||||
} else {
|
|
||||||
buf.push_back(i);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ' ':
|
|
||||||
if (!procString && !procChar) {
|
|
||||||
if (!buf.empty() && !isComment) line.push_back(buf);
|
|
||||||
buf.clear();
|
|
||||||
} else {
|
|
||||||
buf.push_back(i);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (!isComment) buf.push_back(i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!buf.empty()) line.push_back(buf);
|
|
||||||
out.push_back(line);
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
std::vector<std::vector<std::string>> lexer(std::string in);
|
|
||||||
2927
src/main.cpp
2927
src/main.cpp
File diff suppressed because it is too large
Load Diff
250
src/main.h
250
src/main.h
@@ -1,250 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
#include <map>
|
|
||||||
#include <variant>
|
|
||||||
|
|
||||||
// Headers for external libraries
|
|
||||||
#ifdef _WIN32
|
|
||||||
// Note: Windows support is experiemental. Maybe try using a superior
|
|
||||||
// operating system? (cough cough, Linux?)
|
|
||||||
#include <windows.h>
|
|
||||||
#define DLOPEN(path) LoadLibrary(path)
|
|
||||||
#define DLSYM(handle, name) GetProcAddress(handle, name)
|
|
||||||
#define DLCLOSE(handle) FreeLibrary(handle)
|
|
||||||
#define DLERROR() "Windows DLL Error"
|
|
||||||
#else
|
|
||||||
#include <dlfcn.h>
|
|
||||||
#define DLOPEN(path) dlopen(path, RTLD_LAZY)
|
|
||||||
#define DLSYM(handle, name) dlsym(handle, name)
|
|
||||||
#define DLCLOSE(handle) dlclose(handle)
|
|
||||||
#define DLERROR() dlerror()
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
Instructions enum class
|
|
||||||
For each function keyword, an instruction is assigned. See also parser
|
|
||||||
function, interpreter function, Instruction struct
|
|
||||||
*/
|
|
||||||
enum class Instructions {
|
|
||||||
Jump, If,
|
|
||||||
Stdout, Stdin, Stdlnout,
|
|
||||||
Add, Subtract, Multiply, Divide,
|
|
||||||
Equal, Inequal, Greater, Lesser, Not,
|
|
||||||
End, Set, Empty, Gettype, Exists,
|
|
||||||
Setlist, Getlistat, Setlistat, Getlistsize, Listappend, Listprepend,
|
|
||||||
Getstrcharat, Getstrsize,
|
|
||||||
Stoi, Stod, Tostring,
|
|
||||||
Fun, Return, Endfun, Pusharg, Call, Local,
|
|
||||||
Use, Extern, Error, Catch, Try, Exception,
|
|
||||||
Struct, Endstruct, Init
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
Types enum class
|
|
||||||
Assists in type checking in the parser function. For example, the
|
|
||||||
following values correspond to the following types:
|
|
||||||
1 Int
|
|
||||||
3.14 Double
|
|
||||||
"Hello!" String
|
|
||||||
'e' Char
|
|
||||||
true Bool
|
|
||||||
$value Value
|
|
||||||
&var Direct
|
|
||||||
%10 Line
|
|
||||||
See also parser function
|
|
||||||
*/
|
|
||||||
enum class Types {
|
|
||||||
Int, Double, String, Char, Bool, Value, Direct, Line, List, Label, Type, Function, Other
|
|
||||||
};
|
|
||||||
|
|
||||||
// Forward declaration of Literal for list
|
|
||||||
struct Literal;
|
|
||||||
|
|
||||||
/*
|
|
||||||
List struct
|
|
||||||
Contains literal values inside a vector. For example, if the following
|
|
||||||
program was written:
|
|
||||||
setlist #myNums 3 5 9 13
|
|
||||||
The List struct which would be created and stored should look like this:
|
|
||||||
{
|
|
||||||
val = {
|
|
||||||
Literal {
|
|
||||||
val = 3
|
|
||||||
},
|
|
||||||
Literal {
|
|
||||||
val = 5
|
|
||||||
},
|
|
||||||
Literal {
|
|
||||||
val = 9
|
|
||||||
},
|
|
||||||
Literal {
|
|
||||||
val = 13
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
All elements in the list must be of the same type. See also Literal struct.
|
|
||||||
*/
|
|
||||||
struct List {
|
|
||||||
std::vector<Literal> val;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
Direct struct
|
|
||||||
If the program being executed makes a direct reference, it is stored in a Direct
|
|
||||||
struct. For example, if the following line was written:
|
|
||||||
stdin &myVar
|
|
||||||
The Direct struct in the instruction should look like this:
|
|
||||||
{
|
|
||||||
varName = "myVar";
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
struct Direct {
|
|
||||||
std::string varName;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct TypeRef {
|
|
||||||
bool isCustomType = false;
|
|
||||||
std::string customType;
|
|
||||||
Types type;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FunctionRef {
|
|
||||||
std::string fnName;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
Label struct
|
|
||||||
Contains information needed to register labels
|
|
||||||
*/
|
|
||||||
struct Label {
|
|
||||||
std::string id;
|
|
||||||
int lineNum = -1;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
Line struct
|
|
||||||
Contains information needed to jump to lines
|
|
||||||
*/
|
|
||||||
struct Line {
|
|
||||||
int lineNum = -1;
|
|
||||||
bool isLabel = false;
|
|
||||||
std::string label;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
ValueRef struct
|
|
||||||
If the program being executed makes a value reference, it is stored in a ValueRef
|
|
||||||
struct. For example, if the following line was written:
|
|
||||||
stdin &myVar
|
|
||||||
The ValueRef struct in the instruction should look like this:
|
|
||||||
{
|
|
||||||
varName = "myVar";
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
struct ValueRef {
|
|
||||||
std::string varName;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
Instruction struct
|
|
||||||
An instruction usually corresponds to a line in the program being interpreted.
|
|
||||||
For example, if the following line was written:
|
|
||||||
add 5 $myVar &outVar
|
|
||||||
The instruction should look like this:
|
|
||||||
{
|
|
||||||
inst = Instructions::Add;
|
|
||||||
args = {
|
|
||||||
Literal {
|
|
||||||
val = 5
|
|
||||||
},
|
|
||||||
ValueRef {
|
|
||||||
varName = "myVar"
|
|
||||||
},
|
|
||||||
Direct {
|
|
||||||
varName = "outVar"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
inst starts as empty, so empty lines and commented out lines do not get in the
|
|
||||||
way of jump and if.
|
|
||||||
See also: Instructions enum class, Literal struct, ValueRef struct, Direct struct,
|
|
||||||
Line struct, exec function, parser function
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef std::variant<Literal, ValueRef, FunctionRef, TypeRef, Direct, Line> argument;
|
|
||||||
struct Instruction {
|
|
||||||
Instructions inst = Instructions::Empty;
|
|
||||||
std::vector<argument> args;
|
|
||||||
bool isLabel = false;
|
|
||||||
Label label;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FnArg {
|
|
||||||
Direct ref;
|
|
||||||
Types type;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
Function struct
|
|
||||||
Contains information needed to run a Ground function.
|
|
||||||
*/
|
|
||||||
struct Function {
|
|
||||||
Types returnType;
|
|
||||||
std::vector<FnArg> args;
|
|
||||||
std::vector<Instruction> instructions;
|
|
||||||
std::vector<Label> labels;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
Struct struct
|
|
||||||
This struct stores data for structures in Ground.
|
|
||||||
*/
|
|
||||||
struct Struct {
|
|
||||||
std::map<std::string, Literal> values;
|
|
||||||
std::map<std::string, Function> functions;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Error {
|
|
||||||
std::string code;
|
|
||||||
int pops;
|
|
||||||
std::string reporter;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
Literal struct
|
|
||||||
Contains literal values. For example, if the following line was written:
|
|
||||||
stdout "Hello world!"
|
|
||||||
The Literal struct in the instruction should look like this:
|
|
||||||
{
|
|
||||||
val = "Hello world!"; // I am ignoring the variant for simplicity
|
|
||||||
// of documenting the code
|
|
||||||
}
|
|
||||||
All value references are swapped out for their respective Literal they
|
|
||||||
point to. See also variables map, parser function, interpreter function
|
|
||||||
*/
|
|
||||||
struct Literal {
|
|
||||||
std::variant<int, double, bool, std::string, char, List, Struct, Error> val;
|
|
||||||
};
|
|
||||||
|
|
||||||
// C-compatible enum and types for developing libraries for Ground in C
|
|
||||||
typedef enum {
|
|
||||||
GROUND_INT,
|
|
||||||
GROUND_DOUBLE,
|
|
||||||
GROUND_BOOL,
|
|
||||||
GROUND_STRING,
|
|
||||||
GROUND_CHAR
|
|
||||||
} GroundType;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
GroundType type;
|
|
||||||
union {
|
|
||||||
int int_val;
|
|
||||||
double double_val;
|
|
||||||
int bool_val;
|
|
||||||
char* string_val;
|
|
||||||
char char_val;
|
|
||||||
} data;
|
|
||||||
} GroundValue;
|
|
||||||
|
|
||||||
@@ -1,184 +0,0 @@
|
|||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
#include <map>
|
|
||||||
#include "parser.h"
|
|
||||||
#include "../main.h"
|
|
||||||
#include "../data/data.h"
|
|
||||||
#include "../error/error.h"
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
/*
|
|
||||||
parser function
|
|
||||||
This function takes a vector of a vector of strings from the lexer and
|
|
||||||
converts it into a list of instructions that the interpreter can understand.
|
|
||||||
*/
|
|
||||||
vector<Instruction> parser(vector<vector<string>> in) {
|
|
||||||
vector<Instruction> out;
|
|
||||||
for (vector<string> line : in) {
|
|
||||||
Instruction currentInstruction;
|
|
||||||
if (line.size() < 1) {
|
|
||||||
out.push_back(currentInstruction);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
string inst = line[0];
|
|
||||||
if (isLabel(inst)) {
|
|
||||||
currentInstruction.isLabel = true;
|
|
||||||
currentInstruction.label.id = inst.substr(1);
|
|
||||||
line.erase(line.begin());
|
|
||||||
}
|
|
||||||
else if (isFunction(inst)) {
|
|
||||||
currentInstruction.inst = Instructions::Call;
|
|
||||||
FunctionRef newFnRef;
|
|
||||||
newFnRef.fnName = inst.substr(1);
|
|
||||||
currentInstruction.args.push_back(newFnRef);
|
|
||||||
}
|
|
||||||
else if (inst == "stdout") currentInstruction.inst = Instructions::Stdout;
|
|
||||||
else if (inst == "print") currentInstruction.inst = Instructions::Stdout;
|
|
||||||
else if (inst == "stdlnout") currentInstruction.inst = Instructions::Stdlnout;
|
|
||||||
else if (inst == "println") currentInstruction.inst = Instructions::Stdlnout;
|
|
||||||
else if (inst == "stdin") currentInstruction.inst = Instructions::Stdin;
|
|
||||||
else if (inst == "input") currentInstruction.inst = Instructions::Stdin;
|
|
||||||
else if (inst == "add") currentInstruction.inst = Instructions::Add;
|
|
||||||
else if (inst == "subtract") currentInstruction.inst = Instructions::Subtract;
|
|
||||||
else if (inst == "multiply") currentInstruction.inst = Instructions::Multiply;
|
|
||||||
else if (inst == "divide") currentInstruction.inst = Instructions::Divide;
|
|
||||||
else if (inst == "set") currentInstruction.inst = Instructions::Set;
|
|
||||||
else if (inst == "end") currentInstruction.inst = Instructions::End;
|
|
||||||
else if (inst == "jump") currentInstruction.inst = Instructions::Jump;
|
|
||||||
else if (inst == "if") currentInstruction.inst = Instructions::If;
|
|
||||||
else if (inst == "equal") currentInstruction.inst = Instructions::Equal;
|
|
||||||
else if (inst == "inequal") currentInstruction.inst = Instructions::Inequal;
|
|
||||||
else if (inst == "greater") currentInstruction.inst = Instructions::Greater;
|
|
||||||
else if (inst == "lesser") currentInstruction.inst = Instructions::Lesser;
|
|
||||||
else if (inst == "not") currentInstruction.inst = Instructions::Not;
|
|
||||||
else if (inst == "setlist") currentInstruction.inst = Instructions::Setlist;
|
|
||||||
else if (inst == "getlistat") currentInstruction.inst = Instructions::Getlistat;
|
|
||||||
else if (inst == "setlistat") currentInstruction.inst = Instructions::Setlistat;
|
|
||||||
else if (inst == "getlistsize") currentInstruction.inst = Instructions::Getlistsize;
|
|
||||||
else if (inst == "stoi") currentInstruction.inst = Instructions::Stoi;
|
|
||||||
else if (inst == "stod") currentInstruction.inst = Instructions::Stod;
|
|
||||||
else if (inst == "tostring") currentInstruction.inst = Instructions::Tostring;
|
|
||||||
else if (inst == "fun") currentInstruction.inst = Instructions::Fun;
|
|
||||||
else if (inst == "return") currentInstruction.inst = Instructions::Return;
|
|
||||||
else if (inst == "endfun") currentInstruction.inst = Instructions::Endfun;
|
|
||||||
else if (inst == "pusharg") currentInstruction.inst = Instructions::Pusharg;
|
|
||||||
else if (inst == "call") currentInstruction.inst = Instructions::Call;
|
|
||||||
else if (inst == "use") currentInstruction.inst = Instructions::Use;
|
|
||||||
else if (inst == "extern") currentInstruction.inst = Instructions::Extern;
|
|
||||||
else if (inst == "getstrcharat") currentInstruction.inst = Instructions::Getstrcharat;
|
|
||||||
else if (inst == "getstrsize") currentInstruction.inst = Instructions::Getstrsize;
|
|
||||||
else if (inst == "error") currentInstruction.inst = Instructions::Error;
|
|
||||||
else if (inst == "catch") currentInstruction.inst = Instructions::Catch;
|
|
||||||
else if (inst == "try") currentInstruction.inst = Instructions::Try;
|
|
||||||
else if (inst == "exception") currentInstruction.inst = Instructions::Exception;
|
|
||||||
else if (inst == "gettype") currentInstruction.inst = Instructions::Gettype;
|
|
||||||
else if (inst == "exists") currentInstruction.inst = Instructions::Exists;
|
|
||||||
else if (inst == "listappend") currentInstruction.inst = Instructions::Listappend;
|
|
||||||
else if (inst == "listprepend") currentInstruction.inst = Instructions::Listprepend;
|
|
||||||
else if (inst == "struct") currentInstruction.inst = Instructions::Struct;
|
|
||||||
else if (inst == "endstruct") currentInstruction.inst = Instructions::Endstruct;
|
|
||||||
else if (inst == "init") currentInstruction.inst = Instructions::Init;
|
|
||||||
else {
|
|
||||||
error("Unknown instruction " + inst);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 1; i < line.size(); i++) {
|
|
||||||
string arg = line[i];
|
|
||||||
Types type = getType(arg);
|
|
||||||
switch (type) {
|
|
||||||
case Types::Int:
|
|
||||||
{
|
|
||||||
Literal newLit;
|
|
||||||
newLit.val = stoi(arg);
|
|
||||||
currentInstruction.args.push_back(newLit);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Types::Double:
|
|
||||||
{
|
|
||||||
Literal newLit;
|
|
||||||
newLit.val = stod(arg);
|
|
||||||
currentInstruction.args.push_back(newLit);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Types::String:
|
|
||||||
{
|
|
||||||
Literal newLit;
|
|
||||||
newLit.val = arg.substr(1, arg.size() - 2);
|
|
||||||
currentInstruction.args.push_back(newLit);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Types::Char:
|
|
||||||
{
|
|
||||||
Literal newLit;
|
|
||||||
newLit.val = arg[1];
|
|
||||||
currentInstruction.args.push_back(newLit);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Types::Bool:
|
|
||||||
{
|
|
||||||
Literal newLit;
|
|
||||||
if (arg == "true") newLit.val = true;
|
|
||||||
else newLit.val = false;
|
|
||||||
currentInstruction.args.push_back(newLit);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Types::Value:
|
|
||||||
{
|
|
||||||
ValueRef newVal;
|
|
||||||
newVal.varName = arg.substr(1);
|
|
||||||
currentInstruction.args.push_back(newVal);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Types::Direct:
|
|
||||||
{
|
|
||||||
Direct newDir;
|
|
||||||
newDir.varName = arg.substr(1);
|
|
||||||
currentInstruction.args.push_back(newDir);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Types::Line:
|
|
||||||
{
|
|
||||||
Line newLine;
|
|
||||||
string lineRef = arg.substr(1);
|
|
||||||
if (isInt(lineRef)) {
|
|
||||||
newLine.lineNum = stoi(lineRef);
|
|
||||||
} else {
|
|
||||||
newLine.isLabel = true;
|
|
||||||
newLine.label = lineRef;
|
|
||||||
}
|
|
||||||
currentInstruction.args.push_back(newLine);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Types::Type:
|
|
||||||
{
|
|
||||||
TypeRef newTypeRef;
|
|
||||||
string type = arg.substr(1);
|
|
||||||
if (type == "int") newTypeRef.type = Types::Int;
|
|
||||||
else if (type == "double") newTypeRef.type = Types::Double;
|
|
||||||
else if (type == "string") newTypeRef.type = Types::String;
|
|
||||||
else if (type == "char") newTypeRef.type = Types::Char;
|
|
||||||
else if (type == "bool") newTypeRef.type = Types::Bool;
|
|
||||||
else if (type == "list") newTypeRef.type = Types::List;
|
|
||||||
else {
|
|
||||||
newTypeRef.isCustomType = true;
|
|
||||||
newTypeRef.customType = type;
|
|
||||||
};
|
|
||||||
currentInstruction.args.push_back(newTypeRef);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Types::Function:
|
|
||||||
{
|
|
||||||
FunctionRef newFuncRef;
|
|
||||||
newFuncRef.fnName = arg.substr(1);
|
|
||||||
currentInstruction.args.push_back(newFuncRef);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
error("Could not parse argument " + arg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
out.push_back(currentInstruction);
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
#include "../main.h"
|
|
||||||
|
|
||||||
std::vector<Instruction> parser(std::vector<std::vector<std::string>> in);
|
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
#!/usr/bin/env ground
|
#!/usr/bin/env ground
|
||||||
stdlnout "Program args: "
|
stdlnout "Program args: "
|
||||||
getlistsize &args &argsSize
|
getlistsize *args &argsSize
|
||||||
set &counter 0
|
set &counter 0
|
||||||
@loopstart
|
@loopstart
|
||||||
equal $counter $argsSize &bool
|
equal $counter $argsSize &bool
|
||||||
if $bool %end
|
if $bool %end
|
||||||
getlistat &args $counter &item
|
getlistat *args $counter &item
|
||||||
stdlnout $item
|
stdlnout $item
|
||||||
add 1 $counter &counter
|
add 1 $counter &counter
|
||||||
jump %loopstart
|
jump %loopstart
|
||||||
|
|||||||
@@ -20,19 +20,19 @@ stdlnout $testVar
|
|||||||
|
|
||||||
# Lists
|
# Lists
|
||||||
|
|
||||||
setlist &testList "Item 1" "Another Item" "Item the Third"
|
setlist *testList "Item 1" "Another Item" "Item the Third"
|
||||||
getlistat &testList 2 &tmp
|
getlistat *testList 2 &tmp
|
||||||
stdlnout $tmp
|
stdlnout $tmp
|
||||||
|
|
||||||
setlistat &testList 1 "I changed this item"
|
setlistat *testList 1 "I changed this item"
|
||||||
getlistat &testList 1 &tmp
|
getlistat *testList 1 &tmp
|
||||||
stdlnout $tmp
|
stdlnout $tmp
|
||||||
|
|
||||||
listappend &testList "I appended this item"
|
listappend *testList "I appended this item"
|
||||||
getlistat &testList 3 &tmp
|
getlistat *testList 3 &tmp
|
||||||
stdlnout $tmp
|
stdlnout $tmp
|
||||||
|
|
||||||
getlistsize &testList &tmp
|
getlistsize *testList &tmp
|
||||||
stdlnout $tmp
|
stdlnout $tmp
|
||||||
|
|
||||||
# String Operations
|
# String Operations
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ set &testVar "dingus"
|
|||||||
exists &testVar &exist
|
exists &testVar &exist
|
||||||
stdlnout $exist
|
stdlnout $exist
|
||||||
|
|
||||||
setlist &myList "item"
|
setlist *myList "item"
|
||||||
exists &myList &exist
|
exists *myList &exist
|
||||||
stdlnout $exist
|
stdlnout $exist
|
||||||
|
|
||||||
@dingus
|
@dingus
|
||||||
@@ -13,5 +13,8 @@ stdlnout $exist
|
|||||||
exists &doesNotExist &exist
|
exists &doesNotExist &exist
|
||||||
stdlnout $exist
|
stdlnout $exist
|
||||||
|
|
||||||
|
exists *doesNotExist &exist
|
||||||
|
stdlnout $exist
|
||||||
|
|
||||||
exists %doesNotExist &exist
|
exists %doesNotExist &exist
|
||||||
stdlnout $exist
|
stdlnout $exist
|
||||||
|
|||||||
@@ -22,18 +22,18 @@ stdlnout "I called a function"
|
|||||||
|
|
||||||
fun -list !dingus
|
fun -list !dingus
|
||||||
stdlnout "Testing lists in functions"
|
stdlnout "Testing lists in functions"
|
||||||
setlist &dingle "heheheha" "hahahahe" "hmmm"
|
setlist *dingle "heheheha" "hahahahe" "hmmm"
|
||||||
return $dingle
|
return *dingle
|
||||||
endfun
|
endfun
|
||||||
|
|
||||||
call !dingus &outlist
|
call !dingus *outlist
|
||||||
|
|
||||||
getlistsize &outlist &size
|
getlistsize *outlist &size
|
||||||
set &counter 0
|
set &counter 0
|
||||||
@loopstart
|
@loopstart
|
||||||
equal $size $counter &cond
|
equal $size $counter &cond
|
||||||
if $cond %loopend
|
if $cond %loopend
|
||||||
getlistat &outlist $counter &tmp
|
getlistat *outlist $counter &tmp
|
||||||
stdlnout $tmp
|
stdlnout $tmp
|
||||||
add 1 $counter &counter
|
add 1 $counter &counter
|
||||||
jump %loopstart
|
jump %loopstart
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
# A cool list
|
# A cool list
|
||||||
setlist &favWords "hello" "there" "general" "kenobi"
|
setlist *favWords "hello" "there" "general" "kenobi"
|
||||||
stdlnout $favWords
|
stdlnout *favWords
|
||||||
|
|
||||||
set &count 0
|
set &count 0
|
||||||
set &passedThrough true
|
set &passedThrough true
|
||||||
|
|
||||||
@jmpbck
|
@jmpbck
|
||||||
getlistat &favWords $count &tmp
|
getlistat *favWords $count &tmp
|
||||||
stdlnout $tmp
|
stdlnout $tmp
|
||||||
add $count 1 &count
|
add $count 1 &count
|
||||||
getlistsize &favWords &tmp2
|
getlistsize *favWords &tmp2
|
||||||
inequal $count $tmp2 &tmp3
|
inequal $count $tmp2 &tmp3
|
||||||
if $tmp3 %jmpbck
|
if $tmp3 %jmpbck
|
||||||
|
|||||||
Reference in New Issue
Block a user