One powerful notational as well as syntactical tool of Pascal is the declaration of custom enumeration data types.
An enumeration data type is a finite list of named discrete values.Enumerations virtually give names to individual integer values, however, you cannot (directly) do arithmetic operations on it.
An enumeration data type is declared by following the data type identifier with a non-empty comma-separated list of (new, not previously used)identifiers.
typeweekday=(Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday);
The individual list items refer to specific values the data type may assume.The data type identifier identifies the data type as a whole.
Once an enumeration data type has been declared, you can use it like any other data type:
varstartOfWeek:weekday;beginstartOfWeek:=Sunday;end.
The variablestartOfWeek is restricted to assume only legal values of the data typeweekday.Note thatSunday is not enclosed by typewriter quotation marks (') which usually indicate a string literal.The identifierSunday indicates a value in its own right.
Every enumeration data type declaration implicitly defines an order.The comma-separated list is per definition asorted list.The built‑in functionord, short forordinal value, gives you the opportunity to obtain the ordinal value of an enumeration element, that is aninteger-value unique/specific to that enumeration member.
The first element of an enumeration is numbered as 0.The second, if applicable, has the number 1, and so forth.
Some compilers, such as theFPC, allow you to specify explicit indexes for some, or even all elements of an enumeration:
typemonth=(January:=1,February,March,April,May,June,July,August,September,October,November,December);
Here,January will have the ordinal value1.And allfollowing items have an ordinal value greater than1.The automatic assignment of numbers still ensures every enumeration member has a unique number among the entire enumeration data type.February will have the ordinal value 2,March the value 3, and so on.The value 0, however, is not assigned to any element of that enumeration.
Specifying explicit indices is a non-standard extension.InFPC’s{$mode Delphi} you need to use a plain equal sign (=) instead of :=.This is also referred to as “C‑style enumeration declaration”, since the programming language C uses that syntax.
Pascal does not provide a generic function that lets you determine the enumeration element based on a number.There is no function returningJanuary, for instance, if it is supplied with theinteger-value 1.[fn 1]
The standard functionspred andsucc, short forpredecessor andsuccessor respectively, areautomatically defined forevery enumeration data type.These functions return the previous or next value of an enumeration value.For examplesucc(January) will returnFebruary, as it is the successor of the valueJanuary.
However,pred(January) will fail as there is technically no member priorJanuary.An enumeration list isnot cyclical.Although in real life January follows December, the enumeration data typemonth does not “know” that.
Utilizing this functionality you can obtain an enumeration value given its index.succ(Monday,3) evaluates to theweekday value that has the ordinal value 3, thus virtually providing a means for aninverseord function.However, it is necessary to know thefirst element of the enumeration though, and the enumeration may not use anyexplicit indices in its declaration (unlessall indices coincide with the automatic numbering pattern).
Enumeration data type values are automatically eligible to be used with several operators.Since every enumeration value has an ordinal value, they can be ordered and you can test for that.The relational operators
<><=>==<>work in conjunction with enumeration values.For example,January<February will evaluate totrue, becauseJanuary has a smaller ordinal value thanFebruary.
Although,technically youcan compare apples and oranges (spoiler alert: they are unequal), all relational operators only work in conjunction with two values of thesame kind.In Pascal, you cannot compare aweekday value with amonth value.Nonetheless, something likeord(August)>ord(Monday)is legal, since you are then in fact comparinginteger values.
Note, arithmetic operators(+,-, and so on) do not work with enumeration data types, despite their ordinal values.
Boolean as an enumeration data typeThe data typeBoolean is a built‑in special enumeration data type.It is guaranteed that
ord(false) = 0,ord(true) = 1, and, in consequence,pred(true) =false.Boolean is only enumeration data type operations can bedirectly performed on usinglogical operators.
The most basic operator is the negation.It is a unary operator, that means it expects only one operand.In Pascal it uses the keywordnot.By preceding aBoolean expression withnot (and some separator such as a space character), the expression is negated.
| expression | result |
|---|---|
nottrue | false |
notfalse | true |
While this may be pretty straightforward, the so-called logical conjunction, indicated byand, might not be.Thetruth table for it looks like this:
value oftired | value ofintoxicated | result oftiredandintoxicated |
|---|---|---|
false | false | false |
false | true | false |
true | false | false |
true | true | true |
A little more confusing, because it may be contradictory to someone’snatural language, is the wordor.If either operand istrue, the overall expression’s result becomestrue.
value ofraining | value ofsnowing | result ofrainingorsnowing |
|---|---|---|
false | false | false |
false | true | true |
true | false | true |
true | true | true |
Electrical engineers frequently use the symbol to denote this operation.With respect toBoolean’s ordinal value, though, you must “define” that was still.
Like the usual rule in mathematics “multiplication and division first, then addition and subtraction”, a conjunction is evaluated first before a disjunction is.However, since the negation is a unary operator, it is evaluated first in any case.That means you must be really careful not to forget placing parenthesis.The expression
nothungryorthirsty
is fundamentally different to
not(hungryorthirsty)
Enumeration data types belong to the category ofordinal data types.Other ordinal data types are:
integer,char,Boolean.They all have in common, that a value of them can be mapped to a distinctinteger-value.Theord function lets you retrieve that value.
Sometimes, it makes sense to restrict a set of values to a certain range.For instance, the hours on a military time clock may show values from 0 up to and including 23.Yet the data typeinteger will permit other values too.
Pascal allows you to declare (sub‑)range data types.A (sub‑)range data type has a host data type, e. g.integer, and two limits.One lower and one upper limit.A range is specified by giving the limits in ascending order, separated through two periods back-to-back (..):
typemajuscule='A'..'Z';
The limits may be given as any computable expression, as long as it does not depend on run-time data.[fn 2]For example constants (that have already been defined) may be used:
typeintegerNonNegative=0..maxInt;
Note, we named this rangeintegerNonNegative and notnonNegativeInteger, because this will facilitate alphabetical sorting of some documentation tools or inIDEs.
A variable possessing one (sub‑)range data type may only assume valueswithin the range.If the variable exceeds its legal range, the program aborts.The following error message may appear (memory address at the end can vary):
./a.out: value out of range (error #300 at 402a54)
The corresponding test program has been compiled withGPC.Other compilers may emit different messages.
The default configuration of theFPC, however, ignores this.Assigning out-of-range values to variables will not yield an error (if it depends on run-time data).The developers of theFPC cite compatibility reasons to other compilers, which decided to ignore out-of-range values for speed reasons.[fn 3]You need to specifically request that illegal values cannot be assigned to ordinal type variables.This can be done by placing a specially crafted comment prior any (crucial) assignments:{$rangeChecks on} (case-insensitive) or{$R+} for short (case-sensitive) will ensure illegal values are not assigned and the program aborts if any attempts are made anyway.Specifying this compiler switchonce in your source code file is sufficient.FPC’s‑Cr command-line switch has the same effect.
| See also the chapterCase Control Structure inProgramming Fundamentals. |
With the advent of enumeration data types, it may become cumbersome and tedious to check for values just usingif‑branches.
Thecase selection statement unites multipleexclusiveif‑branches in one language construct.[fn 4]
casesign(x)of-1:beginwriteLn('You have entered a negative number.');end;0:beginwriteLn('The numbered you have entered is sign-less.');end;1:beginwriteLn('That is a positive number.');end;end;
Betweencase andof any expression that evaluates to an ordinal value may appear.After that,-1:,0: and1: arecase labels.These case labels mark the start of alternatives.After a case label follows a statement.
-1,0 and1 denote case values.Every case label consists of a non-empty comma-separated list of case values, followed by a colon (:).All case values have to be legal constant values,constant expressions, that are compatible to the comparison expression above, what is written betweencase andof.Every specified case value needs to appear exclusively inone case label.No case label value can appear twice.It is not necessary to put them in order, according their ordinal value, although it can make your source code more readable.
InEP case labels may contain ranges.
programletterReport(input,output);varc:char;beginwrite('Give me a letter: ');readLn(c);casecof'A'..'Z':beginwriteLn('Wow! That’s a big letter!');end;'a'..'z':beginwriteLn('What a nice small letter.');end;end;end.
This shorthand notation allows you to catch many cases.The case label'A'..'Z': includes all upper-case letters, without requiring you to list them all individually.
Take care that no rangeoverlaps with other case label values.This is forbidden.Good processors will complain about such a mistake though.TheGPC yields the error messageduplicate case-constant in `case' statement, theFPC reports justduplicate case label[fn 5], both telling you some information about the location in your source code.
It is important that any (expected) value of the comparison expression matches one case label.If the comparison expression evaluates to a value no case label contains the corresponding value, the program aborts.[fn 6]If this is not desired the “Extended Pascal” standard allows a special case label calledotherwise (note, without a colon).This case treats all values that have no explicit case label associated with them.
programasciiTest(input,output);varc:char;beginwrite('Supply any character: ');readLn(c);casecof// empty statement, so the control characters are not// considered by the otherwise-branch as non-ASCII characters#0..#31,#127:;#32..#126:beginwriteLn('You entered an ASCII printable character.');end;otherwisebeginwriteLn('You entered a non-ASCII character.');end;end;end.
otherwise may only appearat the end.There must be at least one case label beforehand, otherwise (no pun intended) theotherwise case is always taken, rendering the entirecase-statement useless.
BP, that is Delphi, re-uses the wordelse having the same semantics, the same meaning asotherwise.TheFPC andGPC support both, although GPC can be instructed toonly acceptotherwise.
function that returns the successor ofmonth, but forDecember the valueJanuary is returned.case statement is just perfect:functionsuccessor(start:month):month;begincasestartofJanuary..November:beginsuccessor:=succ(start);end;December:beginsuccessor:=January;end;end;end;
For the purposes of this exercise (demonstrating that relational operators such as< are automatically defined for enumeration data types) the following is acceptable too:
functionsuccessor(start:month):month;beginifstart<Decemberthenbeginsuccessor:=succ(start);endelsebeginsuccessor:=January;end;end;
Yet thecase-implementation is, mathematically speaking, more precise.In the first implementation, if the parameter is wrong, out of range, the program aborts.
if…then…else will be “wrongly” defined for illegal values too.case statement is just perfect:functionsuccessor(start:month):month;begincasestartofJanuary..November:beginsuccessor:=succ(start);end;December:beginsuccessor:=January;end;end;end;
For the purposes of this exercise (demonstrating that relational operators such as< are automatically defined for enumeration data types) the following is acceptable too:
functionsuccessor(start:month):month;beginifstart<Decemberthenbeginsuccessor:=succ(start);endelsebeginsuccessor:=January;end;end;
Yet thecase-implementation is, mathematically speaking, more precise.In the first implementation, if the parameter is wrong, out of range, the program aborts.
if…then…else will be “wrongly” defined for illegal values too.value ofhasRained | value ofstreetWet | result of |
|---|---|---|
false | false | true |
false | true | true |
true | false | false |
true | true | true |
Boolean expression in Pascal resulting in the same truth values. SayhasRained andstreetWet areBoolean variables; how would you link them so the entireBoolean expression is the same as the mathematical expression?Boolean is a built-in enumeration data type. This means it is ordered and thus members of this data type can be put in relational ordering. In programing the most frequent translation ofyou will encounter isnothasRainedorstreetWet
hasRained<=streetWet
Boolean being an enumeration data type. Some people, however, who arenot programming in Pascal (e. g. writingpersonal text messages) may use<= as a way of writing which is just the opposite of (that means in mathematics, i. e. with swapped and, is anotherequally valid way of writing). If you are one of those people you may find the shorter expression counterintuitive, because in Pascal<= is in fact ≤ (less than or equal to) and not a ⇐.Boolean is a built-in enumeration data type. This means it is ordered and thus members of this data type can be put in relational ordering. In programing the most frequent translation ofyou will encounter isnothasRainedorstreetWet
hasRained<=streetWet
Boolean being an enumeration data type. Some people, however, who arenot programming in Pascal (e. g. writingpersonal text messages) may use<= as a way of writing which is just the opposite of (that means in mathematics, i. e. with swapped and, is anotherequally valid way of writing). If you are one of those people you may find the shorter expression counterintuitive, because in Pascal<= is in fact ≤ (less than or equal to) and not a ⇐.Notes:
1 intoJanuary. However, this – typecasting – is not a function, especially typecasting does not work properly if the values are out of range (noRTE-generation, nor whatsoever).case-statements are usuallynot translated into a series ofif‑branches.‑‑classic‑pascal,‑‑extended‑pascal, or just‑‑case‑value‑checking). InBP, Delphi will just continue, leaving a missing case unnoticed. As of version 3.2.0 theFPC does not regard this requirement at all.