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;
|
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 {
|
||||||
|
Reference in New Issue
Block a user