// Parse ID ('=' EXP) static String getVariables(SamTokenizer f) throws TokenizerException { try { // Name of the variable. String var = f.getWord(); // Check if the name already exists. if (symTables.lastElement().containsKey(var) || symMap.containsKey(var)) throw new TokenizerException("Error: Duplicate declaration of " + var + "."); // Add the variable with the address to the symbol table. symTables.lastElement().put(var, varCounter); ++varCounter; // Reserve the space in stack for the variable declaration. String asmCode = "PUSHIMM 0\n"; if (f.check('=')) { asmCode += getExp(f); asmCode += ("STOREOFF " + Integer.toString(varCounter - 1) + "\n"); } if (f.check(',')) { asmCode += getVariables(f); } return asmCode; } catch (Exception e) { System.out.println(e.getMessage()); throw new TokenizerException("Error: Invalid variable declaration."); } }
// This function is for generating a valid label to ensure that there are no duplicate label // names. static String getLabel() { String label = "Label"; // Increment the labelcounter until we find a valid name of the label. while (symMap.containsKey(label + Integer.toString(labelCounter))) { ++labelCounter; } label += Integer.toString(labelCounter); ++labelCounter; return label; }
// Parse a method declaration. static String getMethod(SamTokenizer f) throws TokenizerException { try { // The return type for all methods must be int. myCheck(f, "int"); // methodName stores the name of the method. String methodName = f.getWord(); if (symMap.containsKey(methodName)) throw new TokenizerException("Error: Duplicate declaration of method " + methodName); String asmCode = methodName; // The name of the method <-> index of the symbol table of the method in the symTables vector symMap.put(methodName, symTables.size()); symTables.addElement(new LinkedHashMap<String, Integer>()); // Since there cannot be another method declaration inside of a, the symbol table we are // dealing with is // always the last element of the symTables vector. symTables.lastElement().put(methodName, 0); asmCode += ":\n"; myCheck(f, '('); if (!f.check(')')) { // No SaM code generated by getFormals getFormals(f); myCheck(f, ')'); } actMap.put(methodName, params.size()); for (int i = 1; i <= params.size(); ++i) { // Add all formals to the symbol tabel symTables.lastElement().put(params.elementAt(params.size() - i), -i); } asmCode += getBody(f); // Clear the params vector and set varCounter back to 2. params.clear(); varCounter = 2; return asmCode; } catch (Exception e) { System.out.println(e.getMessage()); throw new TokenizerException("Error: Invalid method declaration."); } }
// Parse an expression. static String getExp(SamTokenizer f) throws TokenizerException { try { String asmCode = ""; switch (f.peekAtKind()) { // Single int case INTEGER: return "PUSHIMM " + f.getInt() + "\n"; case OPERATOR: myCheck(f, '('); if (f.check('-')) { // Negative of x = 0 - x; asmCode += "PUSHIMM 0\n"; asmCode += getExp(f); asmCode += "SUB\n"; } else if (f.check('!')) { // Negate x // Return 1 for 0 and return 0 for all the others. asmCode += getExp(f); asmCode += "ISNIL\n"; } else { asmCode += getExp(f); // System.out.println(asmCode); if (f.check(')')) return asmCode; else if (f.check('+') || f.check('|')) asmCode += (getExp(f) + "ADD\n"); else if (f.check('-')) asmCode += (getExp(f) + "SUB\n"); else if (f.check('*') || f.check('&')) asmCode += (getExp(f) + "TIMES\n"); else if (f.check('/')) asmCode += (getExp(f) + "DIV\n"); else if (f.check('<')) asmCode += (getExp(f) + "CMP\n" + "ISPOS\n"); else if (f.check('>')) asmCode += (getExp(f) + "CMP\n" + "ISNEG\n"); else if (f.check('=')) asmCode += (getExp(f) + "CMP\n" + "ISNIL\n"); else throw new TokenizerException("Error: Invalid expression"); } myCheck(f, ')'); return asmCode; case WORD: String newWord = f.getWord(); switch (newWord) { case "true": return "PUSHIMM " + "1" + "\n"; case "false": return "PUSHIMM " + "0" + "\n"; default: // If there is a (, it is an invocation of a method. // EXP->METHOD '(' ACTUALS? ')' if (f.check('(')) { // Check if the name of the method is declared before. if (!symMap.containsKey(newWord)) throw new TokenizerException("Error: Method not declared."); asmCode += "PUSHIMM 0\n"; String sp = ""; if (f.check(')')) { // No actuals if (actMap.get(newWord) != 0) throw new TokenizerException("Error: Invalid number of actuals."); } else { asmCode += getActuals(f, newWord); myCheck(f, ')'); // Store the command for popping out parameters temporarily in this case. sp = "ADDSP -" + Integer.toString(globalCounter) + "\n"; } // Invocation of the method. // If there is no actuals for this method, then the string sp is an empty string. asmCode += ("LINK\n" + "JSR " + newWord + "\n" + "POPFBR\n" + sp); return asmCode; } else { // EXP->LOCATION // Check if the variable is already declared. if (!symTables.lastElement().containsKey(newWord)) throw new TokenizerException("Error: Variable not declared."); // Get the address of the variable from the symbol table. int addr = symTables.lastElement().get(newWord); asmCode += ("PUSHOFF " + Integer.toString(addr) + "\n"); return asmCode; } } default: throw new TokenizerException("Error: Invalid expression."); } } catch (Exception e) { System.out.println(e.getMessage()); throw new TokenizerException("Error: Cannot parse the expression."); } }