Rewrite label system

This commit is contained in:
2025-08-31 15:04:27 +10:00
parent 7961195018
commit 76205a613d

View File

@@ -168,6 +168,31 @@ struct FunctionRef {
string fnName;
};
/*
Label struct
Contains information needed to register labels
*/
struct Label {
string id;
int lineNum = -1;
};
/*
Line struct
Contains information needed to jump to lines
*/
struct Line {
int lineNum = -1;
bool isLabel = false;
string label;
};
/*
labelStack stack
Allows each function to hold it's own set of labels
*/
stack<map<string, int>> labelStack;
/*
ListRef struct
Contains the name of a list referenced by the program. For example, if the
@@ -188,12 +213,6 @@ struct ListRef {
*/
map<string, Literal> variables;
/*
labels map
Contains all labels made in the program, for ease of jumping around the code.
*/
map<string, int> labels;
/*
ValueRef struct
If the program being executed makes a value reference, it is stored in a ValueRef
@@ -208,22 +227,6 @@ struct ValueRef {
string varName;
};
/*
Line struct
If the program being executed makes a line reference, it is stored in a Line
struct. For example, if the following line was written:
jump %10
The Line struct in the instruction should look like this:
{
lineNum = 10;
}
*/
struct Line {
int lineNum;
bool isLabel = false;
string label;
};
/*
Instruction struct
An instruction usually corresponds to a line in the program being interpreted.
@@ -249,9 +252,13 @@ struct Line {
See also: Instructions enum class, Literal struct, ValueRef struct, Direct struct,
Line struct, exec function, parser function
*/
typedef variant<Literal, ValueRef, ListRef, FunctionRef, TypeRef, Direct, Line> argument;
struct Instruction {
Instructions inst = Instructions::Empty;
vector<variant<Literal, ValueRef, ListRef, FunctionRef, TypeRef, Direct, Line>> args;
vector<argument> args;
bool isLabel = false;
Label label;
};
struct FnArg {
@@ -267,7 +274,7 @@ struct Function {
Types returnType;
vector<FnArg> args;
vector<Instruction> instructions;
map<string, int> localLabels;
vector<Label> labels;
};
// C-compatible enum and types for developing libraries for Ground in C
@@ -498,6 +505,21 @@ vector<Instruction> parser(vector<vector<string>> in);
// Forward declaration for the use instruction
vector<vector<string>> lexer(string in);
void preProcessLabels(vector<Instruction> instructions) {
map<string, int> labels;
int definingFunction = 0;
for (int i = 0; i < instructions.size(); i++) {
if (instructions[i].isLabel && definingFunction == 0) {
labels[instructions[i].label.id] = i;
} else if (instructions[i].inst == Instructions::Fun) {
definingFunction++;
} else if (instructions[i].inst == Instructions::Endfun) {
definingFunction--;
}
}
labelStack.push(labels);
}
/*
exec function
This function takes a list of instructions (see Instruction struct above and parser
@@ -505,14 +527,6 @@ vector<vector<string>> lexer(string in);
function for the program.
*/
Literal exec(vector<Instruction> in, bool executingFunction) {
map<string, int>* currentLabels = &labels;
for (auto& [fnName, fn] : functions) {
if (&fn.instructions == &in) {
currentLabels = &fn.localLabels;
break;
}
}
for (int i = 0; i < in.size(); i++) {
Instruction l = in[i];
if (processingFunction) {
@@ -536,9 +550,9 @@ Literal exec(vector<Instruction> in, bool executingFunction) {
} else if (holds_alternative<Line>(l.args[j])) {
Line ln = get<Line>(l.args[j]);
if (ln.isLabel) {
if (currentLabels->find(ln.label) != currentLabels->end()) {
if (labelStack.top().find(ln.label) != labelStack.top().end()) {
Line newLine;
newLine.lineNum = (*currentLabels)[ln.label];
newLine.lineNum = labelStack.top()[ln.label];
l.args[j] = newLine;
} else {
if (l.inst != Instructions::Exists) error("Could not find label " + ln.label);
@@ -670,7 +684,7 @@ Literal exec(vector<Instruction> in, bool executingFunction) {
}
bool first = true;
for (variant<Literal, ValueRef, ListRef, FunctionRef, TypeRef, Direct, Line> k : l.args) {
for (argument k : l.args) {
if (holds_alternative<Literal>(k)) {
listContents.val.push_back(get<Literal>(k));
} else {
@@ -847,7 +861,7 @@ Literal exec(vector<Instruction> in, bool executingFunction) {
if (holds_alternative<ListRef>(l.args[0])) {
listref = get<ListRef>(l.args[0]);
} else {
error("Second argument of listappend must be a list reference");
error("First argument of listappend must be a list reference");
}
if (holds_alternative<Literal>(l.args[1])) {
@@ -1569,7 +1583,7 @@ Literal exec(vector<Instruction> in, bool executingFunction) {
error("Could not find all arguments required for Jump inbuilt");
}
if (holds_alternative<Line>(l.args[0])) {
i = get<Line>(l.args[0]).lineNum - 2;
i = get<Line>(l.args[0]).lineNum - 1;
} else {
error("First argument of jump must be a line reference");
}
@@ -1595,7 +1609,7 @@ Literal exec(vector<Instruction> in, bool executingFunction) {
}
if (isTrue) {
if (holds_alternative<Line>(l.args[1])) {
i = get<Line>(l.args[1]).lineNum - 2;
i = get<Line>(l.args[1]).lineNum - 1;
} else {
error("Second argument of if must be a line reference");
}
@@ -1691,7 +1705,7 @@ Literal exec(vector<Instruction> in, bool executingFunction) {
} else if (holds_alternative<Line>(l.args[0])) {
Line line = get<Line>(l.args[0]);
if (line.isLabel) {
if (labels.find(line.label) != labels.end()) {
if (labelStack.top().find(line.label) != labelStack.top().end()) {
exists = true;
}
} else {
@@ -1890,11 +1904,15 @@ Literal exec(vector<Instruction> in, bool executingFunction) {
// Clear function arguments for next call
fnArgs.clear();
// Process labels
preProcessLabels(functions[ref.fnName].instructions);
// Call the function
Literal retVal = exec(functions[ref.fnName].instructions, true);
// Restore scope
variables = scopeBackup;
labelStack.pop();
// Now, assign the return value in the current scope.
if (expectList) {
@@ -1953,7 +1971,9 @@ Literal exec(vector<Instruction> in, bool executingFunction) {
in += lns += "\n";
}
importing.push(get<string>(get<Literal>(l.args[0]).val));
Literal ret = exec(parser(lexer(in)), false);
vector<Instruction> parsed = parser(lexer(in));
preProcessLabels(parsed);
Literal ret = exec(parsed, false);
importing.pop();
libraries.push_back(libName);
}
@@ -2155,20 +2175,17 @@ vector<vector<string>> lexer(string in) {
}
/*
parser function
This takes multiple lines of code (in the form of vector<vector<string>>)
and turns that human-readable code into a list of instructions.
Refer to the Instruction struct above for more information.
and turns thructions[iat human-readable code into a list of instructions.
Refer to insructions[it.label.lineNum = i;the Instruction struct above for more information.
*/
vector<Instruction> parser(vector<vector<string>> in) {
vector<Instruction> out;
int lineNum = 1;
int functionInstructionIndex = 0;
int lineNum = 0;
for (vector<string> lineTokens : in) {
lineNum ++;
Instruction newInst;
if (lineTokens.empty()) {
if (processingFunction) functionInstructionIndex ++;
out.push_back(newInst);
continue;
};
@@ -2178,11 +2195,8 @@ vector<Instruction> parser(vector<vector<string>> in) {
if (firstInst) {
firstInst = false;
if (isLabel(i)) {
if (processingFunction) {
functions[procFnName].localLabels[i.substr(1)] = functionInstructionIndex;
} else {
labels[i.substr(1)] = lineNum - 1;
}
newInst.isLabel = true;
newInst.label.id = i.substr(1);
}
else if (i == "stdin") newInst.inst = Instructions::Stdin;
else if (i == "stdout") newInst.inst = Instructions::Stdout;
@@ -2212,10 +2226,7 @@ vector<Instruction> parser(vector<vector<string>> in) {
else if (i == "stoi") newInst.inst = Instructions::Stoi;
else if (i == "stod") newInst.inst = Instructions::Stod;
else if (i == "tostring") newInst.inst = Instructions::Tostring;
else if (i == "fun") {
newInst.inst = Instructions::Fun;
functionInstructionIndex = 0;
}
else if (i == "fun") newInst.inst = Instructions::Fun;
else if (i == "return") newInst.inst = Instructions::Return;
else if (i == "endfun") newInst.inst = Instructions::Endfun;
else if (i == "pusharg") newInst.inst = Instructions::Pusharg;
@@ -2329,7 +2340,6 @@ vector<Instruction> parser(vector<vector<string>> in) {
}
}
}
if (processingFunction) functionInstructionIndex++;
out.push_back(newInst);
}
return out;
@@ -2362,7 +2372,9 @@ int main(int argc, char** argv) {
while (getline(file, lns)) {
in += lns += "\n";
}
Literal ret = exec(parser(lexer(in)), false);
vector<Instruction> parsed = parser(lexer(in));
preProcessLabels(parsed);
Literal ret = exec(parsed, false);
if (holds_alternative<int>(ret.val)) {
return get<int>(ret.val);
} else {