Google
 

Trailing-Edge - PDP-10 Archives - decuslib20-01 - decus/20-0003/lecture.1
There are no other files named lecture.1 in the archive.
This lecture will cover a subset of Pascal that is more or less
equivalent in power to Fortran.  I assume that you already know how to
program in some conventional high-level language.



A sample program:

PROGRAM MINMAX(INPUT,OUTPUT);

{This program reads 20 numbers and prints the maximum and minimum}

CONST N=20;

VAR I,U,V,MIN,MAX:INTEGER;
    A:ARRAY[1..N] OF INTEGER;

BEGIN
FOR I := 1 TO N DO
  READ(A[I]);
MIN := A[1]; MAX := MIN;
FOR I := 2 TO N DO
  BEGIN
  IF A[I] < MIN
    THEN MIN := A[I];
  IF A[I] > MAX
    THEN MAX := A[I]
  END;
WRITE('Maximum: ',MAX);
WRITE('Minimum: ',MIN)
END.


Note overall form of the program:
  PROGRAM heading
  LABEL section
  CONST section
  TYPE section
  VAR section
  PROCEDURE and FUNCTION declarations
  BEGIN main body END.
Note that all variables must be defined in the VAR section.  No automatic
declarations as in Fortran or PL/I.

Lexical details:
  free format.  words must be kept contiguous, but can be separated by
	any number of spaces or new lines.  New line = blank
  no column restrictions - program can go anywhere on a line
  comments with {}.  A comment is syntactically equivalent to a space.
  identifiers:  user-defined names (variables, procedures, ...).
	1 to N alphanumerics, 1st alphabetic.  N is implementation
	defined, but must be at least 8.  Names longer than N are
	legal, but are confused.
  reserved words:  words built into the language, e.g. BEGIN, IF.  Can't
	use as variable names.
  integers:  123, -456, digits with possible - sign
  real numbers:  1.2, 5E21, 2.13E-3.  Must have either decimal pt. or E.  If
	decimal pt, must have at least one digit both before and after it.
	.2 and 1. are both illegal.
  strings:  'ABC',  'DON''T'  (use two '' to put one into string).  But
	'A' is a CHAR, not a string

Variables:
  each variable must be declared in the VAR section.  It must have a "type"
	associated with it.  The simplest types are INTEGER and REAL.  We
	will see more complex ones later.
    A,B,C:REAL
  also Boolean, which can have value TRUE or FALSE.  (TRUE and FALSE are
	constants built into the language).
    B:BOOLEAN;  ....  B := TRUE;  ... IF B THEN ...

Constants:
  a constant may be written out, e.g. 1.23
  or an identifier declared in the CONST section
	A = 1.23; B = 55

Expressions:
  numerical:  constants and variables, with operators + - * /, and ().
	+ - * are real if either arg is real, integer if both are integer
	/ is always real
	no exponentiation (use LOG)
	MOD and DIV for integers
  Boolean:  constants, variables, and results of comparisons, with
    operators AND OR NOT.
	The comparisons are <  <=  =  >=  >  <>       <> is not equal
	example:  IF (X < Y+2) OR (Y = Z) OR FREE
  operator precedence:
	()
	NOT
	* / DIV MOD AND
	+ - OR
	< <= = >= > <> IN
    note the horrible consequences:
	IF A > B AND C < D   ==>  IF A > (B AND C) < D - probably wrong
	must use IF (A > B) AND (C < D)

