Program Structure, Lexical Elements & Style

Learn how an Ada compilation unit is organized (context clauses, declarative part, statements), the lexical rules — identifiers, case insensitivity, comments, reserved words, numeric literals with underscores and bases, character and string literals — pragmas, and the conventional GNAT style.

Every Ada program follows the same visible structure, and once you can read it, any Ada source file becomes easy to navigate. A compilation unit starts with context clauses (with and use), then declares a subprogram or package; a subprogram has a declarative part where types, constants and variables are introduced, followed by begin, a sequence of statements, an optional exception section, and end followed by the name. This lesson covers that structure and the lexical rules — how identifiers, comments and literals are written.

Anatomy of a Subprogram

The general shape is: context clause (with Some.Package;), then 'procedure Name is', then declarations, then 'begin', then statements, then optionally 'exception' followed by handlers, then 'end Name;'. Declarations and statements are strictly separated: you cannot declare a variable in the middle of the statement sequence (you would open a declare block for that, covered later). This makes it easy to see at a glance everything a subprogram uses.

The main program is simply a parameterless procedure; its name is chosen by you and the binder is told which unit is the main one (gnatmake uses the file you pass). Any library-level subprogram or package can be a compilation unit. Statements are executed in order; every statement and declaration ends with a semicolon, and blocks are closed by 'end' with the construct's keyword (end if; end loop; end case; end record;), which makes nested code unambiguous.

• Unit layout: context clause → procedure Name is → declarations → begin → statements → [exception handlers] → end Name; • Declarations only in declarative parts, statements only after begin. • Every construct has an explicit closing: end if, end loop, end case, end record, end Name. • The main program is a parameterless library-level procedure.

Identifiers, Reserved Words and Comments

Identifiers start with a letter and contain letters, digits and single underscores (no leading, trailing or double underscores). Ada is case-insensitive: Put_Line, PUT_LINE and put_line are the same identifier, and keywords may be written in any case. By convention (GNAT style) identifiers use Mixed_Case_With_Underscores and keywords are lower case. Ada has 74 reserved words in Ada 2022 (such as begin, end, is, loop, record, package, task, protected, parallel) that cannot be used as identifiers.

Comments start with -- and run to the end of the line; there are no block comments. GNAT's style checker expects two spaces after -- in full-line comments. Pragmas are compiler directives written 'pragma Name (arguments);' — for example pragma Assert (X > 0); or pragma Inline (Fast_Function); — many of them now also exist as aspects written with 'with' on declarations.

• Identifiers: letters, digits, single underscores; case-insensitive. • Convention: Mixed_Case identifiers, lower-case keywords. • Comments: -- to end of line only. • Pragmas: pragma Name (...); many have aspect equivalents (with Inline, with Pre => ...).

Literals

Numeric literals may contain underscores to group digits (1_000_000). A literal with a decimal point is a real literal (3.14, 1.5E3); without one it is an integer literal (42, 1E6). Based literals write the base, a hash, the digits and another hash: 16#FF# (255), 2#1010# (10), 8#777#. Character literals use single quotes ('A'), string literals double quotes ("Ada"); a double quote inside a string is written twice ("She said ""Hi"""). There is no escape character such as \n — you use New_Line or the Character'Val / Latin_1 constants for control characters.

• 1_000_000 — underscores for readability. • 16#FF#, 2#1010#, 8#777# — based literals (bases 2 .. 16). • 3.14, 1.5E3 — real literals need a decimal point. • 'A' character, "text" string; "" inside a string = one quote; no backslash escapes.

Code Examples

Named numbers (constant := value) are exact, typeless values usable with any numeric type. Based literals 16#FF# and 2#1010# are just 255 and 10. The last statement deliberately writes PUT_LINE in capitals to show case insensitivity. Output: Million = 1000000 Mask = 255 Flags = 10 Big = 1.50000E+03 Letter = A She said "Hi" Identifiers and keywords are case-insensitive

--  A compilation unit: context clause, then the main subprogram.
with Ada.Text_IO; use Ada.Text_IO;

