Site hosted by Angelfire.com: Build your free website today!

 

Pascal Variables

Variables store values and information. They allow programs to perform calculations and store data for later retrieval. Variables store numbers, names, text messages, etc.

Pascal supports FOUR standard variable types, which are

 

integer

Integer variables store whole numbers, ie, no decimal places. Examples of integer variables are,

        34       6458     -90    0      1112

char

Character variables hold any valid character which is typed from the keyboard, ie digits, letters, punctuation, special symbols etc. Examples of characters are,

   XYZ   0ABC   SAM_SAID.GET;LOST  [ ] { } = + \ | %   ( ) * $

boolean

Boolean variables, also called logical variables, can only have one of two possible states, true or false.

real

Real variables are positive or negative numbers which include decimal places. Examples are,

 

     34.265   -3.55  0.0   35.997E+11

Here, the symbol E stands for 'times 10 to the power of' Types integer, char and boolean are called ORDINAL types

 

Using Pascal VARIABLES in a program

 

The basic format for declaring variables is,

 

var name : type;

where name is the name of the variable being declared, and type is one of the recognised data types for pascal.

Before any variables are used, they are declared (made known to the program). This occurs after the program heading, and before the keyword begin, eg,

 

program VARIABLESINTRO (output);

   var  number1: integer;

        number2: integer;

        number3: integer;

begin

        number1 := 34;  { this makes number1 equal to 34 }

        number2 := 43;  { this makes number2 equal to 43 }

        number3 := number1 + number2;

        writeln( number1, ' + ', number2, ' =  ', number3 )

end.

 

The above program declares three integers, number1, number2 and number3.To declare a variable, first write the variable name, followed by a colon, then the variable type (int real etc). Variables of the same type can be declared on the same line, ie, the declaration of the three integers in the previous program

 

 var number1: integer;

     number2: integer;

     number3:integer;

could've been declared as follows,

 var number1, number2, number3 : integer;

Each variable is seperated by a comma, the colon signifies there is no more variable names, then follows the data type to which the variables belong, and finally the trusty semi-colon to mark the end of the line.

 

Some example of variable declarations

 

program VARIABLESINTRO2 (output);

   var  number1: integer;

        letter : char;

        money  : real;

begin

        number1 := 34;

        letter  := 'Z';

money   := 32.345;

        writeln( "number1 is ", number1 );

writeln( "letter is  ", letter );

writeln( "money is   ", money )

end.

 

 

VARIABLE NAMES

Variable names are a maximum of 32 alphanumeric characters. Some Pascal versions only recognise the first eight characters. The first letter of the data name must be ALPHABETIC (ie A to Z ). Lowercase characters ( a to z ) are treated as uppercase. Examples of variable names are,

 

RATE_OF_PAY      HOURS_WORKED   B41   X   y   Home_score

                      

Give variables meaningful names, which will help to make the program easier to read and follow. This simplifies the task of error correction.

 

ASSIGNING VALUES TO VARIABLES

Having declared a variable, you often want to make it equal to some value. In pascal, the special operator

 :=

provides a means of assigning a value to a variable. The following portion of code, which appeared earlier, illustrates this.

var number1, number2, number3 : integer;

begin

number1 := 43;   { make number1 equal to 43 decimal }

number2 := 34;   { make number2 equal to 34 decimal }

number3 := number1 + number2;  { number3 equals 77  }

When assigning values to char vari 

 

1. Declare an integer called sum

sum : integer;

2. Declare a character called letter

letter : char;

3. Declare a variable called money which can be used to hold currency

money : real;

4. Declare an integer variable called total and initialise it to zero

total : integer;

total := 0;

5. Declare a variable called loop, which can hold any integer value

loop : integer;

 

 

ARITHMETIC STATEMENTS

The following symbols represent the arithmetic operators, ie, use them when you wish to perform calculations.

 

+   Addition

-   Subtraction

*   Multiplication

/   Division

 

Addition Example

 

program Add (output);

var number1, number2, result : integer;

begin

number1 := 10;

number2 := 20;

result := number1 + number2;

writeln(number1, " plus ", number2, " is ", result )

end.

 

Subtraction Example

 

program Subtract (output);

var number1, number2, result : integer;

begin

number1 := 15;

number2 := 2;

result := number1 - number2;

writeln(number1, " minus ", number2, " is ", result )

end.

 

Multiplication Example

 

program Multiply (output);

var number1, number2, result : integer;

begin

number1 := 10;

number2 := 20;

result := number1 * number2;

writeln(number1, " multiplied by ", number2, " is ", result )

end.

 

Division Example

 

program Divide (output);

var number1, number2, result : integer;

begin

number1 := 20;

number2 := 10;

result := number1 / number2;

writeln(number1, " divided by ", number2, " is ", result )

end.

 

 

DISPLAYING THE VALUE OR CONTENTS OF VARIABLES

The write or writeln statement displays the value of variables on the console screen. To print text, enclose inside single quotes. To display the value of a variable, do NOT enclose using single quotes, eg, the following program displays the content of each of the variables declared.

 

program DISPLAYVARIABLES (output);

var     number1 : integer;

         letter  : char;

         money   : real;

begin

         number1 := 23;

         letter  := 'W';

         money   := 23.73;

         writeln('number1 = ', number1 );

         writeln('letter  = ', letter  );

         writeln('money   = ', money   )

end.

 

The display output from the above program will be,

number1 = 23

letter  = W

money   = 2.3730000000E+01

 

 

GETTING INFORMATION/DATA FROM THE KEYBOARD INTO A PROGRAM

It is convenient to accept data whilst a program is running. The read and readln statements allow you to read values and characters from the keyboard, placing them directly into specified variables.

The program which follows reads two numbers from the keyboard, assigns them to the specified variables, then prints them to the console screen.

 

program READDEMO (input, output);

var     numb1, numb2 : integer;

begin

        writeln('Please enter two numbers separated by a space');

        read( numb1 );

        read( numb2 );

        writeln;

        writeln('Numb1 is ', numb1 , '   Numb2 is ', numb2 )

end.

 

When run, the program will display the message

Please enter two numbers separated by a space

then wait for you to enter in the two numbers. If you typed the two numbers, then pressed the return key, eg,

237  64

then the program will accept the two numbers, assign the value 237 to numb1 and the value 64 to numb2, then continue and finally print

Numb1 is 237  Numb2 is 64

 

Differences between READ and READLN

The readln statement discards all other values on the same line, but read does not. In the previous program, replacing the read statements with readln and using the same input, the program would assign 237 to numb1, discard the value 64, and wait for the user to enter in another value which it would then assign to numb2.The is read as a blank by read, and ignored by readln.

  

SPECIFYING THE DISPLAY FORMAT FOR THE OUTPUT OF VARIABLES

When variables are displayed, our version of Pascal assigns a specified number of character spaces (called a field width) to display them. The field widths for the various data types are,

 

INTEGER -  Number of digits + 1 { or +2 if negative }

CHAR    -  1 for each character

REAL    -  12

BOOLEAN -  4 if true, 5 if false

 

Often, the allotted field size is too big for the majority of display output. Pascal provides a way in which the programmer can specify the field size for each output.

 

writeln('WOW':10,'MOM!':10,'Hi there.');

 

The display output will be as follows,

WOW.......MOM!......Hi there.          ... indicates a space.

Note that to specify the field width of text or a particular variable, use a colon (:) followed by the field size.

'text string':fieldsize, variable:fieldsize

 

 

INTEGER DIVISION

