Program Structure
Hello, World
program Hello;
begin
writeln('Hello, World!');
end. >>SOURCE FORMAT IS FREE
IDENTIFICATION DIVISION.
PROGRAM-ID. HELLO.
PROCEDURE DIVISION.
DISPLAY "Hello, World!"
STOP RUN. A Pascal program is a single
program Name; begin ... end. block. A COBOL program is split into DIVISIONS: IDENTIFICATION DIVISION names the program with PROGRAM-ID, and PROCEDURE DIVISION holds the executable statements. DISPLAY is COBOL's equivalent of Pascal's writeln, and STOP RUN. is the mandatory final statement.Comments
program Comments;
var
total: Integer; { This is a trailing comment }
begin
{ This is a full-line comment }
total := 10;
writeln(total);
end. >>SOURCE FORMAT IS FREE
IDENTIFICATION DIVISION.
PROGRAM-ID. COMMENTS.
DATA DIVISION.
WORKING-STORAGE SECTION.
*> This is a full-line comment
01 WS-TOTAL PIC 9(3) VALUE 10.
PROCEDURE DIVISION.
DISPLAY WS-TOTAL *> This is a trailing comment
STOP RUN. Pascal comments use curly braces
{ ... } (or (* ... *)); COBOL free-format comments start with *> and run to the end of the line. Both languages date from an era where comment syntax had to coexist with fixed-column punch-card layouts, though modern free-form dialects of both have moved past that constraint.The Four Divisions: no Pascal equivalent
program FourDivisions;
var
score: Integer;
begin
score := 95;
writeln('Score: ', score);
end. >>SOURCE FORMAT IS FREE
IDENTIFICATION DIVISION.
PROGRAM-ID. FOUR-DIVISIONS.
ENVIRONMENT DIVISION.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-SCORE PIC 9(3) VALUE 95.
PROCEDURE DIVISION.
DISPLAY "Score: " WS-SCORE
STOP RUN. Pascal has one flat program structure: an optional
uses clause, const/type/var declarations, then a single begin...end. body. COBOL formally separates concerns into up to four DIVISIONs — IDENTIFICATION (naming), ENVIRONMENT (system/file configuration), DATA (every variable's declaration), and PROCEDURE (the executable logic) — a considerably more rigid, bureaucratic structure with no Pascal parallel.Data Types vs. PICTURE Clauses
Integer becomes PIC 9(n)
program IntegerDemo;
var
count: Integer;
begin
count := 42;
writeln(count);
end. >>SOURCE FORMAT IS FREE
IDENTIFICATION DIVISION.
PROGRAM-ID. INTEGER-DEMO.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-COUNT PIC 9(3) VALUE 42.
PROCEDURE DIVISION.
DISPLAY WS-COUNT
STOP RUN. Pascal's
Integer is a single, fixed-width machine type with a range decided by the compiler and platform. COBOL's PIC 9(3) declares exactly how many decimal DIGITS the field holds — 9(3) means up to three digits, 0–999 — a picture of the data's shape rather than a reference to a machine word size, closer in spirit to specifying a column width on a form.Real becomes PIC 9V99 — the central theme of this whole comparison
program RealDemo;
var
price: Real;
begin
price := 19.99;
writeln(price:0:2);
end. >>SOURCE FORMAT IS FREE
IDENTIFICATION DIVISION.
PROGRAM-ID. PICTURE-V-DEMO.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-PRICE PIC 9(2)V99 VALUE 19.99.
PROCEDURE DIVISION.
DISPLAY WS-PRICE
STOP RUN. This is the central theme of this whole comparison. Pascal's
Real is IEEE 754 binary floating point — it carries the same representation error every modern language's float type has (0.1 + 0.2 is not exactly 0.3). COBOL's PIC 9(2)V99 is a genuinely different representation: an implied decimal point (the V) over exact decimal digits, with NO floating-point rounding error at all — precisely why COBOL, not Pascal or any binary-float language, became the language of bank ledgers and financial systems.Static compiler types versus a picture of the data's shape
program TypeCheckDemo;
var
age: Integer;
begin
age := 30;
{ age := 'thirty'; would be a compile-time type error in Pascal }
writeln(age);
end. >>SOURCE FORMAT IS FREE
IDENTIFICATION DIVISION.
PROGRAM-ID. PICTURE-SHAPE.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-AGE PIC 9(3) VALUE 30.
PROCEDURE DIVISION.
DISPLAY WS-AGE
STOP RUN. Both languages check a value against its declared shape, but the mechanism differs: Pascal's type system is abstract (
Integer, Real, String are named types the compiler reasons about). COBOL's PICTURE clause describes the literal shape of the data on the "form" — how many digits, whether signed, where the decimal point falls — closer to specifying a punch-card column layout than to a type in the modern sense.Variables & Assignment
:= becomes MOVE
program AssignDemo;
var
first, second: Integer;
begin
first := 10;
second := first;
writeln(second);
end. >>SOURCE FORMAT IS FREE
IDENTIFICATION DIVISION.
PROGRAM-ID. MOVE-DEMO.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-FIRST PIC 9(3) VALUE 10.
01 WS-SECOND PIC 9(3).
PROCEDURE DIVISION.
MOVE WS-FIRST TO WS-SECOND
DISPLAY WS-SECOND
STOP RUN. Pascal's
:= and COBOL's MOVE ... TO ... both copy a value into a variable, but COBOL spells it as an English verb phrase rather than a symbol — consistent with COBOL's design goal of reading like a specification document a non-programmer manager could follow.Arithmetic: Binary Float vs. Exact Decimal
Operators (+, -) versus ADD / SUBTRACT
program BasicOps;
var
balance: Integer;
begin
balance := 100;
balance := balance + 50;
balance := balance - 20;
writeln('Balance: ', balance);
end. >>SOURCE FORMAT IS FREE
IDENTIFICATION DIVISION.
PROGRAM-ID. ADD-SUBTRACT.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-BALANCE PIC 9(5) VALUE 100.
PROCEDURE DIVISION.
ADD 50 TO WS-BALANCE
SUBTRACT 20 FROM WS-BALANCE
DISPLAY "Balance: " WS-BALANCE
STOP RUN. Pascal uses the familiar
+ and - infix operators with a separate := assignment. COBOL's traditional arithmetic verbs are English sentences: ADD n TO field and SUBTRACT n FROM field both modify the destination field in place, with no separate assignment step and no operator symbols at all. COBOL also supports COMPUTE with ordinary operator syntax, covered next.Expressions versus COMPUTE
program ComputeDemo;
var
principal, rate, timeYears, interest: Real;
begin
principal := 1000.0;
rate := 0.05;
timeYears := 3.0;
interest := principal * rate * timeYears;
writeln(interest:0:2);
end. >>SOURCE FORMAT IS FREE
IDENTIFICATION DIVISION.
PROGRAM-ID. COMPUTE-DEMO.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-PRINCIPAL PIC 9(6)V99 VALUE 1000.00.
01 WS-RATE PIC 9V999 VALUE 0.050.
01 WS-TIME-YEARS PIC 9(2) VALUE 3.
01 WS-INTEREST PIC 9(6)V99.
PROCEDURE DIVISION.
COMPUTE WS-INTEREST = WS-PRINCIPAL * WS-RATE * WS-TIME-YEARS
DISPLAY WS-INTEREST
STOP RUN. COBOL's
COMPUTE statement allows ordinary infix operator expressions — COMPUTE result = a * b * c — reading almost exactly like the Pascal assignment it mirrors. Idiomatic COBOL still tends to prefer the English-verb forms (ADD/SUBTRACT/MULTIPLY/DIVIDE) for simple single operations, reserving COMPUTE for anything with more than one operator.ROUNDED: explicit rounding control with no Pascal parallel
program RoundingDemo;
var
total: Real;
begin
total := 10.0 / 3.0;
writeln(total:0:2); { Pascal truncates/rounds per its own float formatting rules }
end. >>SOURCE FORMAT IS FREE
IDENTIFICATION DIVISION.
PROGRAM-ID. ROUNDING-DEMO.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-TOTAL PIC 9V99.
PROCEDURE DIVISION.
COMPUTE WS-TOTAL ROUNDED = 10 / 3
DISPLAY WS-TOTAL
STOP RUN. COBOL's optional
ROUNDED phrase on an arithmetic statement explicitly requests standard rounding to the destination field's declared decimal places, rather than silent truncation — a control financial-precision COBOL code reaches for constantly and Pascal has no dedicated phrase for at all (Pascal would need an explicit call to Round or similar as a separate step).Strings vs. Fixed-Width Fields
String becomes PIC X(n) — a fixed-width field, not a growable string
program StringDemo;
var
name: string;
begin
name := 'Ada';
writeln(name);
end. >>SOURCE FORMAT IS FREE
IDENTIFICATION DIVISION.
PROGRAM-ID. PIC-X-DEMO.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-NAME PIC X(20) VALUE "Ada".
PROCEDURE DIVISION.
DISPLAY WS-NAME
STOP RUN. Pascal's modern
string type is a managed, growable string. COBOL's PIC X(20) declares a FIXED-WIDTH alphanumeric field — always exactly 20 characters, space-padded on the right if the stored value is shorter. Displaying WS-NAME after storing "Ada" prints "Ada" followed by 17 trailing spaces, not just the three letters — a real behavioral difference from Pascal's exact-length string.String concatenation
program ConcatDemo;
var
greeting: string;
begin
greeting := 'Hello, ' + 'World!';
writeln(greeting);
end. >>SOURCE FORMAT IS FREE
IDENTIFICATION DIVISION.
PROGRAM-ID. CONCAT-DEMO.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-GREETING PIC X(20).
PROCEDURE DIVISION.
STRING "Hello, " "World!" DELIMITED BY SIZE INTO WS-GREETING
DISPLAY WS-GREETING
STOP RUN. Pascal's
+ concatenates strings directly, growing the result. COBOL's STRING ... DELIMITED BY SIZE INTO ... statement is a considerably more verbose verb-based construct — the destination must already be a fixed-width field big enough to hold the result, since COBOL strings never grow dynamically.Arrays vs. OCCURS Tables
Array becomes an OCCURS table
program ArrayDemo;
var
scores: array[1..5] of Integer;
i: Integer;
begin
scores[1] := 10;
scores[2] := 20;
for i := 1 to 2 do
writeln(scores[i]);
end. >>SOURCE FORMAT IS FREE
IDENTIFICATION DIVISION.
PROGRAM-ID. OCCURS-DEMO.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-SCORES.
05 WS-SCORE PIC 9(3) OCCURS 5 TIMES.
01 WS-I PIC 9 VALUE 1.
PROCEDURE DIVISION.
MOVE 10 TO WS-SCORE(1)
MOVE 20 TO WS-SCORE(2)
PERFORM VARYING WS-I FROM 1 BY 1 UNTIL WS-I > 2
DISPLAY WS-SCORE(WS-I)
END-PERFORM
STOP RUN. Pascal's
array[1..5] of Integer declares a fixed-size indexed collection directly. COBOL expresses the same idea with the OCCURS n TIMES clause on a group-item field, nested one level inside a parent 01-level record — table declaration is a property attached to a field, not a standalone type the way Pascal's array is.Control Flow
If / Else
program IfElseDemo;
var
score: Integer;
begin
score := 85;
if score >= 90 then
writeln('A')
else if score >= 80 then
writeln('B')
else
writeln('Below B');
end. >>SOURCE FORMAT IS FREE
IDENTIFICATION DIVISION.
PROGRAM-ID. IF-ELSE-DEMO.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-SCORE PIC 9(3) VALUE 85.
PROCEDURE DIVISION.
IF WS-SCORE >= 90
DISPLAY "A"
ELSE IF WS-SCORE >= 80
DISPLAY "B"
ELSE
DISPLAY "Below B"
END-IF
STOP RUN. The structure is close — Pascal's
if ... then ... else and COBOL's IF ... ELSE ... END-IF both branch on a condition. COBOL requires the explicit scope terminator END-IF in modern free-format style (older fixed-format COBOL relied on the period instead), where Pascal uses begin...end blocks only when a branch has more than one statement.Case becomes EVALUATE
program CaseDemo;
var
dayNumber: Integer;
dayName: string;
begin
dayNumber := 3;
case dayNumber of
1: dayName := 'Monday';
2: dayName := 'Tuesday';
3: dayName := 'Wednesday';
else dayName := 'Unknown';
end;
writeln(dayName);
end. >>SOURCE FORMAT IS FREE
IDENTIFICATION DIVISION.
PROGRAM-ID. EVALUATE-DEMO.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-DAY-NUMBER PIC 9 VALUE 3.
01 WS-DAY-NAME PIC X(10).
PROCEDURE DIVISION.
EVALUATE WS-DAY-NUMBER
WHEN 1 MOVE "Monday" TO WS-DAY-NAME
WHEN 2 MOVE "Tuesday" TO WS-DAY-NAME
WHEN 3 MOVE "Wednesday" TO WS-DAY-NAME
WHEN OTHER MOVE "Unknown" TO WS-DAY-NAME
END-EVALUATE
DISPLAY WS-DAY-NAME
STOP RUN. Pascal's
case...of and COBOL's EVALUATE...WHEN are close structural cousins — both match ordinal/discrete values against a chain of alternatives with a catch-all (Pascal's else, COBOL's WHEN OTHER). COBOL's EVALUATE is notably more powerful: it can also evaluate multiple conditions simultaneously (EVALUATE TRUE ALSO ...), something Pascal's single-value case cannot express at all.Loops
For loop becomes PERFORM VARYING
program ForLoop;
var
counter: Integer;
begin
for counter := 1 to 5 do
writeln(counter);
end. >>SOURCE FORMAT IS FREE
IDENTIFICATION DIVISION.
PROGRAM-ID. PERFORM-VARYING.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-COUNTER PIC 9.
PROCEDURE DIVISION.
PERFORM VARYING WS-COUNTER FROM 1 BY 1 UNTIL WS-COUNTER > 5
DISPLAY WS-COUNTER
END-PERFORM
STOP RUN. Pascal's
for counter := 1 to 5 do always steps by exactly 1 (or -1 with downto), with no step-size option at all. COBOL's PERFORM VARYING ... FROM ... BY ... UNTIL ... spells out the initial value, the step size, and the exit condition explicitly — considerably more verbose, but able to step by any amount, something Pascal's dedicated for cannot do without falling back to a while loop.While loop becomes PERFORM UNTIL
program WhileLoop;
var
count: Integer;
begin
count := 0;
while count < 5 do
begin
writeln(count);
count := count + 1;
end;
end. >>SOURCE FORMAT IS FREE
IDENTIFICATION DIVISION.
PROGRAM-ID. PERFORM-UNTIL.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-COUNT PIC 9 VALUE 0.
PROCEDURE DIVISION.
PERFORM UNTIL WS-COUNT >= 5
DISPLAY WS-COUNT
ADD 1 TO WS-COUNT
END-PERFORM
STOP RUN. Pascal's
while condition do continues WHILE the condition is true. COBOL's PERFORM UNTIL condition is phrased the opposite way — it continues UNTIL the condition becomes true — so translating requires inverting the condition (count < 5 becomes WS-COUNT >= 5), a small but easy-to-miss gotcha when porting logic between the two languages.var Parameters vs. No Parameters at All
Procedure versus paragraph
program ProcedureDemo;
procedure Greet;
begin
writeln('Hello!');
end;
begin
Greet;
Greet;
end. >>SOURCE FORMAT IS FREE
IDENTIFICATION DIVISION.
PROGRAM-ID. PARAGRAPH-DEMO.
PROCEDURE DIVISION.
PERFORM GREET
PERFORM GREET
STOP RUN.
GREET.
DISPLAY "Hello!". A Pascal
procedure is a distinct named unit, declared before use, with its own scope for local variables. A COBOL paragraph is just a label (GREET.) in the PROCEDURE DIVISION followed by statements running to the next label — there is no separate declaration section, no local scope of its own, and no formal parameter list at all.⚠ var Parameters vs. No Parameter Passing — the biggest structural gap
program VarParameterDemo;
procedure ComputeArea(inputRadius: Real; var areaOut: Real);
const
Pi = 3.14159265358979;
begin
areaOut := Pi * inputRadius * inputRadius;
end;
var
radius, area: Real;
begin
radius := 5.0;
ComputeArea(radius, area);
writeln('Area: ', area:0:2);
end. >>SOURCE FORMAT IS FREE
IDENTIFICATION DIVISION.
PROGRAM-ID. NO-PARAMETERS.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-RADIUS PIC 9(3)V99 VALUE 5.
01 WS-AREA PIC 9(5)V99.
PROCEDURE DIVISION.
PERFORM COMPUTE-AREA
DISPLAY "Area: " WS-AREA
STOP RUN.
COMPUTE-AREA.
COMPUTE WS-AREA = 3.14159 * WS-RADIUS * WS-RADIUS. This is the biggest structural gap between the two languages' procedural models. A Pascal procedure declares exactly which arguments it only reads (plain value parameters, passed by value) and which it can modify (
var parameters, passed by reference) — the compiler enforces this contract at every call site. A standard COBOL paragraph takes NO PARAMETERS AT ALL: COMPUTE-AREA simply reads and writes WS-RADIUS and WS-AREA because they happen to be global WORKING-STORAGE fields already in scope. Nothing but a comment or naming convention documents which fields a given paragraph touches.PERFORM THRU: running a range of paragraphs, no Pascal equivalent
{ Pascal has no equivalent at all — calling a sequence of
procedures always means calling each one individually by name;
there is no concept of a contiguous "range" of procedures to run: }
program NoRangeEquivalent;
procedure StepOne;
begin
writeln('Step one');
end;
procedure StepTwo;
begin
writeln('Step two');
end;
begin
StepOne;
StepTwo;
end. >>SOURCE FORMAT IS FREE
IDENTIFICATION DIVISION.
PROGRAM-ID. PERFORM-THRU.
PROCEDURE DIVISION.
PERFORM STEP-ONE THRU STEP-TWO
STOP RUN.
STEP-ONE.
DISPLAY "Step one".
STEP-TWO.
DISPLAY "Step two". COBOL's
PERFORM STEP-ONE THRU STEP-TWO runs every paragraph from STEP-ONE through STEP-TWO in the order they are physically written in the source file — a genuinely new idea for a Pascal programmer, since Pascal calls procedures individually by name and has no notion of a contiguous "range" of them determined by source position rather than an explicit list.Functions vs. Intrinsics
Function return value versus an intrinsic FUNCTION call
program FunctionDemo;
function Square(n: Integer): Integer;
begin
Square := n * n;
end;
begin
writeln(Square(7));
end. >>SOURCE FORMAT IS FREE
IDENTIFICATION DIVISION.
PROGRAM-ID. INTRINSIC-DEMO.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-NUMBER PIC 9(3) VALUE 7.
PROCEDURE DIVISION.
DISPLAY FUNCTION MOD(WS-NUMBER, 3)
STOP RUN. Pascal functions are user-defined:
Square is declared with its own body and return type, and Pascal has no restriction on writing arbitrary custom functions. COBOL DOES support user-defined paragraphs returning values indirectly (via a global field), but its FUNCTION keyword specifically invokes one of a fixed, built-in set of INTRINSIC functions (FUNCTION MOD, FUNCTION SQRT, FUNCTION UPPER-CASE, and dozens more) — closer to Pascal's built-in Sqrt/Round than to a general user-defined function mechanism.Records vs. Group Items
Record becomes a group item — a genuinely close structural match
program RecordDemo;
type
TPerson = record
Name: string;
Age: Integer;
end;
var
person: TPerson;
begin
person.Name := 'Ada';
person.Age := 36;
writeln(person.Name, ' is ', person.Age);
end. >>SOURCE FORMAT IS FREE
IDENTIFICATION DIVISION.
PROGRAM-ID. GROUP-ITEM-DEMO.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-PERSON.
05 WS-NAME PIC X(20) VALUE "Ada".
05 WS-AGE PIC 9(3) VALUE 36.
PROCEDURE DIVISION.
DISPLAY WS-NAME " is " WS-AGE
STOP RUN. This is a genuinely close structural match. Pascal's
record groups named, typed fields under one type; COBOL's hierarchical level-number structure does the same thing — a parent 01 WS-PERSON group item containing child 05-level elementary fields, accessed by name (WS-NAME, WS-AGE) exactly like person.Name/person.Age. The numbering (01, 05, 10, ...) encodes nesting depth instead of Pascal's explicit record...end block syntax.Output & Formatting
writeln formatting versus DISPLAY
program FormatDemo;
var
price: Real;
begin
price := 19.5;
writeln('Price: $', price:0:2);
end. >>SOURCE FORMAT IS FREE
IDENTIFICATION DIVISION.
PROGRAM-ID. FORMAT-DEMO.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-PRICE PIC 9(3)V99 VALUE 19.50.
PROCEDURE DIVISION.
DISPLAY "Price: $" WS-PRICE
STOP RUN. Pascal's
writeln takes explicit width/precision formatting directives per value (price:0:2 means "0 width, 2 decimal places"). COBOL's DISPLAY needs no formatting directive at all for a PICTURE-typed field — the field's own PIC clause already fully determines how many digits and decimal places print, since that shape was fixed at declaration time.Gotchas for Pascal Developers
Fixed-width fields print trailing spaces — a real gotcha
program NoTrailingSpaces;
var
name: string;
begin
name := 'Al';
writeln('[', name, ']'); { prints [Al] exactly, no padding }
end. >>SOURCE FORMAT IS FREE
IDENTIFICATION DIVISION.
PROGRAM-ID. TRAILING-SPACES.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-NAME PIC X(10) VALUE "Al".
PROCEDURE DIVISION.
DISPLAY "[" WS-NAME "]"
STOP RUN. Pascal's
string holds exactly the characters assigned to it — [Al] prints with no padding. COBOL's PIC X(10) field is ALWAYS exactly 10 characters wide; storing "Al" pads the remaining 8 positions with spaces, so DISPLAY "[" WS-NAME "]" prints [Al ] — 8 trailing spaces before the closing bracket, a genuine surprise for anyone assuming a "string" behaves like Pascal's exact-length one.COBOL reads like a specification document — deliberately
program TerseCompare;
var
balance: Integer;
begin
balance := 100;
balance := balance + 50;
writeln(balance);
end. >>SOURCE FORMAT IS FREE
IDENTIFICATION DIVISION.
PROGRAM-ID. VERBOSE-COMPARE.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 WS-BALANCE PIC 9(5) VALUE 100.
PROCEDURE DIVISION.
ADD 50 TO WS-BALANCE
DISPLAY WS-BALANCE
STOP RUN. This is not accidental verbosity — it is COBOL's explicit design goal. COBOL (COmmon Business-Oriented Language) was deliberately designed by its 1959 committee to read like an English-language specification a non-programmer manager could review and approve, not to be terse for the programmer writing it. Pascal, designed a decade later for teaching structured programming, optimizes for a programmer's clarity and brevity instead — a genuine difference in design priorities, not merely a difference in syntax.