protected void parseFormalParameters(Token token, SymTabEntry routineId) throws Exception {
    // Parse the formal parameters if there is an opening left parenthesis.
    token = synchronize(LEFT_PAREN_SET);
    if (token.getType() == LEFT_PAREN) {
      token = nextToken(); // consume (
      TokenType tokenType1 = token.getType();

      ArrayList<SymTabEntry> parms = new ArrayList<SymTabEntry>();
      while (tokenType1 != RIGHT_PAREN) {

        parms.addAll(parseParmSublist(token, routineId));

        token = currentToken();

        tokenType1 = token.getType();
      }

      // This sync needs to check for Int or Char
      token = synchronize(PARAMETER_SET);

      // Closing right parenthesis.
      if (token.getType() == RIGHT_PAREN) {
        token = nextToken(); // consume )
      } else {
        errorHandler.flag(token, MISSING_RIGHT_PAREN, this);
      }

      routineId.setAttribute(ROUTINE_PARMS, parms);
    }
  }
  private SymTabEntry parseRoutineName(Token token, String dummyName) throws Exception {
    SymTabEntry routineId = null;

    // Parse the routine name identifier.
    if (token.getType() == IDENTIFIER) {
      String routineName = token.getText().toLowerCase();
      routineId = symTabStack.lookupLocal(routineName);

      // Not already defined locally: Enter into the local symbol table.
      if (routineId == null) {
        routineId = symTabStack.enterLocal(routineName);
        routineId.appendLineNumber(token.getLineNumber());
      }

      // If already defined, it should be a forward definition.
      else {
        routineId = null;
        errorHandler.flag(token, IDENTIFIER_REDEFINED, this);
      }

      token = nextToken(); // consume routine name identifier

    } else {
      errorHandler.flag(token, MISSING_IDENTIFIER, this);
    }

    // If necessary, create a dummy routine name symbol table entry.
    if (routineId == null) {
      routineId = symTabStack.enterLocal(dummyName);
    }

    return routineId;
  }
  private ArrayList<SymTabEntry> parseParmSublist(Token token, SymTabEntry routineId)
      throws Exception {

    // name = main, definition == function

    Definition parmDefn = null;
    TokenType tokenType = token.getType();
    parmDefn = VALUE_PARM;
    SymTabEntry sublist = null;

    if (tokenType == INT) {
      IntDeclarationsParser intDeclarationsParser = new IntDeclarationsParser(this);
      intDeclarationsParser.setDefinition(parmDefn);
      token = nextToken();
      sublist = intDeclarationsParser.parseIdentifier(token);
      sublist.setTypeSpec(integerType);

    } else if (tokenType == CHAR) {
      IntDeclarationsParser intDeclarationsParser = new IntDeclarationsParser(this);
      intDeclarationsParser.setDefinition(parmDefn);
      token = nextToken();
      sublist = intDeclarationsParser.parseIdentifier(token);
      sublist.setTypeSpec(charType);
    }
    token = nextToken();
    token = currentToken();
    if (token.getType() == COMMA) {
      token = nextToken();
    }

    tokenType = token.getType();
    token = synchronize(PARAMETER_SET);
    ArrayList<SymTabEntry> SC = new ArrayList<SymTabEntry>();
    SC.add(sublist);
    return SC;
  }
  public SymTabEntry parse(Token token, SymTabEntry parentId) throws Exception {

    Token FunctionReturnToken = token;

    Definition routineDefn = null;
    String dummyName = null;
    SymTabEntry routineId = null;
    TokenType routineType = token.getType();

    // Initialize.
    switch ((WookieTokenType) routineType) {
      case INT:
        {
          // save the int data type for use later
          FunctionReturnToken = token;
          token = nextToken(); // consume Int		
          routineDefn = DefinitionImpl.FUNCTION;
          dummyName = "DummyProgramName".toLowerCase() + String.format("%03d", ++dummyCounter);
          break;
        }

      case CHAR:
        {
          // save the char data type for use later
          FunctionReturnToken = token;
          token = nextToken(); // consume Char
          routineDefn = DefinitionImpl.FUNCTION;
          dummyName = "DummyProgramName".toLowerCase() + String.format("%03d", ++dummyCounter);
          break;
        }

      case VOID:
        {
          // save the void data type for use later
          FunctionReturnToken = token;
          token = nextToken(); // consume PROGRAM
          routineDefn = DefinitionImpl.PROCEDURE;
          dummyName = "DummyProgramName".toLowerCase() + String.format("%03d", ++dummyCounter);
          break;
        }

      default:
        {
          routineDefn = DefinitionImpl.PROGRAM;
          dummyName = "DummyProgramName".toLowerCase();
          break;
        }
    }

    // Parse the routine name.
    routineId = parseRoutineName(token, dummyName);

    routineId.setDefinition(routineDefn);
    token = currentToken();

    // Create new intermediate code for the routine.
    ICode iCode = ICodeFactory.createICode();
    routineId.setAttribute(ROUTINE_ICODE, iCode);
    routineId.setAttribute(ROUTINE_ROUTINES, new ArrayList<SymTabEntry>());

    SymTab symTab = symTabStack.push();

    routineId.setAttribute(ROUTINE_SYMTAB, symTab);

    ((SymTabImpl) symTab).setfuncName(routineId.getName());

    parseFormalParameters(token, routineId);
    token = currentToken();

    if (FunctionReturnToken.getType() == INT) {
      routineId.setTypeSpec(integerType);
    } else if (FunctionReturnToken.getType() == CHAR) {
      routineId.setTypeSpec(charType);
    }

    // Parse the routine's block  declaration.
    if (token.getType() == LEFT_BRACE) {

      routineId.setAttribute(ROUTINE_CODE, DECLARED);
      BlockParser blockParser = new BlockParser(this);

      ICodeNode rootNode = blockParser.parse(token, routineId);
      iCode.setRoot(rootNode);
    }
    ArrayList<SymTabEntry> subroutines =
        (ArrayList<SymTabEntry>) parentId.getAttribute(ROUTINE_ROUTINES);
    subroutines.add(routineId);
    // Pop the routine's symbol table off the stack.

    symTabStack.pop();

    return routineId;
  }