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