🔷 Introduction to the Ada Programming Language

Andrew J. Pounds, Ph.D.

🎯 Learning Objectives

After completing this exercise, you will be able to:

1 What is Ada?

Ada is a structured, statically typed, imperative programming language designed by Jean Ichbiah and first standardized in 1983. It was developed under contract to the United States Department of Defense to address the problem of having too many different programming languages being used in defense projects. Ada was named in honor of Augusta Ada King, Countess of Lovelace (Ada Lovelace), who is often credited as the first computer programmer.

Ada was designed with a focus on software engineering principles: reliability, maintainability, and efficiency. It has been used extensively in safety-critical systems such as avionics, air traffic control, railways, banking, military, and space technology. Key features include:

Ada source files typically use the .adb extension for bodies (implementations) and .ads for specifications (interfaces). We will use the GNAT compiler, which is part of the GNU Compiler Collection (GCC) and is a mature, freely available Ada compiler.

2 Your First Ada Program

Create a file called hello.adb with the following content:

with Ada.Text_IO;

procedure Hello is
begin
   Ada.Text_IO.Put_Line("Hello, World!");
end Hello;

Compiling and Running

Open a terminal and navigate to the directory containing your file. Compile and run with:

gnatmake hello.adb
./hello

You should see Hello, World! printed to the console.

The gnatmake command compiles your Ada source and links it into an executable. By default, it creates an executable with the same name as your main procedure (minus the extension).

Understanding the Code

Code Element Explanation
with Ada.Text_IO; Imports the Text_IO package for console input/output
procedure Hello is Declares the main procedure named Hello
begin Marks the start of the executable statements
Ada.Text_IO.Put_Line(...) Writes output to the console followed by a newline
end Hello; Marks the end of the procedure (name repetition is required)
Note: Ada is case-insensitive. You can write BEGIN, Begin, or begin — they all mean the same thing. However, the Ada community follows a convention: keywords in lowercase, identifiers in Mixed_Case with underscores separating words (e.g., My_Variable, Calculate_Sum).

Using the use Clause

To avoid typing the full package name repeatedly, you can add a use clause:

with Ada.Text_IO; use Ada.Text_IO;

procedure Hello is
begin
   Put_Line("Hello, World!");
end Hello;

3 Variable Types

Ada is a statically and strongly typed language, meaning you must declare all variables and their types before using them. Variables are declared in the declarative region between is and begin.

Integer Types

Type Size Range
Short_Short_Integer 8 bits -128 to 127
Short_Integer 16 bits -32,768 to 32,767
Integer 32 bits -2,147,483,648 to 2,147,483,647
Long_Integer 64 bits -9.2×1018 to 9.2×1018
Natural 32 bits 0 to 2,147,483,647 (subtype of Integer)
Positive 32 bits 1 to 2,147,483,647 (subtype of Integer)

Floating-Point Types

Type Size Description
Short_Float 32 bits Single precision (~7 significant digits)
Float 32 bits Single precision (~7 significant digits)
Long_Float 64 bits Double precision (~15 significant digits)
Long_Long_Float 80+ bits Extended precision (platform dependent)

Other Fundamental Types

Type Description Example
Boolean Boolean (True or False) Flag : Boolean := True;
Character Single character Letter : Character := 'A';
String Fixed-length sequence of characters Name : String(1..10);

Variable Declaration Example

with Ada.Text_IO;         use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
with Ada.Float_Text_IO;   use Ada.Float_Text_IO;

procedure Variables is
   -- Each variable must be declared with its type
   Age      : Integer;
   GPA      : Float;
   Name     : String(1..10);
   Enrolled : Boolean;
   Grade    : Character;