procedure L3_Structure is
   --  Declarative part: everything declared before "begin".
   Million : constant := 1_000_000;        --  underscores for readability
   Mask    : constant := 16#FF#;           --  based literal (hexadecimal)
   Flags   : constant := 2#1010#;          --  binary literal
   Big     : constant := 1.5E3;            --  real literal with exponent
   Letter  : constant Character := 'A';
   Quote   : constant String := "She said ""Hi""";   --  "" inside a string is one quote
begin
   --  Sequence of statements.
   Put_Line ("Million =" & Integer'Image (Million));
   Put_Line ("Mask    =" & Integer'Image (Mask));
   Put_Line ("Flags   =" & Integer'Image (Flags));
   Put_Line ("Big     =" & Float'Image (Big));
   Put_Line ("Letter  = " & Letter);
   Put_Line (Quote);
   PUT_LINE ("Identifiers and keywords are case-insensitive");
end L3_Structure;

Structure of an Ada Compilation Unit

Declarations and statements live in separate, clearly marked regions.

procedure Demo is begin Count : Integer := 0; Count := Count + 1; end Demo;

procedure Demo is Count : Integer := 0; begin Count := Count + 1; end Demo;

Declarations are not allowed among statements; put them in the declarative part (or open a declare block).

Put_Line ("Tab:\tEnd");

Put_Line ("Tab:" & Ada.Characters.Latin_1.HT & "End");

Ada strings have no backslash escapes; \t is two ordinary characters. Use Ada.Characters.Latin_1 constants.

Max__Value: Integer; -- double underscore Max_Value: Integer;

Identifiers may not contain consecutive underscores or end with one.

What is 16#1F# in decimal? A. 16 B. 31 C. 161 D. 25 B. 31 — based literal in base 16: 1×16 + 15.

How do you write a comment in Ada? A. // comment B. /* comment */ C. -- comment D. # comment

C. -- comment — runs to the end of the line; Ada has no block comments.

Are Put_Line and PUT_LINE the same identifier? A. Yes, Ada is case-insensitive B. No C. Only inside strings D. Only for keywords

A. Yes — identifiers and reserved words are case-insensitive (string contents are not).

Where must a local variable of a procedure be declared? A. Anywhere B. In the declarative part between 'is' and 'begin' C. After 'end' D. In the exception section

B. In the declarative part between 'is' and 'begin' (or in a nested declare block).

Predict the output of the program above, especially the Big and Quote lines.

Real output: Million = 1000000 Mask = 255 Flags = 10 Big = 1.50000E+03 Letter = A She said "Hi" Identifiers and keywords are case-insensitive Float'Image uses scientific notation (1.50000E+03), and the doubled quotes print as single quote characters.

with Ada.Text_IO;            ← context clause (dependencies)
procedure Report is          ← unit header
   Count : Integer := 0;     ← declarative part
begin                        ← statements start
   ...                       ← sequence of statements
exception                    ← optional handlers
   when others => ...
end Report;                  ← closing, repeats the name
--  A compilation unit: context clause, then the main subprogram.
with Ada.Text_IO; use Ada.Text_IO;

procedure L3_Structure is
   --  Declarative part: everything declared before "begin".
   Million : constant := 1_000_000;        --  underscores for readability
   Mask    : constant := 16#FF#;           --  based literal (hexadecimal)
   Flags   : constant := 2#1010#;          --  binary literal
   Big     : constant := 1.5E3;            --  real literal with exponent
   Letter  : constant Character := 'A';
   Quote   : constant String := "She said ""Hi""";   --  "" inside a string is one quote
begin
   --  Sequence of statements.
   Put_Line ("Million =" & Integer'Image (Million));
   Put_Line ("Mask    =" & Integer'Image (Mask));
   Put_Line ("Flags   =" & Integer'Image (Flags));
   Put_Line ("Big     =" & Float'Image (Big));
   Put_Line ("Letter  = " & Letter);
   Put_Line (Quote);
   PUT_LINE ("Identifiers and keywords are case-insensitive");
end L3_Structure;