Copyright (c) 1998-2000 Stuart King. All rights reserved.

	Welcome to the Irie Pascal Programmer's Reference Manual

-----------------
Table Of Contents
-----------------
1   Introduction
    1.1 Grammar Notation
2   Lexical Elements
    2.1 Character Literals
    2.2 String Literals
    2.3 Whole Numbers
	2.3.1 Decimal Whole Numbers
	2.3.2 Hexadecimal Whole Numbers
	2.3.3 Binary Whole Numbers
    2.4 Reals
    2.5 Special Symbols
    2.6 Reserved Words
    2.7 Identifiers
	2.7.1  Directives
	2.7.2  Built-in Identifiers
	2.7.3  User Defined Identifiers
    2.8 Comments
3   Labels
4   Constants
    4.1 boolean
    4.2 maxbyte
    4.3 maxchar
    4.4 maxint
    4.5 maxword
    4.6 Nil
    4.7 Permission
    4.8 Platform
    4.9 FileMode
    4.10 dir_bit
5   Types
    5.1 Enumerated Types
    5.2 Subrange Types
    5.3 Pointer Types
    5.4 Array Types
    5.5 String Types
    5.6 Record Types
    5.7 Set Types
    5.8 File Types
    5.9 List Types
    5.10 Type Identifiers
	5.10.1 boolean
	5.10.2 byte
	5.10.3 char
	5.10.4 dir
	5.10.5 filename
	5.10.6 integer
	5.10.7 real
	5.10.8 registers
	5.10.9 text
	5.10.10 word
    5.11 Integral Types
6   Variables
    6.1 Pointer Variables
    6.2 Array Variables
    6.3 String Variables
    6.4 Record Variables
    6.5 List Variables
7   Functions And Procedures
    7.1 Built-in Functions
	7.1.1 abs
	7.1.2 arctan
	7.1.3 chr
	7.1.4 concat
	7.1.5 copy
	7.1.6 copyword
	7.1.7 cos
	7.1.8 cosh
	7.1.9 countwords
	7.1.10 dirsep
	7.1.11 eof
	7.1.12 eoln
	7.1.13 exp
	7.1.14 fexpand
	7.1.15 filepos
	7.1.16 filesize
	7.1.17 frac
	7.1.18 getenv
	7.1.19 hex
	7.1.20 int
	7.1.21 ioresult
	7.1.22 isalpha
	7.1.23 isalphanum
	7.1.24 isdigit
	7.1.25 islower
	7.1.26 isprint
	7.1.27 isspace
	7.1.28 isupper
	7.1.29 isxdigit
	7.1.30 keypressed
	7.1.31 length
	7.1.32 ln
	7.1.33 log
	7.1.34 locase
	7.1.35 lowercase
	7.1.36 odd
	7.1.37 ord
	7.1.38 paramcount
	7.1.39 paramstr
	7.1.40 pi
	7.1.41 platform
	7.1.42 pos
	7.1.43 pred
	7.1.44 random
	7.1.45 readkey
	7.1.46 reverse
	7.1.47 round
	7.1.48 sin
	7.1.49 sinh
	7.1.50 sqr
	7.1.51 sqrt
	7.1.52 succ
	7.1.53 swap
	7.1.54 system
	7.1.55 tan
	7.1.56 tanh
	7.1.57 trim
	7.1.58 trunc
	7.1.59 upcase
	7.1.60 uppercase
	7.1.61 urldecode
	7.1.62 wherex
	7.1.63 wherey
    7.2 Built-in Procedures
	7.2.1 append
	7.2.2 assert
	7.2.3 assign
	7.2.4 chdir
	7.2.5 close
	7.2.6 closedir
	7.2.7 clrscr
	7.2.8 dec
	7.2.9 delay
	7.2.10 delete
	7.2.11 dispose
	7.2.12 erase
	7.2.13 exec
	7.2.14 exit
	7.2.15 fill
	7.2.16 flush
	7.2.17 fsplit
	7.2.18 get
	7.2.19 getdate
	7.2.20 getfiledate
	7.2.21 getfilemode
	7.2.22 getfiletime
	7.2.23 gettime
	7.2.24 gotoxy
	7.2.25 halt
	7.2.26 inc
	7.2.27 insert
	7.2.28 intr
	7.2.29 mkdir
	7.2.30 new
	7.2.31 open
	7.2.32 opendir
	7.2.33 pack
	7.2.34 page
	7.2.35 put
	7.2.36 randomize
	7.2.37 rawread
	7.2.38 rawwrite
	7.2.39 read
	7.2.40 readdir
	7.2.41 readln
	7.2.42 rename
	7.2.43 reset
	7.2.44 rewinddir
	7.2.45 rewrite
	7.2.46 rmdir
	7.2.47 seek
	7.2.48 setfiledate
	7.2.49 setfiletime
	7.2.50 sleep
	7.2.51 str
	7.2.52 textbackground
	7.2.53 textcolor
	7.2.54 unpack
	7.2.55 val
	7.2.56 write
	7.2.57 writeln
    7.3 External Functions And Procedures
8   Expressions
    8.1 Operators
	8.1.1 Not Operator
	8.1.2 * Operator
	8.1.3 / Operator
	8.1.4 Div Operator
	8.1.5 Mod Operator
	8.1.6 And Operator
	8.1.7 And_Then Operator
	8.1.8 + Operator
	8.1.9 - Operator
	8.1.10 Or Operator
	8.1.11 Or_Else Operator
	8.1.12 Xor Operator
	8.1.13 shl Operator
	8.1.14 shr Operator
	8.1.15 = Operator
	8.1.16 <> Operator
	8.1.17 < Operator
	8.1.18 <= Operator
	8.1.19 > Operator
	8.1.20 >= Operator
	8.1.21 In Operator
    8.2 Compatible types
9   Statements
    9.1 Empty Statement
    9.2 Assignment Statement
	9.2.1 Assignment Compatibility
	      9.2.1.1 Assignment compatibility with array indexing
	      9.2.1.2 Assignment compatibility with value parameters
	      9.2.1.3 Assignment compatibility with "read"
	      9.2.1.4 Assignment compatibility with assignment statements
	      9.2.1.5 Assignment compatibility with "for"
	      9.2.1.6 Transfer procedures
    9.3 Procedure Statement
    9.4 Goto Statement
    9.5 Compound Statement
    9.6 If Statement
    9.7 Case Statement
    9.8 Repeat Statement
    9.9 While Statement
    9.10 For Statement
    9.11 With Statement
10  Program parameters
Appendix A. Irie Pascal Grammar
Appendix B. Extensions to Pascal as specified by ISO/IEC 7185
    B.1 Relaxed declarations
    B.2 Constant ranges
    B.3 Otherwise
    B.4 Relaxed parameter list congruity
    B.5 Non-numeric statement labels
    B.6 Underscores in identifiers
    B.7 Binary integral constants
    B.8 Hexadecimal integral constants
    B.9 Input and Output automatically declared
    B.10 Double-quoted literals
    B.11 and_then operator
    B.12 or_else operator
    B.13 Bitwise operators
	 B.13.1 shl operator
	 B.13.2 shr operator
	 B.13.3 and (Bitwise) operator
	 B.13.4 or (Bitwise) operator
	 B.13.5 not (Bitwise) operator
	 B.13.6 xor (Bitwise) operator
    B.14 Extended constants
	 B.14.1 maxchar
	 B.14.2 usr_r
	 B.14.3 usr_w
	 B.14.4 usr_x
	 B.14.5 grp_r
	 B.14.6 grp_w
	 B.14.7 grp_x
	 B.14.8 oth_r
	 B.14.9 oth_w
	 B.14.10 oth_x
	 B.14.11 dir_bit
	 B.14.12 platform_dos
	 B.14.13 platform_os2
	 B.14.14 platform_win32
	 B.14.15 platform_linux
	 B.14.16 platform_fbsd
	 B.14.17 platform_solaris
	 B.14.18 platform_solaris_sparc
	 B.14.19 platform_error
	 B.14.20 appendmode
	 B.14.21 readmode
	 B.14.22 writemode
    B.15 Extended types
	 B.15.1 dir
	 B.15.2 filename
	 B.15.3 list
	 B.15.4 string
    B.16 Extended variables
	 B.16.1 exitcode

----------------
1   Introduction
----------------
This is the Irie Pascal Programmer's Reference Manual, and describes
the Irie Pascal language. This manual is not a tutorial and does not
attempt to teach programming. If you are new to programming or new to
Pascal you may need additional information. Fortunately there are many
excellent books which teach programming in Pascal. If you decide to
purchase a Pascal book, you should look for one that covers Standard
Pascal. For information on how to install and use Irie Pascal, see the
Irie Pascal User's Manual which should accompany this manual.

--------------------
1.1 Grammar Notation
--------------------
Context-free grammars are often used to define the syntax of programming
languages because they produce short and precise definitions. A
context-free grammar breaks the syntax of a complex language into a
number of simpler elements called non-terminal symbols. The syntax of
each non-terminal symbol is defined by a production. Each production
consists of a non-terminal symbol followed by some sort of assignment
operator, and then followed by a sequence of special symbols, terminal
symbols and non-terminal symbols. The special symbols are used to describe
how the other symbols can be combined. The terminals symbols are literal
text that can occur in the language being defined. The full context-free
grammar takes the form of a sequence of productions for all the non-terminal
symbols in the language.

