Method for programming multi-level non-volatile memories by controlling the gate voltage