begin
   -- Assign values to variables
   Age      := 25;
   GPA      := 3.85;
   Name     := "Alice     ";  -- Must be exactly 10 characters
   Enrolled := True;
   Grade    := 'A';

   -- Output the values
   Put_Line("Name: " & Name);
   Put("Age: ");
   Put(Age, Width => 0);
   New_Line;
   Put("GPA: ");
   Put(GPA, Fore => 1, Aft => 2, Exp => 0);
   New_Line;
   Put_Line("Enrolled: " & Boolean'Image(Enrolled));
   Put_Line("Grade: " & Grade);
end Variables;
Note: In Ada, the assignment operator is := (colon-equals), not =. The single equals sign = is used only for comparison. This is the same as Pascal.
Tip: Ada's String type has a fixed length that must be specified. For variable-length strings, you can use Ada.Strings.Unbounded, but for beginners, fixed-length strings are simpler.

4 Console Output

Ada provides several output procedures in Ada.Text_IO:

Procedure Description
Put() Outputs without adding a newline
Put_Line() Outputs and adds a newline at the end
New_Line Outputs just a newline
with Ada.Text_IO;         use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
with Ada.Float_Text_IO;   use Ada.Float_Text_IO;

procedure Output_Demo is
   X     : Integer := 42;
   Price : Float := 19.99;
   Item  : String(1..6) := "widget";
begin
   -- Basic output
   Put_Line("The answer is " & Integer'Image(X));

   -- Multiple values with string concatenation
   Put("Item: ");
   Put(Item);
   Put(", Price: $");
   Put(Price, Fore => 1, Aft => 2, Exp => 0);
   New_Line;

   -- Using Put (no newline)
   Put("Processing");
   Put("...");
   Put_Line(" Done!");

   -- Formatted numeric output
   Put("Padded integer: ");
   Put(X, Width => 8);
   New_Line;

   Put("Padded float:   ");
   Put(Price, Fore => 6, Aft => 2, Exp => 0);
   New_Line;
end Output_Demo;

Formatting Output

Ada uses named parameters to format numeric output:

Parameter Description Example
Width Minimum field width for integers Put(X, Width => 5);
Fore Digits before decimal point (for floats) Put(Y, Fore => 3, ...);
Aft Digits after decimal point (for floats) Put(Y, Aft => 2, ...);
Exp Exponent field width (0 = no exponent) Put(Y, Exp => 0);
Tip: Use Exp => 0 for float output when you want decimal notation without scientific notation. Use Width => 0 for integers when you want the minimum width with no padding.

Type Conversion for Output

To convert non-string values to strings for concatenation, use the 'Image attribute:

Put_Line("X = " & Integer'Image(X));
Put_Line("Flag = " & Boolean'Image(Enrolled));

5 Console Input

Ada provides several input procedures in Ada.Text_IO:

Procedure Description
Get() Reads input without consuming the newline
Get_Line() Reads a line of text including consuming the newline
Skip_Line Discards characters up to and including the newline
with Ada.Text_IO;         use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
with Ada.Float_Text_IO;   use Ada.Float_Text_IO;

procedure Input_Demo is
   Name : String(1..20);
   Last : Natural;
   Age  : Integer;
   GPA  : Float;
begin
   -- Reading a string with Get_Line
   Put("Enter your name: ");
   Get_Line(Name, Last);  -- Last contains the actual length read

   -- Reading an integer
   Put("Enter your age: ");
   Get(Age);
   Skip_Line;  -- Consume the newline left in the buffer

   -- Reading a float
   Put("Enter your GPA: ");
   Get(GPA);
   Skip_Line;

   -- Display the results
   New_Line;
   Put_Line("Hello, " & Name(1..Last) & "!");
   Put("Age: ");
   Put(Age, Width => 0);
   New_Line;
   Put("GPA: ");
   Put(GPA, Fore => 1, Aft => 2, Exp => 0);
   New_Line;
end Input_Demo;
Important: When using Get for numeric input, always call Skip_Line afterward to consume the remaining newline character. This prevents problems with subsequent Get_Line calls.

Reading Strings with Get_Line

The Get_Line procedure reads into a fixed-length string and returns the actual number of characters read:

Name : String(1..50);
Last : Natural;
...
Get_Line(Name, Last);
-- Name(1..Last) contains the actual input

6 Assignment Statements and Operators

Basic Assignment

The assignment operator := stores a value in a variable:

declare
   X, Y : Integer;
begin
   X := 10;     -- assign 10 to X
   X := 20;     -- assign new value
   Y := X;      -- copy value from X to Y
end;

Arithmetic Operators

Operator Description Example Result (if A=10, B=3)
+ Addition A + B 13
- Subtraction A - B 7
* Multiplication A * B 30
/ Division (integer or float depending on operands) A / B 3 (integer division)
mod Modulus (remainder) A mod B 1
rem Remainder (different sign behavior) A rem B 1
** Exponentiation A ** 2 100
abs Absolute value abs(-5) 5
Note: In Ada, the / operator performs integer division when both operands are integers, and floating-point division when either operand is a float. This differs from Pascal, which uses separate operators.

Integer vs. Float Division

with Ada.Text_IO;         use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
with Ada.Float_Text_IO;   use Ada.Float_Text_IO;

procedure Division_Demo is
   A, B : Integer;
   X, Y : Float;
begin
   A := 7;
   B := 2;
   X := 7.0;
   Y := 2.0;

   Put("7 / 2 (integer) = ");
   Put(A / B, Width => 0);
   New_Line;  -- prints 3

   Put("7.0 / 2.0 (float) = ");
   Put(X / Y, Fore => 1, Aft => 4, Exp => 0);
   New_Line;  -- prints 3.5000

   Put("7 mod 2 = ");
   Put(A mod B, Width => 0);
   New_Line;  -- prints 1

   -- To get float division from integers, convert one operand
   Put("Float(7) / Float(2) = ");
   Put(Float(A) / Float(B), Fore => 1, Aft => 4, Exp => 0);
   New_Line;  -- prints 3.5000
end Division_Demo;
Tip: Use mod when you need integer division (discarding the remainder) and use the result of /. Use mod when you need only the remainder.

7 Control Structures

The if Statement

Execute code conditionally based on a boolean expression:

with Ada.Text_IO;         use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;

procedure Grade_Calculator is
   Score : Integer;
begin
   Put("Enter your score (0-100): ");
   Get(Score);

   if Score >= 90 then
      Put_Line("Grade: A");
   elsif Score >= 80 then
      Put_Line("Grade: B");
   elsif Score >= 70 then
      Put_Line("Grade: C");
   elsif Score >= 60 then
      Put_Line("Grade: D");
   else
      Put_Line("Grade: F");
   end if;
end Grade_Calculator;
Note: In Ada, use elsif (not else if) for additional conditions. Every if statement must end with end if;.

Multiple Statements in Branches

Unlike Pascal, Ada doesn't require begin/end blocks for multiple statements:

if Score >= 90 then
   Put_Line("Grade: A");
   Put_Line("Excellent work!");
else
   Put_Line("Grade: Below A");
   Put_Line("Keep studying!");
end if;

Comparison Operators

Operator Meaning Example
= Equal to X = 5
/= Not equal to X /= 5
< Less than X < 5
> Greater than X > 5
<= Less than or equal to X <= 5
>= Greater than or equal to X >= 5

Logical Operators

Operator Meaning Example
and Logical AND (X > 0) and (X < 100)
or Logical OR (X < 0) or (X > 100)
not Logical NOT not Found
and then Short-circuit AND (X /= 0) and then (Y/X > 1)
or else Short-circuit OR (X = 0) or else (Y/X > 1)
Tip: Use and then and or else for short-circuit evaluation. This is important when the second condition might cause an error if the first is false (e.g., checking for division by zero).
with Ada.Text_IO;         use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;

procedure Driving_Check is
   Age         : Integer;
   Response    : String(1..3);
   Last        : Natural;
   Has_License : Boolean;
begin
   Put("Enter your age: ");
   Get(Age);
   Skip_Line;

   Put("Do you have a license? (yes/no): ");
   Get_Line(Response, Last);

   Has_License := (Response(1..Last) = "yes");

   if (Age >= 16) and Has_License then
      Put_Line("You can drive.");
   elsif (Age >= 16) and (not Has_License) then
      Put_Line("You're old enough but need a license.");
   else
      Put_Line("You're too young to drive.");
   end if;
end Driving_Check;

The case Statement

Use case when comparing a single value against multiple options:

with Ada.Text_IO;         use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;

procedure Day_Of_Week is
   Day : Integer;
begin
   Put("Enter a day number (1-7): ");
   Get(Day);

   case Day is
      when 1 =>
         Put_Line("Monday");
      when 2 =>
         Put_Line("Tuesday");
      when 3 =>
         Put_Line("Wednesday");
      when 4 =>
         Put_Line("Thursday");
      when 5 =>
         Put_Line("Friday");
      when 6 | 7 =>
         Put_Line("Weekend!");
      when others =>
         Put_Line("Invalid day number");
   end case;
end Day_Of_Week;
Note: Ada's case statement requires that all possible values be covered. Use when others => to handle any values not explicitly listed. You can use | to combine multiple values and .. for ranges: when 1..5 =>.

8 Looping Structures

The Basic loop

The simplest loop runs forever until explicitly exited with exit:

with Ada.Text_IO;         use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;

procedure Loop_Demo is
   I : Integer := 1;
begin
   loop
      Put("Count: ");
      Put(I, Width => 0);
      New_Line;
      I := I + 1;
      exit when I > 5;
   end loop;
end Loop_Demo;

The while Loop

Repeats a block of code as long as a condition is true. The condition is checked before each iteration:

with Ada.Text_IO;         use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;

procedure While_Demo is
   I : Integer;
begin
   -- Count from 1 to 5
   I := 1;
   while I <= 5 loop
      Put("Count: ");
      Put(I, Width => 0);
      New_Line;
      I := I + 1;
   end loop;
end While_Demo;

The loop with exit when (Post-test Loop)

Similar to Pascal's repeat-until, you can place the exit condition at the end:

with Ada.Text_IO;         use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;

procedure Guessing_Game is
   Guess         : Integer;
   Secret_Number : constant Integer := 7;
begin
   loop
      Put("Guess a number (1-10): ");
      Get(Guess);
      Skip_Line;

      if Guess < Secret_Number then
         Put_Line("Too low!");
      elsif Guess > Secret_Number then
         Put_Line("Too high!");
      end if;

      exit when Guess = Secret_Number;
   end loop;

   Put_Line("Correct!");
end Guessing_Game;

The for Loop

Best for counting a specific number of iterations:

with Ada.Text_IO;         use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;

procedure For_Demo is
begin
   -- Basic counting up
   for I in 1 .. 5 loop
      Put("Iteration ");
      Put(I, Width => 0);
      New_Line;
   end loop;

   New_Line;

   -- Counting down
   Put_Line("Countdown:");
   for I in reverse 0 .. 10 loop
      Put(I, Width => 0);
      New_Line;
   end loop;
end For_Demo;
Note: In Ada's for loop, the loop variable is automatically declared and is read-only within the loop. You cannot assign to it. Use reverse to count down.

Nested Loops

with Ada.Text_IO;         use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;

procedure Multiplication_Table is
begin
   Put_Line("Multiplication Table (1-5):");
   New_Line;

   -- Print header row
   Put("    ");
   for Col in 1 .. 5 loop
      Put(Col, Width => 4);
   end loop;
   New_Line;
   Put_Line("    --------------------");

   -- Print table rows
   for Row in 1 .. 5 loop
      Put(Row, Width => 2);
      Put(" |");
      for Col in 1 .. 5 loop
         Put(Row * Col, Width => 4);
      end loop;
      New_Line;
   end loop;
end Multiplication_Table;

Loop Control: exit and Named Loops

with Ada.Text_IO;         use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;

procedure Loop_Control is
begin
   -- exit - exit the loop early
   Put_Line("Finding first multiple of 7:");
   for I in 1 .. 100 loop
      if I mod 7 = 0 then
         Put("Found: ");
         Put(I, Width => 0);
         New_Line;
         exit;  -- exit loop immediately
      end if;
   end loop;

   New_Line;

   -- Using a named loop for nested exits
   Put_Line("Numbers 1-10, skipping multiples of 3:");
   Outer_Loop:
   for I in 1 .. 10 loop
      if I mod 3 = 0 then
         null;  -- skip this iteration (Ada has no 'continue')
      else
         Put(I, Width => 0);
         New_Line;
      end if;
   end loop Outer_Loop;
end Loop_Control;
Tip: Ada does not have a continue statement. Instead, use conditional logic to skip the unwanted iterations, or restructure your loop.

9 Complete Example: Temperature Converter

This program demonstrates input, output, control structures, and loops working together:

with Ada.Text_IO;         use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
with Ada.Float_Text_IO;   use Ada.Float_Text_IO;

procedure Temperature_Converter is
   Choice     : Integer;
   Celsius    : Float;
   Fahrenheit : Float;
   Running    : Boolean;
begin
   Put_Line("=== Temperature Converter ===");
   Put_Line("1. Celsius to Fahrenheit");
   Put_Line("2. Fahrenheit to Celsius");
   Put_Line("3. Quit");

   Running := True;

   while Running loop
      New_Line;
      Put("Enter choice (1-3): ");
      Get(Choice);
      Skip_Line;

      case Choice is
         when 1 =>
            Put("Enter temperature in Celsius: ");
            Get(Celsius);
            Skip_Line;
            Fahrenheit := (Celsius * 9.0 / 5.0) + 32.0;
            Put(Celsius, Fore => 1, Aft => 2, Exp => 0);
            Put(" C = ");
            Put(Fahrenheit, Fore => 1, Aft => 2, Exp => 0);
            Put_Line(" F");

         when 2 =>
            Put("Enter temperature in Fahrenheit: ");
            Get(Fahrenheit);
            Skip_Line;
            Celsius := (Fahrenheit - 32.0) * 5.0 / 9.0;
            Put(Fahrenheit, Fore => 1, Aft => 2, Exp => 0);
            Put(" F = ");
            Put(Celsius, Fore => 1, Aft => 2, Exp => 0);
            Put_Line(" C");

         when 3 =>
            Put_Line("Goodbye!");
            Running := False;

         when others =>
            Put_Line("Invalid choice. Please enter 1, 2, or 3.");
      end case;
   end loop;
end Temperature_Converter;

10 Quick Reference

Task Ada Syntax
Print with newline Put_Line("text");
Print without newline Put("text");
Print integer Put(N, Width => 0);
Print float (formatted) Put(X, Fore => 1, Aft => 2, Exp => 0);
Read string Get_Line(S, Last);
Read integer Get(N); Skip_Line;
Read float Get(X); Skip_Line;
Assignment X := 10;
Integer division A / B (when A, B are Integer)
Modulus (remainder) A mod B
Not equal A /= B
Logical AND (cond1) and (cond2)
Logical OR (cond1) or (cond2)
String concatenation "Hello, " & Name
Type conversion to string Integer'Image(X)
Compile gnatmake filename.adb
Run ./filename

📝 Programming Exercise: Prime Number Analyzer

Write an Ada program that analyzes prime numbers. Your program should:

  1. Prompt the user to enter a positive integer N (must be ≥ 2)
  2. Validate the input: If the user enters a number less than 2, display an error message and ask again (use a loop)
  3. Determine if N is prime: A prime number is only divisible by 1 and itself
  4. If N is prime: Display "N is a prime number!"
  5. If N is not prime: Display "N is not prime. Its smallest factor is F." (where F is the smallest factor other than 1)
  6. Count and display how many prime numbers exist from 2 up to and including N
  7. Ask the user if they want to check another number (y/n). If yes, repeat; if no, exit with a goodbye message

Sample Output

=== Prime Number Analyzer === Enter a positive integer (>= 2): 1 Invalid input. Please enter a number >= 2. Enter a positive integer (>= 2): 29 29 is a prime number! There are 10 prime numbers from 2 to 29. Check another number? (y/n): y Enter a positive integer (>= 2): 100 100 is not prime. Its smallest factor is 2. There are 25 prime numbers from 2 to 100. Check another number? (y/n): n Goodbye!

Hints

Submission

Save your program as prime_analyzer.adb and compile with:

gnatmake prime_analyzer.adb
./prime_analyzer

🚀 Student Starter Code

Use the following template to get started. Fill in each blank (____) with the appropriate code. Read the comments carefully for hints!

Instructions

  1. Save this code as prime_analyzer.adb
  2. Read through all the comments to understand the program structure
  3. Fill in each blank with the appropriate code
  4. Compile and test your program
--  Prime Number Analyzer - Student Starter Code
--  ============================================
--  Complete the sections marked with TODO to finish this program.
--
--  This program will:
--  1. Ask the user for a positive integer >= 2
--  2. Validate the input (reject numbers less than 2)
--  3. Determine if the number is prime
--  4. Find the smallest factor if not prime
--  5. Count all primes from 2 to N
--  6. Allow the user to check multiple numbers
--
--  Author: [Your Name]
--  Date:   [Date]

with Ada.Text_IO;         use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;

procedure Prime_Analyzer is

   --  =========================================================
   --  Function: Check_If_Prime
   --  =========================================================
   --  Determines whether a given number is prime.
   --
   --  Parameters:
   --     Num - the number to check (assume Num >= 2)
   --
   --  Returns:
   --     True if Num is prime, False otherwise
   --
   --  HINT: A number is prime if it has no divisors other than 1 and itself.
   --        Use a for loop to check if any number from 2 to Num-1 divides evenly.
   --        Use the mod operator: if Num mod Divisor = 0, then Divisor divides Num.

   function Check_If_Prime (Num : Integer) return Boolean is
      Found_Divisor : Boolean;
   begin
      --  Special case: 2 is the smallest prime
      if Num = 2 then
         return True;
      end if;

      --  Assume the number is prime until we find a divisor
      Found_Divisor := False;

      --  TODO: Write a for loop that checks each potential divisor
      --  Loop from 2 to Num - 1
      --  If Num mod Divisor = 0, we found a divisor (not prime)

      for Divisor in 2 .. ________ loop
         if Num mod Divisor = ________ then
            Found_Divisor := ________;
            exit;  --  Exit the loop early - no need to keep checking
         end if;
      end loop;

      --  TODO: Return the result
      --  If we found a divisor, the number is NOT prime
      --  HINT: Use "not Found_Divisor" to return True when no divisor was found

      return ________;
   end Check_If_Prime;

   --  =========================================================
   --  Function: Find_Smallest_Factor
   --  =========================================================
   --  Finds the smallest factor of a number (other than 1).
   --
   --  Parameters:
   --     Num - the number to find the factor of (assume Num >= 2 and not prime)
   --
   --  Returns:
   --     The smallest factor > 1
   --
   --  HINT: This is similar to Check_If_Prime, but instead of just checking
   --        if a divisor exists, you return the first divisor you find.

   function Find_Smallest_Factor (Num : Integer) return Integer is
   begin
      --  TODO: Write a for loop to find the smallest divisor
      --  Start from 2 and go up to Num - 1
      --  Return as soon as you find a divisor

      for Divisor in ________ .. Num - 1 loop
         if ________ mod ________ = 0 then
            return ________;
         end if;
      end loop;

      --  If no factor found (shouldn't happen if Num is not prime), return Num
      return Num;
   end Find_Smallest_Factor;

   --  =========================================================
   --  Function: Count_Primes_Up_To
   --  =========================================================
   --  Counts how many prime numbers exist from 2 up to and including Limit.
   --
   --  Parameters:
   --     Limit - the upper bound (inclusive)
   --
   --  Returns:
   --     The count of prime numbers in the range [2, Limit]
   --
   --  HINT: Loop through all numbers from 2 to Limit.
   --        For each number, call Check_If_Prime.
   --        If it's prime, increment a counter.

   function Count_Primes_Up_To (Limit : Integer) return Integer is
      Count : Integer;
   begin
      Count := 0;

      --  TODO: Write a for loop from 2 to Limit
      --  For each number, check if it's prime using Check_If_Prime
      --  If prime, increment Count

      for Num in ________ .. ________ loop
         if ________(________) then
            Count := Count + ________;
         end if;
      end loop;

      return Count;
   end Count_Primes_Up_To;

   --  ===== VARIABLE DECLARATIONS =====
   N                : Integer;           --  The number to analyze
   Smallest_Factor  : Integer;           --  Stores the smallest factor if not prime
   Prime_Count      : Integer;           --  Counts primes from 2 to N
   Continue_Running : Boolean;           --  Flag to control main program loop
   Response         : Character;         --  User's yes/no response

--  ===== MAIN PROGRAM =====
begin
   --  Display program header
   Put_Line("=== Prime Number Analyzer ===");
   New_Line;

   --  Initialize the main loop control variable
   Continue_Running := True;

   --  Main program loop - continues until user chooses to quit
   while Continue_Running loop

      --  ================================================
      --  PART 1: Input Validation
      --  ================================================
      --  TODO: Use a loop with exit when to get valid input
      --  Keep asking until the user enters a number >= 2
      --
      --  HINT: The structure is:
      --     loop
      --        Put(...);
      --        Get(...);
      --        Skip_Line;
      --        exit when ...;
      --        if N < 2 then
      --           Put_Line("error message");
      --        end if;
      --     end loop;

      loop
         Put("Enter a positive integer (>= 2): ");
         Get(________);
         Skip_Line;

         exit when ________ >= ________;

         if ________ < 2 then
            Put_Line("Invalid input. Please enter a number >= 2.");
         end if;
      end loop;

      --  ================================================
      --  PART 2: Check if Prime and Display Result
      --  ================================================
      --  TODO: Call Check_If_Prime to determine if N is prime
      --  If prime: display "N is a prime number!"
      --  If not prime: find smallest factor and display it
      --
      --  HINT: Use an if-else statement

      if ________(________) then
         --  N is prime
         Put(________, Width => 0);
         Put_Line(" is a prime number!");
      else
         --  N is not prime - find and display smallest factor
         Smallest_Factor := ________(________);
         Put(________, Width => 0);
         Put(" is not prime. Its smallest factor is ");
         Put(________, Width => 0);
         Put_Line(".");
      end if;

      --  ================================================
      --  PART 3: Count Primes from 2 to N
      --  ================================================
      --  TODO: Call Count_Primes_Up_To and display the result

      Prime_Count := ________(________);
      Put("There are ");
      Put(________, Width => 0);
      Put(" prime numbers from 2 to ");
      Put(________, Width => 0);
      Put_Line(".");

      --  ================================================
      --  PART 4: Ask to Continue
      --  ================================================
      --  TODO: Ask user if they want to check another number
      --  Read their response into the Response variable
      --  Set Continue_Running to False if they don't enter 'y' or 'Y'

      New_Line;
      Put("Check another number? (y/n): ");
      Get(________);
      Skip_Line;
      New_Line;

      --  Check if user wants to continue
      --  HINT: Use "and" to check if Response is neither 'y' nor 'Y'
      if (Response /= '________') and (Response /= '________') then
         Continue_Running := ________;
      end if;

   end loop;  --  End of main while loop

   --  Display goodbye message
   Put_Line("Goodbye!");

end Prime_Analyzer;

Hints for Each Section

Section Key Hints
Check_If_Prime Loop goes to Num - 1. Check if remainder equals 0. Return not Found_Divisor.
Find_Smallest_Factor Start the loop at 2. Check Num mod Divisor. Return Divisor when found.
Count_Primes_Up_To Loop from 2 to Limit. Call Check_If_Prime(Num). Increment by 1.
Input Validation Read into N. Check if N >= 2. Loop until valid.
Prime Check Call Check_If_Prime(N). Call Find_Smallest_Factor(N).
Count Display Call Count_Primes_Up_To(N). Display Prime_Count and N.
Continue Loop Read into Response. Check for 'y' and 'Y'. Set to False to exit.

Testing Your Program

Test with these inputs to verify your solution:

Input Expected Output
1 "Invalid input" message, asks again
2 "2 is a prime number!", 1 prime
7 "7 is a prime number!", 4 primes
10 "10 is not prime. Smallest factor is 2.", 4 primes
29 "29 is a prime number!", 10 primes
100 "100 is not prime. Smallest factor is 2.", 25 primes

Common Errors to Watch For