The context-free grammar used in this manual has the following notation.
The equal sign is used as the assignment operator in productions to
separate the non-terminal symbol being defined from it's definition.
The special symbols are |, {}, [], and (). The | symbol is used to separate
alternatives (i.e. the grammar allows either the symbols on it's left-hand
side or the symbols on it's right-hand side). The {} symbols are used to
enclose symbols that can be repeated zero, one, or more times. The []
symbols are used to enclose optional symbols (i.e. the grammar allows the
enclosed symbols to either occur once or not occur at all). The () symbols
are used to group symbols that are evaluated together.
The terminal symbols are enclosed in single quotes ('') to distinguish them
For example here are the productions that define the syntax for identifiers.

   identifier = letter { letter | digit }

   letter = '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' |
	    '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' |
	    '_'

   digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'

The productions mean:
An identifier is a letter followed by zero or more letters or digits.
A letter is a lower-case letter or an upper-case letter or an underscore.
A digit is one of the decimal numerals.

The complete grammar for Irie Pascal is given in Appendix A.

--------------------
2   Lexical Elements
--------------------
This chapter describes the elements that make up programs.

----------------------
2.1 Character Literals
----------------------
A character literal is a character enclosed in single quotes (') or
as an extension in double quotes ("). Two single quotes together can be
used to represent single quotes in character literals enclosed in single
quotes. Two double quotes together can be used to represent double quotes
in character literals enclosed in double quotes.
So   "'" and '''' are both character literals containing single quotes.
And """" and '"' are both character literals containing double quotes.

Character literals are case-sensitive so 'X' is not equal to 'x'.
The syntax for character literals is as follows

   character-literal = ''' string-element-one ''' |
		       '"' string-element-two '"'

   string-element-one = '''' | printable-character

   string-element-two = '""' | printable-character

   printable-character = any character (including a space) that has a visual
			 representation.

NOTE: The production for printable-character doesn't follow the usual
notation because 1) it's tedious to write out every possible printable
character and 2) the definition for a printable character depends on
the character set being used.

Here are some examples of valid character literals:
   'A'    '+'    ' '    ''''     '"'
   "A"    "+"    " "    "'"      """"

-------------------
2.2 String Literals
-------------------
A string literal is a sequences of zero, two or more characters enclosed in
single quotes (') or as an extension in double quotes. Literals with
one character are character literals not string literals. Two single quotes
together can be used to represent single quotes in string literals enclosed
in single quotes. Two double quotes together can be used to represent
double quotes in string literals enclosed in double quotes. So
"Don't" and 'Don''t' are both string literals containing   Don't.
String literals are case-sensitive, so 'Hello' is not equal to 'HELLO'.
There is no explicit limit on the length of string literals but since
string literals can not span more than one line, then the limit on the
length of a line (400) implicitly limits the length of string literals.

The syntax for string literals is as follows

   string-literal = empty-string | other-string

   empty-string = '''' | '""'

   other-string =
       ''' string-element-one string-element-one {string-element-one ''' |
       '"' string-element-two string-element-two {string-element-two '"'

   string-element-one = '''' | printable-character

   string-element-two = '""' | printable-character

   printable-character = any character (including a space) that has a visual
			 representation.

NOTE: The production for printable-character doesn't follow the usual
notation because 1) its tedious to write out every possible printable
character and 2) the definition for a printable character depends on
the character set being used.

Here are some examples of valid string literals:
   ''     '   '  'Don''t'        'Say "Hello"'     '!@#$%^&*()'
   ""     "   "  "Don't"         "Say ""Hello"""   "!@#$%^&*()"

-----------------
2.3 Whole Numbers
-----------------
Whole numbers are numbers with no fractional part.
Leading zeroes are not significant in whole numbers

The syntax for whole numbers is

   whole-number = decimal-whole-number |
	     hexadecimal-whole-number |
	     binary-whole-number

Irie Pascal supports whole numbers with values between
    -2147483647  and  +4294967295

---------------------------
2.3.1 Decimal Whole Numbers
---------------------------
A decimal whole numnber uses base 10.

The syntax for decimal whole numbers is as follows:

   decimal-whole-number = [sign] digit { digit }

   sign = [ '+' | '-' ]

   digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'

Here are some examples of valid decimal whole number

   100     -0      +7453    000005

-------------------------------
2.3.2 Hexadecimal Whole Numbers
-------------------------------
As an extension Irie Pascal supports hexadecimal (base 16) whole numbers.

The syntax for hexadecimal whole numbers is as follows:

   hexadecimal-whole-numbers = [sign] '$' hex-digit { hex-digit }

   sign = [ '+' | '-' ]

   digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'

   hexdigit = digit |
	      'a' | 'b' | 'c' | 'd' | 'e' | 'f' |
	      'A' | 'B' | 'C' | 'D' | 'E' | 'F'

Here are some examples of valid hexadecimal whole numbers

   $64     -$0      +$FF       -$000ab4

--------------------------
2.3.3 Binary Whole Numbers
--------------------------
As an extension Irie Pascal supports binary (base 2) whole numbers.

The syntax for binary whole numbers is as follows:

   binary-whole-numbers = [sign] '%' bit { bit }

   sign = [ '+' | '-' ]

   bit = '0' | '1'

Here are some examples of valid binary whole numbers

   %01100110     -%0      +%11111111

---------
2.4 Reals
---------
Reals are numbers with fractional parts. Leading zeroes are not significant
in reals.

The syntax for reals is as follows

   real = [sign] unsigned-real

   sign = [ '+' | '-' ]

   unsigned-real =
       digit-sequence '.' fractional-part [ exponent scale-factor ] |
       digit-sequence exponent scale-factor

       digit-sequence = digit { digit }

       fractional-part = digit-sequence

       exponent = 'e' | 'E'

       scale-factor = [ sign ] | digit-sequence

Here are some examples of real numbers:
   -1.23456e2   which is equal to -123.456
   -1.23456e02  which is also equal to -123.456
   009863434455e-07   which is equal to 986.3434455
   7e-1 which is equal to 0.7

Irie Pascal supports reals with values between
about   1e308        and about        -1e308

-------------------
2.5 Special Symbols
-------------------
Special symbols have special meanings to the compiler.

The syntax for special symbols is given below:

   special-symbol =
	 '+' | '-' | '*' | '/' |
	 '=' | '<>' | '<' | '<=' | '>' | '>=' |
	 '(' | ')' |
	 '[' | ']' | '(.' | '.)' |
	 ':=' | '.' | ',' | ';' | '..' |
	 '^' | '@'
   
------------------
2.6 Reserved Words
------------------
Keywords have pre-defined and fixed meanings to the compiler.
The case of keywords is usually not significant so although the
syntax below uses all lowercase letters for keywords the compiler will
by default recognize keywords regardless of the case of the letters.
NOTE: There is a compiler option (-p) that will make identifiers
and keywords case-sensitive.

The syntax for keywords is given below:

   keywords := 'and' | 'and_then' | 'array' |
	       'begin' |
	       'case' | 'const' |
	       'div' | 'do' | 'downto' |
	       'else' | 'end' |
	       'file' | 'for' | 'function' |
	       'goto' |
	       'if' | 'in' |
	       'label' | 'list'
	       'mod' |
	       'nil' | 'not' |
	       'of' | 'or' | 'or_else' | 'otherwise' |
	       'packed' | 'procedure' | 'program' |
	       'record' | 'repeat' |
	       'set' | 'shl' | 'shr' |
	       'then' | 'to' | 'type' |
	       'until' |
	       'var' |
	       'while' | 'with' |
	       'xor'

Attempts to declare an identifier with the same name as a keyword will
be rejected by the compiler.

---------------
2.7 Identifiers
---------------
Identifiers are sequences of letters and digits that start with a letter.
As an extension, Irie Pascal also supports identifiers that contain
and/or start with underscores (_). By default identifiers are not
case-sensitive so
	   x    and     X
are normally considered to be the same identifier. NOTE: There is a
compiler option (-p) that will make keywords and identifiers case-sensitive.
Some programmers prefer case-sensitive languages since these languages
consider identifiers that differ only in case to be different identifiers.
This is often used to allow strongly related identifiers to have the same
"spelling" (i.e. differ only in case).
For example consider the code fragment below.

type
   STUDENT = record
      name : string;
      address : string;
      grade : integer;
   end;
var
   student : STUDENT;

The use of the same "spelling" for the variable "student" and it's
type "STUDENT" emphasize the connection between the two.

You should use this compiler option with caution (or not at all) since
this feature of Irie Pascal is not supported by many (if any) other
Pascal compilers.

The syntax for identifiers is given below:

   identifier = letter { letter | digit }

   letter = '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' |
	    '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' |
	    '_'

   digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'

-----------------
2.7.1  Directives
-----------------
Directives are special identifiers that can be used to give the compiler
extra information about a declaration. The compiler recognizes directives
only at specific points in a declaration, and this recognition is not
affected by and does not affect, any meaning the directive's identifier may
have outside of these specific points. So for example the "forward"
directive is recognized even if the identifier "forward" has been declared
to have some other meaning, and the use of the "forward" directive does
not affect any meaning that "forward" has been declared to have.

NOTE: Irie Pascal supports the "forward" and "external" directives
(see "7 Functions and Procedures" for more information).

---------------------------
2.7.2  Built-in Identifiers
---------------------------
Built-in identifiers are automatically declared by the compiler.
Unlike keywords, you can declare identifiers with the same name as
built-in identifiers, if you do then your declaration will override the
declaration made by the compiler. So for example the following declaration

   type
      boolean = (no, yes);

will override the declaration given by the compiler
   type
      boolean = (false, true);

Some built-in identifiers are extensions and are therefore only
declared when extensions are enabled.

-------------------------------
2.7.3  User Defined Identifiers
-------------------------------
User defined identifiers are created and bound to program entities using
declarations. You can then reference the entities using the identifiers.
Identifiers can be bound to the following kinds of entities:
   Labels, Constants, Types, Variables, Procedures, and Functions.

------------
2.8 Comments
------------
Comments are sequences of characters enclosed in 
      {      or       (* 
and
      }      or       *)

Comments are treated like spaces by the compiler and therefore have no
effect on your program except possible to separate identifiers
(e.g.   the compiler treats i(* comment *)j   like two separate
identifiers        i j    and not a single identifier   ij ).

By default comments can not be nested (i.e. by default comments can not
contain other comments). So comments like

   (* outer (* inner comment *) comment *)

will be terminated at the first close comment marker, like below

   (* outer (* inner comment *)

the last part

    comment *)

will not be treated as part of the comment and will cause a syntax
error.

There is a compiler option (-nc) that causes the compiler to support
nested comments. When this compiler option is enabled the compiler
recognizes the end of comments only when the number of close comment
markers matches the number of open comment markers. So the example
comment above will terminate only after the second *).

Both open comment markers (* and { are considered to be equivalent,
and both close comment markers *) and } are considered to be equivalent.
So attempting to trick the compiler into accepting nested comments with
something like

   (* outer { inner comment } comment *)

will not work.

Nested comments are disabled by default since in Standard Pascal comments
do not nest.

----------
3   Labels
----------
Labels are markers which you can place in front of statements so that
the statements can be referenced by "goto" statements. Labels can
be digit sequences or as an extension identifiers. Leading zeroes
are not significant in labels which are digit sequences, so "009" and "9"
are the same label.

Labels must be declared (in a label declaration group) before they can be
used.

The syntax for label declaration groups is given below:

   label-declaration-group = 'label' label { ',' label } ';'

   label = digit-sequence | identifier

-------------
4   Constants
-------------
Constants can be character literals, string literals, whole numbers, reals,
or constant identifiers. Character and string literals, whole numbers,
and reals have already been described in previous sections
(See "2.1 Character Literals", "2.2 String Literals", "2.3 Whole Numbers",
and "2.4 Reals").
Constant identifiers are identifiers that have been bound to a constant
using a constant declaration.

Constant declarations must be placed in constant declaration groups.

The syntax for constant declaration groups is given below:

   constant-declaration-group =
	 'const' constant-declaration ';' { constant-declaration ';' }

   constant-declaration = identifier '=' constant

   constant = whole-number | real | character-literal | string-literal |
	      constant-identifier

Here is an example of a constant definition group:

const
   Space = ' ';
   message = 'Hello';
   first = 1;
   last = 10;
   DaysInYear = 365.25;
   minint = -maxint;

-----------
4.1 boolean
-----------
Irie Pascal supports two built-in enumerated constants "false" and "true"
which are associated with the built-in type "boolean". The ordinal value
of "false" is zero and the ordinal value of "true" is one.

-----------
4.2 maxbyte
-----------
As an extension Irie Pascal supports the built-in integral constant
"maxbyte" which is equal to the largest byte value supported by
Irie Pascal (255).

-----------
4.3 maxchar
-----------
As an extension Irie Pascal supports the built-in character constant
"maxchar" which is equal to the largest character value supported by
Irie Pascal.

----------
4.4 maxint
----------
Irie Pascal supports the built-in integral constant "maxint" which is
equal to the largest supported integer value.

-----------
4.5 maxword
-----------
As an extension Irie Pascal supports the built-in word constant "maxword"
which is equal to the largest word value supported by Irie Pascal.

-------
4.6 Nil
-------
Irie Pascal supports a built-in constant "nil" associated with all pointer
types, this constant can be assigned to any pointer variable to indicate
that the variable doesn't point anywhere. Any pointer variable can also
be compared with "nil".

--------------
4.7 Permission
--------------
As an extension Irie Pascal supports nine built-in integral constants which
can be used with the built-in procedures "mkdir" and "getfilemode" to
specify or identify read, write, and execute permissions. Three constants
"usr_r", "usr_w", and "usr_x" specify or identify user read, write,
and execute permissions respectively (i.e. permissions associated with the
file or directories owner). Three constants "grp_r", "grp_w", and "grp_x"
specify or identify group read, write, and execute permissions
respectively (i.e. permissions associated with users belonging to the
file or directories owner's group). Three constants "oth_r", "oth_w",
and "oth_x" specify or identify other read, write, and execute permissions
respectively (i.e. permissions associated with users who do not belong
to the file or directory owner's group).

------------
4.8 Platform
------------
As an extension Irie Pascal supports seven integral constants
"platform_dos", "platform_os2", "platform_win32", "platform_linux",
"platform_fbsd", "platform_solaris", and "platform_solaris_sparc" which can
be compared with the value returned by the built-in function "platform" to
determine the platform your program is running on.

------------
4.9 FileMode
------------
As an extension Irie Pascal supports three integral constants "readmode",
"writemode", and "appendmode" which can be used with the built-in "open"
procedure to specify the mode the file should be opened in.
See also "7.2.31 open".

------------
4.10 dir_bit
------------
As an extension Irie Pascal supports the integral constant "dir_bit",
which can be AND'd with "mode" returned by "getfilemode" to determine
if a file is a directory.

---------
5   Types
---------
Types specify sets of valid values, and every constant, variable and
function return value is associated with a specific type. Most types must
be defined before they can be used, the exceptions to this rule are pointer
types. Pointer types are allowed to be used before they are defined to
allow self-referencing structures (such as linked lists) to be built.

Irie Pascal supports the following types:
   enumerated types, subrange types, pointer types, array types,
   string types, record types, set types, file types, list types,
   type-identifiers

Type identifiers are identifiers that have been bound to a type
using a type declaration.

Type declarations must be placed in type declaration groups.

The syntax for type declaration groups is given below:

   type-declaration-group =
	'type' identifier '=' type-declaration ';' { type-declaration ';' }

   type-declaration = identifier '=' type-denoter

   type-denoter = type-identifier | new-type

   type-identifier = identifier

   new-type = new-ordinal-type | new-structured-type | new-pointer-type

   new-ordinal-type = enumerated-type | subrange-type

   new-structured-type = [ 'packed' ] array-type |
			 [ 'packed' ] record-type |
			 [ 'packed' ] set-type |
			 [ 'packed' ] file-type |
			 [ 'packed' ] list-type |
				      string-type

   new-pointer-type = '^' domain-type |
		      '@' domain-type

   domain-type = type-identifier

Here is an example of a type declaration group:

type
   symbols = record
      name : string;
      value : integer;
   end;
   SymbolTable = list of symbols;
   color = (red, green, blue);
   cardinal = 0..maxint;
   IntegerList = array[1..100] of integer;
   characters = set of char;

--------------------
5.1 Enumerated Types
--------------------
Enumerated types specify a finite set of ordered values. Each of these
ordered values is associated with an identifier (a enumerated constant)
and has integer type.

The syntax for enumerated types is given below:

   enumerated-type = '(' identifier-list ')'

   identifier-list = identifier { ',' identifier }

Here are some examples of enumerated types

   (red, blue, green)
   (low, medium, high)
   (married, divorced, widowed, single)

------------------
5.2 Subrange Types
------------------
Subrange types specify a contiguous subset of an ordinal type. This
ordinal type is known as the host type and the values of a subrange
type have the same type as it's host type.

The syntax for subrange types is give below:

   subrange-type = constant '..' constant

Here are some examples of subrange types:

   -100..+100
   true..true
   'a'..'z'

-----------------
5.3 Pointer Types
-----------------
Pointer types specify the special value "nil" and a set of values
identifying variables associated with them. The built-in procedure
"new" creates a pointer variable and associates it with the variables type.
The built-in procedure "dispose" destroys a pointer variable and
disassociates it from the variables type.

The syntax for pointer types is given below:

   pointer-type = '^' domain-type |
		  '@' domain-type

   domain-type = type-identifier

Here are some examples of pointer types:

   ^integer
   ^real

---------------
5.4 Array Types
---------------
Array types specify collections of values of the same type (called
the array's component type) and associates an index type with the
collections. Each member of an array's collection is called an array
element and is identified by a value of the array's index type.
An array's component type may itself be an array, and the component
type of the component type may also be an array. It is sometimes
easier to think about an array of arrays as a multi-dimensional
array (i.e. an array specifying a collection with an axis for each
array component, where each element is identified by values from
each component arrays index type).

Packed arrays of char having a lower bound of one and an upper bound
of two or greater are fixed length strings and have special properties.
Normally values of array types can be tested for equality and inequality
but can not be tested to see whether one is less than the other. Fixed
length strings can be tested not only for equality and inequality but
also can be tested to see whether one is less than the other. Fixed
length strings unlike other arrays can also be read from and written to
text files as a unit using the built-in procedures "read",
"readln", "write", and "writeln".

The syntax for array types is given below

    array-type = 'array' '[' index-type-list ']' 'of' component-type

    index-type-list = index-type { ',' index-type }

    index-type = ordinal-type

    ordinal-type = enumerated-type |
		   subrange-type |
		   ordinal-type-identifier

    component-type = type-denoter

Here are some examples of array types:

    array[1..10] of real
    array[char] of boolean
    array[-456..-450] of integer

NOTE:
As a shorthand notation a multi-dimensional array type can be created
by listing the index types of each of the component arrays.
In other words

    array[1..10, char, boolean] of integer

is a shorthand notation for

    array[1..10] of array[char] of array[boolean] of integer

----------------
5.5 String Types
----------------
As an extension Irie Pascal supports variable length strings using the
built-in type "string". Variable length strings specify collections of
characters whose length does not exceed a maximum value.

The syntax for string types is given below:

   string-type = 'string' |
		 'string' '[' size ']' |
		 'string' '(' size ')'

   size = integer

where
   size is an integral constant, between 1 and 1048576, which specifies the
   maximum length of the string. If size is not specified the maximum
   length used is 255.

For example to create a variable length string type called "name" with
a maximum length of 80 use
   name = string[80];
or
   name = string(80);
To create a variable length string type called 'address' with a maximum
length of 255 use
   address = string;
or
   address = string[255];
or
   address = string(255);

----------------
5.6 Record Types
----------------
Record types specify collections of values. A record type may be empty
(i.e. specify a collection with no values). Each member of a record
type's collection is called a field and is identified by a field
identifier, with the possible exception of the variant selector which
sometimes does not have a field identifier. Each member in a record's
collection has a particular type (which can be a record type).

Sometimes groups of fields in a record type are mutually exclusive.
You can use a variant part in a record type to specify mutually
exclusive groups of fields (these mutually exclusive groups are
called variants). Each variant part contains a variant selector,
the value of the variant selector determines which variant if any
is active.

The syntax for record types is given below:

    record-type = 'record' field-list 'end'

    field-list = fixed-part ';' variant-part [ ';' ] |
		 fixed-part [ ';' ] |
		 variant-part [ ';' ] |
		 empty

    fixed-part = record-section { ';' record-section }

    record-section = id-list ':' type-denoter

    id-list = identifier { ',' identifier }

    variant-part = 'case' variant-selector 'of' variant-body

    variant-selector = [ identifier ':' ] ordinal-type-identifier

    variant-body = variant-list [ [;] variant-part-completer ] |
		   variant-part-completer

    variant-list = variant { ';' variant }

    variant = case-constant-list ':' '(' field-list ')'

    case-constant-list = case-specifier { ',' case-specifier }

    case-specifier = case-constant [ '..' case-constant ]

    case-constant = ordinal-constant

    variant-part-completer = 'otherwise' '(' field-list ')'

Here are some examples of valid record types:

    record end
    record ; end

The record types above are empty.

    record
      name : string;
      grade : integer;
    end

The record type above has two fields which are identified by
"name" of type "string" and "grade" of type "integer".

Given the type below

    type
       clothes = (shoe, pants, shirt);

the following record type is valid

    record
	price : real;
	case kind : clothes of
	   shoe : ( size : integer; );
	   pants : ( waist, length : integer );
	   shirt : ( neck : integer; sleeve : integer )
    end

and contain seven fields

"price", "kind", "size", "waist", "length", "neck", and "sleeve".

The fields "price" and "kind" are always present and the value of the
field "kind" determine which of the variants if any is present. The
variants are ("size") and ("waist" and "length") and ("neck" and "sleeve").
    
-------------
5.7 Set Types
-------------
Set types specify combination of values of the same ordinal type
(called the set's base type). The same value can not appear more
than once. A set can be empty (i.e. have no values).

The syntax for set types is given below:

   set-type = 'set' 'of' ordinal-type

Here are some examples of set types

   set of char
   set of boolean

--------------
5.8 File Types
--------------
File types specify collections of values that are persistent (i.e. they
remain stored when your program is not running) and have the same type
(called the file's component type). File component types can not be file
types or types which contain file types.

The syntax for file types is given below:

   file-type = 'file' 'of' component-type

--------------
5.9 List Types
--------------
As an extension Irie Pascal supports list types. List types are ordered
collections values of a single type (called the list's component type).
Each member of a list's collection is identified by it's position in
the list.

The syntax for list types is given below:

   list-type = 'list' 'of' component-type

---------------------
5.10 Type Identifiers
---------------------
A type identifier is an identifier that is bound to a type with a type
definition.

The following built-in type identifiers are supported by Irie Pascal:
   boolean, char, dir, filename, integer, real, text, word

--------------
5.10.1 boolean
--------------
"boolean" is a built-in enumerated type with two values "false" and "true".
The ordinal value of "false" is zero and the ordinal value of "true" is
one. The conditional statement "if" and the looping statements "while"
and "repeat/until" use boolean expressions. The operators "and", "or",
"not", "and_then", "or_else" operate on boolean expressions.

-----------
5.10.2 byte
-----------
As an extension Irie Pascal supports the built-in type "byte" whoose
values are whole numbers between 0 and 255 (maxbyte)
(see also "2.3 Whole Numbers").

-----------
5.10.3 char
-----------
"char" is a built-in ordinal type with values of the current character
set.

----------
5.10.4 dir
----------
As an extension Irie Pascal supports the built-in type "dir" whose
values are directory handles
(See also "7.2.32 opendir", "7.2.40 readdir", "7.2.44 rewinddir",
and "7.2.6 closedir").

---------------
5.10.5 filename
---------------
As an extension Irie Pascal supports the built-in string type "filename"
which is the recommended type for variables used to store file and
directory names.

--------------
5.10.6 integer
--------------
"integer" is a built-in ordinal type whoose values are whole numbers
between -2147483647 and +2147483647 (maxint)
(see also "2.3 Whole Numbers").

-----------
5.10.7 real
-----------
"real" is a built-in type whose values are numbers with fractional parts
(see also "2.4 Reals").

----------------
5.10.8 registers
----------------
As an extension Irie Pascal supports the built-in type "registers",
which is a variant record type used to store the x86 processor registers
before and after calls to the built-in procedure "intr".

The record layout is given below:

regtype = (byteregs, wordregs)

registers =  record
		 case regtype of
		 byteregs : ( al, ah, afill1, afill2 : byte;
			      bl, bh, bfill1, bfill2 : byte;
			      cl, ch, cfill1, cfill2 : byte;
			      dl, dh, dfill1, dfill2 : byte;
			    );
		 wordregs : eax, ebx, ecx, edx, esi, edi, cflag : word;
	      end;

-----------
5.10.9 text
-----------
"text" is a built-in file type whose values are sequences of lines.
A line is a sequence of characters and every lines in a "text" file
is terminated by an end-of-line character except possibly the last line.

------------
5.10.10 word
------------
As an extension Irie Pascal supports the built-in ordinal type "word"
whoose values are whole numbers between 0 and 4294967295 (maxword)

-------------------
5.11 Integral Types
-------------------
Integral types are one of the following types, or subranges of one
of the following types.
   byte
   integer
   word

-------------
6   Variables
-------------
Variables are typed storage locations, and store values of their types.
Variables must be declared before they are used. Variable identifiers are
identifiers that have been bound to a variable using a variable
declaration. Variable declarations must occur in variable declaration
groups.

The syntax for variable declaration groups is given below:

   variable-declaration-group =
	  'var' variable-declaration { ';' variable-declaration }

   variable-declaration = identifier-list ':' type-denoter

   identifier-list = identifier { ',' identifier }

---------------------
6.1 Pointer Variables
---------------------
Pointer variables store either the special value "nil" or a reference to
another variable. The built-in procedure "new" is used to create variables
referenced by pointer variables. The built-in procedure "dispose" is used
to destroy variables referenced by pointer variables.

-------------------
6.2 Array Variables
-------------------
Array elements can be accessed using the notation
   ArrayName[Index]
where "ArrayName" is the name of the array variable and "Index" is an
expression whose value is one of the values specified by the array's
index type (see also "5.4 Array Types"). You can use either this notation
   ArrayName[Index1][Index2]...[IndexN]
or this notation
   ArrayName[Index1, Index2,...IndexN]
to access array elements in multi-dimensional array variables.

--------------------
6.3 String Variables
--------------------
The individual characters in a string variable can be accessed using
array notation. For example if "name" is a string variable then

   name[2]

accesses the second character in the string stored in "name".

You can use the following built-in procedures and functions to
manipulate variables of string types:
   concat, copy, length, lowercase, pos, reverse, trim, uppercase,
   delete, insert, str, val

You can use the "+" operator to perform string concatenation.
For example here is a hello world program using string concatenation.

   program good(output);
   begin
      writeln('hello' + ' ' + 'world' + '!')
   end.

--------------------
6.4 Record Variables
--------------------
Record variable fields can be accessed using the following notation
   RecordName.FieldName
where "RecordName" is the name of the record variable
and "FieldName" is the name of the field.

------------------
6.5 List Variables
------------------
You can use the following built-in procedures and functions with
variables of list types:
   new, dispose, insert, delete, length

You can access the components of a list variable just like an array
variable. The syntax is
     list-variable '[' integral-expression ']'
where
     integral-expression is an expression of integral type that specifies
     the position in the list of the component being accessed.
For example if "i" is an integer and "lv" is a list variable the
statement below will write each component of "lv".
     for i := 1 to length(lv) do
	writeln(lv[i])

----------------------------
7   Functions And Procedures
----------------------------
Pascal encourages modular programming (i.e. creating complex programs
from smaller and simpler modules). Ideally these modules should resemble
so called "black boxes" where the implementation details about how the
module performs its work is kept hidden inside the module, the user of
the module only needs to know "what" the module does and not "how".

Pascal supports two kinds of modules, "functions" and "procedures".
The difference between functions and procedures is that functions
return a value to their callers and are used in expressions, while
procedures do not return a value to their callers and are used in
procedure statements. Since functions and procedures are so similar
the generic term subroutine will be used to refer to both.

The recommended way of passing information into and out of subroutines
is by use of parameters. The other way of passing information into and
out of subroutines is via global variables, however this method should be
used cautiously since it may make a program more difficult to understand
and maintain. Subroutines may have a list of formal parameters, these
formal parameters are used by the subroutine to access information passed
into it by parameters. When the subroutine is called the caller must supply
an actual parameter for each formal parameter in the subroutine. The
actual parameter is the information being passed into or out of the
subroutine.

Irie Pascal supports four kinds of parameters (value parameters,
variable parameters, function parameters, and procedure parameters).

Value parameters are passed by value (i.e. when the subroutine is called
the actual parameter is an expression, and the value of the expression is
passed into the formal parameter). The subroutine can use the formal
parameter to access the value passed to it but any changes it makes
to the formal parameter will not affect the actual parameter.

Variable parameters are passed by reference (i.e. when the subroutine
is called the actual parameter is a variable, and the address of this
variable is passed into the formal parameter). The subroutine can
use the formal parameter to access the variable (via it's address)
and any changes it makes to the formal parameter will immediately
affect the actual parameter.

Function parameters store addresses of functions (i.e. when the
subroutine is called the actual parameter is a function, and the
address of this function is passed into the formal parameter).
The subroutine can use the address stored in the formal parameter
to call the function.

Procedure parameters store addresses of procedures (i.e. when the
subroutine is called the actual parameter is a procedure, and the
address of this procedure is passed into the formal parameter).
The subroutine can use the address stored in the formal parameter
to call the procedure.

For example here is an example of a simple program with a procedure.

   program simple(output);

      procedure say (message : string);
      begin
	 writeln(message)
      end;

   begin
      say('Hello world')
   end.

The program contains a procedure called "say" which takes a single
value parameter. When the procedure is called "say('Hello world')"
the actual parameter is the expression 'Hello world' which is passed
into the formal parameter "message". So "message" now has the value
'Hello world'. The call to the built-in procedure "writeln" causes the
value of message (i.e. 'Hello world') to be written to the standard
output stream.

Irie Pascal supports recursive function and procedure calls (i.e.
Irie Pascal allows functions and procedures to call themselves
either directly or indirectly). For example a procedure A
can call itself or it can call another procedure say B which in turn
calls procedure A.

Functions and procedures must be declared before they can be called.
This creates a problem when you have functions or procedures that
call each other. For example suppose you have the program below.

   program test(output);

      procedure a(x : integer);
      begin
	 writeln(x);
	 b(x+1)
      end;

      procedure b(x : integer);
      begin
	 writeln(x);
	 a(x+1)
      end;

   begin
      a(1);
   end.

If you try to compile this program the compiler will complain about
the call to "procedure b" that occurs in "procedure a" because this call
occurs before "procedure b" is declared.
You can try to correct this problem by moving the declaration of
"procedure b" before the declaration of "procedure a" like so

   program test(output);

      procedure b(x : integer);
      begin
	 writeln(x);
	 a(x+1)
      end;

      procedure a(x : integer);
      begin
	 writeln(x);
	 b(x+1)
      end;

   begin
      a(1);
   end.

but then the compiler will complain about the call to "procedure a"
that occurs in "procedure b", because this call now occurs before
"procedure a" is declared.

The "forward" directive can be used to solve this kind of problem as
illustrated by the program below:

program test(output);

   procedure b(x : integer); forward;

   procedure a(x : integer);
   begin
      writeln(x);
      b(x+1)
   end;

   procedure b;
   begin
      writeln(x);
      a(x+1)
   end;

begin
   a(1);
end.

You will notice that there are two declarations for procedure b.

The first declaration is called a forward declaration and includes
the name of the procedure and the formal parameter list
("x:integer" in this case) and the directive "forward", but does not
include the procedure block.
The second declaration includes the name of the procedure and the
procedure block but does not include the formal parameter list.

As an extension Irie Pascal supports calling functions and procedures
inside Windows DLLs using the "external" directive.
See 7.3 External Functions And Procedures below for more information.

The syntax for function and procedure declarations is given below:

   function-declaration =
	   function-heading ';' directive-specification |
	   function-identification ';' function-block |
	   function-heading ';' function-block

   procedure-declaration =
	   procedure-heading ';' directive-specification |
	   procedure-identification ';' procedure-block |
	   procedure-heading ';' procedure-block

   procedure-heading = 'procedure' identifier [ formal-parameter-list ]

   procedure-identification = 'procedure' procedure-identifier

   procedure-identifier = identifier

   procedure-block = block

   function-heading =
	'function' identifier [ formal-parameter-list ] ':' result-type

   function-identification = 'function' function-identifier

   function-identifier = identifier

   procedure-block = block

   function-block = block

   formal-parameter-list =
	'(' formal-parameter-section { ';' formal-parameter-section } ')'

   formal-parameter-section = value-parameter-specification |
			      variable-parameter-specification |
			      procedure-parameter-specification |
			      function-parameter-specification

   value-parameter-specification = identifier-list ':' type-identifier

   variable-parameter-specification =
	     'var' identifier-list ':' type-identifier

   procedure-parameter-specification = procedure-heading

   function-parameter-specification = function-heading

   directive-specification = forward-directive | external-directive

   forward-directive = 'forward'

   external-directive = 'external' 'dll' '=' dllname ['name' '=' name]
			[stdcall] [cdecl]

   result-type = type-identifier

----------------------
7.1 Built-in Functions
----------------------
Irie Pascal supports the following built-in functions.

---------
7.1.1 abs
---------
Purpose: Returns the absolute value of its input.
Syntax:
   abs-call = 'abs' '(' num ')'

   num = integral-expression | real-expression

Standard Pascal: Yes
Platforms: All
Example:
   abs(-10) is equal to 10
Notes:
The type of the value returned by this function is always the
same as the type of its input.

------------
7.1.2 arctan
------------
Purpose: Returns the arctangent of its input
Syntax:
   arctan-call = 'arctan' '(' num ')'

   num = integral-expression | real-expression

Standard Pascal: Yes
Platforms: All
Notes:
The type of the value returned by this function is always real.

---------
7.1.3 chr
---------
Purpose: Returns the character whose ordinal value is equal to its input.
Syntax:
   chr-call = 'chr' '(' num ')'

   num = integral-expression

Standard Pascal: Yes
Platforms: All
Notes:

------------
7.1.4 concat
------------
Purpose: Returns a string formed by concatenating its input.
Syntax:
     concat-call = 'concat' '(' s { ',' s } ')'

     s = character-expression | string-expression

Standard Pascal: No
Platforms: All
Notes:
For example you could do something like
   message := concat('Hello', ' ', 'world', '!');
to make message equal to 'Hello world!'
You can also concatenate strings and characters using the "+"
operator like
   message := 'Hello' + ' ' + 'world' + '!';

----------
7.1.5 copy
----------
Purpose: Returns a string formed by copying from an input string starting
	 from a specified position.
Syntax:
       copy-call = 'copy' '(' s ',' p [ ',' n ')'

       s = character-expression | string-expression

       p = integral-expression

       n = integral-expression

Standard Pascal: No
Platforms: All
Notes:
   "s" is the source of characters
   "p" specifies the position from which to start copying characters.
       If "p" is greater than the number of charaters in "s" then
       no characters are copied.
   "n" specifies the number of characters to copy. If "n" is omitted or is
       greater than the number of characters in "s" from "p" to the end,
       then all characters in "s" starting from "p" to the end are copied.

For example
    copy('Testing...', 5, 2)    is equal to 'in'
and
    copy('Testing...', 7)       is equal to 'g...'
and
    copy('Testing...', 1, 1000) is equal to 'Testing...'
and
    copy('Testing...', 50) is equal to ''

--------------
7.1.6 copyword
--------------
Purpose: Returns a string formed by copying a word from an input string.
Syntax:
   copyword-call = 'copyword' '(' s ',' i [ ',' s2 ] ')'

   s = character-expression | string-expression

   i = integral-expression

   s2 = character-expression | string-expression

Standard Pascal: No
Platforms: All
Notes:
    "s" is the input string from which the word is copied
    "i" is the word index.
	Words are numbered starting from one, so it is an error if
	"i" is less than one. If "i" is greater than the number of
	words in "s" then an empty string is returned.
    "s2" if present is a string of special characters used to
	deliminate words. If "s2" is not present then the default
	special characters (i.e. SPACE, TAB, RETURN, and LINEFEED)
	are used to deliminate words.

Here are some simple examples using the default special characters.

   copyword('example', 1) is equal to 'example'
and
   copyword('   example    ', 1) is equal to 'example'
and
   copyword('example', 2) is equal to ''
and
   copyword('   another     example   ', 2) is equal to 'example'

Here are some examples using "," as the special character to
extract fields from comma-deliminated strings.

   copyword('1234, name, value', 1, ',') is equal to '1234'
and
   copyword('1234, name, value', 2, ',') is equal to ' name'
and
   copyword('1234, name, value', 3, ',') is equal to ' value'

See also "countwords"

---------
7.1.7 cos
---------
Purpose: Returns the cosine of its input (expressed in radians).
Syntax:
   cos-call = 'cos' '(' num ')'

   num = integral-expression | real-expression
Standard Pascal: Yes
Platforms: All
Notes:
The type of the value returned by this function is always real.

----------
7.1.8 cosh
----------
Purpose: Returns the hyperbolic cosine of its input.
Syntax:
   cosh-call = 'cosh' '(' num ')'

   num = integral-expression | real-expression
Standard Pascal: No
Platforms: All
Notes:
The type of the value returned by this function is always real.

----------------
7.1.9 countwords
----------------
Purpose: Returns the number of words in an input string.
Syntax:
   countwords-call = 'countwords' '(' s [ ',' s2 ] ')'

   s = character-expression | string-expression

   s2 = character-expression | string-expression

Standard Pascal: No
Platforms: All
Notes:
    "s" is the input string whoose words are counted
    "s2" if present is a string of special characters used to
	deliminate words. If "s2" is not present then the default
	special characters (i.e. SPACE, TAB, RETURN, and LINEFEED)
	are used to deliminate words.

Here are some simple examples using the default special characters.

   countwords('example') is equal to 1
and
   countwords('   example    ') is equal to 1
and
   countwords('   another     example   ') is equal to 2

Here are some examples using "," as the special character to
count fields in comma-deliminated strings.

   countwords('1234, name, value', ',') is equal to 3

See also "copyword"

-------------
7.1.10 dirsep
-------------
Purpose: Returns the directory seperator for the current platform.
Syntax
   dirsep-call = 'dirsep'
Standard Pascal: No
Platforms: All
Notes:
On Windows, DOS, OS/2 the value returned is "\".
On Linux, FreeBSD, Solaris/x86 and Solaris_sparc the value returned is "/".

----------
7.1.11 eof
----------
Purpose: Returns "true" or "false" depending on whether its input
	 (which is a file variable) is at end-of-file.
Syntax:
   eof-call = 'eof' [ '(' f ')' ]

   f = file-variable
 
   If "f" is omitted then the built-in file variable "input" shall be used as
     input to this function.
Standard Pascal: Yes
Platforms: All
Notes:

-----------
7.1.12 eoln
-----------
Purpose: Returns "true" or "false" depending on whether its input
	 (which is a file variable) is at end-of-line.
Syntax:
   eoln-call = 'eoln' [ '(' t ')' ]

   t = text-file-variable

   If "t" is omitted then the built-in text file variable "input" shall be
     used as input to this function.
Standard Pascal: Yes
Platforms: All
Notes:

----------
7.1.13 exp
----------
Purpose: Returns the value of "e" raised to the power of its input.
Syntax:
   exp-call = 'exp' '(' num ')'

   num = integral-expression | real-expression
Standard Pascal: Yes
Platforms: All
Notes:
The type of the value returned by this function is always real.

--------------
7.1.14 fexpand
--------------
Purpose: Returns the full pathname of its input (which is a filename).
Syntax:
   fexpand-call = 'fexpand' '(' s ')'

   s = character-expression | string-expression

Standard Pascal: No
Platforms: All
Notes:

--------------
7.1.15 filepos
--------------
Purpose: Returns the value of the file position indicator of a file.
Syntax:
   filepos-call = 'filepos' '(' f ')'

   f = file-variable

Standard Pascal: No
Platforms: All
Notes:
This function returns an integral value.
The file variable "f" must be open.
For a text file variable the value of the file position indicator may
not be equal to the number of characters read/written so far.
For a binary file the value of the file position indicator is equal to
the number of characters read/written so far.

---------------
7.1.16 filesize
---------------
Purpose: Returns the size of a file.
Syntax:
   filesize-call = 'filesize' '(' f ')'

   f = file-variable

Standard Pascal: No
Platforms: All
Notes:
This function returns an integral value.
The file variable "f" must be open.

-----------
7.1.17 frac
-----------
Purpose: Returns the fractional part of a real expression.
Syntax:
   frac-call = 'frac' '(' r ')'

   r = real-expression

Standard Pascal: No
Platforms: All
Notes:
For example frac(7.234) is equal to 0.234
The type of the value returned by this function is always real.

-------------
7.1.18 getenv
-------------
Purpose: Returns the environment variable specified by its input.
Syntax:
   genenv-call = 'getenv' '(' s ')'

   s = character-expression | string-expression

Standard Pascal: No
Platforms: All
Notes:
If a string matching "s" can not be found in the environment list then an
empty string is returned.

----------
7.1.19 hex
----------
Purpose: Returns the hexadecimal representation of its input as a string.
Syntax:
    hex-call = 'hex' '(' i ')'

    i = integral-expression

Standard Pascal: No
Platforms: All
Notes:
For example hex(16) is equal to '10'.

----------
7.1.20 int
----------
Purpose: Returns the integral part of a real expression.
Syntax:
   int-call = 'int' '(' r ')'

   r = real-expression
Standard Pascal: No
Platforms: All
Notes:
For example int(7.234) is equal to 7.0
The type of the value returned by this function is always real.

---------------
7.1.21 ioresult
---------------
Purpose: Returns the error code of the last input/output operation.
Syntax:
   ioresult-call = 'ioresult'
Standard Pascal: No
Platforms: All
Notes:
By default (when I/O checking is enabled) your program automatically
checks for errors after each I/O operation and terminates with an error
message if any errors are detected. If you do not want this default
behavior you can disable I/O checking (either globally using the "i"
compiler option or locally using the "i" compiler directive) and call
this function to determine if any I/O errors occurred.
(See "Appendix F" of the "Irie Pascal Users Manual" for a list of the error
codes returned by this function.
This function resets the error code to zero after it is called, so if you
call this function twice after an I/O operation then the second call
will always return 0. If you need to refer to the error code more than once
you can save the error code into a variable.
For example:
   errcode := IOResult;
   if errcode <> 0 then
       case errcode of
	1: writeln('Error erasing file');
	2: writeln('Error renaming file');
	3: writeln('File is undefined')
       end

--------------
7.1.22 isalpha
--------------
Purpose: Returns "true" or "false" depending on whether its input
	 is a alphabetic character.
Syntax:
   isalpha-call = 'isalpha' '(' c ')'

   c = character-expression

Standard Pascal: No
Platforms: All
Notes:

-----------------
7.1.23 isalphanum
-----------------
Purpose: Returns "true" or "false" depending on whether its input
	 is a alphanumeric character.
Syntax:
   isalphanum-call = 'isalphanum' '(' c ')'

   c = character-expression

Standard Pascal: No
Platforms: All
Notes:

--------------
7.1.24 isdigit
--------------
Purpose: Returns "true" or "false" depending on whether its input
	 is a digit character.
Syntax:
   isdigit-call = 'isdigit' '(' c ')'

   c = character-expression

Standard Pascal: No
Platforms: All
Notes:

--------------
7.1.25 islower
--------------
Purpose: Returns "true" or "false" depending on whether its input
	 is a lower case letter.
Syntax:
   islower-call = 'islower' '(' c ')'

   c = character-expression

Standard Pascal: No
Platforms: All
Notes:

--------------
7.1.26 isprint
--------------
Purpose: Returns "true" or "false" depending on whether its input
	 is a printable character.
Syntax:
   isprint-call = 'isprint' '(' c ')'

   c = character-expression

Standard Pascal: No
Platforms: All
Notes:

--------------
7.1.27 isspace
--------------
Purpose: Returns "true" or "false" depending on whether its input
	 is a white space character.
Syntax:
   isspace-call = 'isspace' '(' c ')'

   c = character-expression

Standard Pascal: No
Platforms: All
Notes:

--------------
7.1.28 isupper
--------------
Purpose: Returns "true" or "false" depending on whether its input
	 is an upper case letter.
Syntax:
   isupper-call = 'isupper' '(' c ')'

   c = character-expression

Standard Pascal: No
Platforms: All
Notes:

---------------
7.1.29 isxdigit
---------------
Purpose: Returns "true" or "false" depending on whether its input
	 is a hexadecimal digit character.
Syntax:
   isxdigit-call = 'isxdigit' '(' c ')'

   c = character-expression

Standard Pascal: No
Platforms: All
Notes:

-----------------
7.1.30 keypressed
-----------------
Purpose: Returns "true" or "false" depending on whether there are
	 unread key presses waiting in the keyboard buffer.
Syntax:
    keypressed-call = 'keypressed'

Standard Pascal: No
Platforms: Windows, DOS, OS/2
Notes:

-------------
7.1.31 length
-------------
Purpose: Returns the length of its input.
Syntax:
   length-call = 'length' '(' v ')'

   v = list-variable | string-variable

Standard Pascal: No
Platforms: All
Notes:

---------
7.1.32 ln
---------
Purpose: Returns the natural logarithm of its input.
Syntax:
   ln-call = 'ln' '(' num ')'

   num = integral-expression | real-expression
Standard Pascal: Yes
Platforms: All
Notes:
The type of the value returned by this function is always real.

----------
7.1.33 log
----------
Purpose: Returns the logarithm to the base 10 of its input.
Syntax:
   log-call = 'log' '(' num ')'

   num = integral-expression | real-expression
Standard Pascal: Yes
Platforms: All
Notes:
The type of the value returned by this function is always real.

-------------
7.1.34 locase
-------------
Purpose: Returns the lowercase letter corresponding to its input.
	 If there is no lowercase letter corresponding to its input
	 then its input is returned.
Syntax:
   locase-call = 'locase' '(' c ')'

   c = character-expression
Standard Pascal: No
Platforms: All
Notes:

----------------
7.1.35 lowercase
----------------
Purpose: Returns a string formed by converting all upper case characters
	 in its input to lower case characters and leaving all other
	 characters unchanged.
Syntax:
   lowercase-call = 'lowercase' '(' s ')'

   s = string-expression
Standard Pascal: No
Platforms: All
Notes:

----------
7.1.36 odd
----------
Purpose: Returns "true" or "false" depending on whether its input
	 is an odd number.
Syntax:
   odd-call = 'odd' '(' i ')'

   i = integral-expression
Standard Pascal: Yes
Platforms: All
Notes:

----------
7.1.37 ord
----------
Purpose: Returns the ordinal value of its input.
Syntax:
   ord-call = 'ord' '(' o ')'

   o = ordinal-expression

Standard Pascal: Yes
Platforms: All
Notes:
The type of the value returned by this function is always integer
or word.

-----------------
7.1.38 paramcount
-----------------
Purpose: Returns the number of arguments passed to the program.
Syntax:
   paramcount-call = 'paramcount'
Standard Pascal: No
Platforms: All
Notes:
For example the following is the sample program "args.pas".

   program args(output);
   begin
      writeln('Number of program arguments =', paramcount)
   end.

If you compile it and run it as follows
    ipc args
    ivm args this is a test
then the output would be
    Number of program arguments = 4

---------------
7.1.39 paramstr
---------------
Purpose: Returns the ith program argument string where i is its input.
Syntax:
   paramstr-cal = 'paramstr' '(' i ')'

   i = integral-expression
Standard Pascal: No
Platforms: All
Notes:
If there is no ith program argument an empty string is returned.

---------
7.1.40 pi
---------
Purpose: Returns the value of the mathematical constant pi.
Syntax:
   pi-call = 'pi'
Standard Pascal: No
Platforms: All
Notes:

---------------
7.1.41 platform
---------------
Purpose: Returns an integer indicating the platform the program is
	 running on.
Syntax:
   platform-call = 'platform'
Standard Pascal: No
Platforms: All
Notes:
As an extension Irie Pascal supports seven integer constants
"platform_dos", "platform_os2", "platform_win32", "platform_linux",
"platform_fbsd", "platform_solaris", and "platform_solaris_sparc" which
can be compared with the value returned by this function.

----------
7.1.42 pos
----------
Purpose: Searches for one string in another.
Syntax:
   pos-call = 'pos' '(' needle ',' haystack [ ',' start ')'

   needle = character-expression | string-expression

   haystack = character-expression | string-expression

   start = integral-expression

Standard Pascal: No
Platforms: All
Notes:
This functions searches "haystack" starting at position "start"
for "needle" and returns 0 if "needle" is not found or returns the
position of "needle" in "haystack". If "start" is omitted then the search
begins at position 1. If "start" is greater than the length of "haystack"
then 0 is returned.
For example
   pos('o', 'Hello world')    is equal to 5
   pos('o', 'Hello world', 1) is equal to 5
   pos('o', 'Hello world', 6) is equal to 8
   pos('o', 'Hello world', 256) is equal to 0

-----------
7.1.43 pred
-----------
Purpose: Returns an ordinal value that is one less than its input.
Syntax:
   pred-call = 'pred' '(' o ')'

   o = ordinal-expression

Standard Pascal: Yes
Platforms: All
Notes:
The type of the value returned by this function is always the same
as the type of its input.

-------------
7.1.44 random
-------------
Purpose: Returns a pseudo-random number.
Syntax:
   random-call = 'random' [ '(' i ')' ]

   i = integral-expression

Standard Pascal: No
Platforms: All
Notes:
If "i" is not specified then "random" returns a real value between
0 and 1.
If "i" is specified then "random" returns an integral value
between 0 and "i"-1.
See also "7.2.36 randomize".

--------------
7.1.45 readkey
--------------
Purpose: Returns a character containing the next keypress in the keyboard
	 buffer. If there are no keypresses in the keyboard buffer then
	 this function waits until a key is pressed (you can use
	 the "keypressed" function to check for keypresses before
	 calling this function).
Syntax:
   readkey-call = 'readkey'

Standard Pascal: No
Platforms: Windows, DOS, and OS/2
Notes:
If the key pressed is a printable character then this function simply
returns the character, however if the keypressed is not printable
(e.g. Page Up) then this function actually returns two characters on
separate calls to this function. In other words this function has to
be called twice to completly read non-printable key presses from the
keyboard buffer. The first call to this function returns "chr(0)" and
the second returns the scan code for the key.

--------------
7.1.46 reverse
--------------
Purpose: Returns a string created by reversing the characters in its input.
Syntax:
   reverse-call = 'reverse' '(' s ')'

   s = character-expression | string-expression

Standard Pascal: No
Platforms: All
Notes:
For example
    reverse('Hello')    is equal to 'olleH'

------------
7.1.47 round
------------
Purpose: Returns the integral value closes to its input.
Syntax:
   round-call = 'round' '(' r ')'

   r = real-expression

Standard Pascal: Yes
Platforms: All
Notes:
For example round(7.234) is equal to 7.
The type of the value returned by this function is always integer
or word.

----------
7.1.48 sin
----------
Purpose: Returns the sine of its input (expressed in radians).
Syntax:
   sin-call = 'sin' '(' num ')'

   num = integral-expression | real-expression

Standard Pascal: Yes
Platforms: All
Notes:
The type of the value returned by this function is always real.

-----------
7.1.49 sinh
-----------
Purpose: Returns the hyperbolic sine of its input.
Syntax:
   sinh-call = 'sinh' '(' num ')'

   num = integral-expression | real-expression

Standard Pascal: No
Platforms: All
Notes:
The type of the value returned by this function is always real.

----------
7.1.50 sqr
----------
Purpose: Returns the square of its input
Syntax:
   sqr-call = 'sqr' '(' num ')'

   num = integral-expression | real-expression

Standard Pascal: Yes
Platforms: All
Notes:
The type of the value returned by this function is always the same as
the type of its input.

-----------
7.1.51 sqrt
-----------
Purpose: Returns the square-root of its input
Syntax:
   sqrt-call = 'sqrt' '(' num ')'

   num = integral-expression | real-expression

Standard Pascal: Yes
Platforms: All
Notes:
The type of the value returned by this function is always real.

-----------
7.1.52 succ
-----------
Purpose: Returns an ordinal value that is one more than its input.
Syntax:
   succ-call = 'succ' '(' o ')'

   o = ordinal-expression

Standard Pascal: Yes
Platforms: All
Notes:
The type of the value returned by this function is always the same
as the type of its input.

-----------
7.1.53 swap
-----------
Purpose: Returns an integral value calculated by reversing the byte
	 ordering of its input.
Syntax:
   swap-call = 'swap' '(' i ')'

   i = integral-expression

Standard Pascal: No
Platforms: All
Notes:
For example assuming 32 bit little endian integers then 256 is stored in
four bytes as follows:

   0 0 1 0

So swap(256) results in the following integer:

   0 1 0 0

which is equal to 65536

-------------
7.1.54 system
-------------
Purpose: Passes its input to the command processor, which will attempt to
execute it as a command.
Syntax:
   system-call = 'system' '(' s ')'

   s = string-expression

Standard Pascal: No
Platforms: All
Notes:
If there is an error then "system" returns a non-zero value indicating
the kind of error.
If there is no error then "system" returns zero.

See also "7.2.13 Exec".

For example the sample program "batch.pas" below is a very primitive
batch processor. It sends each line in the input file to the command
processor to be executed.

   program batch(f, output);
   var
      f : text;
      s : string;
      err : integer;
   begin
      reset(f);    (* open input file or standard input file *)
      while not eof(f) do
	 begin
	    readln(f, s);
	    writeln('Executing ', s);
	    err := system(s);      (* Pass 's' to the command processor *)
	    writeln('Error code is ', err)
	 end
   end.

----------
7.1.55 tan
----------
Purpose: Returns the tangent of its input (expressed in radians).
Syntax:
   tan-call = 'tan' '(' num ')'

   num = integral-expression | real-expression

Standard Pascal: No
Platforms: All
Notes:
The type of the value returned by this function is always real.

-----------
7.1.56 tanh
-----------
Purpose: Returns the hyperbolic tangent of its input.
Syntax:
   tanh-call = 'tanh' '(' num ')'

   num = integral-expression | real-expression

Standard Pascal: No
Platforms: All
Notes:
The type of the value returned by this function is always real.

-----------
7.1.57 trim
-----------
Purpose: Returns a string created by removing all leading and trailing
	 spaces from its input.
Syntax:
   trim-call = 'trim' '(' s ')'

   s = string-expression

Standard Pascal: No
Platforms: All
Notes:
For example
    trim(' hello ') is equal to 'hello'

------------
7.1.58 trunc
------------
Purpose: Returns an integral value formed by removing the fractional
	 part of its input.
Syntax:
   trunc-call = 'trunc' '(' r ')'

   r = real-expression

Standard Pascal: Yes
Platforms: All
Notes:
For example trunc(7.234) is equal to 7.
The type of the value returned by this function is always integer or word.

-------------
7.1.59 upcase
-------------
Purpose: Returns the uppercase letter corresponding to its input.
	 If there is no uppercase letter corresponding to its input
	 then its input is returned.
Syntax:
   upcase-call = 'upcase' '(' c ')'

   c = character-expression

Standard Pascal: No
Platforms: All
Notes:

----------------
7.1.60 uppercase
----------------
Purpose: Returns a string formed by converting all lower case characters
	 in its input to upper case characters and leaving all other
	 characters unchanged.
Syntax:
   uppercase-call = 'uppercase' '(' s ')'

   s = string-expression

Standard Pascal: No
Platforms: All
Notes:

----------------
7.1.61 urldecode
----------------
Purpose: Decodes a URL encoded string and returns the decoded result.
Syntax:
   urldecode-call = 'urldecode' '(' s ')'

Standard Pascal: No
Platforms: All
Notes:
"s" is the URL encoded string to decode.

The decoding is a simple two step process.
First all pluses "+" are converted to spaces " ".
Second all hexadecimal sequences "%xx" are converted to the
equivalent binary character.

This function can be useful in Common Gateway Interface (CGI)
programs.

-------------
7.1.62 wherex
-------------
Purpose: Returns the column the cursor is on.
Syntax:
   wherex-call = 'wherex'

Standard Pascal: No
Platforms: Windows and DOS
Notes:
The left-most column is column number one (not zero).

-------------
7.1.63 wherey
-------------
Purpose: Returns the row the cursor is on.
Syntax:
   wherex-call = 'wherex'

Standard Pascal: No
Platforms: Windows and DOS
Notes:
The top-most row is row number one (not zero).

-----------------------
7.2 Built-in Procedures
-----------------------
Irie Pascal supports the following built-in procedures.

------------
7.2.1 append
------------
Purpose: Opens a file for writing at the end of the file, and associates
	 a file variable with the opened file.
Syntax:
   append-call = 'append' '(' f [',' s ] ')'

   f = file-variable

   s = filename

Standard Pascal: No
Platforms: All
Notes:
If the file does not exist it is created. If the file exists its contents
are preserved. In either case all writes occur at the end of the file.

If a filename ("s") is specified then the filename is assigned to the
file variable before the file is opened (the file must be closed).
After the file is opened all writes will occur at the end of the file
regardless of calls to the built-in seek procedure (See "7.2.45 rewrite",
"7.2.3 assign", "7.2.31 open", "7.2.43 reset", and "7.2.47 seek").

------------
7.2.2 assert
------------
Purpose: This procedure is based on the C language macro of the same name.
	 The assert procedure can be enabled/disabled using the -A compiler
	 option. When enabled this procedure evaluates its input, which must
	 be a boolean expression. If the expression evaluates to false
	 the program is terminated. If the expression evaluates to true
	 this procedure does nothing.
	 The idea behind this procedure is that you use it during debugging
	 to verify that the variables in your program have the values you
	 expect, and after your program is debugged you don't have to
	 search your program and remove the calls to this procedure, instead
	 you just disable this procedure using a compiler option.
	 You should use this procedure only to test conditions that MUST be
	 true if your program is working correctly. A common mistake in using
	 this procedure is to test normal error conditions that may happen
	 even if your program is bug-free (such as out of memory or
	 invalid user input)
Syntax:
   assert-call = 'assert' '(' b ')'

   b = boolean-expression

Standard Pascal: No
Platforms: All
Notes:

------------
7.2.3 assign
------------
Purpose: Assigns a name to a file variable.
Syntax:
   assign-call = 'assign' '(' f ',' name ')'

   f = file-variable

   name = character-expression | string-expression

Standard Pascal: No
Platforms: All
Notes:
The file variable "f" must be closed.

For example to open a file named 'README.TXT' for reading use
    assign(f, 'README.TXT');
    reset(f);

You can't use this function to rename a file, use the "rename" procedure
if you want to do that.

-----------
7.2.4 chdir
-----------
Purpose: Changes the current directory.
Syntax:
  chdir-call = 'chdir' '(' name ')'

  name = character-expression | string-expression

Standard Pascal: No
Platforms: All
Notes:
"name" specifies the name of the directory that is to be the new
current directory.

-----------
7.2.5 close
-----------
Purpose: Flushes and then closes a file.
Syntax:
   close-call = 'close' '(' f ')'

   f = file-variable

Standard Pascal: No
Platforms: All
Notes:

--------------
7.2.6 closedir
--------------
Purpose: Closes a directory.
Syntax:
   closedir-call = 'closedir' '(' d ')'

   d = directory-variable

Standard Pascal: No
Platforms: All
Notes:
Irie Pascal allows you to open, read, rewind, and close directories
(See also "7.2.32 opendir", "7.2.40 readdir", "7.2.44 rewinddir").

------------
7.2.7 clrscr
------------
Purpose: Clears the screen and moves the cursor to the top left corner
	 of the screen.
Syntax:
   clrscr-call = 'clrscr'
Standard Pascal: No
Platforms: Windows and DOS
Notes:

---------
7.2.8 dec
---------
Purpose: Decrements an ordinal variable by a specified amount or by one.
Syntax:
   dec-call = 'dec' '(' o [',' i ] ')'

   o = ordinal-variable

   i = integral-expression

Standard Pascal: No
Platforms: All
Notes:
If "i" is omitted then "o" is decremented by one.
Using this function is slightly more efficient than using
    o := o - i;

-----------
7.2.9 delay
-----------
Purpose: Stops the program for a specified number of milli-seconds.
Syntax:
   delay-call = 'delay' '(' ms ')'

   ms = integral-expression

Standard Pascal: No
Platforms: Windows, DOS, OS/2
Notes:
"ms" is the number of milli-seconds to stop the program.

-------------
7.2.10 delete
-------------
Purpose: Deletes components from a list or a string.
Syntax:

   delete-call = delete-list | delete-string

   delete-list = 'delete' '(' l ',' start [',' count ] ')'

   delete-string = 'delete' '(' s ',' start [ ',' count ] ')'

   l = list-variable

   start = integral-expression

   count = integral-expression

   s = string-variable

Standard Pascal: No
Platforms: All
Notes:
"start" specifies the position in the list or string to start deleting from.
"count" specifies the number of components to delete. If "count" is omitted
then all components from "start" to the end are deleted.

--------------
7.2.11 dispose
--------------
Purpose: Releases memory allocated using "new".
Syntax:
   dispose-call = dispose-pointer | dispose-list

   dispose-pointer = 'dispose' '(' p ')'

   dispose-list = 'dispose' '(' l ')'

   p = pointer-variable

   l = list-variable
 
Standard Pascal: Yes
Platforms: All
Notes:
After the call to dispose the pointer variable or list variable is
undefined.

------------
7.2.12 erase
------------
Purpose: Deletes a file.
Syntax:
   erase-call = 'erase' '(' f ')'

   f = file-variable

Standard Pascal: No
Platforms: All
Notes:
The file must be closed and have a name associated with it.

-----------
7.2.13 exec
-----------
Purpose: Executes a program.
Syntax:
   exec-call = 'exec' '(' p ',' 'a' ')'

   p = character-expression | string-expression

   a = character-expression | string-expression

Standard Pascal: No
Platforms: All
Notes:
"p" specifies the program to execute.
"a" specifies the arguments (if any) to be passed to the program
(see also "7.1.54 system", "7.1.38 paramcount" and "7.1.39 paramstr").

The code returned by the program if any is stored in the built-in
variable "exitcode".

-----------
7.2.14 exit
-----------
Purpose: Terminates the function/procedure/program in which it is used,
	 and optionally returns a value.
Syntax:
   exit-call = 'exit' [ '(' e ')' ]

   e = expression

Standard Pascal: No
Platforms: All
Notes:
"i" if specifies is the value to be returned by the function or program

If used in a function then "exit" terminates the function.
If used in a function named "f" then "exit(e)" is equivalent to
      f := e;
      exit
If used in a procedure then "exit" terminates the procedure.
If used in a procedure then "exit(x)" is an error since you can
    not return a value from a procedure.
If used not in a function or procedure but in the main program
  then "exit" terminates the program.
If used not in a function or procedure but in the main program
  then "exit(e)" is equivalent to:
      ExitCode := e;
      exit
      (i.e. the program is terminated with "e" as the exit code).

See also "7.2.25 halt".

-----------
7.2.15 fill
-----------
Purpose: Fills a variable with a specified value.
Syntax:
   fill-call = 'fill' '(' v ',' i ')'

   v = variable

   i = integral-expression

Standard Pascal: No
Platforms: All
Notes:
"v" specifies the variable to fill.
"i" is an integral expression which evaluates to the
    value used to fill the variable.

------------
7.2.16 flush
------------
Purpose: Flushes the a file's buffers (i.e. all data waiting to be written
	 to the file is written).
Syntax:
   flush-call = 'flush' '(' f ')'

   f = file-variable

Standard Pascal: No
Platforms: All
Notes:
The file associated with "f" must be open.

-------------
7.2.17 fsplit
-------------
Purpose: Splits a filename into its component parts.
Syntax:
   fsplit-call = fsplit '(' s ',' [ d ] ',' [ n ] ',' [ e ] ')'

   s = character-expression | string-expression

   d = string-variable

   n = string-variable

   e = string-variable

Standard Pascal: No
Platforms: All
Notes:
"s" specifies the filename to be split.
"d" specifies a variable to store the directory part of the filename.
"n" specifies a variable to store the name part of the filename (minus
    the extension.
"e" specifies a variable to store the extension part of the filename.

Although "d", "n", and "e" are optional at least one must be specified.

----------
7.2.18 get
----------
Purpose: Reads the next component in a file into the file variable's buffer.
Syntax:
   get-call = 'get' '(' f ')'

   f = file-variable

Standard Pascal: Yes
Platforms: All
Notes:

--------------
7.2.19 getdate
--------------
Purpose: Retrieves the current system date.
Syntax:
   getdate-call = 'getdate' '(' year ',' month ',' day ',' day_of_week ')'

   year = integer-variable or word-variable

   month = integer-variable or word-variable

   day = integer-variable or word-variable

   day_of_week = integer-variable or word-variable

Standard Pascal: No
Platforms: All
Notes:
"year" stores the current year
"month" stores the current month (1 to 12).
"day" stores the current day of the month (1 to 31)
"day_of_week" stores the current day of the week
     (0 to 6 counting from Sunday).

Suppose the current system date is Wednesday September 30, 1998 then after
    GetDate(year, month, day, day_of_week)
    year = 1998
    month = 9
    day = 30
    day_of_week = 3

------------------
7.2.20 getfiledate
------------------
Purpose: Returns the date a file was last modified.
Syntax:
   getfiledate-call = 'getfiledate' '(' name ',' year ',' month ',' day ')'

   name = character-expression | string-expression

   year = integer-variable or word-variable

   month = integer-variable or word-variable

   day = integer-variable or word-variable

Standard Pascal: No
Platforms: All
Notes:
"name" is the name of the file to test.
"year" stores the year the file was last modified.
"month" stores the month the file was last modified (1 to 12)
"day" stores the day of the month the file was last modified (1 to 31)

------------------
7.2.21 getfilemode
------------------
Purpose: Gets a file's mode.
Syntax:
   getfilemode-call = 'getfilemode' '(' name ',' mode ')'

   name = character-expression | string-expression

   mode = integer-variable or word-variable

Standard Pascal: No
Platforms: All
Notes:
"name" is the name of the file to test.
"mode" stores the file mode.

After the call "mode" can be AND'd with the following built-in constants
to determine information about the file:
The constants "usr_r", "usr_w", and "usr_x" can be AND'd with "mode"
to determine the user read, write, and execute permissions for the file.
The constants "grp_r", "grp_w", and "grp_x" can be AND'd with "mode"
to determine the group read, write, and execute permissions for the file.
The constants "oth_r", "oth_w", and "oth_x" can be AND'd with "mode"
to determine the read, write, and execute permissions for persons other
than the files owner who are not part of the file owner group.
The "dir_bit" constant can be AND'd with "mode" to determine if the file
really is a directory.

------------------
7.2.22 getfiletime
------------------
Purpose: Returns the time a file was last modified.
Syntax:
   getfiletime-call = 'getfiletime' '(' name ',' hour ',' min ',' sec ')'

   name = character-expression | string-expression

   hour = integer-variable or word-variable

   min = integer-variable or word-variable

   sec = integer-variable or word-variable

Standard Pascal: No
Platforms: All
Notes:
"name" is the name of the file to test.
"hour" stores the hour the file was last modified (0 to 23)
"min" stores the minute the file was last modified (0 to 59)
"sec" stores the second the file was last modified (0 to 61)

--------------
7.2.23 gettime
--------------
Purpose: Retrieves the current system time.
Syntax:
   gettime-call = 'gettime' '(' hour ',' min ',' sec ')'

   hour = integer-variable or word-variable

   min = integer-variable or word-variable

   sec = integer-variable or word-variable

Standard Pascal: No
Platforms: All
Notes:
"hour" stores the current hour (0 to 23)
"min" stores the current minute (0 to 59)
"sec" stores the current second (0 to 61)

-------------
7.2.24 gotoxy
-------------
Purpose: Moves the cursor
Syntax:
   gotoxy-call = 'gotoxy' '(' x ',' y ')'

   x = integral-expression

   y = integral-expression

Standard Pascal: No
Platforms: Windows and DOS
Notes:
"x" specifies the screen column (i.e. horizontal coordinate) to move the
cursor to.
"y" specifies the screen row (i.e. vertical coordinate) to move the cursor
to.
For example to move the cursor to the top left hand corner of the screen
use  "gotoxy(1, 1)"

-----------
7.2.25 halt
-----------
Purpose: Terminates the program and optionally returns an integral value
	 to the program's caller.
Syntax:
   halt-call = 'halt' [ '(' i ')' ]

   i = integral-expression

Standard Pascal: No
Platforms: All
Notes:
"i" if specified is the value returned by the program.

----------
7.2.26 inc
----------
Purpose: Increments an ordinal variable by a specified amount or by one.
Syntax:
   inc-call = 'inc' '(' o [ ',' amount ] ')'

   o = ordinal-variable

   amount = integral-expression

Standard Pascal: No
Platforms: All
Notes:
If "amount" is omitted then "o" is incremented by one.
Using this function is slightly more efficient than using
    o := o + amount;

-------------
7.2.27 insert
-------------
Purpose: Inserts a component into a string or a list.
Syntax:
   insert-call = insert-list | insert-string

   insert-list = 'insert' '(' v ',' l [ ',' p ] ')'

   insert-string = 'insert' '(' s1 ',' s2 [ ',' p ] ')'

   v = expression

   l = list-variable

   s1 = character expression | string-expression

   s2 = string-variable

Standard Pascal: No
Platforms: All
Notes:
"v" is the component to insert into the list "l", and must be assignment
   compatible with the list's component type.
"l" is the list variable to insert into.
"s1" s the component to insert into the string "s2".
"s2" is the string variable to insert into.
"p" if specified indicates the position to perform the insertion. If "p" is
   omitted the insertion is performed at the end of the string or list.

-----------
7.2.28 intr
-----------
Purpose: Executes a x86 processor interrupt.
Syntax:
   intr-cal = 'intr' '(' intno ',' regs ')'

   into = integral-expression

   regs = registers-variable

Standard Pascal: No
Platforms: DOS only
Notes:
For example the following simple program uses interrupt $10
to clear the screen.

program cls;
var
   regs : registers;
begin
   fill(regs, 0);
   regs.eax := $0012;
   intr($10, regs)
end.
------------
7.2.29 mkdir
------------
Purpose: Makes a directory
Syntax:
   mkdir-call = 'mkdir' '(' name ')'

   name = character-expression | string-expression
Standard Pascal: No
Platforms: All
Notes:
"name" is the name of the directory to create.

----------
7.2.30 new
----------
Purpose: Initializes a list or creates a variable for a pointer.
Syntax:
   new-call = new-list | new-pointer

   new-list = 'new' '(' l ')'

   new-pointer = 'new' '(' p ')'

   l = list-variable

   p = pointer-variable

Standard Pascal: Yes
Platforms: All
Notes:

-----------
7.2.31 open
-----------
Purpose: Open a file.
Syntax:
   open-call = 'open' '(' fv ',' name ',' mode ')'

   fv = file-variable

   name = character-expression | string-expression

   mode = integral-expression

Standard Pascal: No
Platforms: All
Notes:
"name" is the name of the file to open.
"mode" is the file mode. You can use the built-in constants "readmode",
"writemode", and "appendmode" to specify the file mode. The "readmode"
and "writemode" constants can be added or or'd together to specify that
the file be opened for both reading and writing.

For example

   open(f, "test.txt", readmode+writemode);

will open the file "test.txt" for both reading and writing. It is an
error if the file "test.txt" does not exist. If you wish to create a new
file for reading and writing you must create it first with "rewrite" or
using "open" with "writemode" only, and then close the filee, before
opening it again for reading and writing.

See also "7.2.1 append", "7.2.43 reset", "7.2.45 rewrite".

--------------
7.2.32 opendir
--------------
Purpose: Opens a directory.
Syntax:
   opendir-call = 'opendir' '(' d, name ')'

   d = directory-variable
   name = string-variable

Standard Pascal: No
Platforms: All
Notes:
"d" is the directory variable associate with the opened directory
"name" is the name of the directory to open
Irie Pascal allows you to open, read, rewind, and close directories
(See "7.2.6 closedir", "7.2.40 readdir", and "7.2.44 rewinddir").

-----------
7.2.33 pack
-----------
Purpose: Copies some or all of the contents of an unpacked array
	 into a packed array.
Syntax:
   pack-call = 'pack' '(' u ',' x ',' p ')'

   u = unpacked-array-variable

   x = expression

   p = packed-array-variable

	where "u" is an unpacked array
	  and "x" is an expression that is assignment compatible
	      with the index type of "u" and specifies the first
	      element of "u" to copy.
	  and "p" is a packed array
Standard Pascal: Yes
Platforms: All
Notes:
The elements of "u" and "a" must have the same type.

For example suppose you have the following arrays

   p : packed array[1..10] of integer;
   u : array[-10..10] of integer;

then

   pack(u, 1, p)

copies elements 1 to 10 of "u" into elements 1 to 10 of "p".
Or in a more complicated example

   pack(u, 9, p)

copies elements 9 to 10 of "u" into elements 1 to 2 of "p"

-----------
7.2.34 page
-----------
Purpose: This procedure is supposed to affect a text file in such
	 a way that subsequent output to the file appears on a new
	 page.
Syntax:
   page-call = 'page' '(' t ')'

   t = text-file-variable

Standard Pascal: Yes
Platforms: All
Notes:
Currently this procedure simply writes a form-feed to the text file.

----------
7.2.35 put
----------
Purpose: Writes the contents of a file's buffer to a file and
	 empties the file's buffer leaving it undefined.
Syntax:
   put-call = 'put' '(' f ')'

   f = file-variable

Standard Pascal: Yes
Platforms: All
Notes:
If "f" is a file variable then the file's buffer can be accessed
with "f^" or "f@".

----------------
7.2.36 randomize
----------------
Purpose: Initializes the random number generator with a seed.
Syntax:
   randomize-call = 'randomize' [ '(' i ')' ]

   i = integral-expression

Standard Pascal: No
Platforms: All
Notes:
"i" if specified is the seed used to initialize the random number generator.
If "i" is omitted then the random number generated is initialized with a
seed derived from the current system date and time. Specifying "i" is useful
if you want a repeatable sequence of random numbers.

--------------
7.2.37 rawread
--------------
Purpose: Reads up to a specified number of characters into a
	 character buffer.
Syntax:
   rawread-call = 'rawread' '(' f ',' buffer ',' count ',' actual ')'

   f = file-variable

   buffer = array-variable

   count = integral-expression

   actual = integer-variable or word-variable

Standard Pascal: No
Platforms: All
Notes:
"buffer" must be a packed array of char variable and stores the characters
   read by this procedure.
"count" specifies the maximum number of characters to read.
"actual" stores the actual number of characters read by this procedure.
"actual" may be less than "count" if there was an I/O error (you can check
for this by disabling I/O checking and using the IOResult function) or if
end of file was reached.

---------------
7.2.38 rawwrite
---------------
Purpose: Writes up to a specified number of characters from a character
	 buffer to a file.
Syntax:
   rawwrite-call = 'rawwrite' '(' f ',' buffer ',' count ',' actual ')'

   f = file-variable

   buffer = array-variable

   count = integral-expression

   actual = integral-variable

Standard Pascal: No
Platforms: All
Notes:
"buffer" must be a packed array of char variable and stores the characters
   to be written by this procedure.
"count" specifies the maximum number of characters to write.
"actual" stores the actual number of characters written by this procedure.
"actual" may be less than "count" if there was an I/O error (you can check
for this by disabling I/O checking and using the IOResult function).

-----------
7.2.39 read
-----------
Purpose: This procedure reads data from a file into one or more variables.
Syntax:
   read-call = 'read' read-parameter-list

   read-parameter-list =
     '(' [ file-variable ',' ] variable-access { ',' variable-access } ')'

Standard Pascal: Yes
Platforms: All
Notes:
If the file-variable is omitted then the built-in text file variable
"input" is used.
When this procedure reads from a text file it first attempts to convert
the text data into binary data suitable for storage in variables. In
addition when reading from a text file the variables in the variable list
must be of type real, string, char, or an integral type

--------------
7.2.40 readdir
--------------
Purpose: Reads a directory (i.e. retrieves the name of a file in the
	 directory).
Syntax:
   readdir-call = 'readdir' '(' d ',' name ')'

   d = directory-variable

   name = string-variable

    where "d" is a directory variable (i.e. a variable of the built-in
	  type "dir").
Standard Pascal: No
Platforms: All
Notes:
"d" is the directory variable associated with the directory to read.
"name" stores the filename of the next file in the directory.
See also "7.2.6 closedir", "7.2.32 opendir", and "7.2.44 rewinddir".

-------------
7.2.41 readln
-------------
Purpose: This procedure reads a line of data from a text file into one or
	 more variables. Any data left on the line after the read is ignored.
Syntax:
   readln-call = 'readln' readln-parameter-list

   readln-parameter-list =
     [ '(' ( file-variable | variable-access ) { ',' variable-access } ')' ]

Standard Pascal: Yes
Platforms: All
Notes:
If the file-variable is omitted then the built-in text file variable
"input" is used.
When this procedure reads from a text file it first attempts to convert
the text data into binary data suitable for storage in variables. In
addition when reading from a text file the variables in the variable list
must be of type real, string, char, or an integral type.

-------------
7.2.42 rename
-------------
Purpose: Renames the file a file.
Syntax:
   rename-call = 'rename' '(' f ',' name ')'

   f = file-variable

   name = character-expression | string-expression

Standard Pascal: No
Platforms: All
Notes:
This procedure changes the name of the file associated with the
file variable "f" to "name". This is more than just changing the name
associated with the file variable, the actual name of the file is changed.

------------
7.2.43 reset
------------
Purpose: Opens a file for reading.
Syntax:
   reset-call = 'reset' '(' f [ ',' name ] ')'

   f = file-variable

   name = character-expression | string-expression

Standard Pascal: Yes
Platforms: All
Notes:
If "name" is specified then "name" is assigned to the file variable before
the file is opened (the file must be closed). See also "7.2.1 append",
"7.2.45 rewrite", "7.2.3 assign", "7.2.31 open", and "7.2.47 seek".

----------------
7.2.44 rewinddir
----------------
Purpose: Rewinds a directory so that reads start with the first
	 file in the directory.
Syntax:
   rewind-call = 'rewinddir' '(' d ')'

   d = directory-variable

Standard Pascal: No
Platforms: All
Notes:
See also "7.2.6 closedir", "7.2.32 opendir", and "7.2.40 readdir".

--------------
7.2.45 rewrite
--------------
Purpose: Opens a file for writing.
Syntax:
   rewrite-call = 'rewrite' '(' f [ ',' name ] ')'

   f = file-variable

   name = character-expression | string-expression

Standard Pascal: Yes
Platforms: All
Notes:
If the file exists it's contents are deleted.
If the file does not exist it is created.
If a filename ("n") is specified then the filename is assigned to the
file variable before the file is opened (the file must be closed). See
also "7.2.1 append", "7.2.3 assign", "7.2.32 open", "7.2.43 reset",
and "7.2.47 seek".

------------
7.2.46 rmdir
------------
Purpose: Removes (deletes) a directory
Syntax:
   rmdir-call = 'rmdir' '(' name ')'

   name = character-expression | string-expression

Standard Pascal: No
Platforms: All
Notes:
"name" is the name of the directory to delete.

-----------
7.2.47 seek
-----------
Purpose: Sets the position indicator for a file.
Syntax:
   seek-call = 'seek' '(' f ',' offset ')'

   f = file-variable

   offset = integral-expression

Standard Pascal: No
Platforms: All
Notes:
"offset" specifies the new position indicator for the file.
The file associated with "f" must be open with Read access or Read/Write
access, this is necessary because the built-in functions "eof" and "eoln"
need to be able to read the file if the program can seek to any location
in the file.
See also "7.1.11 eof", "7.1.12 eoln", "7.2.31 open", "7.2.43 reset".

------------------
7.2.48 setfiledate
------------------
Purpose: Sets a files date (i.e. last modification date).
Syntax:
   setfiledate-call = 'setfiledate' '(' f ',' year ',' mon ',' day ')'

   f = file-variable

   year = integral-expression

   mon = integral-expression

   day = integral-expression

Standard Pascal: No
Platforms: All
Notes:
"year" specifies the year.
"mon" specifies the month (1 to 12)
"day" specifies the day (1 to 31).

------------------
7.2.49 setfiletime
------------------
Purpose: Sets a files time (i.e. last modification time).
Syntax:
   setfiletime-call = 'setfiletime' '(' f ',' hour ',' min ',' sec ')'

   f = file-variable

   hour = integral-expression

   min = integral-expression

   sec = integral-expression

Standard Pascal: No
Platforms: All
Notes:
"hour" specifies the hour (0 to 23)
"min" specifies the minute (0 to 59)
"sec" specifies the second (0 to 61).

------------
7.2.50 sleep
------------
Purpose: Pauses execution of the program for a specified number of seconds.
Syntax:
   sleep-call = 'sleep' '(' i ')'

   i = integral-expression

Standard Pascal: No
Platforms: All
Notes:
"i" specifies the number of seconds to sleep.

----------
7.2.51 str
----------
Purpose: Converts an integral or real expression into a string and
	 assigns the converted string to a variable.
Syntax:
   str-call = str-integral | str-real

   str-integral = 'str' '(' i [':' width] ',' s ')'

   str-real = 'str' '(' r [ ':' width [ ':' frac ] ] ',' s ')'

   i = integral-expression

   width = integral-expression

   s = string-variable

   r = real-expression

   frac = integral-expression

Standard Pascal: No
Platforms: All
Notes:
"i" specifies the integral expression to convert
"s" stores the converted string.
"width" specifies the maximum width of the converted string
"frac" specifies the number of digits after the decimal point.

If "width" is omitted then eight is assumed for integral conversion
and nine is assumed for real conversions.

If "frac" is omitted then the real expression is converted into a
string in exponential form.
If "frac" is present then the real expression is converted into
a string in fixed form.

For example
    str(1034:6, s) will store '  1034' in "s"
    str(3.1:8, s) will store '3.1E+001' in "s"
    str(-3.14:6:2, s) will store ' -3.14' in "s"
The string value is padded on the left if necessary.

---------------------
7.2.52 textbackground
---------------------
Purpose: Sets the current text background color.
Syntax:
   textbackground-call = 'textbackground' '(' bc ')'

   bc = integral-expression

Standard Pascal: No
Platforms: Windows only
Notes:
"bc" specifies the text background color.
Calling this function does not immediately change the background color
of the screen. The background colors of characters already on the screen
are not changed, what this function does is to change the background color
of characters written to the screen after the function call.
The following table shows the values of "bc" and
the corresponding background colors.

value  color
  0    Black
  1    Blue
  2    Green
  3    Cyan
  4    Red
  5    Magenta
  6    Brown
  7    White

----------------
7.2.53 textcolor
----------------
Purpose: Sets the current text foreground color.
Syntax:
   textcolor-call = 'textbackground' '(' fc ')'

   fc = integral-expression

Standard Pascal: No
Platforms: Windows only
Notes:
"fc" specifies the text foreground color.
Calling this function does not immediately change the foreground color
of the screen. The foreground colors of characters already on the screen
are not changed, what this function does is to change the foreground color
of characters written to the screen after the function call.
The following table shows the values of "fc" and
the corresponding foreground colors.

value  color
  0    Black
  1    Blue
  2    Green
  3    Cyan
  4    Red
  5    Magenta
  6    Brown
  7    White
  8    Grey
  9    Light Blue
 10    Light Green
 11    Light Cyan
 12    Light Red
 13    Light Magenta
 14    Yellow
 15    High-intensity white

-------------
7.2.54 unpack
-------------
Purpose: Copies some or all of the elements of a packed array into
	 an unpacked array.
Syntax:
   unpack-call = 'unpack' '(' p ',' u ',' x ')'

   p = packed-array-variable

   x = expression

   u = unpacked-array-variable

Standard Pascal: Yes
Platforms: All
Notes:
"x" must be assignment compatible with the index type of "u" and specifies
the position in "u" to receive the first array element.
The elements of "u" and "a" must have the same type.

For example suppose you have the following arrays

   p : packed array[1..10] of integer;
   u : array[-10..10] of integer;

then

   unpack(p, u, 1)

copies elements -10 to -1 of "p" into elements 1 to 10 of "u".

----------
7.2.55 val
----------
Purpose: Converts a string expression into an integer, word or real value
	 and assigns the converted value to a variable.
Syntax:
   val-call = val-integer | val-word | val-real

   val-integer = 'val' '(' s ',' i ',' offset ')'

   val-word = 'val' '(' s ',' w ',' offset ')'

   val-real = 'val' '(' s ',' r ',' offset ')'

   s = character-expression | string-expression

   i = integer-variable

   w = word-variable

   r = integer-variable

Standard Pascal: No
Platforms: All
Notes:
"i" stores the converted integer value
"w" stores the converted word value
"r" stores the converted real value
"offset" stores the position of the first character in "s" that could not
  be converted or zero if all characters where converted.

For example given integer variables "i" and "x" the following statement
    val('123EB', i, x)
will store 123 in "i" and 4 in "x".

------------
7.2.56 write
------------
Purpose: This procedure writes data from one or more variables into a file
Syntax:
   write-call = 'write' write-parameter-list

   write-parameter-list =
     '(' [ file-variable ',' ] write-parameter { ',' write-parameter } ')'

   write-parameter = expression [ ':' expression [ ':' expression ] ]

Standard Pascal: Yes
Platforms: All
Notes:
When this procedure writes to a non-text file then the write-parameters
are simply expressions, and the binary value of the expressions are
written to the file.
When this procedure writes to a text file it first attempts to convert
the binary data stored in the variables into text data. In addition
when writing to a text file the variables in the variable list must
must be of type boolean, real, string, char, or an integral type.

--------------
7.2.57 writeln
--------------
Purpose: This procedure writes a line of data from one or more variables
	 into a text file
Syntax:
   writeln-call = 'writeln' writeln-parameter-list

   writeln-parameter-list =
     [ '(' ( file-variable | write-parameter ) { ',' write-parameter } ')' ]

   write-parameter = expression [ ':' expression [ ':' expression ] ]

Standard Pascal: Yes
Platforms: All
Notes:
When this procedure writes to a text file it first attempts to convert
the binary data stored in the variables into text data. In addition
when writing to a text file the variables in the variable list must
must be of type boolean, real, string, char, or an integral type.

-------------------------------------
7.3 External Functions And Procedures
-------------------------------------
As an extension Irie Pascal supports calling functions and procedures
in Windows DLLs, using the "external" directive. Only 32 bit DLLs are
supported. This is a powerful feature of Irie Pascal, however using this
feature successfully requires you to understand a little bit about the
calling conventions (i.e. how parameters are passed to and from functions)
used by Windows DLLs. Windows DLLs support two calling conventions
"stdcall" and "cdecl", the one most often used is "stdcall". By default
Irie Pascal will assume that the calling convention is "stdcall" unless
"cdecl" is specified.

Unfortunately the two calling conventions are not implemented in
exactly the same way by all Windows compilers. So if you want to
call functions and procedures in a DLL you may need to know which
compiler was used to create it (and also what compiler options were used).

This document does not describe the various ways different compilers
implement the "stdcall" and "cdecl" calling conventions. Instead what
this document does is describe how Irie Pascal implements the "stdcall"
and "cdecl" calling conventions.

1) Irie Pascal passes parameters from right to left for both "stdcall"
and "cdecl".

2) Irie Pascal expects the callee to cleanup the stack using "stdcall",
but the caller cleans up the stack using "cdecl".

3) Irie Pascal searches for the function or procedure in the DLL using
the name given, but if the function or procedure is not found then "_"
is prefixed to the name and the DLL is searched again.
Note: This is done because some compilers automatically prefix function
and procedure names with "_" but other compilers don't.

4) Irie Pascal expects values of the following types (i.e. byte, char,
integer, word, subranges, enumerated types) to be returned in the EAX
register.

5) Irie Pascal expects values of real type to be returned on the math
coprocessor stack.

6) Irie Pascal expects values of record and array type to be returned
using a hidden pointer passed by the caller (i.e. the caller is expected
to pass a pointer to the memory location where the callee should put the
return value).

7) Irie Pascal does not support returning values of the following types
(i.e. dir, file, list, set, string) from external functions and procedures.

8) Irie Pascal supports passing expressions of the following types by
value (i.e byte, char, integer, real, record, word, enumerated types,
and subrange types).

9) Irie Pascal supports passing variables of the following types by
reference (i.e. array, byte, char, integer, real, record, word, string,
enumerated types, and subrange types).

10) Irie Pascal does not yet support passing functions or procedures.
This feature would be very useful since it would allow Irie Pascal programs
to take full advantage of the Windows API (which uses call-back functions
heavily). This feature didn't make it into the current release largely
because it will be tricky to implement.

In order call external functions and procedures successfully you may
need to understand a little bit about Irie Pascal types.
Below is a brief description if Irie Pascal types.

First the simple types:
byte - This is an 8 bit unsigned numeric (integral) type.
char - This is an 8 bit non-numeric type.
enumerated (including boolean) - 32 bit numeric (non-integral) type.
integer - 32 bit signed numeric (integral) type.
real - 64 bit signed numeric (non-integral) type.
word - 32 bit unsigned numeric (integral) type.

subrange types are treated like their host types (e.g. subranges of
char are treated like chars, and subranges of integer are treated like
integers).

Next the comples types:
array - These are contiguous sequences of the elements.
	For example
	      array[1..4] of integer
	is simply a sequence of 4 integers (with no gaps in between).
	Multi-demensional arrays are treated as follows:
	  array[m][n][o][p] of type
	is treated like
	  array[m] of array[n] of array[o] of array[p] of type.
	NOTE: This is the opposite of the way demensions are ordered
	by C language compilers.
pointer - This is a 32 bit numeric type, which contains the offset of
	  a variable from the beginning of the IVM Executables Data segment.
	  The values of pointers are probably meanless outside of Irie Pascal
	  programs and therefore pointers can not be passed to or from
	  external functions. However if you wish to pass the address of
	  a variable to an external function or procedure you can just
	  pass it by reference. 
record - These are simply sequences of the fields. The size of the gaps
	 (if any) between fields is determined by the size of the fields
	 and the current alignment setting (see the -a compiler option).
string -  These are length prefixed sequences of characters.
	  Strings with maximum lengths of less than or equal to 255 are
	  prefixed by a byte containing the actual length of the string.
	  String with maximun lengths greater than or equal to 256 are
	  prefixed by an integer containing the actual length of the
	  string. NOTE: This representation is typical of how strings
	  are represented in Pascal but is very different from the way
	  way strings are repesented in C (i.e. null terminated sequences
	  of char).

The other types (such as "file" and "list") are not described here since
they can not be passed to or from external functions or procedures.

Most functions in Windows DLLs are written in C, so you will usually
be converting back of forth between C types and Irie Pascal types. Below
is a quick conversion table, which shows the Irie Pascal type which most
closely matches various C types. You can use the table below to help you
decide which Irie Pascal type to use when passing parameters. It is assumed
in the table below that the C compiler is a 32 bit compiler. Irie Pascal
does not support calling functions or procedures in 16 bit DLLs.

C type - Recommended Irie Pascal type(s)
-----------------------------------------
BOOL - byte or boolean
char - char
WORD, DWORD, int, long - integer or word
short - not supported
double - real
float - not supported
enum - byte or enumerated
struct - record
array - array
pointer - pass by reference

NOTE: The C types in all capitals like BOOL, WORD, and DWORD are not
actually defined as part of the C language, but are common types
declared in C programs.

Using BOOL parameters:
----------------------
The C languages does not define a boolean type so it is common to define
one, however there are two popular ways this can be done. One way is to
define the boolean type as "char" or "unsigned char", in which case the
nearest Irie Pascal type is "byte". The other common way to define the
boolean type is as a enumerated type with the values "false", and "true".
However sometimes C compiler treat enumerated types with less than 256
elements as "unsigned char", and other times as "int". If the enumerated
type is treated as "unsigned char" then again the nearest Irie Pascal type
is "byte", if on the other hand the enumerate type is treated like "int"
then the nearest Irie Pascal type is "boolean".

Using WORD, DWORD, int and long parameters:
-------------------------------------------
The C types "WORD", "DWORD", "int" and "long" are all 32 bit integral types
so the nearest Irie Pascal types are "integer" or "word" depending on whether
you wish to treat the types as signed or unsigned.

Using short parameters:
-----------------------
The C type "short" is not directly supported, since it is a 16 bit type.
If you wich to pass "short" it is recommended that you create a record
type like below
type
   short = record
	     low : byte;
	     high : byte
	   end;

You can then pass variables of type "short". You can convert from
"short" to integer as follows

    i := s.low + s.high shr 8;

where
    i is an integer variable
  and
    s is a "short" variable.

Similarly you can convert from integer to short as follows:

    s.low := i mod 256;
    s.high := i div 256;

Using array parameters:
-----------------------
Passing multi-dimensional arrays between Irie Pascal and C requires
care since the ordering used by Pascal and C for the dimensions is
opposite (i.e.

   a : array[1..4][1..2] of integer;

is equivalent to

   int a[2][4];

Using pointer parameters:
-------------------------
1) The C language does not support call by reference so it is common when
passing a variable to function to be modified, to pass a pointer to
the variable. The function can't modify the pointer but it can modify
the variable. Pascal supports call by reference so you should use it in
cases where you need to pass a pointer to a variable.
2) The C language also does not support passing arrays to functions, however
the close relationship between arrays and pointers in C means that passing
a pointer to the first element in an array is almost equivalent to
passing the array. Irie Pascal supports passing arrays, so in this case
you should pass an array by reference.
3) A special case to passing arrays, is passing C strings (arrays of
null-terminated chars). The solution is to pass an array of char by
reference, however you also have to convert between the string representation
used by C (i.e. null-terminated array of char) to the string representation
used by Irie Pascal (i.e. length prefixed array of char).

When you want to call a C function that expects a pointer parameters it is
up to you to determine (perhaps by reading a description of the function)
which one of three scenarios just described in being used.

The sample program "winhello.pas" is an example of how to call a function
in a Windows DLL.

The syntax for the "external" directive is given below:

   external-directive = 'external' 'dll' '=' dllname ['name' '=' name]
			[stdcall] [cdecl]
where
   "dllname" is a string literal that is the name of the Windows DLL to call
and
   "name" is the name of the function or procedure in the DLL
   If "name" is not specified then the name of the function or procedure
   in the DLL is assumed to be the same as the name of the function or
   procedure in the declaration.
and
   "stdcall" specifies that the stdcall calling sequence should be used
   (This is the default).
and
   "cdecl" specifies that the cdecl calling sequence should be used

-------------
8 Expressions
-------------
Expressions specify a sequence of operations to be performed that
result in a single value of a particular type.

The syntax for expressions is given below:

   expression = shift-expression [ relational-operator shift-expression]

   shift-expression = simple-expression [ shift-operator simple-expression]

   simple-expression = term { adding-operator term }

   term = factor { multiplying-operator factor }

   factor = [sign] unsigned-constant |
	    [sign] variable-access |
	    [sign] '(' expression ')' |
	    function-designator |
	    'not' factor |
	    set-constructor

   sign = '+' | '-'

   unsigned-constant = unsigned-whole-number |
		       unsigned-real |
		       character-string |
		       constant-identifier |
		       'nil'

   variable-access = entire-variable |
		     component-variable |
		     identified-variable |
		     buffer-variable

   entire-variable = variable-identifier

   component-variable = indexed-variable | field-designator

   indexed-variable =
      array-variable '[' index-expression { ',' index-expression } ']'

   field-designator = record-variable '.' field-specifier |
		      field-designator-identifier

   field-specifier = field-identifier

   identified-variable = pointer-variable '^' | pointer-variable '@'

   buffer-variable = file-variable '^' | file-variable '@'

   set-constructor = '[' [ member-designator { ',' member-designator } ] ']'

   member-designator = expression [ '..' expression ]

   function-designator = function-identifier [ actual-parameter-list ]

   actual-parameter-list = '(' actual-parameter { ',' actual-parameter } ')'

   actual-parameter = expression |
		      variable-access |
		      procedure-identifier |
		      function-identifier
		      omitted-parameter

   omitted-parameter =

   relational-operator = '=' | '<>' | '<' | '<=' | '>' | '>=' | 'in'

   shift-operator = 'shl' | shr'

   adding-operator = '+' | '-' | 'or' | 'or_else' | 'xor'

   multiplying-operator = '*' | '/' | 'div' | 'mod' | 'and' | 'and_then'

-------------
8.1 Operators
-------------
Below is a table of all the operators supported by Irie Pascal in
order of decreasing precedence. All operators on the same line have
the same precedence.

   -----------------------------
   not
   -----------------------------
   *  /  div  mod  and  and_then
   -----------------------------
   +  -  or  or_else  xor
   -----------------------------
   shl  shr
   -----------------------------
   =  <>  <  <=  >  >=  in
   -----------------------------

------------------
8.1.1 Not Operator
------------------
The "not" operator takes a single operand and specifies one of two
operations depending on the type of the operand. If the operand is
of type boolean then the "not" operator specifies a boolean NOT (i.e
if the value of the operand is true the result of the operation is false
and if the value of the operand is false the result of the operation is
true). If the operand is of integral type then the "not" operator specifies
a bitwise NOT (i.e. the result of the operation is calculated by flipping
all the bits in the operand).

----------------
8.1.2 * Operator
----------------
The "*" operator takes two operands and specifies one of two operations
depending on the type of the operands.

If the operands are of integral type or real then the "*" operator
specifies multiplication. If both operands are of integral type then the
result of the operation is of integral type. If both operands are
of type real then the result of the operation is of type real. If one
operand is of integral type and the other is of type real then the
integral operand is converted to real before the multiplication is performed
and the result of the operation is of type real.

If the operands are set-types then the "*" operator specifies set
intersection (i.e. the result of the operation is a set whose members
are those members common to both operands).

----------------
8.1.3 / Operator
----------------
The "/" operator takes two operands and specifies division. The operands
must be of integral type or real type, and the integral operands are first
converted to real before the division is performed. The result of the
operation is of type real.

------------------
8.1.4 Div Operator
------------------
The "div" operator takes two operands and specifies division. The operands
must both be of integral type. The result of the operation is of integral
type (note: The remainder from the division is discarded).

------------------
8.1.5 Mod Operator
------------------
The "mod" operator takes two operands and specifies modulus. The operands
must both be of integral type. When the operands are positive then the
result of the operation is the remainder from dividing the left operand by
the right operand. The result of the operation is of integral type. 

------------------
8.1.6 And Operator
------------------
The "and" operator takes two operands and specifies one of two operations
depending on the type of the operands.

If the operands are of type boolean then the "and" operator specifies
boolean AND. The result of the operation is of type boolean and is equal
to true of both operands are true, and false if either operand is false.
By default short circuit evaluation is used when performing the boolean
AND (i.e. The left operand is evaluated first and if it is false then
the right operand is not evaluated because the result of the operation
must be false). The "-sc" compiler option that can be used to
enable/disable short-circuit evaluation.

If the operands are of integral type then the "and" operator specifies
bitwise AND. The result of the operation is of integral type.

-----------------------
8.1.7 And_Then Operator
-----------------------
As an extension Irie Pascal supports the "and_then" operator, which takes
two boolean operands and specifies boolean AND. The result of the operation
is of type boolean. The difference between this operator and the "and"
operator is that this one can not be used to perform bitwise AND and
short circuit evaluation is always used when evaluating this operator.

----------------
8.1.8 + Operator
----------------
The "+" operator takes one or two operands and specifies one of three
operations depending on the type of the operands.

If there is only one operand and it is of integral type or real then
this operator specifies unary-plus and in fact has no effect.

If there are two operands and they are of integral type or real then the
"+" operator specifies addition. If both operands are of integral type
then the result of the operation is of integral type. If both operands are
of type real then the result of the operation is of type real. If one
operand is of integral type and the other is of type real then the integral
operand is converted to real before the addition is performed and the
result of the operation is of type real.

If there are two operands and they are of set type then the "+" operator
specified set union (i.e. the result of the operation is a set with all
the members from either operand).

As an extension Irie Pascal supports the use of the "+" to specify string
concatenation where there are two operands and they are of type string or
char.

----------------
8.1.9 - Operator
----------------
The "-" operator takes one or two operands and specifies one of two
operations depending on the type of the operands.

If there is only one operand and it is of integral type or real then
this operator specifies unary-minus. The result of this operation has the
same type as it's operand and has the same magnitude as it's operand but
the opposite sign.

If there are two operands and they are of integral type or real then the
"-" operator specifies subtraction. If both operands are of integral type
then the result of the operation is of integral type. If both operands are
of type real then the result of the operation is of type real. If one
operand is of integral type and the other is of type real then the integral
operand is converted to real before the subtraction is performed and the
result of the operation is of type real.

If there are two operands and they are of set type then the "-" operator
specified set difference (i.e. the result of the operation is a set with
those members are in the left operand but not in the right operand).

------------------
8.1.10 Or Operator
------------------
The "or" operator takes two operands and specifies one of two operations
depending on the type of the operands.

If the operands are of type boolean then the "or" operator specifies
boolean OR. The result of the operation is of type boolean and is equal
to true of either operand is true, and false if both operands are false.
By default short circuit evaluation is used when performing the boolean
OR (i.e. The left operand is evaluated first and if it is true then
the right operand is not evaluated because the result of the operation
must be true). The "-sc" compiler option that can be used to
enable/disable short-circuit evaluation.

If the operands are of integral type then the "or" operator specifies
bitwise OR. The result of the operation is of integral type.

-----------------------
8.1.11 Or_Else Operator
-----------------------
As an extension Irie Pascal supports the "or_else" operator, which takes two
boolean operands and specifies boolean OR. The result of the operation is
of type boolean. The difference between this operator and the "or" operator
is that this one can not be used to perform bitwise OR and short circuit
evaluation is always used when evaluating this operator.

-------------------
8.1.12 Xor Operator
-------------------
As an extension Irie Pascal supports the "xor" operator, which takes two
operands and specifies one of two operations depending on the type of the
operands.

If the operands are of type boolean then the "xor" operator specifies
boolean XOR. The result of the operation is of type boolean and is equal
to true if one but not both operands are true, and false if both operands
are false.

If the operands are of integral type then the "xor" operator specifies
bitwise XOR. The result of the operation is of integral type.

-------------------
8.1.13 shl Operator
-------------------
As an extension Irie Pascal supports the "shl" operator, which takes two
operands of integral type and specifies bit-shift left. The result of the
operation is the left operand shifted left by the number of bits specified
by the right operand. The right operand must be greater than or equal to
zero.

-------------------
8.1.14 shr Operator
-------------------
As an extension Irie Pascal supports the "shr" operator, which takes two
operands of integral type and specifies bit-shift right. The result of the
operation is the left operand shifted right by the number of bits specified
by the right operand. The right operand must be greater than or equal to
zero.

-----------------
8.1.15 = Operator
-----------------
The "=" operator takes two operands and compares them for equality. If one
operand is of integral type and the other is of type real then the integral
operand is converted to real before the comparison is made. The result of
this operation is of type boolean and is true if the operands are equal
and false otherwise.

-----------------
8.1.16 <> Operator
-----------------
The "<>" operator takes two operands and compares them for equality. If one
operand is of integral type and the other is of type real then the integral
operand is converted to real before the comparison is made. The result of
this operation is of type boolean and is true if the operands are not equal
and true otherwise.

-----------------
8.1.17 < Operator
-----------------
The "<" operator takes two operands and compares them. If one operand is of
integral type and the other is of type real then the integral operand is
converted to real before the comparison is made. The result of this
operation is of type boolean and is true if the left operand is less than
the right operand.

------------------
8.1.18 <= Operator
------------------
The "<=" operator takes two operands and specifies one of two operations
depending on the type of the operands.

The operands are simple types or string types then this operator compares
them. If one operand is of integral type and the other is of type real then
the integral operand is converted to real before the comparison is made.
The result of this operation is of type boolean and is true if the left
operand is less than or equal to the right operand.

If the operands are set types then the "<=" operator specifies set
inclusion. The result of this operation is true if all the members
of the left operand are in the right operand.

-----------------
8.1.19 > Operator
-----------------
The ">" operator takes two operands and compares them. If one operand is of
integral type and the other is of type real then the integral operand is
converted to real before the comparison is made. The result of this
operation is of type boolean and is true if the left operand is greater
than the right operand.

------------------
8.1.20 >= Operator
------------------
The ">=" operator takes two operands and specifies one of two operations
depending on the type of the operands.

The operands are simple types or string types then this operator compares
them. If one operand is of integral type and the other is of type real then
the integral operand is converted to real before the comparison is made.
The result of this operation is of type boolean and is true if the left
operand is greater than or equal to the right operand.

If the operands are set types then the ">=" operator specifies set
inclusion. The result of this operation is true if all the members
of the right operand are in the left operand, and is false otherwise.

------------------
8.1.21 In Operator
------------------
The "in" operator takes two operands, the left operand is of set type
and the right operands of ordinal type. The result of this operation
is of type boolean and is true if the right operand is a member of the
left operand, and is false otherwise.

--------------------
8.2 Compatible types
--------------------
Irie Pascal implements the type compatibility rules defined by Standard
Pascal (ISO/IEC 7185), and adds one more to support variable length
string types. The first four rules below are taken from ISO/IEC 7185 and
the last one is the one added to support variable length string types.

Types T1 and T2 shall be designated compatible if any of the following
statements is true:

1. T1 and T2 are the same type.
2. T1 is a subrange of T2, or T2 is a subrange of T1, or both T1 and T2 are
      subranges of the same host type.
3. T1 and T2 are set-types of compatible base-types, and either both T1 and
   T2 are designated packed or neither T1 nor T2 is designated packed.
4. T1 and T2 are fixed-length-string-types with the same number of
      components.
5. Either T1 is a variable-length-string-type and T2 is a
      variable-length-string-type,
   or T1 is a variable-length-string-type and T2 is a
      fixed-length-string-type, and the number of components in T2 is less
      than or equal to the maximum length of T1,
   or T1 is a variable-length-string-type and T2 is the char-type
   or T2 is a variable-length-string-type and T1 is a
      fixed-length-string-type, and the number of components in T1 is less
      than or equal to the maximum length of T2,
   or T2 is a variable-length-string-type and T1 is the char-type.

------------
9 Statements
------------
The statements in a program specify the specific actions that the program
can perform. Programs perform their actions (or run) by executing the
statements that they contain. Pascal programs begin executing at the first
statement in the main program block. Program execution generally flows
from left to right and top to bottom, however there are a number of
statements which can alter this flow of execution.

Statements can be grouped in a number of ways. For example statements
can be separated into two groups, simple statement and structured statements,
where simple statements are statements that do not contain other statements,
while structured statements are statements that do contain other statements.
Other groups of statements include conditional statements and repetitive
statements. Conditional statements allow programs to make decisions (i.e.
they test a particular condition and change the flow of execution depending
on the result). Repetitive statements allow the program to loop (i.e.
execute one or more statements repeatedly).

Labels can be placed in front of statements to mark them as targets for
"goto" statements. As an extension Irie Pascal allows labels to be
identifiers as well as sequences of digits. See also "3 Labels".

The syntax for statements is given below:

   statement = [ label ':' ] ( simple-statement | structured-statement )

   label = digit-sequence | identifier

   simple-statement = empty-statement |
		      assignment-statement |
		      procedure-statement |
		      goto-statement

   structured-statement = compound-statement |
			  conditional-statement |
			  repetitive-statement |
			  with-statement

   compound-statement = 'begin' statement-sequence 'end'

   statement-sequence = statement { ';' statement }

   conditional-statement = if-statement |
			   case-statement

   repetitive-statement = repeat-statement |
			  while-statement |
			  for-statement

-------------------
9.1 Empty Statement
-------------------
Empty statements don't do anything and are usually created when Pascal
syntax requires a statement to exist but you don't specify one.
For example if you write

   begin
   end

then technically according to Pascal syntax there must be a statement
between the "begin" and the "end", and since there is nothing there the
empty statement is said to exist there. Empty statements also commonly
occur when statements sequences have a trailing semi-colon. In Pascal the
semi-colon is used as a statement separator and not a statement terminator
so the following statement sequence

   a;
   b;

actually contains three statements, the statement "a", the statement "b"
and an empty statement following "b". Since a semi-colon follows "b" then
it must separate "b" from another statement.

The syntax for the empty statement is given below:

   empty-statement =


------------------------
9.2 Assignment Statement
------------------------
Assignments statements specify that an expression is to be evaluated and
the result stored in a variable. The value produced from evaluating the
expression must be assignment compatible with the type of the variable
(See "9.2.1 Assignment Compatibility" for details).

For example

   x := 1+1

is a simple example. When this statement is executed the expression "1+1"
is evaluated, and the value "2" is placed in the variable "x".

The syntax for the assignment statement is given below:

   assignment-statement = variable-access ':=' expression

   variable-access = entire-variable |
		     component-variable |
		     identified-variable |
		     buffer-variable

   entire-variable = variable-identifier

   component-variable = indexed-variable | field-designator

   indexed-variable =
      array-variable '[' index-expression { ',' index-expression } ']'

   field-designator = record-variable '.' field-specifier |
		      field-designator-identifier

   field-specifier = field-identifier

   identified-variable = pointer-variable '^' | pointer-variable '@'

   buffer-variable = file-variable '^' | file-variable '@'

See "8 Expression" for the syntax of expressions.

------------------------------
9.2.1 Assignment Compatibility
------------------------------
Irie Pascal implements the assignment compatibility rules defined by
Standard Pascal (ISO/IEC 7185), and adds one more to support variable
length string types. The first five rules below are taken from ISO/IEC 7185
and the last one is the one added to support variable length string types.

A value "V" of type T2 is assignment compatible with a type T1 if any of
the following is true:

1. T1 and T2 are the same type, and that type is not a file type or a type
   which contains a file type.

2. T1 is the real-type and T2 is an integral-type.

3. T1 and T2 are compatible ordinal-types, and V is in the closed interval
   specified by T1.

4. T1 and T2 are compatible set-types, and all the members of V are in the
   closed interval specified by the base-type of T1.

5. T1 and T2 are fixed length string types with the same length.

6. T1 is a variable length string type and either
      T2 is a variable length string type
      or T2 is a fixed length string type
      or T2 is a char-type.
   In addition the length of V must not be greater then the maximum
   length of T1.

----------------------------------------------------
9.2.1.1 Assignment compatibility with array indexing
----------------------------------------------------
The value of an index-expression shall be assignment compatible with the
index-type of the array variable.

For example given:

   var x : array[1..10] of integer;

and

   x[i] := 20;

then "i" (the value of the index-expression) shall be assignment compatible
with "1..10" (the index-type of the array variable).

------------------------------------------------------
9.2.1.2 Assignment compatibility with value parameters
------------------------------------------------------
When passing a parameter by value the actual-parameter shall be
assignment compatible with the type of the formal-parameter.

For example given:

   function IsDigit(c : char) : Boolean;
   begin
      if c in ['0'..'9'] then
	 IsDigit := true
      else
	 IsDigit := false
   end;

and

   while not IsDigit(key) do
       read(key)

then "key" (the actual-parameter in IsDigit(key) shall be
assignment compatible with "char" (the type of the formal-parameter).

--------------------------------------------
9.2.1.3 Assignment compatibility with "read"
--------------------------------------------
When using the built-in procedure "read" to store an input value into
a variable the input value shall be assignment compatible with the type of
the variable to which it is stored.

For example given:

   var s : string[40];

and

   read(s);

then the value read in by "read(s)" must be assignment compatible with
"string[40]".

-----------------------------------------------------------
9.2.1.4 Assignment compatibility with assignment statements
-----------------------------------------------------------
The value of the expression on the right-hand side of an assignment statement
shall be assignment compatible with the type of the left-hand side (i.e.
either the variable or the function-identifier on the left-hand side).

For example given:

   var age : 0..100;

and

   age := v;

then "v" (the right-hand side of the assignment statement) shall be
assignment compatible the "0..100" (the type of the left-hand side of the
assignment statement).

-------------------------------------------
9.2.1.5 Assignment compatibility with "for"
-------------------------------------------
The initial value and the final value in a for-statement shall be
assignment compatible with the type of the control variable if the
statement of the for-statement is executed (See "9.10 For Statement").

For example given:

   for i := low to high do writeln(i);

then "low" (the initial value) and "high" (the final value) shall be
assignment compatible with the type of "i" (the control variable) if
"writeln(i)" is executed. NOTE: "writeln(i)" will get executed unless
"low" is greater than "high".

---------------------------
9.2.1.6 Transfer procedures
---------------------------
In the statement pack(a,i,z) and unpack(z,a,i) the value of "i" shall be
assignment compatible with the index-type of "a".

For example given:

   var a : array[1..100] of real;
       z : packed array[1..100] of real;
       i : integer;

and

   pack(a,i,z) or unpack(z,a,i)

then "i" shall be assignment compatible with "1..100"
(the index-type of "a").

-----------------------
9.3 Procedure Statement
-----------------------
Procedure statements specify that a procedure is to be executed and
that a list of arguments if any are to be passed into the procedure.
When procedures are executed program execution is transferred to the
first statement in the procedure's statement block. After the execution
of a procedure program execution resumes with the statement after the
procedure call (See "7 Functions And Procedures").

For example

   writeln('1 + 1 = ', 1+1)

is a simple example. When this statement is executed the parameters
"'1 + 1 = '" and "1+1" are passed into the procedure and then it is
executed. In this case the "writeln" procedure prints the parameters
to the standard output stream.

The syntax for procedure statements is given below:

   procedure-statement = procedure-identifier
   (
       [ actual-parameter-list ] |
       read-parameter-list |
       readln-parameter-list |
       write-parameter-list |
       writeln-parameter-list
   )

   procedure-identifier = identifier

   actual-parameter-list = '(' actual-parameter { ',' actual-parameter } ')'

   actual-parameter = expression |
		      variable-access |
		      procedure-identifier |
		      function-identifier |
		      omitted-parameter

   omitted-parameter =

   read-parameter-list =
     '(' [ file-variable ',' ] variable-access { ',' variable-access } ')'

   readln-parameter-list =
     [ '(' ( file-variable | variable-access ) { ',' variable-access } ')' ]

   write-parameter-list =
     '(' [ file-variable ',' ] write-parameter { ',' write-parameter } ')'

   write-parameter = expression [ ':' expression [ ':' expression ] ]

   writeln-parameter-list =
     [ '(' ( file-variable | write-parameter ) { ',' write-parameter } ')' ]

------------------
9.4 Goto Statement
------------------
Goto statements specify that program execution is to be transferred to
the statement prefixed by the goto statement's label. Standard
(ISO/IEC 7185) Pascal describes the rules governing the use of
goto statements as follows:

A label, if any, of a statement S shall be designated as prefixing S.
The label shall be permitted to occur in a goto-statement G if and only
if any of the following three conditions is satisfied.

   a) S contains G.
   b) S is a statement of a statement-sequence containing G.
   c) S is a statement of the statement-sequence of the compound-statement
      of the statement-part of a block containing G.

To fully understand these rules you will probably need a copy of the
Standard (ISO/IEC 7185) but the following explanation should suffice for
most people.

The rules are basically saying that you can't use a goto statement to
transfer execution into the middle of a statement. The first two rules
cover goto statements that refer to statements in the current block,
while the last rule covers goto statements that refer to statements in
an enclosing block.

If a goto statement transfers execution out of the current block then
the call-stack is unwound (i.e. functions and procedure calls are terminated)
until the block containing the statement referred to be the goto statement
is reached. So for example if the main program calls a procedure A, and
procedure A calls procedure B, and procedure B calls procedure C, and a
goto statement in procedure C transfers execution back to procedure A
then procedures C and B are terminated.

Below is a simple program illustrating the use of the goto statement

   program ten(output);
   label loop;
   var
      count : integer;
   begin
      count := 1;
      loop: writeln(count);
      count := count + 1;
      if count <= 10 then goto loop
   end.

NOTE: The label "loop" used in this program is declared before it is used
(which is a requirement for all labels).

The syntax for goto statements is given below:

   goto-statement = 'goto' label

   label = digit-sequence | identifier

----------------------
9.5 Compound Statement
----------------------
Compound statements are used to group a number of statements into a
single statement. When a compound statement is executed, program execution
is transferred to the first statement in the statement group and generally
continues left to right, top to bottom unless diverted by one of the
statements executed. You usually use compound statements when Pascal
syntax says that only one statement is allowed at a particular point but you
want to put more than one, so you put the statements in a compound statement
and Pascal syntax is satisfied because the compound statement is a single
statement.

For example look at the program fragment below:

   write('Do you want to continue');
   readln(answer);
   if (answer = 'n') or (answer = 'N') then
     begin
	writeln('Program terminated by user');
	halt
     end

here we want to write a message to the screen and stop if the user
answers "n" or "N", but this requires two statements and the then part
of an if statement allows only a single statement. The solution as you
can see is just to put the two statements into a compound statement.

The syntax for compound statements is given below:

   compound-statement = 'begin' statement-sequence 'end'

   statement-sequence = statement { ';' statement }

----------------
9.6 If Statement
----------------
If statements conditionally execute one or two statements. If statements
contain a boolean expression, a "then-part", and may optionally contain an
"else-part". When an if statement is executed the boolean expression is
evaluated and what happens next depends on the result of the evaluation.
If the expression is evaluated and found to be true then the statement in
the "then-part" is executed, and program execution resumes at the statement
after the if statement (the else-part is skipped if present). If the
expression is evaluated and found to be false then the "else-part" is
executed if one is present and program control resumes at the statement
after the if statement, if an else part is not present then program
execution is transferred immediately to the statement after the if
statement.

For example

   if x > y then
      writeln('x is greater than y')
   else
      writeln('x is NOT greater than y')

is an if statement.
When this statement is executed the boolean expression "x > y" is evaluated
and if true the statement "writeln('x is greater than y')" is executed,
and if the boolean expression is false the statement
"writeln('x is NOT greater than y')" is executed.

The syntax for if statements is given below:

   if-statement = 'if' boolean-expression then-part [ else-part ]

   then-part = 'then' statement

   else-part = 'else' statement

------------------
9.7 Case Statement
------------------
Case statements conditionally execute one, two, or more statements.
Case statements contain an ordinal expression, zero, one or more case list
elements, and optionally a case statement completer. Case list elements
contain one or more constants and a statement. Case statement completers
contain a statement sequence. When a case statement is executed the ordinal
expression is evaluated and the value used to conditionally execute either
the statement in one of the case list elements or the statement sequence in
the case statement completer. If the expression evaluates to a value equal
to one of the constants in a case list element then the statement in that
case list element is executed. If the expression evaluates to a value that
is not equal to one of the constants in a case list element then the
statement sequence in the case statement completer is executed (if there is
no case statement completer then this is an error). After executing either
the statement in the case list element or the statement sequence in the
case statement completer program execution resumes at the statement after
the case statement.

Constant ranges can be used to specify a number of contiguous constants
(for example 1..5 is the same as 1, 2, 3, 4, 5).

No two case list elements can contain the same constant, so

   case x of
    1, 2, 3 : write('1 to 3');
    2 :  write('2');
   end

is an error since both case list elements contain "2".

For example the program fragment below shows an ordinal type and
a procedure with a case statement.

   type
       DayOfWeek =
	(monday, tuesday, wednesday, thursday, friday, saturday, sunday);

   procedure WriteDayOfWeek(day : DayOfWeek);
   begin
      case day of
	 monday:    write('monday');
	 tuesday:   write('tuesday');
	 wednesday: write('wednesday');
	 thursday:  write('thursday');
	 friday:    write('friday');
	 saturday:  write('saturday');
	 sunday:    write('sunday');
      end
   end;

When the case statement is executed the ordinal expression "day" is evaluated
and if it is equal to "tuesday" for example then since the second case list
element contains a constant equal to "tuesday" then the statement in the
second case list element is executed (i.e. write('tuesday')).

Below is a slightly more complex example.

   program example(input, output);
   var
      c : char;
   begin
      write('Enter a digit :');
      readln(c);
      case c of
      '0'..'9' : writeln('OK');
      'a'..'z', 'A'..'Z' : writeln('That is a letter');
      otherwise writeln('What is that?');
      end
   end.

When the case statement is executed the ordinal expression "c" is
evaluated and the value used as follows:
If the value is a digit then the statement in the first case list element is
executed.
If the value is a letter then the statement in the second case list elements
is executed.
If the value is not a digit or a letter then the statement sequence in the
case statement completer is executed.

Due to an implementation limit Irie Pascal handles case statements
differently depending on the type of the ordinal expression.
If the ordinal expression in the case statement has a type with less than or
equal to 1024 values then Irie Pascal implements the case statement using a
jump table and the rule that no two case list elements can have the same
constant is enforced. In addition, with the table implementation the ordinal
expression is evaluated only once.
If the ordinal expression in the case statement has a type with more than
1024 values then Irie Pascal implements the case statement as a series of
if statements and the rule that no two case list elements can have the same
constant is NOT enforced. In addition, with the if statement implementation
the ordinal expression is evaluated once for each case list element until
a match is found.
In practice only integer or word expression are likely to have types with
ranges greater than 1024. You could create an enumerated type with more than
1024 values but that is unlikely.

The syntax for case statements is given below:

   case-statement = 'case' case-index case-body [ ';' ] 'end'

   case-index = ordinal-expression

   case-body = case-list-elements [ [ ';' ] case-statement-completer ] |
	       case-statement-completer

   case-list-elements = case-list-element { ';' case-list-element }

   case-list-element = case-constant-list ':' statement

   case-constant-list = case-specifier { ',' case-specifier }

   case-specifier = case-constant [ '..' case-constant ]

   case-constant = ordinal-constant

   case-statement-completer = 'otherwise' statement-sequence

--------------------
9.8 Repeat Statement
--------------------
Repeat statements are used to repeatedly execute one or more statements
in a loop. Repeat statements contain a statement sequence and a loop
condition. When a repeat statement is executed the statement sequence is
executed as long as the loop condition is satisfied. The loop condition
is tested after the statement sequence is executed so the statement sequence
will always be executed at least once. The loop condition is a boolean
expression and is satisfied as long as the expression evaluates to false.
Usually the statement sequence will perform some action that will eventually
cause the loop condition to fail and thus terminate the loop. It is also
possible to use a goto statement to terminate the loop.

For example below is a very simple program which illustrates the use
of the repeat statement.

   program ten(output);
   var
      count : 1..11;
   begin
      count := 1;
      repeat
	writeln(count);
	count := count + 1
      until count > 10
   end.

The syntax for repeat statements is given below

  repeat-statement = 'repeat' statement-sequence 'until' boolean-expression

-------------------
9.9 While Statement
-------------------
While statements are used to repeatedly execute a statement in a loop.
While statements contain a statement and a loop condition. When a while
statement is executed the statement is executed as long as the loop condition
is satisfied. The loop condition is tested before the statement is executed
so it is possible that the statement will not be executed at all. The loop
condition is a boolean expression and is satisfied as long as the expression
evaluates to true. Usually the statement will perform some action that will
eventually cause the loop condition to fail and thus terminate the loop. It
is also possible to use a goto statement to terminate the loop.

For example below is a very simple program which illustrates the use
of the while statement.

   program ten(output);
   var
      count : 1..11;
   begin
      count := 1;
      while count <= 10 do
	 begin
	   writeln(count);
	   count := count + 1;
	 end
   end.

The syntax for while statements is given below

  while-statement = 'while' boolean-expression 'do' statement

------------------
9.10 For Statement
------------------
For statements are used to repeatedly execute a statement in a loop, while
at the same time counting each loop iteration. For statements contain a
control variable, an initial value, a final value, and a statement.
There are two kind of for statements, one kind counts upwards, and the
other kind counts downwards.

For statements that count upwards are executed as follows:
First the initial value is compared with the final value, and if the initial
value is greater than the final value then the execution of the for
statement is terminated immediately and the statement contained in the
for statement is never executed. If the initial value is not greater than
the final value, then the initial value is assigned to the control variable
and the looping begins. For each iteration of the loop the statement
contained in the for statement is executed and then the control variable
is incremented by one. The loop continues as long as the control variable
is less than or equal to the final value.

For statements that count downwards are executed as follows:
First the initial value is compared with the final value, and if the initial
value is less than the final value then the execution of the for
statement is terminated immediately and the statement contained in the
for statement is never executed. If the initial value is not less than
the final value then the initial value is assigned to the control variable
and the looping begins. For each iteration of the loop the statement
contained in the for statement is executed and then the control variable
is decremented by one. The loop continues as long as the control variable
is greater than or equal to the final value.

You should not depend on the control variable having any particular value
after execution of a for statement unless the for statement was left
using a goto statement.

Normally when executing a for statement it is best if the value of the
control variable is changed only by the for statement. If another statement
alters the value of the control variable it usually means that there is
a bug somewhere in your program. In an apparent effort to protect
programmers from making that kind of mistake Standard (ISO/IEC 7185) Pascal
defines a number of rules that restrict how control variables are used.
Irie Pascal implements these rules.

The first rule is that control variables must be declared at the same
level as the for statement (i.e. if the for statement is in a function or
procedure then the control variable must be local to that function or
procedure, and if the for statement is in the main program block then the
control variable must be global). Keeping the control variable local
makes it easier to control access.

The second rule is that neither the for statement nor any function or
procedure local to the block containing the for statement shall contain
a statement that "threatens" the control variable.
A statement "threatens" the control variable if the execution of the
statement could possibly alter the control variable.
So for example
  An assignment statement "threatens" the control variable if the control
  variable is the variable being assigned to.

  A function or procedure call "threatens" the control variable if the
  control variable is being passed by reference.

  A "read" or "readln" statement "threatens" the control variable if the
  control variable is used in the read-parameter-list or the
  readln-parameter-list.
  
  A "for" statement "threatens" the control variable if it uses the
  same control variable.

The syntax for the "for" statement is given below:

   for-statement =
     'for' control-variable ':=' initial-value ('to' | 'downto') final-value
     'do' statement

   control-variable = variable-identifier

   initial-value = ordinal-expression

   final-value = ordinal-expression

-------------------
9.11 With Statement
-------------------
With statements allow the fields of a record variable to be accessed
without specifying the record-variable each time. With statements contain
a record variable list and a statement. When a with statement is executed
the statement it contains is executed, however the fields in the record
variable can be accessed using the field identifier alone.

For example give the following type and variable

   type
     student = record
	 name : string;
	 address : string;
	 grade : integer;
     end;

   var
     s : student;

then

   with s do
      begin
	 name := 'John';
	 address := 'main street';
	 grade := 20;
      end

is equivalent to

   begin
      s.name := 'John';
      s.address := 'main street';
      s.grade := 20;
   end

Since some record types can contain other record types
you can have nested with statements like

   with record1 do
      with record2 do
	with record3 do
	    statement

or you can use the following shorthand

  with record1, record2, record3 do
     statement

The syntax for the with statement is given below:

   with-statement = 'with' record-variable-list 'do' statement

   record-variable-list = record-variable { ';' record-variable }

---------------------
10 Program parameters
---------------------
Program parameters are identifiers which appear after the program name
(placed between parentheses). In addition to appearing after the program
name, most program parameters must also appear in a global variable
declaration. Two special program parameters "input" and "output" are
the exceptions to this rule. The appearance of the two special program
parameters, after the program name, automatically declares them as two
special file variables which reference the standard-input and
standard-output streams.

You can use program parameters to access command-line arguments passed to
your program (see also extended procedures "paramcount" and "paramstr"). For
example suppose you want to write a program to append two files together,
writing the appended files to a third file, then you might write a program
similar to the sample program below.

   (**********************************************************************
   ** This program appends two files together, writing the appended files
   ** out to a third file.
   *)
   program append(in1, in2, out, output);
   type
      char_file = file of char;
   var
      in1 : char_file;     (* first input file *)
      in2 : char_file;     (* second input file *)
      out : char_file;     (* output file *)

      (***************************************************************
      ** PURPOSE: Writes copies the contents of one file into another.
      ** ARGUMENTS:
      **    'f' - the input file
      **    'g' - the output file
      ** NOTES: It is up to the caller to open and close the files.
      *)
      procedure WriteFile(var f, g: char_file);
      var
	 c : char;
      begin
	 while not eof(f) do
	    begin
	       read(f, c);
	       write(g, c)
	    end
      end;

      (**********************************************
      ** PURPOSE: Writes a help screen and then halts
      *)
      procedure syntax;
      begin
	 writeln('Appends two files together and writes the output to a third file');
	 writeln('Syntax');
	 writeln('   ivm append in1 in2 out');
	 writeln('where "in1" is the first input file');
	 writeln('and   "in2" is the second input file');
	 writeln('and   "out" is the output file');
	 halt
      end;

   begin
      if paramcount <> 3 then
	 syntax;
      rewrite(out);
      reset(in1);
      WriteFile(in1, out);
      close(in1);
      reset(in2);
      WriteFile(in2, out);
      close(in2)
      close(out);
   end.

The first thing to notice about this program is the line below:

   program append(in1, in2, out, output);

Here four program parameters are being used "in1", "in2", "out", and "output".
The first program parameter "in1" accesses the first command-line argument
The second program parameter "in2" accesses the second command-line argument.
The third program parameter "out" accesses the third command-line argument.
The fourth program parameter "output" declares the special file variable
which references the standard-output stream, and has nothing to do with
command-line arguments. "output" does not have to be the last program
parameter, it can be used in the first, or second or any position. Since
"output" does not access any command-line arguments it can appear in any
position (not just the fourth and last position) without disturbing the
command-line arguments accessed by the other program parameters. In other
words all of the following are equivalent

   program append(output, in1, in2, out);
or
   program append(in1, output, in2, out);
or
   program append(in1, in2, output, out);
or
   program append(in1, in2, out, output);

And in each of the four cases "in1" accesses the first command-line argument
and "in2" accesses the second command-line argument
and "out" accesses the third command-line argument.

The second thing to notice about the program are the following lines.

   var
      in1 : char_file;     (* first input file *)
      in2 : char_file;     (* second input file *)
      out : char_file;     (* output file *)

Here the program parameters (except for "output") appear in global variable
declarations as required. They are declared to be variables of type
"char_file" which has been declared to be "file of char". Now since they are
declared to be file variables it means that the command-line arguments
accessed specify the names of the external files associated with the file
variables. What this means is that if the file variables are opened (using
"reset", "rewrite", or "append") then the external file which is opened is
the one specified by the command-line argument accessed.
For example if the program is run with the line

   ivm append x.txt y.txt a:\z.txt

then when "in1" is opened the file "x.txt" is opened
and when "in2" is opened the file "y.txt" is opened
and when "out" is opened the file "a:\z.txt" is opened.

The final thing to notice about the program are the following lines.

      if paramcount <> 3 then
	 syntax;

These lines cause the procedure "syntax" to be called if the number of
command-line arguments is not 3. These lines are intended to prevent
problems if the user does not enter 3 command-line arguments.

Suppose for example that this program was run with no command-line arguments.
The first program argument "in1" will access the first command-line argument
which does not exist so the empty string will specify the external file
associated with this file variable. Similarly the empty string will specify
the external files associated with the file variables "in2" and "out".

You might ask what happens if you open a file variable associated with an
external file specified by an empty string? Well, if you open such a
file variable for reading (with "reset") then the external file opened
is the standard input stream. If you open such a file for writing
(with "rewrite" or "append") then the external file opened is the standard
output stream.

I didn't want this effect when I wrote the sample program above so I
inserted the lines

      if paramcount <> 3 then
	 syntax;

to avoid this.

So far I have described how file-type program parameters are handled.
You can also use string-type program parameters. They also access the
command-line arguments, but in a different way. The command-line
argument accessed is simply assigned to the string-type program parameter.

If you use program parameters other than file-type or string-type then
the command-line argument is ignored. The compiler will issue a warning,
that the command-line argument has an invalid type, but otherwise do
nothing.

For example look at this rather strange program.

   program strange(f, s1, dummy, s2);
   var
      f : text;
      s1, s2 : string;
      dummy : real;
   begin
      rewrite(f);
      writeln(f, s1);
      writeln(f, s2)
   end.

If you compile it you will get some warnings but ignore them.
If you run the program with

   ivm strange out.txt first skip second

then the first program parameter "f" will access "out.txt", and since
"f" is a file-type program argument when "rewrite" is used on "f" the
file "out.txt" will be opened for writing.
The second program parameter "s1" will access "first", and since this
is a string-type program argument then "first" will be assigned to "s1".
The third program parameter "dummy" is not a file-type or string-type
program parameter so the third command-line argument "skip" will be
ignored.
The fourth program parameter "s2" will access "second", and since this
is a string-type program argument then "second" will be assigned to "s2".

So the effect of the following three lines

      rewrite(f);
      writeln(f, s1);
      writeln(f, s2)

is that a text file "out.txt" is opened and two lines are written to it.
The first line will be "first" and the second will be "second".

-------------------------------
Appendix A. Irie Pascal Grammar
-------------------------------
The start symbol for this grammar is "program".

   actual-parameter = expression |
		      variable-access |
		      procedure-identifier |
		      function-identifier
		      omitted-parameter

   actual-parameter-list = '(' actual-parameter { ',' actual-parameter } ')'

   adding-operator = '+' | '-' | 'or' | 'or_else' | 'xor'

   array-type = 'array' '[' index-type-list ']' 'of' component-type

   assignment-statement = variable-access ':=' expression

   block = declarative-part statement-part

   buffer-variable = file-variable '^' | file-variable '@'

   case-body = case-list-elements [ [ ';' ] case-statement-completer ] |
	       case-statement-completer

   case-constant = ordinal-constant

   case-constant-list = case-specifier { ',' case-specifier }

   case-index = ordinal-expression

   case-list-element = case-constant-list ':' statement

   case-list-elements = case-list-element { ';' case-list-element }

   case-specifier = case-constant [ '..' case-constant ]

   case-statement = 'case' case-index case-body [ ';' ] 'end'

   case-statement-completer = 'otherwise' statement-sequence

   component-type = type-denoter

   component-variable = indexed-variable | field-designator

   compound-statement = 'begin' statement-sequence 'end'

   conditional-statement = if-statement |
			   case-statement

   constant = whole-number | real | character-literal | string-literal |
	      constant-identifier

   constant-declaration = identifier '=' constant

   constant-declaration-group =
	 'const' constant-declaration ';' { constant-declaration ';' }

   control-variable = variable-identifier

   declarative-part = { pre-declaration } { sub-block-declaration }

   directive-specification = forward-directive | external-directive

   forward-directive = 'forward'

   external-directive = 'external' 'dll' '=' dllname ['name' '=' name]
			[stdcall] [cdecl]

   domain-type = type-identifier

   else-part = 'else' statement

   empty-statement =

   entire-variable = variable-identifier

   expression = shift-expression [ relational-operator shift-expression]

   factor = [sign] unsigned-constant |
	    [sign] variable-access |
	    [sign] '(' expression ')' |
	    function-designator |
	    'not' factor |
	    set-constructor

   field-designator = record-variable '.' field-specifier |
		      field-designator-identifier

   field-designator-identifier = identifier

   field-list = fixed-part ';' variant-part [ ';' ] |
	 fixed-part [ ';' ] |
	 variant-part [ ';' ] |
	 empty

   field-specifier = field-identifier

   file-type = 'file' 'of' component-type

   final-value = ordinal-expression

   fixed-part = record-section { ';' record-section }

   for-statement =
     'for' control-variable ':=' initial-value ('to' | 'downto') final-value
     'do' statement

   formal-parameter-list =
	'(' formal-parameter-section { ';' formal-parameter-section } ')'

   formal-parameter-section = value-parameter-specification |
			      variable-parameter-specification |
			      procedure-parameter-specification |
			      function-parameter-specification

   function-block = block

   function-declaration =
	   function-heading ';' directive-specification |
	   function-identification ';' function-block |
	   function-heading ';' function-block

   function-designator = function-identifier [ actual-parameter-list ]

   function-heading =
	'function' identifier [ formal-parameter-list ] ':' result-type

   function-identification = 'function' function-identifier

   function-identifier = identifier

   function-parameter-specification = function-heading

   goto-statement = 'goto' label

   identified-variable = pointer-variable '^' | pointer-variable '@'

   identifier-list = identifier { ',' identifier }

   if-statement = 'if' boolean-expression then-part [ else-part ]

   indexed-variable =
      array-variable '[' index-expression { ',' index-expression } ']'

   index-type = ordinal-type

   index-type-list = index-type { ',' index-type }

   initial-value = ordinal-expression

   label = digit-sequence | identifier

   label-declaration-group = 'label' label { ',' label } ';'

   list-type = 'list' 'of' component-type

   member-designator = expression [ '..' expression ]

   multiplying-operator = '*' | '/' | 'div' | 'mod' | 'and' | 'and_then'

   new-ordinal-type = enumerated-type | subrange-type

   new-pointer-type = '^' domain-type |
		      '@' domain-type

   new-structured-type = [ 'packed' ] array-type |
			 [ 'packed' ] record-type |
			 [ 'packed' ] set-type |
			 [ 'packed' ] file-type |
			 [ 'packed' ] list-type |
				      string-type

   new-type = new-ordinal-type | new-structured-type | new-pointer-type

   omitted-parameter =

   ordinal-type = new-ordinal-type | ordinal-type-identifier

   pre-declaration = label-declaration-group |
		     constant-declaration-group |
		     type-declaration-group |
		     variable-declaration-group

   procedure-block = block

   procedure-declaration =
	   procedure-heading ';' directive-specification |
	   procedure-identification ';' procedure-block |
	   procedure-heading ';' procedure-block

   procedure-heading = 'procedure' identifier [ formal-parameter-list ]

   procedure-identification = 'procedure' procedure-identifier

   procedure-identifier = identifier

   procedure-parameter-specification = procedure-heading

   procedure-statement = procedure-identifier
   (
       [ actual-parameter-list ] |
       read-parameter-list |
       readln-parameter-list |
       write-parameter-list |
       writeln-parameter-list
   )

   program = 'program' program-name [ '(' program-args ')' ] ';' block '.'

   program-args = identifier-list

   read-parameter-list =
     '(' [ file-variable ',' ] variable-access { ',' variable-access } ')'

   readln-parameter-list =
     [ '(' ( file-variable | variable-access ) { ',' variable-access } ')' ]

   record-section = identifier-list ':' type-denoter

   record-type = 'record' field-list 'end'

   record-variable-list = record-variable { ';' record-variable }

   relational-operator = '=' | '<>' | '<' | '<=' | '>' | '>=' | 'in'

   repeat-statement = 'repeat' statement-sequence 'until' boolean-expression

   repetitive-statement = repeat-statement |
			  while-statement |
			  for-statement

   result-type = type-identifier

   set-constructor = '[' [ member-designator { ',' member-designator } ] ']'

   set-type = 'set' 'of' ordinal-type

   shift-expression = simple-expression [ shift-operator simple-expression]

   shift-operator = 'shl' | shr'

   sign = '+' | '-'

   simple-expression = term { adding-operator term }

   simple-statement = empty-statement |
		      assignment-statement |
		      procedure-statement |
		      goto-statement

   size = whole-number

   statement = [ label ':' ] ( simple-statement | structured-statement )

   statement-part = compound-statement

   statement-sequence = statement { ';' statement }

   string-type = 'string' |
		 'string' '[' size ']' |
		 'string' '(' size ')'

   structured-statement = compound-statement |
			  conditional-statement |
			  repetitive-statement |
			  with-statement

   sub-block-declaration = function-declaration | procedure-declaration

   term = factor { multiplying-operator factor }

   then-part = 'then' statement

   type-declaration = identifier '=' type-denoter

   type-declaration-group =
	'type' identifier '=' type-declaration ';' { type-declaration ';' }

   type-denoter = type-identifier | new-type

   type-identifier = identifier

   unsigned-constant = unsigned-integer |
		       unsigned-real |
		       character-string |
		       constant-identifier |
		       'nil'

   value-parameter-specification = identifier-list ':' type-identifier

   variable-access = entire-variable |
		     component-variable |
		     identified-variable |
		     buffer-variable

   variable-declaration = identifier-list ':' type-denoter

   variable-declaration-group =
	  'var' variable-declaration { ';' variable-declaration }

   variable-parameter-specification =
	     'var' identifier-list ':' type-identifier

   variant = case-constant-list ':' '(' field-list ')'

   variant-body = variant-list [ [;] variant-part-completer ] |
		  variant-part-completer

   variant-list = variant { ';' variant }

   variant-part = 'case' variant-selector 'of' variant-body

   variant-part-completer = 'otherwise' '(' field-list ')'

   variant-selector = [ identifier ':' ] ordinal-type-identifier

   while-statement = 'while' boolean-expression 'do' statement

   with-statement = 'with' record-variable-list 'do' statement

   writeln-parameter-list =
     [ '(' ( file-variable | write-parameter ) { ',' write-parameter } ')' ]

   write-parameter = expression [ ':' expression [ ':' expression ] ]

   write-parameter-list =
     '(' [ file-variable ',' ] write-parameter { ',' write-parameter } ')'

-------------------------------------------------------------
Appendix B. Extensions to Pascal as specified by ISO/IEC 7185
-------------------------------------------------------------
Irie Pascal supports a number of extensions to Standard Pascal.
Some of these extensions were added for compatibility with Turbo Pascal and
Extended Pascal, while others were added because I thought they might be
useful.

Extensions can be enabled/disabled using the -E compiler option.

------------------------
B.1 Relaxed declarations
------------------------
Standard Pascal requires that all declarations/definitions of the same
kind must be made together in a single group and that the groups must
appear in a specific order. The order required by Standard Pascal is:
   Label declaration group
   Constant definition group
   Type definition group
   Variable declaration group
   sub-block declaration group

When "relaxed declarations" is enabled there can be more than one of each
kind of group and groups can appear in any order except that the
sub-block declaration group must be last.

So if "relaxed declarations" is enabled then the following program is legal,

   program summing(output);
   const
      first = 1;
      last = 100;
   type
      num = first..last;
   var
      i : num;
   type
      atype = array[first..last] of integer;
   var
      a : atype;
      sum : integer;
   begin
      sum := 0;
      for i := first to last do
	 begin
	    sum := sum + i;
	    a[i] := sum
	 end;
      for i := last downto first do
	 writeln(i, a[i]);
   end.

even though it has two type definition groups
  "type num = first..last;"
and
  "type atype = array[first..last] of integer;"
and two variable declaration groups
  "var i : num;"
and
  "var a : atype; sum : integer;"

In Standard Pascal or with "relaxed declarations" disabled you would have to
combine these groups so you would have the following

   program summing(output);
   const
      first = 1;
      last = 100;
   type
      num = first..last;
      atype = array[first..last] of integer;
   var
      i : num;
      a : atype;
      sum : integer;
   begin
      sum := 0;
      for i := first to last do
	 begin
	    sum := sum + i;
	    a[i] := sum
	 end;
      for i := last downto first do
	 writeln(i, a[i]);
   end.

-------------------
B.2 Constant ranges
-------------------
You can use constant ranges to specify a number of consecutive case
constants.
To use a constant range you specify the first constant, and the last
constant, separated by '..' as follows:
   first..last

You could use the constant range
   1..5
to specify the following constants
   1, 2, 3, 4, 5

For example suppose "c" is a char variable and you want to use a
case statement to write the word "Letter" if "c" contains a letter, and
the word "Digit" if "c" contains a digit, then you could specify each
constant individually as follows:

   case c 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',
      '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('Letter');
      '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
	 : write('Digit');
   end;

Or you could use constant ranges like the following:

   case c of
      'a'..'z', 'A'..'Z'
	 : write('Letter');
      '0'..'9'
	 : write('Digit');
   end;

Constant ranges can be used in case statements, like in the example above, 
and in variant records.
  
-------------
B.3 Otherwise
-------------
You can use the keyword "otherwise" in case statements and variant records
to specify "all values that haven't been used yet". You can also use
"else" instead of "otherwise" (this feature was added in order to improve
compatibility with Turbo Pascal).

For example in the following variant record

   type
      character = record
	 case c : char of
	 'a'..'z', 'A'..'Z'
	    : (vowel : Boolean);
	 '0'..'9'
	    : (value : integer);
	 otherwise
	    ();
      end;

when "otherwise" is used, the following values have already been specified
   'a'..'z', 'A'..'Z', and '0'..'9'
so otherwise specifies all character values except
   'a'..'z', 'A'..'Z', and '0'..'9'

------------------------------------
B.4 Relaxed parameter list congruity
------------------------------------
Standard Pascal says the following parameter lists
   (VAR a, b : integer)
and
   (VAR c : integer; VAR d : integer)
are not congruous even though the individual parameters are congruous
because Standard Pascal compares formal parameter sections.
So in the example above the parameter lists are not congruous for two
reasons:
1) The first parameter list has one formal parameter section
      "VAR a, b : integer"
   while the second parameter list has two formal parameter section
      "VAR c : integer" and "VAR d : integer"
2) The individual parameter sections are not congruous
  (i.e.. "VAR a, b : integer" is not congruous with "VAR c : integer")

Irie Pascal checks for parameter list congruity by comparing the
individual parameters without regard to the formal-parameter-sections.
So the example above would be considered congruous since
   "a" and "c" are both integer variable parameters
and
   "b" and "d" are both integer variable parameters

Parameter list congruity becomes important when passing functions/procedures
since the parameter list of the actual function/procedure parameter must be
congruous with the parameter list of the corresponding formal
function/procedure parameter.

Relaxed parameter list congruity can not be disabled.

--------------------------------
B.5 Non-numeric statement labels
--------------------------------
Irie Pascal supports non-numeric statement labels.

For example in the following program "loop" is used as a statement label.

   program name(output);
   label loop;
   var
   i : integer;
   begin
      i := 1;
      loop:
      writeln(i);
      i := i + 1;
      if i <= 20 then goto loop;
   end.

------------------------------
B.6 Underscores in identifiers
------------------------------
Irie Pascal supports identifiers which contain and/or start with
underscores ("_").

---------------------------------
B.7 Binary whole number constants
---------------------------------
Binary whole number constants begin with "%", and are followed by one or
more binary digits.

The following are examples of valid binary whole number constants
   %0   %1      %01110101010101010111101

The following are not valid binary whole number constants
   %2    %      %151       %g

--------------------------------------
B.8 Hexadecimal whole number constants
--------------------------------------
Hexadecimal whole number constants begin with "$", and are followed by one
or more hexadecimal digits.

The following are examples of valid hexadecimal whole number constants
   $9   $A123      $ffff

The following is not a valid hexadecimal whole number constant
   $abgd
since "g" is not a hexadecimal digit.

-------------------------------------------
B.9 Input and Output automatically declared
-------------------------------------------
Standard (ISO/IEC 7185) Pascal specifies that whenever the required
identifiers "Input" and "Output" are referenced in a program that they
must by declared (i.e. appear as program parameters). However because
some Pascal compilers do not enforce this requirement many Pascal programs
do not meet this specification. In order to allow Irie Pascal to compile
these programs without requiring the user to insert "Input" and "Output"
into the program parameter list, I decided that by default Irie Pascal
should automatically declare Input and Output.

---------------------------
B.10 Double-quoted literals
---------------------------
You can use double quotation marks to form character and string literals.

For example you could use
   "Hello world"
instead of
   'Hello world'

Double-quoted literals can be useful if you want to create literals with
single quotes in them since you don't have to use two single quotes to
represent one single quote.

For example you could use
   "Don't go away"
which is equivalent to
   'Don''t do away'

----------------------
B.11 and_then operator
----------------------
The "and_then" operator is similar to the "and" operator except that
short-circuit evaluation is always used for "and_then" regardless of
the setting of the "sc" compiler option.

See "8.1.7 And_Then Operator" for more information.

---------------------
B.12 or_else operator
---------------------
The "or_else" operator is similar to the "or" operator except that
short-circuit evaluation is always used for "or_else" regardless of
the setting of the "sc" compiler option.

See "8.1.11 Or_Else Operator" for more information.

----------------------
B.13 Bitwise operators
----------------------
Irie Pascal defines several bitwise operators.

-------------------
B.13.1 shl operator
-------------------
The "shl" operator performs a left bit-shift, and returns the result of
this bit-shift. The left operand is the integral expression to be shifted,
and the right operand, which is also integral, specifies the number of bits
to shift.

For example
    4 shl 2
is equal to 16,
since 4 shifted left by 2 bits is 16.

-------------------
B.13.2 shr operator
-------------------
The "shr" operator performs a right bit-shift, and returns the result of
this bit-shift. The left operand is the integral expression to be shifted,
and the right operand, which is also integral, specifies the number of bits
to shift.

For example
    4 shr 2
is equal to 1, since 4 shifted right by 2 bits is 1.

-----------------------------
B.13.3 and (Bitwise) operator
-----------------------------
The bitwise "and" operator takes two integral operands and produces
an integral result. A bit in the result is 1 if the bit in the
corresponding position in the left operand is 1 AND the bit
in the corresponding position in the right operand is 1.
Otherwise the result bit is 0.

For example
   5 and 3 = 1
Since
      101    (which is 5 in binary)
and   011    (which is 3 in binary)
---------
 =    001
---------
NOTE: Bit zero is 1 in the result since bit zero is one in both
the left and right operands. All other bits are zero.

----------------------------
B.13.4 or (Bitwise) operator
----------------------------
The bitwise "or" operator takes two integral operands and produces
an integral result. A bit in the result is 1 if the bit in the
corresponding position in the left operand is 1 OR the bit
in the corresponding position in the right operand is 1 OR
both bits are 1.
Otherwise the result bit is 0.

For example
   5 or 3 = 7
Since
      101    (which is 5 in binary)
or    011    (which is 3 in binary)
---------
 =    111
---------

-----------------------------
B.13.5 not (Bitwise) operator
-----------------------------
The bitwise "not" operator takes an integral operand and produces
an integral result. A bit in the result is 1 if the bit in the
corresponding position in the operand is 0. A bit in the result
is 0 if the bit in the corresponding position in the operand is 1.

For example
   not 1 = -2
Since
not   00000000 00000000 00000000 00000001   = 1
-----------------------------------------
      11111111 11111111 11111111 11111110   = -2

-----------------------------
B.13.6 xor (Bitwise) operator
-----------------------------
The bitwise "xor" operator takes two integral operands and produces
an integral result. A bit in the result is 1 either the bit in the
corresponding position in the left operand is 1 OR the bit
in the corresponding position in the right operand is 1, but not
both. Otherwise the result bit is 0.

For example
   5 xor 3 = 6
Since
      101    (which is 5 in binary)
xor   011    (which is 3 in binary)
---------
 =    110
---------

-----------------------
B.14 Extended constants
-----------------------
Irie Pascal defines a number of built-in constants which are
not part of Standard Pascal. The constants are referred to
here as extended constants.

--------------
B.14.1 maxchar
--------------
Irie Pascal defines "maxchar" which is a built-in character constant,
whose value is the maximum character value allowed.

Syntax: maxchar

------------
B.14.2 usr_r
------------
Irie Pascal defines "usr_r" which is a built-in integer constant.
You can use this constant with the "mkdir" procedure to specify
that the directory owner has read permission.
You can also "or" this constant with a file mode to determine
if the file owner has read permission.

Syntax: usr_r

------------
B.14.3 usr_w
------------
Irie Pascal defines "usr_w" which is a built-in integer constant.
You can use this constant with the "mkdir" procedure to specify
that the directory owner has write permission.
You can also "or" this constant with a file mode to determine
if the file owner has write permission.

Syntax: usr_w

------------
B.14.4 usr_x
------------
Irie Pascal defines "usr_x" which is a built-in integer constant.
You can use this constant with the "mkdir" procedure to specify
that the directory owner has execute permission.
You can also "or" this constant with a file mode to determine
if the file owner has execute permission.

Syntax: usr_x

------------
B.14.5 grp_r
------------
Irie Pascal defines "grp_r" which is a built-in integer constant.
You can use this constant with the "mkdir" procedure to specify
that the directory owner's group has read permission.
You can also "or" this constant with a file mode to determine
if the file owner's group has read permission.

Syntax: grp_r

------------
B.14.6 grp_w
------------
Irie Pascal defines "grp_w" which is a built-in integer constant.
You can use this constant with the "mkdir" procedure to specify
that the directory owner's group has write permission.
You can also "or" this constant with a file mode to determine
if the file owner's group has write permission.

Syntax: grp_w

------------
B.14.7 grp_x
------------
Irie Pascal defines "grp_x" which is a built-in integer constant.
You can use this constant with the "mkdir" procedure to specify
that the directory owner's group has execute permission.
You can also "or" this constant with a file mode to determine
if the file owner's group has execute permission.

Syntax: grp_x

------------
B.14.8 oth_r
------------
Irie Pascal defines "oth_r" which is a built-in integer constant.
You can use this constant with the "mkdir" procedure to specify
that (the world) everyone has read permission.
You can also "or" this constant with a file mode to determine
if (the world) everyone has read permission.

Syntax: oth_r

------------
B.14.9 oth_w
------------
Irie Pascal defines "oth_w" which is a built-in integer constant.
You can use this constant with the "mkdir" procedure to specify
that (the world) everyone has write permission.
You can also "or" this constant with a file mode to determine
if (the world) everyone has write permission.

Syntax: oth_w

-------------
B.14.10 oth_x
-------------
Irie Pascal defines "oth_x" which is a built-in integer constant.
You can use this constant with the "mkdir" procedure to specify
that (the world) everyone has execute permission.
You can also "or" this constant with a file mode to determine
if (the world) everyone has execute permission.

Syntax: oth_x

---------------
B.14.11 dir_bit
---------------
Irie Pascal defines "dir_bit" which is a built-in integer constant.
You can "or" this constant with a file mode to determine if the
file is a directory.

Syntax: dir_bit

--------------------
B.14.12 platform_dos
--------------------
Irie Pascal defines "platform_dos" which is a built-in integer constant.
You can compare this constant with the value returned by the "platform"
function to determine if your program is being executed by the dos version
of the interpreter.

--------------------
B.14.13 platform_os2
--------------------
Irie Pascal defines "platform_os2" which is a built-in integer constant.
You can compare this constant with the value returned by the "platform"
function to determine if your program is being executed by the OS/2
version of the interpreter.

----------------------
B.14.14 platform_win32
----------------------
Irie Pascal defines "platform_win32" which is a built-in integer constant.
You can compare this constant with the value returned by the "platform"
function to determine if your program is being executed by the Win32
(i.e. Win95/98/NT3.51/NT4.0 version of the interpreter).

----------------------
B.14.15 platform_linux
----------------------
Irie Pascal defines "platform_linux" which is a built-in integer constant.
You can compare this constant with the value returned by the "platform"
function to determine if your program is being executed by the Linux
version of the interpreter.

---------------------
B.14.16 platform_fbsd
---------------------
Irie Pascal defines "platform_fbsd" which is a built-in integer constant.
You can compare this constant with the value returned by the "platform"
function to determine if your program is being executed by the FreeBSD
version of the interpreter.

------------------------
B.14.17 platform_solaris
------------------------
Irie Pascal defines "platform_solaris" which is a built-in integer constant.
You can compare this constant with the value returned by the "platform"
function to determine if your program is being executed by the Solaris/x86
version of the interpreter.

------------------------------
B.14.18 platform_solaris_sparc
------------------------------
Irie Pascal defines "platform_solaris_sparc" which is a built-in integer
constant. You can compare this constant with the value returned by the
"platform" function to determine if your program is being executed by
the Solaris/Sparc version of the interpreter.

----------------------
B.14.19 platform_error
----------------------
Irie Pascal defines "platform_error" which is a built-in integer constant.
You can compare this constant with the value returned by the "platform"
function to determine if the call to "platform" failed.

------------------
B.14.20 appendmode
------------------
Irie Pascal defines "appendmode" which is a built-in integer constant.
You can use this constant with the "open" function to specify that the
file should be opened in append mode.

----------------
B.14.21 readmode
----------------
Irie Pascal defines "readmode" which is a built-in integer constant.
You can use this constant with the "open" function to specify that the
file should be opened for reading (i.e. input). You can combine
(with "+" or "or") this constant with "writemode" to specify that the
file should be opened for both reading and writing.

-----------------
B.14.22 writemode
-----------------
Irie Pascal defines "writemode" which is a built-in integer constant.
You can use this constant with the "open" function to specify that the
file should be opened for writing (i.e. output). You can combine
(with "+" or "or") this constant with "readmode" to specify that the
file should be opened for both reading and writing.

-------------------
B.15 Extended types
-------------------
Irie Pascal defines a number of extended types
(i.e. built-in types that are not a part of Standard Pascal).

----------
B.15.1 dir
----------
Irie Pascal defines a type identifier called "dir" which is the
type of directory variables, which are used in the
directory manipulation procedures.

See "7.2.6 closedir", "7.2.32 opendir", "7.2.40 readdir", and
"7.2.44 rewinddir".

---------------
B.15.2 filename
---------------
Irie Pascal defines a type identifier called "filename" which is the
string type most suitable for variables used to store filenames.

Syntax: filename

For example to declare a variable to store filenames use
var
   name : filename;

NOTE: You can also use string types such as
var
   name : packed array[1..N] of char;
or
   name : string;

But I recommend you use "filename" since this type is likely to be
the most suitable type for storing filenames.

-----------
B.15.3 list
-----------
Irie Pascal defines a new keyword "list" in order to provide support
for lists. To create a list type use the syntax below.

Syntax: [packed] list of Type
where
   "Type" is the type of the components in the list.

If you use "packed" then the list is likely to be more efficient in
terms of memory but less efficient in terms of speed.

You must use "new" to initialize a list variable before you use it.
The syntax is:
    new(list-variable)

You can use "dispose" to release the memory used by a list variable
after you have finished with it. The syntax is:
    dispose(list-variable)

You can use "insert" to add components to a list variable.

You can use "delete" to remove components from a list variable.

You can use the "length" function to determine the number of components in a
list variable.

You can access the components of a list variable just like an array
variable. The syntax is
     lv '[' p ']'
where
     "lv" is the list variable being accessed
     "p" is the position of the component being accessed
For example if "i" is an integer and "lv" is a list variable then the
statement below will write each component of "lv".
     for i := 1 to length(lv) do
	writeln(lv[i])

-------------
B.15.4 string
-------------
Standard Pascal considers packed arrays of char with a lower bound of 1 to
be strings. However these are fixed length strings (i.e.. the only text that
can be assigned to these strings is text of exactly the same length as the
length of the array).

Irie Pascal supports variable length strings using a new type "string".

For example to create a variable length string type called "name" with
a maximum length of 80 use
   name = string[80];
or
   name = string(80);

To create a variable length string type called "address" with a maximum length
of 255 use
   address = string;
or
   address = string[255];
or
   address = string(255);

The advantage of variable length strings is that any string can be assigned
to them, whether fixed or variable length, as long as the length of the
string being assigned does not exceed the string's maximum length.
Even characters can be assigned to variable length strings.

You can use the "+" operator to perform string concatenation.

-----------------------
B.16 Extended variables
-----------------------
Irie Pascal defines one extended variable
(i.e. a built-in variable that is not a part of Standard Pascal).

---------------
B.16.1 exitcode
---------------
Irie Pascal defines "exitcode" which is a built-in integer variable,
whose value is returned to the calling program when your program exits.

Syntax: exitcode

For example suppose you want to return a value of 1 from your program
(perhaps to indicate that your program detected an error) then you can
use the following code

   exitcode := 1;
   halt;

NOTE: You can treat "exitcode" like any other integer variable
(i.e. you can assign to it, use it in an expression, pass it as an
argument to a function, etc).

END
