// 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.");
    }
  }
 static String getActuals(SamTokenizer f, String methodName) throws TokenizerException {
   try {
     int actualCounter = 0;
     ++actualCounter;
     String asmCode = "";
     asmCode += getExp(f);
     while (f.check(',')) {
       ++actualCounter;
       asmCode += getExp(f);
     }
     if (actualCounter != actMap.get(methodName))
       throw new TokenizerException("Error: Invalid number of actuals.");
     globalCounter = actualCounter;
     actualCounter = 0;
     return asmCode;
   } catch (Exception e) {
     System.out.println(e.getMessage());
     throw new TokenizerException("Error: Invalid actuals");
   }
 }
  // 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.");
    }
  }