Statements:
  assignment
	X := 10
	A := A + 1
       uses := so you can tell assignment from comparison
    The left and right sides must have exactly the same type, except that
	you can assign an integer to a real:
	    REALVAR := 1
	You can't assign a real to an integer (there are explicit ROUND
	and TRUNC functions to let you do this).
    This is particularly frustrating with strings.  If you have a variable
	that accepts a 10-character string, you can't assign '123456789'
	to it.

  WHILE statement:  
	WHILE I < 20 DO
	   I := I + 2
    Note that the WHILE statement allows exactly 1 statement in the loop.
    To do more than one thing, use BEGIN END to turn a group of statements
    into one:
	WHILE I < 20 DO
	  BEGIN I := I + 2; WRITE(I) END
    Note the use of semicolons:  they separate lists of statements between
    begin and end.  It is best to think of BEGIN and END as ( and ), with
    ; acting like , to separate items in a list.
	WHILE statement:  the test is done before the body.  That is,
	  if I is initially >= 20, the body is never done.

  FOR statement:
	FOR I := 1 TO 20 DO
	   WRITE(3*I)
    Loop is done 20 times.  I takes on values from 1 to 20.
    No BY clause.
    Always steps by 1.  To go backwards:
	FOR I := 20 DOWNTO 1 DO ...
    The body is exactly one statement.  To do more than one thing, BEGIN END
	FOR I := 1 TO 20 DO
	   BEGIN X := I*3;  WRITE(X) END

  IF-THEN-ELSE statement:
	IF I > X
	  THEN WRITE('I is bigger')
	  ELSE WRITE('X is at least as big')
    The ELSE is optional.
    The IF is any Boolean expression.
    The THEN and ELSE are single statements.  To do more than one thing,
      BEGIN END.  Note that IF statements can nest:
	IF I > X
	  THEN IF Y > I
	    THEN WRITE('Y is biggest')
	    ELSE WRITE('I is biggest')
	  ELSE IF Y > X
	    THEN WRITE('Y is biggest')
	    ELSE BEGIN WRITE('X is biggest'); MAX := X END

  REPEAT statement
	REPEAT 
	  X := X + 1;
	  WRITE(X + 2)
	 UNTIL X > LAST
    This is the only form that allows more than one statement inside
      without BEGIN-END.  REPEAT-UNTIL are sort of a builtin BEGIN-END.
    UNTIL test is done after the loop.  So the loop is always done at
      least once.

  CASE statement
	CASE I+2 OF
	  1: WRITE('It is a one');
	  2: WRITE('It is a two');
	  3,4,5: WRITE('It is 3, 4, or 5')
	  END
    You can use any scalar type.  Not just integers, but CHAR, BOOLEAN,
    and user-defined types such as COLOR:
	CASE CH OF
	  'A','B','C','D','E','F','G','H','I','J','K','L','M',
	  'N','O','P','Q','R','S','T','U','V','W','X','Y','Z':
	      WRITE('ALPHABETIC');
          '1','2','3','4','5','6','7','8','9','0': WRITE('NUMERIC')
	  END;
    Note that there is no way to say 'A'..'Z'.  There is an OTHERWISE
    in the proposed Pascal standard, but not in the current standard.
    DEC-20 Pascal allows OTHERS.

  GOTO
	IF X > 2
	  THEN BEGIN WRITE('ILLEGAL SYNTAX'); GOTO 666 END
    GOTO is one word
    The label is always a number
    Labels must be declared in the label section, and defined with a colon:
	PROGRAM TEST(INPUT,OUTPUT);
	LABEL 666;
	VAR X:INTEGER;
	BEGIN
	READ(X);
	IF X > 2  THEN GOTO 666;
	WRITE(X);
 666:	WRITE('THE END')
	END.

Arrays:
   You must declare any array in the VAR section:
	X,Y: ARRAY[0..100]OF INTEGER
   Note that you specific lower and upper bounds.  These may be zero or
     negative.  Must be integers.  To access an element, use brackets:
	X[1] := X[P] + 1;
   Two dimensional arrays are theoretically just arrays of array:
	TWODIM: ARRAY[0..10] OF ARRAY[0..10] OF INTEGER
     But no one wants to type that out.  The following is exactly
     equivalent:
	TWODIM: ARRAY[0..10,0..10] OF INTEGER
   You can access two dimensional arrays either way:
	TWODIM[I,I] := TWODIM [I] [I] + 1
   You can assign arrays:
	X := Y
     But no other operation will work.  The two arrays must have exactly
     the same type.
   
Simple numerical I/O:
   Any file you are going to use must be listed in the PROGRAM statement.
   If you just have one input and one output, you normally call them
   INPUT and OUTPUT.  This is most convenient because INPUT and OUTPUT
   are predeclared, and are the defaults for READ and WRITE.  So if
   you say
	PROGRAM TEST(INPUT,OUTPUT)
   you can just use READ(X) and WRITE(Y).  If you have no input, leave
   out the INPUT.
	READ(X,Y,Z) - read into variables X, Y, and Z.  Skips blanks
	  and end of line.  "free format" read.
	WRITE(X,Y,X+2,'hi there') - writes out values of X, Y, X+2,
	  and the message hi there (without quotes).
	WRITELN(X) - like WRITE(X), but puts an end of line after it.
	WRITELN alone can be used to go to a new line



			PROCEDURES and FUNCTIONS

