I am getting this error but cannot find any information on it in either TECS edition 2 or this forum. If I were to guess, the error is stemming from the way I am handling subroutines and do statements.
My compileDo method:
void CompilationEngine::compileDo() {
tokenizer.advance(); // 'do'
// Handle the subroutine call directly
std::string identifier = tokenizer.identifier();
tokenizer.advance();
std::string subroutineName;
int nArgs = 0;
if (tokenizer.getCurrentToken() == ".") {
tokenizer.advance();
std::string methodName = tokenizer.identifier();
tokenizer.advance(); // Advance past method name
auto [kind, index] = getVariableInfo(identifier);
if (kind != "none") {
// Method call on another object
vmWriter.writePush(kind, index);
subroutineName = symbolTableClass.typeOf(identifier) + "." + methodName;
nArgs = compileExpressionList() + 1;
} else {
// Function call
subroutineName = identifier + "." + methodName;
nArgs = compileExpressionList() + 1;
}
} else {
// Method call on the current object
subroutineName = currentClass + "." + identifier;
vmWriter.writePush("pointer", 0);
nArgs = compileExpressionList() + 1;
}
tokenizer.advance(); // Advance past the closing parenthesis ')'
vmWriter.writeCall(subroutineName, nArgs);
tokenizer.advance(); // Advance past ';'
vmWriter.writePop("temp", 0); // Discard the return value of the call
// vmWriter.writeReturn(); <-- I am unsure of whether to include this or not
}
The section to handle identifiers inside of CompileExpression.compileTerm:
case JackTokenizer::TokenElements::IDENTIFIER: {
std::string curIdentifier = tokenizer.identifier();
tokenizer.advance();
if (tokenizer.getCurrentToken() == "[") {
// varName '[' expression ']'
auto [kind, index] = getVariableInfo(curIdentifier);
vmWriter.writePush(kind, index, "// compileTerm, line 441: " + curIdentifier);
tokenizer.advance(); // Advance past '['
compileExpression();
tokenizer.advance(); // Advance past ']'
vmWriter.writeArithmetic("add");
vmWriter.writePop("pointer", 1);
vmWriter.writePush("that", 0);
} else if (tokenizer.getCurrentToken() == "(" || tokenizer.getCurrentToken() == ".") {
// Handle subroutine call directly within compileTerm
std::string subroutineName;
int nArgs = 0;
if (tokenizer.getCurrentToken() == ".") {
tokenizer.advance();
std::string methodName = tokenizer.identifier();
tokenizer.advance(); // Advance past method name
auto [kind, index] = getVariableInfo(curIdentifier);
if (kind != "none") {
// Method call on another object
vmWriter.writePush(kind, index);
subroutineName = symbolTableSubroutine.typeOf(curIdentifier) + "." + methodName;
nArgs = compileExpressionList() + 1;
} else {
// Function call
subroutineName = curIdentifier + "." + methodName;
nArgs = compileExpressionList();
}
} else {
// Method call on the current object
subroutineName = currentClass + "." + curIdentifier;
vmWriter.writePush("pointer", 0);
nArgs = compileExpressionList() + 1;
}
tokenizer.advance(); // Advance past the closing parenthesis ')'
vmWriter.writeCall(subroutineName, nArgs);
} else {
// Attribute access
auto [kind, index] = getVariableInfo(curIdentifier);
if (kind != "none") {
vmWriter.writePush(kind, index, "// compileTerm, line 490: " + curIdentifier);
}
}
break;
I understand this code is a nightmare to look at, so here is the repo to see the full thing:
https://github.com/blacknand/nand2tetris/tree/compiler_II/10_jack_compiler/CompilerIf anyone thinks it is better to start from scratch then I will, I feel like I am missing something crucial because it just does not click for me.