I am creating a miniature computer using an Arduino, and I am creating a full-scale interpreter for it. Everything works, and the code begins to run after calling the runCode method, but once the run is finished it doesn't return to the calling function. I have Serial outputs to tell me where the code reaches.
My code contains an "Function" object with a name and a function pointer, an object to run the code (with a working Lexer object that splits the inputted code by spaces), and an in-computer editor (which completely works except the one function) to input programs to be run.
The function that calls the runCode method for my code-running object (called Joker) is in the editor. The problem is, once the runCode finishes, it does not return. The system halts. I will post the Function class, runCode Method, and calling method.
P.S. There are Serial prints to determine where the code reaches. It outputs "Function End!", but not "Failed!"/"Succeeded".
P.P.S. It uses a parallax 4x20 Back-lit Single-pin Serial LCD which completely 100% works.
P.P.P.S It uses the QueueList library which is basically a dynamic list that works like a stack.
One more note: The code heavliy uses dynamic lists, function pointers, and lambda expressions, so.... be prepared....
Code for Function class (no it does not have any actual functions):
class Function {
public:
String f_name;
bool (*f_run) (QueueList<float> &stack, SoftwareSerial &lcd);
};
Code for runCode method:
bool Joker::runCode(QueueList<String> lineTable, SoftwareSerial &lcd) {
// Set up lexer
Lexer lexer;
// Get all lexer words
lexer.getWords(lineTable);
String cur_word = "";
float num_val = 0.0f;
bool quit = false;
while(!quit) {
cur_word = lexer.nextWord();
if(cur_word == "")
quit = true;
else {
// Get word in uppercase
cur_word.toUpperCase();
Serial.println(cur_word);
// Parse the first number from it
num_val = cur_word.toFloat();
// Check if we have a function
if(queueListContains(cur_word, dictionary)) {
Function theFunc = getDictionaryFunction(cur_word, dictionary);
if(!theFunc.f_run(stack, lcd)) {
error(F("Unable to process word!!"), lcd);
return false;
}
} else if(num_val != 0) { // check if the parse was good
stack.push(num_val); // if it was: push num to the stack
} else if(num_val == 0) { // if zero it could be parsing a zero or it could have failed
if(cur_word.indexOf("0") != -1) // if it didn't fail:
stack.push(num_val); // push to the stack
else { // otherwise:
error(F("Unknown word!!"), lcd); // Unknown word error
return false;
}
} else {
error(F("Unknown word!!"), lcd);
return false;
}
}
}
// Test printing the stack
/*while(!stack.isEmpty()) {
lcd.print(stack.pop());
lcd.print(' ');
}*/
Serial.print(F("Function end!"));
return true;
}
And the caller method:
void line_editor::RunProgram(SoftwareSerial &lcd) {
Serial.println("Running program!!");
// Move to top line
currentLine = 0;
while(!lineTableB.isEmpty()) {
lineTableA.push(lineTableB.pop());
// Serial.print(lineTableB.peek());
}
// Clear the string
lcd.write(12);
delay(5);
lcd.write(128);
// Joker language object
Joker joker;
QueueList<Function> PrintingWords;
// Create the printing functions
Function printWord;
printWord.f_name = "BC"; // print "Beginning Card"
printWord.f_run = [] (QueueList<float> &stack, SoftwareSerial &lcd) {
if(stack.isEmpty()) {
return false;
}
float num = stack.pop();
lcd.print(num);
lcd.write(13);
return true;
};
PrintingWords.push(printWord);
// Print the whole stack
Function printStack;
printStack.f_name = "AC"; // print "All Cards"
printStack.f_run = [] (QueueList<float> &stack, SoftwareSerial &lcd) {
while(!stack.isEmpty()) {
lcd.print(stack.pop());
lcd.print(' ');
}
lcd.write(13);
return true;
};
PrintingWords.push(printStack);
// Add all the functions
joker.addWords(PrintingWords);
// Run Program here...
if(joker.runCode(lineTableA, lcd))
Serial.println("Success!!");
else
Serial.println("Failed!!");
// lineTableA.push(lineTableB.pop());
Serial.println("Here!!");
return;
}
Sorry if I confused anyone. If there are any questions, then leave a comment, and I'll try to clear up the confusion. Any help would be appreciated.
EDIT::ADDING FULL CODE: Here is a LINK to the rest of the code on github.
Also, here is the rest of the Joker.cpp:
void Joker::addWords(QueueList<Function> new_dict) {
while(!new_dict.isEmpty()) {
dictionary.push(new_dict.pop());
}
}
bool Joker::queueListContains(String theWord, QueueList<Function> &list) {
Serial.println("Finding word:");
QueueList<Function> temp;
while(!list.isEmpty()) {
Function r = list.pop();
temp.push(r);
Serial.print(">> ");
Serial.println(theWord);
Serial.print(">> equals? ");
Serial.println(r.f_name);
delay(5);
if(r.f_name.equals(theWord)) {
while(!temp.isEmpty())
list.push(temp.pop());
return true;
}
}
while(!temp.isEmpty())
list.push(temp.pop());
return false;
}
Function Joker::getDictionaryFunction(String theWord, QueueList<Function> &list) {
QueueList<Function> temp;
while(!list.isEmpty()) {
Function theFunction = list.pop();
temp.push(theFunction);
if(theFunction.f_name.equals(theWord)) {
while(!temp.isEmpty()) {
list.push(temp.pop());
}
return theFunction;
}
}
}
void Joker::error(String message, SoftwareSerial &lcd) {
lcd.write(12);
delay(5);
lcd.write(128);
lcd.print(message);
delay(2000);
}
And the header:
#pragma once
class Joker {
private:
bool queueListContains(String theWord, QueueList<Function> &list);
Function getDictionaryFunction(String theWord, QueueList<Function> &list);
public:
QueueList<float> stack;
QueueList<Function> dictionary;
void error(String message, SoftwareSerial &lcd);
void addWords(QueueList<Function> new_dict);
bool runCode(QueueList<String> lineTable, SoftwareSerial &lcd);
};
String
class, because that could fragment memory. However in this particular case, it is probably something more sinister.