Let us start with a PROCEDURE.  A procedure is equivalent to a
SUBROUTINE subprogram in Fortran and an un-typed PROCEDURE in PL/I.
It is way of taking some part of your program and encapsulating
it into a self-contained module.  Whenever that part is needed,
it is called for by name.  There are two major advantages to using
PROCEDURES:
  - that a piece of code can appear just once but be called
	from many different parts of the program
  - that low-levels details can be moved into procedures, so
	that the main body of the program doesn't need to be
	cluttered up with them.

An example:

	program demo(output);

	var i:integer;
	    y:real;

	procedure panswer(y:integer);
	{Panswer prints an answer.  If the number is "reasonable",
	 it prints it using a legible format, e.g. 123.4567.  But
	 if it is too small or too large for this format, the
	 more general E format is used}
		begin
		if (x > 0.0001) and (x < 1000)
			then writeln('the answer is',x:10:4)
			else writeln('the answer is',x)
		end;

	procedure done;
		begin
		writeln('Thats all, folks')
		end;

	begin
	for i := 1 to 10 do
	  begin
	  y := i * i;
	  panswer(y)
	  end;
	done
	end.

 - procedures are declared after the VAR section of the program,
	but before the main BEGIN-END body.
 - a procedure declaration looks like a small program.  It can
	have all the sections of a program: label, const,
	var, etc.  The only difference is that the first statement
	is the PROCEDURE header instead of a PROGRAM header.
 - to call a procedure, just mention its name.  Do *not* say CALL.

Any time PANSWER appears in the main program, all the statements
inside the definition of PANSWER get executed.  When the last
statement in the procedure is finished, control returns to the
statement following the call to the procedure.

How parameters are passed:
  - parameters are listed inside parentheses after the procedure
	name.  If there are no parameters, the entire list is
	omitted.  No parentheses either.  The syntax used is
	the same as for declaring variables in a VAR section:

    procedure onearg(i:integer)
    procedure twoarg(i:integer;j:integer)   
    procedure twomore(i,j:integer)  {same effect as twoarg}
    procedure threearg(i,j:integer;k:real)
    procedure noarg

  - when you call the procedure, you supply one expression
	for each parameter.  Pascal will evaluate each expression
	and set the corresponding parameter to that value.

     procedure f(i,j:integer;x:real);

	Whenever you call F, you must supply two integers and one
	real, the order INTEGER, INTEGER, REAL.  Pascal assigns the
	first integer to I, the second to J, and the real to X.
	Then it executes the body of the procedure.

     procedure f(i,j:integer);
	begin
	writeln(i+j)
	end;
     ...
     f(3,4)
     ...

	f(i,j:integer) requires two integers.  In this case 3 and 4
	are supplied.  So I is set to 3 and J to 4.  Then the body
	is executed.  In this case it will print I+J, which is 7.

A note on names:

Note that all names defined within the procedure are available
only within the procedure:

program test(output);
var x,y:integer;
procedure demo(i:integer);
  var x,z:integer;
  begin
  x := i*i;
  z := x*i;
  writeln(x,z);
  y := z
  end;
begin
x := 1;
y := 2;
demo(x,y)
end.

The X inside DEMO is a different variable than the one defined in
the main program.  X := I*I sets the X inside the procedure.
X := 1 is in the main program, and thus sets the X defined there.
Note that Z can be referenced within either the main program or
the subroutine.  In general you can "see out of" a procedure, but
not "into" it.  That is:
  - inside a procedure you can refer to either variables defined
	in the procedure or those defined in the main program.
	[the one exception is that when a variable inside and one
	outside have the same name, you can't refer to the outside
	one.  any reference to that name gets the inside variable.]
  - outside a procedure you cannot refer to any variable inside
	the procedure
The names of parameters are considered to be inside the procedure.



Call by reference:

