forked from ground/ground
Rewrite label system
This commit is contained in:
126
src/main.cpp
126
src/main.cpp
@@ -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 {
|
||||
|
Reference in New Issue
Block a user