There is a special operator, DIV, used when you wish to divide one integer by another (ie, you can't use / ). The following program demonstrates this,

 

program INTEGER_DIVISION (output);

var     number1, number2, number3 : integer;

begin

       number1 := 4;

       number2 := 8;

       number3 := number2 DIV number1;

       writeln( number2:2,' divided by ',number1:2,' is ',number3:2)

end.

 

Sample Output

8 divided by  4 is  2

 

MODULUS

The MOD keyword means MODULUS, ie, it returns the remainder when one number is divided by another,

The modulus of 20 DIV 5 is 0

The modulus of 21 DIV 5 is 1

 

program MODULUS (output);

var     number1, number2, number3 : integer;

begin

       number1 := 3;

       number2 := 10;

       number3 := number2 MOD number1;

       writeln( number2:2,' modulus ',number1:2,' is ',number3:2)

end.

 

Sample Output

10 modulus  3 is  1

 

MAKING DECISIONS

Most programs need to make decisions. There are several statements available in the Pascal language for this. The IF statement is one of the them. The RELATIONAL OPERATORS, listed below, allow the programmer to test various variables against other variables or values.

 

=   Equal to

>   Greater than

  Less than

<>  Not equal to

<=  Less than or equal to

>=  Greater than or equal to

 

The format for the IF THEN Pascal statement is,

if  condition_is_true  then

execute_this_program_statement;

The condition (ie, A < 5 ) is evaluated to see if it's true. When the condition is true, the program statement will be executed. If the condition is not true, then the program statement following the keyword then will be ignored.

 

program IF_DEMO (input, output);  {Program demonstrating IF THEN statement}

var     number, guess : integer;

begin

        number := 2;

        writeln('Guess a number between 1 and 10');

        readln( guess );

        if number = guess then  writeln('You guessed correctly. Good on you!');

        if number <> guess  then  writeln('Sorry, you guessed wrong.')

end.

 

Executing more than one statement as part of an IF

To execute more than one program statement when an if statement is true, the program statements are grouped using the begin and end keywords. Whether a semi-colon follows the end keyword depends upon what comes after it. When followed by another end or end. then it no semi-colon, eg,

 

program IF_GROUP1 (input, output);

var     number, guess : integer;

begin

        number := 2;

        writeln('Guess a number between 1 and 10');

        readln( guess );

        if number = guess then

        begin

            writeln('Lucky you. It was the correct answer.');

            writeln('You are just too smart.')

        end;

        if number <> guess then   writeln('Sorry, you guessed wrong.')

end.

 

program IF_GROUP2 (input, output);

var     number, guess : integer;

begin

        number := 2;

        writeln('Guess a number between 1 and 10');

        readln( guess );

        if number = guess then

        begin

           writeln('Lucky you. It was the correct answer.');

           writeln('You are just too smart.')

        end

end.

 

 

IF THEN ELSE

The IF statement can also include an ELSE statement, which specifies the statement (or block or group of statements) to be executed when the condition associated with the IF statement is false. Rewriting the previous program using an IF THEN ELSE statement,

 

{ Program example demonstrating IF THEN ELSE statement }

 

program IF_ELSE_DEMO (input, output);

var     number, guess : integer;

begin

        number := 2;

        writeln('Guess a number between 1 and 10');

        readln( guess );

        if number = guess  then

           writeln('You guessed correctly. Good on you!')

        else

           writeln('Sorry, you guessed wrong.')

end.

 

There are times when you want to execute more than one statement when a condition is true (or false for that matter). Pascal makes provison for this by allowing you to group blocks of code together by the use of the begin and end keywords. Consider the following portion of code,

        if number = guess  then

        begin

           writeln('You guessed correctly. Good on you!');

           writeln('It may have been a lucky guess though')

        end      {no semi-colon if followed by an else }

        else

        begin

           writeln('Sorry, you guessed wrong.');

           writeln('Better luck next time')

        end;     {semi-colon depends on next keyword }

 

 

THE AND OR NOT STATEMENTS

The AND, OR and NOT keywords are used where you want to execute a block of code (or statement) when more than one condition is necessary.

 

  AND   The statement is executed only if BOTH conditions are true,

  if  (A = 1) AND (B = 2) then writeln('Bingo!');

  OR    The statement is executed if EITHER argument is true,

  if (A = 1) OR (B = 2) then writeln('Hurray!');

  NOT   Converts TRUE to FALSE and vsvs

  if NOT ((A = 1) AND (B = 2)) then writeln('Wow, really heavy man!');

 

 

CONSTANTS

When writing programs, it is desirable to use values which do not change during the programs execution. An example would be the value of PI, 3.141592654

In a program required to calculate the circumference of several circles, it would be simpler to write the words PI, instead of its value 3.14. Pascal provides CONSTANTS to implement this.

To declare a constant, the keyword const is used, followed by the name of the constant, an equals sign, the constants value, and then a semi-colon, eg,

 

const PI = 3.141592654;

From now on, in the Pascal program, you use PI. When the program is compiled, the compiler replaces every occurrence of the word PI with its actual value. Thus, constants provide a short hand means of writing values, and help to make programs easier to read. The following program demonstrates the use of constants.

 

program CIRCUMFERENCE (input,output);

const   PI = 3.141592654;

var     Circumfer, Diameter : real;

begin

        writeln('Enter the diameter of the circle');

        readln(Diameter);

        Circumfer := PI * Diameter;

        writeln('The circles circumference is ',Circumfer)

end.

 

SPECIFYING THE NUMBER OF DECIMAL PLACES FOR DISPLAYING REALS

The following change to the above program will print out the circumference using a fieldwidth of ten, and two decimal places.

 

       writeln('The circles circumference is ',Circumference:10:2);

 

LOOPS

The most common loop in Pascal is the FOR loop. The statement inside the for block is executed a number of times depending on the control condition. The format's for the FOR command is,

 

FOR var_name := initial_value TO final_value DO  program_statement;

FOR var_name := initial_value TO final_value DO

begin

    program_statement; {to execute more than one statement in a for }

    program_statement; {loop, you group them using the begin and    }

    program_statement  {end statements                              }

end;                   {semi-colon here depends upon next keyword   }

FOR var_name := initial_value DOWNTO final_value DO  program_statement;

You must not change the value of the control variable (var_name) inside the loop. The following program illustrates the for statement.

program  CELCIUS_TABLE ( output );

var      celcius : integer; farenhiet : real;

begin

         writeln('Degree''s Celcius   Degree''s Farenhiet');

         for  celcius := 1  to  20  do

         begin

             farenhiet := ( 9 / 5 ) * celcius + 32;

             writeln( celcius:8, '      ',farenhiet:16:2 )

         end

end.

 

NESTED LOOPS

A for loop can occur within another, so that the inner loop (which contains a block of statements) is repeated by the outer loop.

RULES RELATED TO NESTED FOR LOOPS

1. Each loop must use a seperate variable

2. The inner loop must begin and end entirely within the outer loop.

 

 

THE WHILE LOOP

The while loop is similar to the for loop shown earlier, in that it allows a {group of} program statement(s) to be executed a number of times. The structure of the while statement is,

 

while   condition_is_true  do

begin

        program statement;

        program statement

end;         {semi-colon depends upon next keyword}

or, if only a single program statement is to be executed,

while   condition_is_true   do   program statement;

The program statement(s) are executed when the condition evaluates as true. Somewhere inside the loop the value of the variable which is controlling the loop (ie, being tested in the condition) must change so that the loop can finally exit.

 

 

REPEAT

The REPEAT statement is similar to the while loop, how-ever, with the repeat statement, the conditional test occurs after the loop. The program statement(s) which constitute the loop body will be executed at least once. The format is,

 

repeat

     program statement;

until  condition_is_true;   {semi-colon depends on next keyword}

There is no need to use the begin/end keywords to group more than one program statement, as all statements between repeat and until are treated as a block.

 

 

The CASE statement

The case statement allows you to rewrite code which uses a lot of if else statements, making the program logic much easier to read. Consider the following code portion written using if else statements,

 

if operator = '*' then result := number1 * number2

   else if operator = '/' then result := number1 / number2

       else if operator = '+' then result := number1 + number2

           else if operator = '-' then result := number1 - number2

               else  invalid_operator = 1;

Rewriting this using case statements,

case  operator  of

      '*' : result:= number1 * number2;

      '/' : result:= number1 / number2;

      '+' : result:= number1 + number2;

      '-' : result:= number1 - number2;

otherwise    invalid_operator := 1

end;

The value of operator is compared against each of the values specified. If a match occurs, then the program statement(s) associated with that match are executed. If operator does not match, it is compared against the next value. The purpose of the otherwise clause ensures that appropiate action is taken when operator does not match against any of the specified cases.

You must compare the variable against a constant, how-ever, it is possible to group cases as shown below,

 

case  user_request  of

      'A' :

      'a' :  call_addition_subprogram;

      's' :

      'S' :  call_subtraction_subprogram;

end;

 

 

ENUMERATED DATA TYPES

Enumerated variables are defined by the programmer. It allows you to create your own data types, which consist of a set of symbols. You first create the set of symbols, and assign to them a new data type variable name.

Having done this, the next step is to create working variables to be of the same type. The following portions of code describe how to create enumerated variables.

 

type  civil_servant = ( clerk, police_officer, teacher, mayor );

var   job, office : civil_servant;

The new data type created is civil_servant. It is a set of values, enclosed by the ( ) parenthesis. These set of values are the only ones which variables of type civil_servant can assume or be assigned. The next line declares two working variables, job and office, to be of the new data type civil_servant.

 

The following assignments are valid,

job := mayor;

office := teacher;

if office = mayor then writeln('Hello mayor!');

The list of values or symbols between the parenthesis is an ordered set of values. The first symbol in the set has an ordinal value of zero, and each successive symbol has a value of one greater than its predecessor.

police_officer < teacher

evaluates as true, because police_officer occurs before teacher in the set.

 

MORE EXAMPLES ON ENUMERATED DATA TYPES

type beverage = ( coffee, tea, cola, soda, milk, water );

     color    = ( green, red, yellow, blue, black, white );

var  drink : beverage;

     chair : color;

drink := coffee;

chair := green;

if chair = yellow then drink := tea;

 

ADDITIONAL OPERATIONS WITH USER DEFINED VARIABLE TYPES

Consider the following code,

 

type Weekday = ( Monday, Tuesday, Wednesday, Thursday, Friday );

var  Workday : Weekday;

The first symbol of the set has the value of 0, and each symbol which follows is one greater. Pascal provides three additional operations which are performed on user defined variables. The three operations are,

 ord( symbol )   returns the value of the symbol, thus ord(Tuesday)

                 will give a value of 1

 pred( symbol )  obtains the previous symbol, thus

                 pred(Wednesday) will give Tuesday

 succ( symbol )  obtains the next symbol, thus succ(Monday)

                 gives Tuesday

Enumerated values can be used to set the limits of a for statement, or as a constant in a case statement, eg,

for Workday := Monday to Friday

     .........

case Workday of

      Monday : writeln('Mondays always get me down.');

      Friday : writeln('Get ready for partytime!')

end;

Enumerated type values cannot be input from the keyboard or outputted to the screen, so the following statements are illegal,

writeln( drink );

readln( chair );

 

 

SUBRANGES

Just as you can create your own set of pre-defined data types, you can also create a smaller subset or subrange of an existing set which has been previously defined. Each subrange consists of a defined lower and upper limit. Consider the following,

 

type DAY = (Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday);

     Weekday = Monday..Friday;     {subrange of DAY}

     Weekend = Saturday..Sunday;   {subrange of DAY}

     Hours   = 0..24;              {subrange of integers}

     Capitals= 'A'..'Z';           {subrange of characters}

NOTE: You cannot have subranges of type real.

 

ARRAYS

An array is a structure which holds many variables, all of the same data type. The array consists of so many elements, each element of the array capable of storing one piece of data (ie, a variable).

An array is defined as follows,

 

type  array_name = ARRAY [lower..upper] of data_type;

Lower and Upper define the boundaries for the array. Data_type is the type of variable which the array will store, eg, type int, char etc. A typical declaration follows,

type  intarray = ARRAY [1..20] of integer;

This creates a definition for an array of integers called intarray, which has 20 separate locations numbered from 1 to 20. Each of these positions (called an element), holds a single integer. The next step is to create a working variable to be of the same type, eg,

var  numbers : intarray;

Each element of the numbers array is individually accessed and updated as desired. To assign a value to an element of an array, use

 

numbers[2] := 10;

This assigns the integer value 10 to element 2 of the numbers array. The value or element number (actually its called an index) is placed inside the square brackets. To assign the value stored in an element of an array to a variable, use

 

number1 := numbers[2];

This takes the integer stored in element 2 of the array numbers, and makes the integer number1 equal to it. Consider the following array declarations

 

const  size = 10;

       last = 100;

type   sub = 'a'..'z';

       color = (green, yellow, red, orange, blue );

var    chararray : ARRAY [1..size] of char;   {an array of 10 characters. First element is chararray[1], last element is chararry[10] }

       intarray  : ARRAY [sub] of integer;       {an array of 26 integers. First element is intarray['a'] last element is intarray['z']  }

       realarray : ARRAY [5..last] of real;       {an array of 95 real numbers. First element is realarray[5] last element is realarray[100]   }

       artstick  : ARRAY [-3..2] of color;         {an array of 6 colors. First element is artstick[-3] last element is artstick[2]  }

       huearray  : ARRAY [color] of char;       {an array of 6 characters. First element is huearray[green] last element is huearray[blue]   }

 

CHARACTER ARRAYS

You can have arrays of characters. Text strings from the keyboard may be placed directly into the array elements. You can print out the entire character array contents. The following program illustrates how to do this,

 

program CHARRAY (input,output );

type word = PACKED ARRAY [1..10] of char;

var  word1 : word;

     loop  : integer;

begin

  writeln('Please enter in up to ten characters.');

  readln( word1 );  { this reads ten characters directly from the

                      standard input device, placing each character

                      read into subsequent elements of word1 array }

  writeln('The contents of word1 array is ');

  for loop := 1 to 10 do                      {print out each element}

     writeln('word1[',loop,'] is ',word1[loop] );

  writeln('Word1 array contains ', word1 )   {print out entire array}

end.

 

Note the declaration of PACKED ARRAY, and the use of just the array name in conjuction with the readln statement. If the user typed in

Hello there

then the contents of the array word1 will be,

 word1[1] = H

 word1[2] = e

 word1[3] = l

 word1[4] = l

 word1[5] = o

 word1[6] =     { a space }

 word1[7] = t

 word1[8] = h

 word1[9] = e

 word1[10]= r

The entire contents of a packed array of type char can also be outputted to the screen simply the using the array name without an index value, ie, the statement

 writeln('Word1 array contains ', word1 );

will print out all elements of the array word1, displaying

 Hello ther

 

INTEGER ARRAYS

Arrays can hold any of the valid data types, including integers. Integer arrays cannot be read or written as an entire unit, only packed character arrays can. The following program demonstrates an integer array, where ten successive numbers are inputted, stored in separate elements of the array numbers, then finally outputted to the screen one at a time.

 

program INT_ARRAY (input,output );

type int_array = ARRAY [1..10] of integer;

var  numbers : int_array;

     loop  : integer;

begin

  writeln('Please enter in up to ten integers.');

  for loop := 1 to 10 do

     readln( numbers[loop] );

  writeln('The contents of numbers array is ');

  { print out each element }

  for loop := 1 to 10 do

     writeln('numbers[',loop:2,'] is ',numbers[loop] )

end.

 

INITIALISATION OF PACKED CHARACTER ARRAYS

Packed arrays of characters are initialised by equating the array to a text string enclosed by single quotes, eg,

 

type  string = PACKED ARRAY [1..15] of char;

var   message : string;

      message := 'Good morning!  ';  {must be fifteen characters long}

 

MULTIDIMENSIONED ARRAYS

The following statement creates a type definition for an integer array called multi of 10 by 10 elements (100 in all). Remember that arrays are split up into row and columns. The first index is the row, the second index is the column.

 

type  multi = ARRAY [1..10, 1..10] of integer;

begin work : multi;

To print out each of the various elements of work, consider

  for  row := 1 to 10 do

    for  column := 1 to 10 do

        writeln('Multi[',row,',',column,'] is ',multi[row,column];

 

 

HOW CHARACTERS ARE INTERNALLY REPRESENTED

Internally, most computers store characters according to the ASCII format. ASCII stands for American Standard Code for Information Interchange. Characters are stored according to a numbered sequence, whereby A has a value of 64 decimal, B a value of 65 etc. Several functions which manipulate characters follow.

CHR

The chr or character position function returns the character associated with the ASCII value being asked, eg,

      chr( 65 )   will return the character   A

 

ORD

The ord or ordinal function returns the ASCII value of a requested character. In essence, it works backwards to the chr function. Ordinal data types are those which have a predefined, known set of values.

Each value which follows in the set is one greater than the previous. Characters and integers are thus ordinal data types.

     ord( 'C' )   will return the value   67

 

SUCC

The successor function determines the next value or symbol in the set, thus

     succ( 'd' )  will return  e

 

PRED

The predecessor function determines the previous value or symbol in the set, thus

     pred( 'd' )  will return  c

 

 

COMPARISON OF CHARACTER VARIABLES

Character variables, when compared against each other, is done using the ASCII value of the character. Consider the following portion of code,

 

var  letter1, letter2 : char;

begin

     letter1 := 'A';  letter2 := 'C';

     if letter1 < letter2   then

        writeln( letter1, ' is less than ',letter2 )

     else

        writeln( letter2, ' is less than ',letter1 )

end.

 

STRING ARRAYS, COMPARISON OF

Packed character arrays of the same length are comparable. There follows a short program illustrating this,

 

program PACKED_CHAR_COMPARISON (output);

type  string1 = packed array [1..6] of char;

var   letter1, letter2 : string1;

begin

      letter1 := 'Hello ';

      letter2 := 'HellO ';

      if letter1 < letter2 then

         writeln( letter1,' is less than ',letter2)

      else

         writeln( letter2,' is less than ',letter1)

end.

 

 

COMMON FUNCTIONS

The Pascal language provides a range of functions to perform data transformation and calculations. The following section provides an explanation of the commonly provided functions,

 

ABS

The ABSolute function returns the absolute value of either an integer or real, eg,

      ABS( -21 )    returns   21

      ABS( -3.5)    returns   3.5000000000E+00

 

COS

The COSine function returns the cosine value, in radians, of an argument, eg,

      COS( 0 )       returns  1.0

 

EXP

The exponential function calculates e raised to the power of a number, eg,

      EXP(10 )      returns e to the power of 10

There is no function in Pascal to calculate expressions such as an, ie,

      23  is 2*2*2  = 8

These are calculated by using the formula

     an = exp( n * ln( a ) )

 

LN

The logarithm function calculates the natural log of a number greater than zero.

 

ODD

The odd function determines when a specified number is odd or even, returning true when the number is odd, false when it is not.

 

ROUND

The round function rounds its number (argument) to the nearest integer. If the argument is positive

    rounding is up for fractions greater than or equal to .5

    rounding is down for fractions less than .5

If the number is negative

     rounding is down (away from zero) for fractions >= .5

     rounding is up (towards zero) for fractions < .5

 

SIN

The sine function returns the sine of its argument, eg,

      SIN( PI / 2 )    returns  1.0

 

SQR

The square function returns the square (ie the argument multiplied by itself) of its supplied argument,

      SQR( 2 )         returns  4

 

SQRT

This function returns {always returns a real} the square root of its argument, eg,

 

      SQRT( 4 )        returns  2.0000000000E+00

 

TRUNC

This function returns the whole part (no decimal places) of a real number.

      TRUNC(4.87)      returns 4

      TRUNC(-3.4)      returns 3

 

 

MODULAR PROGRAMMING USING PROCEDURES AND FUNCTIONS

Modular programming is a technique used for writing large programs. The program is subdivided into small sections. Each section is called a module, and performs a single task.

Examples of tasks a module might perform are,

    displaying an option menu

    printing results

    calculating average marks

    sorting data into groups

 

A module is known by its name, and consists of a set of program statements grouped using the begin and end keywords. The module (group of statements) is executed when you type the module name. Pascal uses three types of modules. The first two are called PROCEDURES, the other a FUNCTION.

 

Simple procedures do not accept any arguments (values or data) when the procedure is executed (called).

Complex procedures accept values to work with when they are executed.

Functions, when executed, return a value (ie, calculate an answer which is made available to the module which wants the answer)

 

Procedures help support structured program design, by allowing the independant development of modules. Procedures are essentially sub-programs.

 

SIMPLE PROCEDURES

Procedures are used to perform tasks such as displaying menu choices to a user. The procedure (module) consists of a set of program statements, grouped by the begin and end keywords. Each procedure is given a name, similar to the title that is given to the main module.

Any variables used by the procedure are declared before the keyword begin.

 

PROCEDURE  DISPLAY_MENU;

begin

     writeln('<14>Menu choices are');

     writeln(' 1: Edit text file');

     writeln(' 2: Load text file');

     writeln(' 3: Save text file');

     writeln(' 4: Copy text file');

     writeln(' 5: Print text file')

end;

 

The above procedure called DISPLAY_MENU, simply executes each of the statements in turn. To use this in a program, we write the name of the procedure, eg,

 

program PROC1 (output);

 

PROCEDURE  DISPLAY_MENU;

begin

     writeln('<14>Menu choices are');

     writeln(' 1: Edit text file');

     writeln(' 2: Load text file');

     writeln(' 3: Save text file');

     writeln(' 4: Copy text file');

     writeln(' 5: Print text file')

end;

begin

writeln('About to call the procedure');

DISPLAY_MENU;

writeln('Now back from the procedure')

end.

 

In the main portion of the program, it executes the statement

writeln('About to call the procedure');

then calls the procedure DISPLAY_MENU. All the statements in this procedure are executed, at which point we go back to the statement which follows the call to the procedure in the main section, which is,

writeln('Now back from the procedure')

The sample output of the program is

 

About to call the procedure

Menu choices are

 1: Edit text file

 2: Load text file

 3: Save text file

 4: Copy text file

 5: Print text file

Now back from the procedure

  

PROCEDURES AND LOCAL VARIABLES

A procedure can declare it's own variables to work with. These variables belong to the procedure in which they are declared. Variables declared inside a procedure are known as local.

Local variables can be accessed anywhere between the begin and matching end keywords of the procedure. The following program illustrates the use and scope (where variables are visible or known) of local variables.

 

program LOCAL_VARIABLES (input, output);

var   number1, number2 : integer;  {these are accessible by all}

procedure add_numbers;

var   result : integer;            {result belongs to add_numbers}

begin

      result := number1 + number2;

      writeln('Answer is ',result)

end;

begin                              {program starts here}

      writeln('Please enter two numbers to add together');

      readln( number1, number2 );

      add_numbers

end.

 

PROCEDURES WHICH ACCEPT ARGUMENTS

Procedures may also accept variables (data) to work with when they are called.

Declaring the variables within the procedure

 

The variables accepted by the procedure are enclosed using parenthesis.

The declaration of the accepted variables occurs between the procedure name and the terminating semi-colon.

 

Calling the procedure and Passing variables (or values) to it

 

When the procedure is invoked, the procedure name is followed by a set of parenthesis.

The variables to be passed are written inside the parenthesis.

The variables are written in the same order as specified in the procedure.

 

Consider the following program example,

 

program ADD_NUMBERS (input, output);

procedure CALC_ANSWER ( first, second : integer );

var   result : integer;

begin

      result := first + second;

      writeln('Answer is ', result )

end;

var   number1, number2 : integer;

begin

      writeln('Please enter two numbers to add together');

      readln( number1, number2 );

      CALC_ANSWER( number1, number2)

end.

 

 

Value Parameters

In the previous programs, when variables are passed to procedures, the procedures work with a copy of the original variable. The value of the original variables which are passed to the procedure are not changed.

The copy that the procedure makes can be altered by the procedure, but this does not alter the value of the original. When procedures work with copies of variables, they are known as value parameters.

Consider the following code example,

 

program  Value_Parameters (output);

procedure  Nochange ( letter : char; number : integer );

begin

     writeln( letter );

     writeln( number );

     letter := 'A';        {this does not alter mainletter}

     number := 32;         {this does not alter mainnumber}

     writeln( letter );

     writeln( number )

end;

var  mainletter : char;    {these variables known only from here on}

     mainnumber : integer;

begin

     mainletter := 'B';

     mainnumber := 12;

     writeln( mainletter );

     writeln( mainnumber );

     Nochange( mainletter, mainnumber );

     writeln( mainletter );

     writeln( mainnumber )

end.

 

 

Variable parameters

Procedures can also be implemented to change the value of original variables which are accepted by the procedure. To illustrate this, we will develop a little procedure called swap. This procedure accepts two integer values, swapping them over.

Previous procedures which accept value parameters cannot do this, as they only work with a copy of the original values. To force the procedure to use variable parameters, preceed the declaration of the variables (inside the parenthesis after the function name) with the keyword var.

This has the effect of using the original variables, rather than a copy of them.

 

program  Variable_Parameters (output);

procedure  SWAP ( var value1, value2 : integer );

var   temp : integer;

begin

      temp := value1;

      value1 := value2;  {value1 is actually number1}

      value2 := temp     {value2 is actually number2}

end;

var   number1, number2 : integer;

begin

      number1 := 10;

      number2 := 33;

      writeln( 'Number1 = ', number1,' Number2 = ', number2 );

      SWAP( number1, number2 );

      writeln( 'Number1 = ', number1,' Number2 = ', number2 )

end.

 

When this program is run, it prints out

 

Number1 = 10  Number2 = 33

Number1 = 33  Number2 = 10

 

FUNCTIONS - A SPECIAL TYPE OF PROCEDURE WHICH RETURNS A VALUE

Procedures accept data or variables when they are executed. Functions also accept data, but have the ability to return a value to the procedure or program which requests it. Functions are used to perform mathematical tasks like factorial calculations.

A function

begins with the keyword function

is similar in structure to a procedure

somewhere inside the code associated with the function, a value is assigned to the function name

a function is used on the righthand side of an expression

can only return a simple data type

 

The actual heading of a function differs slightly than that of a procedure. Its format is,

 

      function  Function_name (variable declarations) : return_data_type;

After the parenthesis which declare those variables accepted by the function, the return data type (preceeded by a colon) is declared.

 

function  ADD_TWO ( value1, value2 : integer ) : integer;

begin

     ADD_TWO := value1 + value2

end;

The following line demonstrates how to call the function,

result := ADD_TWO( 10, 20 );

thus, when ADD_TWO is executed, it equates to the value assigned to its name (in this case 30), which is then assigned to result.

 

RECORDS

A record is a user defined data type suitable for grouping data elements together. All elements of an array must contain the same data type.

A record overcomes this by allowing us to combine different data types together. Suppose we want to create a data record which holds a student name and mark. The student name is a packed array of characters, and the mark is an integer.

We could use two seperate arrays for this, but a record is easier. The method to do this is,

define or declare what the new data group (record) looks like

create a working variable to be of that type

 

The following portion of code shows how to define a record, then create a working variable to be of the same type.

TYPE   studentname = packed array[1..20] of char;

       studentinfo = RECORD

name : studentname;

mark : integer

     END;

VAR    student1 : studentinfo;

The first portion defines the composition of the record identified as studentinfo. It consists of two parts (called fields). The first part of the record is a packed character array identified as name. The second part of studentinfo consists of an integer, identified as mark.

The declaration of a record begins with the keyword record, and ends with the keyword end;

The next line declares a working variable called student1 to be of the same type (ie composition) as studentinfo.

Each of the individual fields of a record are accessed by using the format,

 

      recordname.fieldname := value or variable;

An example follows,

      student1.name := 'JOE BLOGGS          ';  {20 characters}

      student1.mark := 57;

 

Lets create a new data record suitable for storing the date

  

type  date = RECORD

                day   : integer;

                month : integer;

                year  : integer

             END;

 

This declares a NEW data type called date. This date record consists of three basic data elements, all integers. Now declare working variables to use in the program. These variables will have the same composition as the date record.

var   todays_date : date;

defines a variable called todays_date to be of the same data type as that of the newly defined record date.

 

 

ASSIGNING VALUES TO RECORD ELEMENTS

These statements assign values to the individual elements of the record todays_date,

 

todays_date.day   := 21;

todays_date.month := 07;

todays_date.year  := 1985;

NOTE the use of the .fieldname to reference the individual fields within todays_date.

 

Sample program illustrating records

 

program   RECORD_INTRO (output);

type  date = record

                month, day, year : integer

             end;

var   today : date;

begin

      today.day    :=   25;

      today.month  :=   09;

      today.year   := 1983;

      writeln('Todays date is ',today.day,':',today.month,':',

               today.year)

end.

 

Records of the same type are assignable.

var  todays_date, tomorrows_date : date;

begin

     todays_date.day   := 9;

     todays_date.month := 7;

     todays_date.year  := 1976;

     tomorrows_date    := todays_date;

The last statement copies all the elements of todays_date into the elements of tomorrows_date. This statement adds one to the value stored in the field day of the record tomorrows_date.

 

tomorrows_date.day := tomorrows_date.day + 1;

 

RECORDS AND PROCEDURES

The following program demonstrates passing a record to a procedure, which updates the record, then prints the updated time.

 

program  TIME (input,output);

type     time = record

                   seconds, minutes, hours : integer

                end;

var  current, next : time;

{ function to update time by one second }

procedure  timeupdate( var now : time); {variable parameter}

var  newtime : time;                    {local variable}

begin

     newtime := now;                    {use local instead of orginal}

     newtime.seconds := newtime.seconds + 1;

     if  newtime.seconds = 60  then

     begin

        newtime.seconds := 0;

        newtime.minutes := newtime.minutes + 1;

        if  newtime.minutes = 60  then

        begin

             newtime.minutes := 0;

             newtime.hours := newtime.hours + 1;

             if  newtime.hours = 24  then

                newtime.hours := 0

        end

     end;

     writeln('The updated time is ',newtime.hours,':',newtime.minutes,

             ':',newtime.seconds)

end;

begin

      writeln('Please enter in the time using hh mm ss');

      readln( current.hours, current.minutes, current.seconds );

      timeupdate( current )

end.

 

ARRAYS OF RECORDS

can also be created, in the same way as arrays of any of the four basic data types. The following statement declares a record called date.

 

type  date = record

                 month, day, year : integer

             end;

Lets now create an array of these records, called birthdays.

var   birthdays : array[1..10] of date;

This creates an array of 10 elements. Each element consists of a record of type date, ie, each element consists of three integers, called month, day and year. Pictorially it looks like,

 

             |----------------|

             |     month      | <----<----------------

             |----------------|      |                |

             |      day       |      |--Element 1     |

             |----------------|      |                |

             |     year       | <----                 |

             |----------------|                       |

             |     month      | <----                 |

             |----------------|      |                |

             |      day       |      |--Element 2     |

             |----------------|      |                |--< birthdays

             |     year       | <----                 |

             |----------------|                       |

                                                      |

             |----------------|                       |

             |     month      | <----                 |

             |----------------|      |                |

             |      day       |      |--Element 10    |

             |----------------|      |                |

             |     year       | <----<----------------

             |----------------|         

           

Consider the following assignment statements.

birthdays[1].month :=    2;

birthdays[1].day   :=   12;

birthdays[1].year  := 1983;

birthdays[1].year  := birthdays[2].year;

which assign various values to the array elements.

 

RECORDS CONTAINING ARRAYS

Records can also contain arrays as a field. Consider the following example, which shows a record called month, whose element name is actually an array.

 

type  monthname = packed array[1..4] of char;

      month = RECORD

                 days : integer;

                 name : monthname

              END;

var  this_month : month;

     this_month.days    := 31;  this_month.name[0] := 'J';

     this_month.name[1] := 'a'; this_month.name[2] := 'n';

     this_month.name := 'Feb ';

 

 

RECORDS WITHIN RECORDS

Records can also contain other records as a field. Consider where both a date and time record are combined into a single record called date_time, eg,

 

type  date = RECORD

                day, month, year : integer

             END;

      time = RECORD

                hours, minutes, seconds : integer

             END;

      date_time = RECORD

                     sdate : date;

                     stime : time

                  END;

This defines a record whose elements consist of two other previously declared records. The statement

var   today  : date_time;

declares a working variable called today, which has the same composition as the record date_time. The statements

today.sdate.day     :=   11;

today.sdate.month   :=    2;

today.sdate.year    := 1985;

today.stime.hours   :=    3;

today.stime.minutes :=    3;

today.stime.seconds :=   33;

sets the sdate element of the record today to the eleventh of february, 1985. The stime element of the record is initialised to three hours, three minutes, thirty-three seconds

 

with RECORDS

The with statement, in association with records, allows a quick and easy way of accessing each of the records members without using the dot notation.

Consider the following program example, where the variable student record is initialised. Note how the name of the record is associated with each of the initialised parts. Then look at the code that follows, and note the difference being the absence of the record name.

 

program withRecords( output );

 

typeGender = (Male, Female);

Person = Record

Age : Integer;

Sex : Gender

end;

var Student : Person;

begin

Student.Age := 23;

Student.Sex := Male;

with Student do begin

Age := 19;

Sex := Female

end;

with Student do begin

Writeln( 'Age := ', Age );

case Sex of

Male   : Writeln( 'Sex := Male' );

Female : Writeln( 'Sex := Female' )

end

end

end.

 

SETS

Sets exist in every day life. They are a way of classifying common types into groups. In Pascal, we think of sets as containing a range of limited values, from an initial value through to an ending value.

Consider the following set of integer values,

 

1, 2, 3, 4, 5, 6, 7, 8, 9, 10

This is a set of numbers (integers) whose set value ranges from 1 to 10. To define this as a set type in Pascal, we would use the following syntax.

 

program SetsOne( output );

type  numberset = set of 1..10;

var  mynumbers : numberset;

begin

end.

 

The statement

type  numberset = set of 1..10;

declares a new type called numberset, which represents a set of integer values ranging from 1 as the lowest value, to 10 as the highest value. The value 1..10 means the numbers 1 to 10 inclusive. We call this the base set, that is, the set of values from which the set is taken. The base set is a range of limited values. For example, we can have a set of char, but not a set of integers, because the set of integers has too many possible values, whereas the set of characters is very limited in possible values.

 

The statement

 var  mynumbers : numberset;

makes a working variable in our program called mynumbers, which is a set and can hold any value from the range defined in numberset.

SET OPERATIONS

The typical operations associated with sets are,

assign values to a set

determine if a value is in one or more sets

set addition (UNION)

set subtraction (DIFFERENCE)

set commonality (INTERSECTION)

 

 

Assigning Values to a set: UNION

Set union is essentially the addition of sets, which also includes the initialisation or assigning of values to a set. Consider the following statement which assigns values to a set

 

program SetsTWO( output );

type  numberset = set of 1..10;

var  mynumbers : numberset;

begin

mynumbers := [];

mynumbers := [2..6]

end.

The statement

mynumbers := [];

assigns an empty set to mynumbers. The statement

mynumbers := [2..6];

assigns a subset of values (integer 2 to 6 inclusive) from the range given for the set type numberset. Please note that assigning values outside the range of the set type from which mynumbers is derived will generate an error, thus the statement

mynumbers := [6..32];

is illegal, because mynumbers is derived from the base type numberset, which is a set of integer values ranging from 1 to 10. Any values outside this range are considered illegal. Determining if a value is in a set

Lets expand the above program example to demonstrate how we check to see if a value resides in a set. Consider the following program, which reads an integer from the keyboard and checks to see if its in the set.

 

program SetsTHREE( input, output );

type  numberset = set of 1..10;

var  mynumbers : numberset;

     value : integer;

begin

mynumbers := [2..6];

value := 1;

while( value <> 0 ) do

begin

writeln('Please enter an integer value, (0 to exit)');

readln( value );

if value <> 0 then

begin

if value IN mynumbers then

writeln('Its in the set')

else

writeln('Its not in the set')

end

end

end.

More on set UNION, combining sets

Lets now look at combining some sets together. Consider the following program, which creates two sets, then joins the sets together to create another.

 

program SetsUNION( input, output );

type  numberset = set of 1..40;

var  mynumbers, othernumbers, unionnumbers : numberset;

     value : integer;

begin

mynumbers := [2..6];

othernumbers := [4..10];

unionnumbers := mynumbers + othernumbers + [14..20];

value := 1;

while( value <> 0 ) do

begin

writeln('Please enter an integer value, (0 to exit)');

readln( value );

if value <> 0 then

begin

if value IN unionnumbers then

writeln('Its in the set')

else

writeln('Its not in the set')

end

end

end.

The statement

var  mynumbers, othernumbers, unionnumbers : numberset;

declares three sets of type numberset. The statement

 

mynumbers := [2..6];

assigns a subset of values (integer 2 to 6 inclusive) from the range given for the set type numberset. The statement

 

othernumbers := [4..10];

assigns a subset of values (integer 4 to 10 inclusive) from the range given for the set type numberset. The statement

 

unionnumbers := mynumbers + othernumbers + [14..20];

assigns the set of values in mynumbers, othernumbers and the set of values of 14 to 20 to unionnumbers. If a specific value occurs in more than one set (as is the case of 4, 5, and 6, which are in mynumbers and othernumbers), then the other duplicate value is ignored (ie, only one instance of the value is copied to the new set.

This means that unionnumbers contains the values

 

Set Subtraction, DIFFERENCE

In this operation, the new set will contain the values of the first set that are NOT also in the second set.

 

program SetsDIFFERENCE( input, output );

type  numberset = set of 1..40;

var  mynumbers, othernumbers, unionnumbers : numberset;

     value : integer;

begin

mynumbers := [2..6];

othernumbers := [4..10];

unionnumbers := mynumbers - othernumbers;

value := 1;

while( value <> 0 ) do

begin

writeln('Please enter an integer value, (0 to exit)');

readln( value );

if value <> 0 then

begin

if value IN unionnumbers then

writeln('Its in the set')

else

writeln('Its not in the set')

end

end

end.

unionnumbers contains the values

 

 

Set Commonality, INTERSECTION

In this operation, the new set will contain the values which are common (appear as members) of the specified sets.

 

program SetsINTERSECTION( input, output );

type  numberset = set of 1..40;

var  mynumbers, othernumbers, unionnumbers : numberset;

     value : integer;

begin

mynumbers := [2..6];

othernumbers := [4..10];

unionnumbers := mynumbers * othernumbers * [5..7];

value := 1;

while( value <> 0 ) do

begin

writeln('Please enter an integer value, (0 to exit)');

readln( value );

if value <> 0 then

begin

if value IN unionnumbers then

writeln('Its in the set')

else

writeln('Its not in the set')

end

end

end.

unionnumbers contains the values

 

 

FILE HANDLING

So far, data has been inputted from the keyboard, and outputted to the console screen.

The keyboard is known as the standard input device, and the console screen is the standard output device. Pascal names these as INPUT and OUTPUT respectively.

Occasions arise where data must be derived from another source other than the keyboard. This data will exist external to the program, either stored on diskette, or derived from some hardware device.

In a lot of cases, hardcopy (a printout) of program results is needed, thus the program will send the output to either the printer or the disk instead of the screen.

A program which either reads information from, or writes information to, a place on a disk, is performing FILE Input/Output (I/O).

A File is a collection of information. In Pascal, this information may be arranged as text (ie a sequence of characters), as numbers (a sequence of integers or reals), or as records. The information is collectively known by a sequence of characters, called a FILENAME.

You have already used filenames to identify the source programs written and used in this tutorial.

 

USING A FILE IN PASCAL

Files are referred to in Pascal programs by the use of filenames. You have already used two default filenames, input and output. These are associated with the keyboard and console screen. To derive data from another source, it must be specified in the program heading, eg,

 

program  FILE_OUTPUT( input, fdata );

This informs Pascal that you will be using a file called fdata. Within the variable declaration section, the file type is declared, eg

var  fdata : file of char;

This declares the file fdata as consisting of a sequence of characters. Pascal provides a standard definition called TEXT for this, so the following statement is identical,

var   fdata : TEXT;

 

BASIC FILE OPERATIONS

Once the file is known to the program, the operations which may be performed are, The file is prepared for use by RESET or REWRITE

Information is read or written using READ or WRITE

The file is then closed by using CLOSE

 

 

PREPARING A FILE READY FOR USE

The two commands for preparing a file ready for use in a program are RESET and REWRITE. Both procedures use the name of the file variable you want to work with. They also accept a string which is then associated with the file variable, eg

 

var  filename : string[15];

     readln( filename );

RESET ( fdata, filename );

This prepares the file specified by filename for reading. All reading operations are performed using fdata.

REWRITE ( fdata, filename );

This prepares the file specified by filename for writing. All write operations are performed using fdata. If the file already exists, it is re-created, and all existing information lost!

 

 

READING AND WRITING TO A FILE OF TYPE TEXT

The procedures READ and WRITE can be used. These procedures also accept the name of the file, eg,

 

writeln( fdata, 'Hello there. How are you?');

writes the text string to the file fdata rather than the standard output device. Turbo Pascal users must use the assign statement, as only one parameter may be supplied to either reset or rewrite.

 

assign( fdata, filename );

reset(  fdata );

rewrite( fdata );

 

CLOSING A FILE

When all operations are finished, the file is closed. This is necessary, as it informs the program that you have finished with the file. The program releases any memory associated with the file, ensuring its (the files) integrity.

CLOSE( fdata );        {closes file associated with fdata}

Once a file has been closed, no further file operations on that file are possible (unless you prepare it again).

 

SAMPLE FILE OUTPUT PROGRAM TO WRITE DATA TO A TEXT FILE

 

program  WRITETEXT (input, output, fdata );

var  fdata : TEXT;

     ch    : char;

     fname : packed array [1..15] of char;

begin

     writeln('Enter a filename for storage of text.');

     readln( fname );

     rewrite( fdata, fname );        {create a new fdata          }

     readln;                         {clear input buffer          }

     read( ch );                     {read character from keyboard}

     while  ch <> '*' do             {stop when an * is typed     }

     begin

        write( fdata, ch );          {write character to fdata    }

        read( ch )                   {read next character         }

     end;

     write( fdata, '*');             {write an * for end of file  }

     close( fdata )                  {close file fdata            }

end.

 

THE COMPOSITION OF TEXT FILES

Text files are arranged as a sequence of variable length lines.

Each line consists of a sequence of characters.

Each line is terminated with a special character, called

END-OF-LINE (EOLN)

The last character is another special character, called

END-OF-FILE (EOF)

 

THIS IS WHAT A TEXT FILE LOOKS LIKE

 

He was not quite as old as people estimated. In fact, the furrowedEOLN

brow that swept many a street was only fourty-five.EOLN

Life had not been easy for the hunchback, it's difficult to playEOLN

any game when all you can see are your feet. In spite of theEOLN

hardships, he was as gentle as a roaring elephant going overEOLN

Niagara falls.EOF

 

End of File and End of Line

 

EOF

Accepts the name of the input file, and returns true if there is no more data to be read.

EOLN

Accepts the name of the input file, and is true if there are no more characters on the current line.

When reading information from a text file, the character which is read can be compared against EOLN or EOF. Consider the following program which displays the contents of a text file on the console screen.

 

program  SHOWTEXT ( infile, input, output );

var   ch : char;

    fname : packed array [1..15] of char;

    infile: TEXT;

begin

    writeln('Please enter name of text file to display.');

    readln( fname );

    reset( infile, fname );     {open a file using filename stored in}

                                {array fname                         }

    while not eof( infile ) do

    begin

       while not eoln( infile ) do

       begin

           read( infile, ch );

           write( ch )

       end;

       readln( infile );       {read  eoln character}

       writeln                 {write eoln character}

    end;

    close( infile )             {close filename specified by fname}

end.

 

 

FILES OF NUMBERS

Files may also consist of integers or reals. The procedures read and write can be used to transfer one value at a time.

The procedures readln and writeln cannot be used with file types other than text.

 

FILES OF RECORDS

Files can also contain records. Using read or write, it is possible to transfer a record at a time.

 

STRINGS

The following program illustrates using STRINGS (a sequence of characters) in a DG Pascal program. STRING is type defined as a packed array of type char.

Message is then declared as the same type as STRING, ie, a packed array of characters, elements numbered one to eight.

 

PROGRAM DGSTRING (INPUT, OUTPUT);

TYPE STRING = PACKED ARRAY [1..8] OF CHAR;

VAR  MESSAGE : STRING;

BEGIN

        WRITELN('HELLO BRIAN.');

        MESSAGE := '12345678';

        WRITELN('THE MESSAGE IS ', MESSAGE)

END.

 

Turbo Pascal, how-ever, allows an easier use of character strings by providing a new keyword called STRING. Using STRING, you can add a parameter (how many characters) specifying the string length. Consider the above program re-written for turbo pascal.

 

PROGRAM TPSTRING (INPUT, OUTPUT);

VAR  MESSAGE : STRING[8];

BEGIN

        WRITELN('HELLO BRIAN.');

        MESSAGE := '12345678';

        WRITELN('THE MESSAGE IS ', MESSAGE)

END.

 

Obviously, the turbo pascal version is easier to use. BUT, the following program shows a similar implementation for use on the DG.

 

PROGRAM DGSTRING2 (INPUT, OUTPUT);

CONST   $STRINGMAXLENGTH = 8;         {defines maxlength of a string}

%INCLUDE 'PASSTRINGS.IN';             {include code to handle strings}

VAR  MESSAGE : $STRING_BODY;

BEGIN

        WRITELN('HELLO BRIAN.');

        MESSAGE := '12345678';

        WRITELN('THE MESSAGE IS ', MESSAGE)

END.

 

Strings

DG Pascal also provides the following functions for handling and manipulating strings.

 

APPEND

concatenate two strings. calling format is

 APPEND( string1, string2 );

where string2 is added onto the end of string1.

 

LENGTH

returns a short_integer which represents the length (number of

characters) of the string.

 LENGTH( stringname );

 

SETSUBSTR

replaces a substring in a target string with a substring from

a source string.

 SETSUBSTR( Targetstr, tstart, tlen, Sourcestr, sstart );

 

where

Targetstr is the target string

 

tstart is an integer representing the start position

 

        (within Targetstr) of the substring that is to be replaced

 

tlen is an integer representing the length of the substring

 

that you are replacing in Targetstr

 

Sourcestr is the source string which contains the substring

 

sstart is an integer which specifies the starting position

 

of the substring within Sourcestr

 

 

POINTERS

Pointers enable us to effectively represent complex data structures, to change values as arguments to functions, to work with memory which has been dynamically allocated, and to store data in complex ways.

A pointer provides an indirect means of accessing the value of a particular data item. Lets see how pointers actually work with a simple example,

  

program pointers1( output );

typeint_pointer = ^integer;

variptr : int_pointer;

begin

new( iptr );

iptr^ := 10;

writeln('the value is ', iptr^);

dispose( iptr )

end.

 

The line

typeint_pointer = ^integer;

declares a new type of variable called int_pointer, which is a pointer (denoted by ^) to an integer.The line

 

variptr : int_pointer;

declares a working variable called iptr of type int_pointer. The variable iptr will not contain numeric values, but will contain the address in memory of a dynamically created variable (by using new). Currently, there is no storage space allocated with iptr, which means you cannot use it till you associate some storage space to it. Pictorially, it looks like,

The line  

new( iptr );

creates a new dynamic variable (ie, its created when the program actually runs on the computer). The pointer variable iptr points to the location/address in memory of the storage space used to hold an integer value. Pictorially, it looks like,

The line  

iptr^ := 10;

means go to the storage space allocated/associated with iptr, and write in that storage space the integer value 10. Pictorially, it looks like,

The line  

dispose( iptr )

means deallocate (free up) the storage space allocated/associated with iptr, and return it to the computer system. This means that iptr cannot be used again unless it is associated with another new() statement first. Pictorially, it looks like,

 

POINTERS

Pointers which do not reference any memory location should be assigned the value nil. Consider the following program, which expands on the previous program.

 

 

program pointers2( output );

typeint_pointer = ^integer;

variptr : int_pointer;

begin

new( iptr );

iptr^ := 10;

writeln('the value is ', iptr^);

dispose( iptr );

iptr := nil;

if iptr = nil

   then writeln('iptr does not reference any variable')

else

   writeln('The value of the reference for iptr is ', iptr^)

end.

 

The line

iptr := nil;

assigns the value nil to the pointer variable iptr. This means that the pointer is valid and stil exists, but it does not point to any memory location or dynamic variable. The line

 

if iptr = nil

tests iptr to see if its a nil pointer, ie, that it is not pointing to a valid reference. This test is very useful and will come in use later on when we want to construct more complex data types like linked lists.

 

 

POINTERS

Pointers of the same type may be equated and assigned to each other. Consider the following program

 

program pointers3( output );

typeint_pointer = ^integer;

variptr1, iptr2 : int_pointer;

begin

new( iptr1 );

new( iptr2 );

iptr1^ := 10;

iptr2^ := 25;

writeln('the value of iptr1 is ', iptr1^);

writeln('the value of iptr2 is ', iptr2^);

dispose( iptr1 );

iptr1 := iptr2;

iptr1^ := 3;

writeln('the value of iptr1 is ', iptr1^);

writeln('the value of iptr2 is ', iptr2^);

dispose( iptr2 );

end.

 

The lines

new( iptr1 );

new( iptr2 );

creates two integer pointers named iptr1 and iptr2. They are not associated with any dynamic variables yet, so pictorially, it looks like,

The lines  

iptr1^ := 10;

iptr2^ := 25;

assigns dynamic variables to each of the integer variables. Pictorially, it now looks like,

The lines  

dispose( iptr1 );

iptr1 := iptr2;

remove the association of iptr1 from the dynamic variable whose value was 10, and the next line makes iptr1 point to the same dynamic variable that iptr2 points to. Pictorially, it looks like,

The line  

iptr1^ := 3;

assigns the integer value 3 to the dynamic variable associated with iptr1. In effect, this also changes iptr2^. Pictorially, it now looks like,

The programs output is

 

the value of iptr1 is 10

the value of iptr2 is 25

the value of iptr1 is 3

the value of iptr2 is 3

 

 

SUMMARY OF POINTERS

A pointer can point to a location of any data type, including records. Its basic syntax is,

type  Pointertype = ^datatype;

var  NameofPointerVariable : Pointertype;

 

The procedure new allocates storage space for the pointer to use

 

The procedure dispose deallocates the storage space associated with a pointer

 

A pointer can be assigned storage space using new, or assigning it the value from a pointer of the same type (eg, iptr1 := iptr2; )

 

A pointer can be assigned the value nil, to indicate that it is not pointing to any storage space

 

The value at the storage space associated with a pointer may be read or altered using the syntax

NameofPointerVariable^

 

A pointer may reference a type which has not yet been created (this will be covered next)

 

 

POINTERS: Referencing data types that do not yet exist

The most common use of pointers is to reference structured types like records. Often, the record definition will contain a reference to the pointer,

 

type  rptr = ^recdata;

recdata = record

number : integer;

code   : string;

nextrecord : rptr

end;

var  currentrecord : rptr;

In this example, the definition for the field nextrecord of recdata includes a reference to the pointer of type iptr. As you can see, rptr is defined as a pointer of type recdata, which is defined on the next lines. This is allowed in Pascal, for pointer types. Using a definition of recdata, this will allow us to create a list of records, as illustrated by the following picture.

In this case, a list is simply of number of records (all of the same type), linked together by the use of pointers.

 

POINTERS

Lets construct the actual list as shown below, as an example.

 

program PointerRecordExample( output );

type  rptr = ^recdata;

recdata = record

number : integer;

code   : string;

nextrecord : rptr

end;

var  startrecord : rptr;

begin

new( startrecord );

if startrecord = nil then

begin

writeln('1: unable to allocate storage space');

exit

end;

startrecord^.number := 10;

startrecord^.code := 'This is the first record';

new( startrecord^.nextrecord );

if startrecord^.nextrecord = nil then

begin

writeln('2: unable to allocate storage space');

exit

end;

startrecord^.nextrecord^.number := 20;

startrecord^.nextrecord^.code := 'This is the second record';

new( startrecord^.nextrecord^.nextrecord );

if startrecord^.nextrecord^.nextrecord = nil then

begin

writeln('3: unable to allocate storage space');

exit

end;

startrecord^.nextrecord^.nextrecord^.number := 30;

startrecord^.nextrecord^.nextrecord^.code := 'This is the third record';

startrecord^.nextrecord^.nextrecord^.nextrecord := nil;

writeln( startrecord^.number );

writeln( startrecord^.code );

writeln( startrecord^.nextrecord^.number );

writeln( startrecord^.nextrecord^.code );

writeln( startrecord^.nextrecord^.nextrecord^.number );

writeln( startrecord^.nextrecord^.nextrecord^.code );

dispose( startrecord^.nextrecord^.nextrecord );

dispose( startrecord^.nextrecord );

dispose( startrecord )

end.

 

The lines of code

new( startrecord );

if startrecord = nil then

begin

writeln('1: unable to allocate storage space');

exit

end;

startrecord^.number := 10;

startrecord^.code := 'This is the first record';

create the beginning of the list, which pictorially looks like,

The lines of code

 

new( startrecord^.nextrecord );

if startrecord^.nextrecord = nil then

begin

writeln('2: unable to allocate storage space');

exit

end;

startrecord^.nextrecord^.number := 20;

startrecord^.nextrecord^.code := 'This is the second record';

link in the next record, which now looks like,

The lines of code

 

new( startrecord^.nextrecord^.nextrecord );

if startrecord^.nextrecord^.nextrecord = nil then

begin

writeln('3: unable to allocate storage space');

exit

end;

startrecord^.nextrecord^.nextrecord^.number := 30;

startrecord^.nextrecord^.nextrecord^.code := 'This is the third record';

startrecord^.nextrecord^.nextrecord^.nextrecord := nil;

link in the third and final record, also setting the last nextrecord field to nil. Pictorially, the list now looks like,

 

The remaining lines of code print out the fields of each record.

 

POINTERS

The previous program can be rewritten to make it easier to read, understand and maintain. To do this, we will use a dedicated pointer to maintain and initialise the list, rather than get into the long notation that we used in the previous program, eg,

 

startrecord^.nextrecord^.nextrecord^.number := 30;

The modified program now looks like,

program PointerRecordExample2( output );

type  rptr = ^recdata;

recdata = record

number : integer;

code   : string;

nextrecord : rptr

end;

var  startrecord, listrecord : rptr;

begin

new( listrecord );

if listrecord = nil then

begin

writeln('1: unable to allocate storage space');

exit

end;

startrecord := listrecord;

listrecord^.number := 10;

listrecord^.code := 'This is the first record';

new( listrecord^.nextrecord );

if listrecord^.nextrecord = nil then

begin

writeln('2: unable to allocate storage space');

exit

end;

listrecord := listrecord^.nextrecord;

listrecord^.number := 20;

listrecord^.code := 'This is the second record';

new( listrecord^.nextrecord );

if listrecord^.nextrecord = nil then

begin

writeln('3: unable to allocate storage space');

exit

end;

listrecord := listrecord^.nextrecord;

listrecord^.number := 30;

listrecord^.code := 'This is the third record';

listrecord^.nextrecord := nil;

while startrecord <> nil do

begin

listrecord := startrecord;

writeln( startrecord^.number );

writeln( startrecord^.code );

startrecord := startrecord^.nextrecord;

dispose( listrecord )

end

end.

 

In this example, the pointer listrecord is used to create and initialise the list. After creation of the first record, it is saved in the pointer startrecord. The lines of code

 

new( listrecord );

if listrecord = nil then

begin

writeln('1: unable to allocate storage space');

exit

end;

startrecord := listrecord;

listrecord^.number := 10;

listrecord^.code := 'This is the first record';

creates the first record and initialises it, then remembers where it is by saving it into startrecord. Pictorially, it looks like,

The lines of code

 

new( listrecord^.nextrecord );

if listrecord^.nextrecord = nil then

begin

writeln('2: unable to allocate storage space');

exit

end;

listrecord := listrecord^.nextrecord;

listrecord^.number := 20;

listrecord^.code := 'This is the second record';

add a new record to the first by linking it into listrecord^.nextrecord, then moving listrecord to the new record. Pictorially, it looks like,

The lines of code

 

new( listrecord^.nextrecord );

if listrecord^.nextrecord = nil then

begin

writeln('3: unable to allocate storage space');

exit

end;

listrecord := listrecord^.nextrecord;

listrecord^.number := 30;

listrecord^.code := 'This is the third record';

listrecord^.nextrecord := nil;

add the last record to the previous by linking it into listrecord^.nextrecord, then moving listrecord to the new record. Pictorially, it looks like,

Note how much easier the code looks than the previous example.

 

 

POINTERS

Lets modify the previous program which introduced a separate pointer for tranversing the links of records. This time, rather than statically creating three records, we will allow the use to enter the details as the list is created.

The modified program appears below.

 

program PointerRecordExample3( input, output );

type  rptr = ^recdata;

recdata = record

number : integer;

code : string;

nextrecord : rptr

end;

varstartrecord, listrecord, insertptr : rptr;

digitcode : integer;

textstring : string;

exitflag, first : boolean;

begin

exitflag := false;

first := true;

while exitflag = false do

begin

writeln('Enter in a digit [-1 to end]');

readln( digitcode );

if digitcode = -1 then

exitflag := true

else

begin

writeln('Enter in a small text string');

readln( textstring );

new( insertptr );

if insertptr = nil then

begin

writeln('1: unable to allocate storage space');

exit

end;

if first = true then begin

startrecord := insertptr;

listrecord := insertptr;

first := false

end

else begin

listrecord^.nextrecord := insertptr;

listrecord := insertptr

end;

insertptr^.number := digitcode;

insertptr^.code := textstring;

insertptr^.nextrecord := nil

end

        end;

        while startrecord <> nil do

        begin

     listrecord := startrecord;

             writeln( startrecord^.number );

     writeln( startrecord^.code );

     startrecord := startrecord^.nextrecord;

     dispose( listrecord )

end

end.

 

The program uses three pointers. startrecord remembers the start or head of the list, listrecord is used to link between the previous record and the next/current one, and insertptr is used to create a new record which is then linked into the chain.

 

 

POINTERS

 

An example of constructing a list of words and line numbers

The following program illustrates a buggy method of reading a small file and generating a list of words and associated line numbers. It does this using a linked list.

Its been ported from a C equivalent example in the C programming module. It fails on large text files (generates a heap overflow error). Proper handling of error situations is minimised so as to concentrate primarily on code execution.

Use it at your own peril.

 

program findwords( input, output );

{ $M 32000, 65536 }

const TRUE = 1;

      FALSE = 0;

      BS = 8;

      TAB = 9;

      LF = 10;

      VT = 11;

      FF = 12;

      CR = 13;

{  this holds the line numbers for each word. Its double linked for

   ease of freeing memory later on }

type listptr = ^list;

     list = record

              line : integer;       { line number of occurrence     }

              nextline : listptr;   { link to next line number      }

              prevline : listptr    { link to previous line number  }

     end;

{ this holds the word with a link to a struct list holding line

   numbers. Double linking to simplify freeing of memory later on   }

    wordptr = ^words;

    words = record

              word : string;        { pointer to word                 }

              lines : listptr;      { pointer to list of line numbers }

              nextword : wordptr;   { pointer to next word in list    }

              prevword : wordptr;   { pointer to previous word in list}

     end;

var

   head, tail : wordptr;   { beginning and end of list       }

   fin : file of char;     { input file handle               }

   filename : string;      { name of input file              }

   thisisfirstword : integer;  { to handle start of list words=0 }

{ customised exit routine to provide orderly shutdown }

procedure myexit( exitcode : integer );

var

   word_ptr, tempw : wordptr;

   line_ptr, templ : listptr;

begin

   { close input file }

   close( fin );

   { free any allocated memory }

   writeln('Deallocating memory:');

   word_ptr := head;

   while  word_ptr <> nil do

   begin

      tempw := word_ptr;               { remember where we are        }

      line_ptr := word_ptr^.lines;     { go through line storage list }

      while line_ptr <> nil do

      begin

         templ := line_ptr;                { remember where we are    }

         line_ptr := line_ptr^.nextline;   { point to next list       }

         dispose( templ )                  { free current list        }

      end;

      word_ptr := word_ptr^.nextword;      { point to next word node  }

      dispose( tempw )                     { free current word node   }

   end;

   { return to OS }

   halt( exitcode )

end;

{ check to see if word already in list, 1=found, 0=not present }

function checkforword( word : string ) : integer;

var ptr : wordptr;

begin

   ptr := head;                     { start at first word in list }

   while ptr <> nil do

   begin

      if  ptr^.word = word then   { found the word?                  }

         checkforword := TRUE;     { yes, return found                }

      ptr := ptr^.nextword        { else cycle to next word in list  }

   end;

   checkforword := FALSE           { word has not been found in list  }

end;

{ enter word and occurrence into list }

procedure makeword( word : string; line : integer );

var

   newword, word_ptr : wordptr;

   newline, line_ptr : listptr;

begin

   if checkforword( word ) = FALSE then

   begin

      { insert word into list }

      newword := new( wordptr );

      if newword = nil then

      begin

         writeln('Error allocating word node for new word: ', word );

         myexit( 1 )

      end;

      { add newnode to the list, update tail pointer }

      if thisisfirstword = TRUE then

      begin

        head := newword;

        tail := nil;

        thisisfirstword := FALSE;

        head^.prevword := nil

      end;

      newword^.nextword := nil;    { node is signified as last in list }

      newword^.prevword := tail;   { link back to previous node in list }

      tail^.nextword := newword;   { tail updated to last node in list }

      tail := newword;

      { allocate storage for the word including end of string NULL }

      tail^.word := word;

      { allocate a line storage for the new word }

      newline := new( listptr );

      if newline = nil then

      begin

         writeln('Error allocating line memory for new word: ', word);

         myexit( 3 )

      end;

      newline^.line := line;

      newline^.nextline := nil;

      newline^.prevline := nil;

      tail^.lines := newline

   end

   else

   begin

       { word is in list, add on line number }

      newline := new( listptr );

      if newline = nil then

      begin

         writeln('Error allocating line memory for existing word: ', word);

         myexit( 4 )

      end;

      { cycle through list to get to the word }

      word_ptr := head;

      while  word_ptr <> nil do

      begin

         if  word_ptr^.word = word then

             break;

         word_ptr := word_ptr^.nextword;

      end;

      if word_ptr = nil then

      begin

         writeln('ERROR - SHOULD NOT OCCUR ');

         myexit( 5 )

      end;

      { cycle through the line pointers }

      line_ptr := word_ptr^.lines;

      while  line_ptr^.nextline <> nil do

         line_ptr := line_ptr^.nextline;

      { add next line entry }

      line_ptr^.nextline := newline;

      newline^.line := line;

      newline^.nextline := nil;

      newline^.prevline := line_ptr  { create back link to previous line number }

   end

end;

{ read in file and scan for words }

procedure processfile;

var

   ch : char;

   loop, in_word, linenumber : integer;

   buffer : string;

begin

   in_word := 0;       { not currently in a word }

   linenumber := 1;    { start at line number 1  }

   loop := 0;          { index character pointer for buffer[] }

   buffer := '';

   read( fin, ch );

   while not Eof( fin ) do

   begin

       case ch of

         chr(CR) : begin

                    if in_word = 1 then begin

                      in_word := 0;

                      makeword( buffer, linenumber );

                      buffer := '';

                    end;

                    linenumber := linenumber + 1

                   end;

        ' ', chr(LF), chr(TAB), chr(VT), chr(FF), ',' , '.'  :

                   begin

                    if in_word = 1 then begin

                       in_word := 0;

                       makeword( buffer, linenumber );

                       buffer := '';

                    end

                   end;

        else

                   begin

                    if in_word = 0 then begin

                       in_word := 1;

                       buffer := buffer + ch

                     end

                     else begin

                       buffer := buffer + ch

                     end

                    end;

      end; { end of switch }

      read( fin, ch )

   end  { end of while }

end;

{ print out all words found and the line numbers }

procedure printlist;

var

   word_ptr : wordptr;

   line_ptr : listptr;

begin

   writeln('Word list follows:');

   word_ptr := head;

   while  word_ptr <> nil do

   begin

      write( word_ptr^.word, ': ' );

      line_ptr := word_ptr^.lines;

      while line_ptr <> nil  do

      begin

         write( line_ptr^.line, ' ' );

         line_ptr := line_ptr^.nextline

      end;

      writeln;

      word_ptr := word_ptr^.nextword

   end

end;

procedure initvars;

begin

   head := nil;

   tail := nil;

   thisisfirstword := TRUE

end;

begin

   writeln('Enter filename of text file: ');

   readln( filename );

   assign( fin, filename );

   reset( fin );

   {  if  fin = nil then

      begin

         writeln('Unable to open ',filename,' for reading');

         myexit( 1 )

      end;

   }

   initvars;

   processfile;

   printlist;

   myexit(0)

end.

 

 

COMMAND LINE ARGUMENTS

When a program is invoked, it may accept arguments from the command line such as the name of a data file to process.

In TurboC, the two functions ParamCount and ParamStr are used to retrieve these values.

ParamCount

This function returns the number of arguments of the command line which follow the name of the program. In this example below,

 

        test  file1.c  file2.pas

the program test is invoked with two parameters. ParamStr

This function returns a string representing the value of the command-line parameter.

 

program commandline( output );

var arguments : integer;

begin

    if ParamCount = 0 then

    begin

         writeln( 'No parameters supplied' );

         halt(1)

    end

    else begin

         writeln('There are ', ParamCount, ' parameters' );

         for arguments := 1 to ParamCount do

             Writeln( 'Parameter ',arguments,' = ',ParamStr(arguments) );

    end

end.