Suppose you want to be able to change the values of variables
from inside a procedure.  Consider the following:

    procedure p(i:integer);
	begin
	i := i*i
	end;

    begin
    j := 2;
    p(j);
    writeln(j)

This will write "2".  The call P(J) will set I to 2 and then
execute the body of the procedure.  The body of the procedure
sets I to 4, but does not change J.  That is, it is like doing
this:
   j := 2;
   i := j;
   i := i*i;
   writeln(j)

Sometimes you want to be able to change a variable from inside
the procedure.  In this case, put a VAR in front of the parameter:

    procedure p(var x,y:integer;z:integer);
	begin
	x := z*z;
	y := z*x;
	z := y
	end;

    begin
    a := 1; b := 2; c := 3;
    procedure(a,b,c);
    writeln(a,b,c)
    end

In this case X and Y are called by reference.  That is any time you
refer to X and Y inside the procedure, you really mean the variable
that matched them in the call, A and B.  The values of A and B are
not copied when the call is made.  Rather these variables themselves
are used.  So any change that is made to X and Y changes A and B.
C however is copied into Z.  The example above will print
	9	27	3

Note that names don't matter.  Suppose you have
    procedure p(var i,j:integer);
	...
    p(j,i)
Now J on the outside corresponds to I on the inside and visa versa.

Reference parameters must corresond to variables, since that is the
only thing whose value can be changed.  Normal ("value") parameters
can correspond to any kind of expression, since the value of the
expression is only assigned.


Functions:

A function is like a procedure, but it returns a value.  A function
is called from within an expression, rather than as a separate
statement.  E.g. if F is a function, you might write:

   x := 2 * f(1,2) + 3

First F is called, with the values 1 and 2.  The result is multplied
by 2 and 3 is added.

function f(i,j:integer):integer;
  var x:integer;
  begin
  x := 2*i + 3*j;
  f := x
  end;

Note the extra ":integer" in the header.  This means that F returns an
integer value.  The insides of a function are just like the insides
of a procedure, with one addition:  You have to say what the function
returns.  This is done by using the name of the function on the left
side of an assignment.

    f := x

So the function returns the value of X.  This assignment can be
anywhere inside the function.  You can do such assignments more than
once.  You cannot, however, use the name of the functionn on the
right side of an assignment to look at the current value.  Any
appearance of the function name on the right side of an assignment
is assumed to be a CALL of the function.

By the way, the above statement  x := 2 * f(1,2) + 3 assigns
19 to X.  F(1,2) returns 8.

There are a number of functions and procedures built into Pascal.  Here
are some of them.  Unless otherwise stated, they return the same
type of variable as they accept.  That is, ABS(-123) is 123, an integer,
but ABS(-123.0) is 123.0, a real.

   abs(x) - absolute value. integer or real
   sqr(x) - square.  integer or real
   odd(x) - TRUE if X is odd, otherwise FALSE.  integer
   succ(x) - x must be a denumerable type.  returns the next thing.
	e.g.
	TYPE
	  COLOR=(RED,BLUE,GREEN)
	...
	C := SUCC(RED);   {sets C to BLUE}
   pred(x) - x must be a denumerable type.  returns the previous thing
   ord(x) - x must be a denumerable type, or CHAR.  returns the internal
	code for X.  For enumerated types, the first is 0, the second 1,
	etc.  That is ORD(RED) is 0, ORD(BLUE) is 1, etc.  For CHAR,
	this gives you the ASCII (or EBCDIC, if IBM) code for the character
   char(x) - x must be an integer.  Gives you the character whose ASCII
	(or EBCDIC if IBM) value is x.  ORD(CHR(X)) = X
   trunc(x) - x real - returns an integer.  Throws away everything
	after the decimal point.
   round(x) - x real - returns an integer.  Rounds, i.e. .5 or greater is
	rounded up.
   eoln(x) - x a text file - TRUE if X^ is an end of line, else FALSE
   eof(x) - x a file - TRUE if X^ is beyond the last item in the file,
	else FALSE
   sin(x), cos(x), arctan(x) - x real - trig functions.  Uses radians
   exp(x) - x real - e to the x power
   ln(x) - x real - natural log of x
   sqrt(x) - x real - square root of x