
	Welcome to the Irie Pascal Programmer's Reference Manual

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

Table Of Contents
1 Introduction
    1.1 Preface
    1.2 Grammar notation
2 Lexical elements
    2.1 Lexical elements
    2.2 Character literals
    2.3 String literals
    2.4 Whole-numbers
        2.4.1 Whole-numbers
        2.4.2 Decimal whole-numbers
        2.4.3 Hexadecimal whole-numbers
        2.4.4 Binary whole-numbers
    2.5 Real numbers
    2.6 Special symbols
    2.7 Reserved words
    2.8 Identifiers
        2.8.1 Identifiers
        2.8.2 Built-in identifiers
        2.8.3 User-defined identifiers
        2.8.4 Directives
            2.8.4.1 Directives
            2.8.4.2 external
            2.8.4.3 forward
    2.9 Comments
3 Labels
    3.1 Labels
4 Constants
    4.1 Constants
    4.2 maxbyte
    4.3 maxchar
    4.4 maxint
    4.5 maxword
    4.6 nil
    4.7 Boolean Constants
    4.8 Feature constants
        4.8.1 Feature constants
        4.8.2 feature_calldll
        4.8.3 feature_closedir
        4.8.4 feature_clrscr
        4.8.5 feature_delay
        4.8.6 feature_gotoxy
        4.8.7 feature_idispatch
        4.8.8 feature_intr
        4.8.9 feature_keypressed
        4.8.10 feature_mysql
        4.8.11 feature_odbc
        4.8.12 feature_opendir
        4.8.13 feature_popen
        4.8.14 feature_readdir
        4.8.15 feature_readkey
        4.8.16 feature_rewinddir
        4.8.17 feature_textbackground
        4.8.18 feature_textcolor
        4.8.19 feature_wherex
        4.8.20 feature_wherey
    4.9 FileMode constants
        4.9.1 Filemode constants
        4.9.2 appendmode
        4.9.3 readmode
        4.9.4 writemode
    4.10 Permission constants
        4.10.1 Permission constants
        4.10.2 dir_bit
        4.10.3 grp_r
        4.10.4 grp_w
        4.10.5 grp_x
        4.10.6 oth_r
        4.10.7 oth_w
        4.10.8 oth_x
        4.10.9 usr_r
        4.10.10 usr_w
        4.10.11 usr_x
    4.11 Platform constants
        4.11.1 Platform constants
        4.11.2 platform_dos
        4.11.3 platform_error
        4.11.4 platform_fbsd
        4.11.5 platform_linux
        4.11.6 platform_os2
        4.11.7 platform_solaris
        4.11.8 platform_solaris_sparc
        4.11.9 platform_win32
    4.12 Recordset type constants
        4.12.1 Recordset type constants
        4.12.2 rsdefault
        4.12.3 rsdynamic
        4.12.4 rsforward
        4.12.5 rskeyset
        4.12.6 rsstatic
5 Types
    5.1 Types
    5.2 Array types
    5.3 Enumerated types
    5.4 File types
    5.5 List types
    5.6 Object types
        5.6.1 Object types
        5.6.2 Generic objects
    5.7 Ordinal types
    5.8 Pointer types
    5.9 Record types
    5.10 Set types
    5.11 String types
    5.12 Subrange types
    5.13 Integral types
    5.14 Built-in type identifiers
        5.14.1 Built-in type identifiers
        5.14.2 binary type
        5.14.3 boolean type
        5.14.4 byte type
        5.14.5 char type
        5.14.6 connection type
            5.14.6.1 Connection type
            5.14.6.2 connection.close
            5.14.6.3 connection.execute
            5.14.6.4 connection.open
            5.14.6.5 connection.selectdatabase
            5.14.6.6 connection.databasename
            5.14.6.7 connection.dbmsname
            5.14.6.8 connection.dbmsver
            5.14.6.9 connection.dmver
            5.14.6.10 connection.odbcver
            5.14.6.11 connection.procedures
            5.14.6.12 connection.readonly
            5.14.6.13 connection.transactions
            5.14.6.14 connection.transsupport
        5.14.7 dir type
        5.14.8 error type
        5.14.9 filename type
        5.14.10 integer type
        5.14.11 real type
        5.14.12 recordset type
            5.14.12.1 Recordset type
            5.14.12.2 recordset.close
            5.14.12.3 recordset.moreresults
            5.14.12.4 recordset.movenext
            5.14.12.5 recordset.open
            5.14.12.6 recordset.eof
            5.14.12.7 recordset.field
        5.14.13 registers type
        5.14.14 regtype type
        5.14.15 text type
        5.14.16 word type
6 Variables
    6.1 Variables
    6.2 Array variables
    6.3 File variables
    6.4 List variables
    6.5 Object variables
    6.6 Pointer variables
    6.7 Record variables
    6.8 Set variables
    6.9 String variables
    6.10 Built-in variable identifiers
        6.10.1 Built-in variable identifiers
        6.10.2 errors
        6.10.3 exitcode
        6.10.4 input
        6.10.5 output
7 Functions and procedures
    7.1 Functions and procedures
    7.2 Built-in functions
        7.2.1 Built-in functions
        7.2.2 abs
        7.2.3 arctan
        7.2.4 chr
        7.2.5 concat
        7.2.6 copy
        7.2.7 copyword
        7.2.8 cos
        7.2.9 cosh
        7.2.10 countwords
        7.2.11 createobject
        7.2.12 dirsep
        7.2.13 eof
        7.2.14 eoln
        7.2.15 exp
        7.2.16 fexpand
        7.2.17 filematch
        7.2.18 filepos
        7.2.19 filesize
        7.2.20 frac
        7.2.21 getenv
        7.2.22 getlasterror
        7.2.23 hex
        7.2.24 int
        7.2.25 ioresult
        7.2.26 isalpha
        7.2.27 isalphanum
        7.2.28 isdigit
        7.2.29 islower
        7.2.30 isnull
        7.2.31 isprint
        7.2.32 isspace
        7.2.33 isupper
        7.2.34 isxdigit
        7.2.35 keypressed
        7.2.36 length
        7.2.37 ln
        7.2.38 log
        7.2.39 locase
        7.2.40 lowercase
        7.2.41 odd
        7.2.42 ord
        7.2.43 paramcount
        7.2.44 paramstr
        7.2.45 pi
        7.2.46 platform
        7.2.47 pos
        7.2.48 pred
        7.2.49 random
        7.2.50 readkey
        7.2.51 reverse
        7.2.52 round
        7.2.53 sin
        7.2.54 sinh
        7.2.55 sqr
        7.2.56 sqrt
        7.2.57 succ
        7.2.58 supported
        7.2.59 swap
        7.2.60 system
        7.2.61 tan
        7.2.62 tanh
        7.2.63 trim
        7.2.64 trunc
        7.2.65 unixplatform
        7.2.66 upcase
        7.2.67 uppercase
        7.2.68 urldecode
        7.2.69 version
        7.2.70 wherex
        7.2.71 wherey
    7.3 Built-in Procedures
        7.3.1 Built-in procedures
        7.3.2 append
        7.3.3 assert
        7.3.4 assign
        7.3.5 chdir
        7.3.6 close
        7.3.7 closedir
        7.3.8 clrscr
        7.3.9 crc32
        7.3.10 dec
        7.3.11 delay
        7.3.12 delete
        7.3.13 dispose
        7.3.14 erase
        7.3.15 exec
        7.3.16 exit
        7.3.17 fill
        7.3.18 flush
        7.3.19 fsplit
        7.3.20 get
        7.3.21 getdate
        7.3.22 getfiledate
        7.3.23 getfilemode
        7.3.24 getfiletime
        7.3.25 gettime
        7.3.26 gotoxy
        7.3.27 halt
        7.3.28 inc
        7.3.29 insert
        7.3.30 intr
        7.3.31 mkdir
        7.3.32 msdos
        7.3.33 new
        7.3.34 open
        7.3.35 opendir
        7.3.36 pack
        7.3.37 page
        7.3.38 popen
        7.3.39 put
        7.3.40 randomize
        7.3.41 rawread
        7.3.42 rawwrite
        7.3.43 read
        7.3.44 readdir
        7.3.45 readln
        7.3.46 rename
        7.3.47 reset
        7.3.48 rewinddir
        7.3.49 rewrite
        7.3.50 rmdir
        7.3.51 seek
        7.3.52 setfiledate
        7.3.53 setfiletime
        7.3.54 sleep
        7.3.55 str
        7.3.56 textbackground
        7.3.57 textcolor
        7.3.58 traperrors
        7.3.59 unpack
        7.3.60 val
        7.3.61 write
        7.3.62 writeln
    7.4 External functions And procedures
8 Expressions
    8.1 Expressions
    8.2 Operators
        8.2.1 Operators
        8.2.2 Arithmetic operators
            8.2.2.1 Arithmetic operators
            8.2.2.2 Addition operator
            8.2.2.3 Subtraction operator
            8.2.2.4 Multiplication operator (real numbers)
            8.2.2.5 Division operator (real numbers)
            8.2.2.6 div operator
            8.2.2.7 mod operator
        8.2.3 Equality operators
            8.2.3.1 Equality operators
            8.2.3.2 Is equal operator
            8.2.3.3 Is not equal operator
        8.2.4 Relational operators
            8.2.4.1 Relational operators
            8.2.4.2 Is less than operator
            8.2.4.3 Is less than or equal operator
            8.2.4.4 Is greater than operator
            8.2.4.5 Is greater than or equal operator
        8.2.5 Boolean operators
            8.2.5.1 Boolean operators
            8.2.5.2 not operator
            8.2.5.3 and operator
            8.2.5.4 and_then operator
            8.2.5.5 or operator
            8.2.5.6 or_else operator
            8.2.5.7 xor operator
        8.2.6 String operators
            8.2.6.1 String operators
            8.2.6.2 Concatenation
        8.2.7 Set operators
            8.2.7.1 Set operators
            8.2.7.2 Set union operator
            8.2.7.3 Set difference  operator
            8.2.7.4 Set intersection operator
            8.2.7.5 in operator
        8.2.8 Bitwise operators
            8.2.8.1 Bitwise operators
            8.2.8.2 not operator (bitwise)
            8.2.8.3 and operator (bitwise)
            8.2.8.4 or operator (bitwise)
            8.2.8.5 xor operator (bitwise)
            8.2.8.6 shl operator
            8.2.8.7 shr operator
    8.3 Compatible Types
9 Statements
    9.1 Statements
    9.2 Empty statement
    9.3 Assignment statement
        9.3.1 Assignment statement
        9.3.2 Assignment compatibility
            9.3.2.1 Assignment compatibility
            9.3.2.2 Assignment compatibility with array indexing
            9.3.2.3 Assignnment compatibility with value parameters
            9.3.2.4 Assignment compatibility with "read"
            9.3.2.5 Assignment compatibility with assignment Statements
            9.3.2.6 Assignment compatibility with "for"
            9.3.2.7 Transfer procedures
    9.4 Procedure statement
    9.5 Goto statement
    9.6 Compound statement
    9.7 If statement
    9.8 Case statement
    9.9 Repeat statement
    9.10 While statement
    9.11 For statement
    9.12 With statement
    9.13 Procedure method call
10 Program Parameters
    10.1 Program parameters
11 Appendix A
    11.1 Irie Pascal Grammar
12 Appendix B
    12.1 Extensions to Pascal as specified by ISO/IEC 7185
    12.2 Relaxed declarations
    12.3 Constant ranges
    12.4 Otherwise
    12.5 Relaxed parameter list congruity
    12.6 Non-numeric statement labels
    12.7 Underscores in identifiers
    12.8 Binary whole-number constants
    12.9 Hexadecimal whole-number constants
    12.10 Input and Output automatically declared
    12.11 Double-quoted literals
    12.12 and_then operator
    12.13 or_else operator
    12.14 Bitwise operators
    12.15 Extended constants
    12.16 Extended types
    12.17 Extended variables
    12.18 Extended functions
    12.19 Extended procedures

---------------
1 Introduction:
---------------

------------
1.1 Preface:
------------
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.2 Grammar notation:
---------------------
In this manual the syntax of the Irie Pascal language is described using
a context-free grammar. Context-free grammars are often used to describe
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 its definition.
The special symbols are |, {}, [], and (). The | symbol is used to separate
alternatives (i.e. the grammar allows either the symbols on its left-hand
side or the symbols on its right-hand side). The {} symbols are used to
enclose symbols that can appear zero, one, or more times. The []
symbols are used to enclose optional symbols (i.e. optional symbols
can appear zero or one times). The () symbols are used to group symbols
that are evaluated together. The terminal symbols are enclosed in single
quotes ('') to distinguish them from non-terminal symbols. 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 lowercase letter or an uppercase letter or an underscore.
A digit is one of the decimal numerals.

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

See also 11.1 Irie Pascal Grammar.

-------------------
2 Lexical elements:
-------------------

---------------------
2.1 Lexical elements:
---------------------
Lexical elements are the smallest groups of characters that
are meaningful in an Irie Pascal program.

See also 2.2 Character literals, 2.3 String literals,
2.4.1 Whole-numbers, 2.5 Real numbers, 2.6 Special symbols,
2.7 Reserved words, 2.8.1 Identifiers, and 2.9 Comments.

-----------------------
2.2 Character literals:
-----------------------
A character literal represents a single character and can take one
of three different forms.

The first form is the character being represented enclosed in single
quotes ('). As a special case if the character being represented is
a single quote then the character literal consists of two single quotes
together enclosed by single quotes. For example

   'A' represents the character A

and

   '''' represents the character '

Character literals are case-sensitive so 'X' is not equal to 'x'. This
first form is the only form defined by Standard Pascal.

The second form is the character being represented enclosed in double
quotes ("). As a special case if the character being represented is
a double quote then the character literal consists of two double quotes
together encloded by double quotes. For example

   "A" represents the character A

and

   """" represents the character "

Character literals are case-sensitive so "X" is not equal to "x". This
second form is an extension to Standard Pascal and is provided
mainly to make it easy to represent characters containing single
quotes (i.e. you can use "'" instead of '''').

The third form is a pound sign followed by the character code of the
character being represented. For example

   #65 represents the character A (assuming the ANSI or ASCII character set)

and

   #9 represents the tab character (assuming the ANSI or ASCII character set)

The syntax for character literals is as follows

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

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

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

   character-code = digit-sequence

   digit-sequence = digit { digit }

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

   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 more examples of valid character literals:
   'A'    '+'    ' '    ''''     '"'
   "A"    "+"    " "    "'"      """"
   #65    #43    #32    #39      #34

See also 2.1 Lexical elements, 2.3 String literals, 5.14.5 char type,
and 12.11 Double-quoted literals.

--------------------
2.3 String literals:
--------------------
String literals are 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) 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 string literals:
   ''     '   '  'Don''t'        'Say "Hello"'     '!@#$%^&*()'
   ""     "   "  "Don't"         "Say ""Hello"""   "!@#$%^&*()"

See also 2.1 Lexical elements, 2.2 Character literals, 5.2 Array types,
5.11 String types, and 12.11 Double-quoted literals.

------------------
2.4 Whole-numbers:
------------------

--------------------
2.4.1 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

See also 2.1 Lexical elements, 2.4.2 Decimal whole-numbers,
2.4.3 Hexadecimal whole-numbers, and 2.4.4 Binary whole-numbers.

----------------------------
2.4.2 Decimal whole-numbers:
----------------------------
A decimal whole numnber uses base 10.

The syntax for decimal whole numbers is as follows:

   decimal-whole-number = digit-sequence

   digit-sequence = digit { digit }

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

Here are some examples of valid decimal whole number

   100     0      7453    000005

See also 2.4.1 Whole-numbers.

--------------------------------
2.4.3 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 = '$' hex-digit-sequence

   hex-digit-sequence = hex-digit { hex-digit }

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

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

Here are some examples of valid hexadecimal whole numbers

   $64     $0      +$FF       $000aB4

See also 2.4.1 Whole-numbers,
and 12.9 Hexadecimal whole-number constants.

---------------------------
2.4.4 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 = '%' bit-sequence

   bit-sequence = bit { bit }

   bit = '0' | '1'

Here are some examples of valid binary whole numbers

   %01100110     %0      +%11111111

See also 2.4.1 Whole-numbers, and 12.8 Binary whole-number constants.

-----------------
2.5 Real numbers:
-----------------
Real numbers are numbers with fractional parts. Leading zeroes are not
significant in reals.

The syntax for real numbers is as follows

   real-number =
       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 real numbers with values between about

   1e308

and about

  -1e308

See also 2.1 Lexical elements.

--------------------
2.6 Special symbols:
--------------------
Special symbols have special meanings to the compiler.

The syntax for special symbols is given below:

   special-symbol =
     '+' | '-' | '*' | '/' |
     '=' | '<>' | '<' | '<=' | '>' | '>=' |
     '(' | ')' |
     '[' | ']' | '(.' | '.)' |
     ':=' | '.' | ',' | ';' | '..' |
     '^' | '@'

See also 2.1 Lexical elements.

-------------------
2.7 Reserved words:
-------------------
Reserved words (also called 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 reserved words and
identifiers case-sensitive.

The syntax for keywords is given below:

   keywords = 'and' | 'and_then' | 'array' |
           'begin' |
           'case' | 'class' | 'const' |
           'div' | 'do' | 'downto' |
           'else' | 'end' |
           'file' | 'for' | 'function' |
           'goto' |
           'if' | 'in' |
           'label' | 'list'
           'mod' |
           'nil' | 'not' |
           'object' | '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.

See also 2.1 Lexical elements.

----------------
2.8 Identifiers:
----------------

------------------
2.8.1 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 reserved words 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 its
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'

See also 2.1 Lexical elements, 2.8.4.1 Directives,
2.8.2 Built-in identifiers, 2.8.3 User-defined identifiers,
and 12.7 Underscores in identifiers.

---------------------------
2.8.2 Built-in identifiers:
---------------------------
Built-in identifiers are automatically declared by the compiler.
Unlike keywords, you can declare your own 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 created by the compiler

   type
      boolean = (false, true);

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

See also 2.8.1 Identifiers.

-------------------------------
2.8.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.

See also 2.8.1 Identifiers, 3.1 Labels, 4.1 Constants, 5.1 Types,
6.1 Variables, and 7.1 Functions and procedures.

-----------------
2.8.4 Directives:
-----------------

-------------------
2.8.4.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.

See also 2.8.1 Identifiers, 2.8.4.3 forward, and 2.8.4.2 external.

-----------------
2.8.4.2 external:
-----------------
The "external" directive specifies that the function or procedure being
declared is located outside of the program. Currently the only external
functions and procedures supported are functions and procedures located
in Windows DLLs.

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 convention should be used
   (This is the default).
and
   "cdecl" specifies that the cdecl calling convention should be used

See also 2.8.4.1 Directives, 2.8.4.3 forward,
and 7.4 External functions And procedures.

----------------
2.8.4.3 forward:
----------------
The "forward" directive specifies that the current function or procedure
declaration is incomplete, and the full declaration will occur later
on in the program.

See also 7.1 Functions and procedures, 2.8.4.1 Directives,
and 2.8.4.2 external.

-------------
2.9 Comments:
-------------
Comments are sequences of characters enclosed in 

      {      or       (* 

and

      }      or       *)

As an extension Irie Pascal also recognizes comments beginning with //
(in which case the // and any text that follows on the same line
is ignored). So for example the line below is a comment.

   //rest of the text on the line

Comments are treated like spaces by the compiler and therefore have no
effect on your program except possible to separate identifiers
For example 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.

Support for nested comments is disabled by default since in Standard Pascal
comments do not nest.

See also 2.1 Lexical elements.

---------
3 Labels:
---------

-----------
3.1 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

Example:

//*************************************************************
//This program counts counts from 1 to 10 using goto
//*************************************************************
program count(output);
label write_count;
const
   minimum = 1;
   maximum = 10;
var
   count : integer;
begin
   count := minimum;
   write_count: writeln(count);
   count := count + 1;
   if count <= maximum then goto write_count
end.

See also 2.8.3 User-defined identifiers, 2.8.1 Identifiers,
9.1 Statements, 9.5 Goto statement, 12.6 Non-numeric statement labels,
and 12.2 Relaxed declarations.

------------
4 Constants:
------------

--------------
4.1 Constants:
--------------
Constants can be character literals, string literals, whole numbers,
real numbers, or constant identifiers. Character and string literals,
whole numbers, and real numbers have already been described in previous
sections

Constant identifiers are identifiers that have been bound to a constant
using a constant declaration or by an enumerated type 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 = [sign] whole-number |
              [sign] real-number |
              [sign] constant-identifier
                     character-literal |

   sign = '+' | '-'

Here is an example of a constant definition group:

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

See also 2.8.3 User-defined identifiers, 2.8.1 Identifiers, 4.2 maxbyte,
4.3 maxchar, 4.4 maxint, 4.5 maxword, 4.6 nil, 4.7 Boolean Constants,
4.8.1 Feature constants, 4.9.1 Filemode constants,
4.10.1 Permission constants, 4.11.1 Platform constants,
4.12.1 Recordset type constants, 5.3 Enumerated types,
and 12.2 Relaxed declarations.

------------
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).

See also 4.1 Constants, and 12.15 Extended constants.

------------
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 (#255).

See also 4.1 Constants, 5.14.4 byte type, and 12.15 Extended constants.

-----------
4.4 maxint:
-----------
Irie Pascal supports the built-in integer constant "maxint" which is
equal to the largest supported integer value (2,147,483,647).

See also 4.1 Constants, and 5.14.10 integer type.

------------
4.5 maxword:
------------
As an extension Irie Pascal supports the built-in word constant "maxword"
which is equal to the largest supported word value (4,294,967,295).

See also 4.1 Constants, 5.14.16 word type, and 12.15 Extended constants.

--------
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".

As an extension Irie Pascal associates "nil" with all object types. This
constant can be assiged to any object reference to indicate the the
reference doesn't point at any object. Any object reference can be
compared with "nil".

See also 4.1 Constants, 5.6.1 Object types, and 5.8 Pointer types.

----------------------
4.7 Boolean Constants:
----------------------
Irie Pascal supports a built-in enumerated type named "boolean",
which defines two enumerated constants as below:

type
   boolean = (false, true);

The ordinal value of "false" is zero.
The ordinal value of "true" is one.

See also 4.1 Constants, 5.3 Enumerated types, 5.8 Pointer types,
and 5.14.3 boolean type.

----------------------
4.8 Feature constants:
----------------------

------------------------
4.8.1 Feature constants:
------------------------
Irie Pascal supports several built-in constants that an application
can pass to the built-in function "supported" to determine if particular
features are available on the current platform.

One approuch is to have your application check on start-up to make
sure all necessary features are available. If a necessary feature
is not available your application could then report which feature
is missing and abort.

Another approuch is to have your application run with reduced
functionality if certain features are not available.

For example an application could pass the "feature_odbc" constant to
the "supported" function to determine if ODBC is supported before
attempting to use ODBC to connect to a database.

See also 4.1 Constants, 4.8.2 feature_calldll, 4.8.3 feature_closedir,
4.8.4 feature_clrscr, 4.8.5 feature_delay, 4.8.6 feature_gotoxy,
4.8.7 feature_idispatch, 4.8.8 feature_intr, 4.8.9 feature_keypressed,
4.8.10 feature_mysql, 4.8.11 feature_odbc, 4.8.12 feature_opendir,
4.8.13 feature_popen, 4.8.14 feature_readdir, 4.8.15 feature_readkey,
4.8.16 feature_rewinddir, 4.8.17 feature_textbackground,
4.8.18 feature_textcolor, 4.8.19 feature_wherex, 4.8.20 feature_wherey,
7.2.58 supported, and 12.15 Extended constants.

----------------------
4.8.2 feature_calldll:
----------------------
This constant can be used to determine if the current platform supports
calling external functions and procedures in DLLs.

Example:

if supported(feature_calldll) then
   begin
      //Calling DLLs is supported so go ahead and make the calls.
   end
else
   begin
      //Calling DLLs is not supported so do something else of abort.
   end

See also 4.8.1 Feature constants, 7.2.58 supported,
and 7.4 External functions And procedures.

-----------------------
4.8.3 feature_closedir:
-----------------------
This constant can be used to determine if the current platform supports
the built-in procedure "closedir".

Example:

if (supported(feature_closedir)) and
   (supported(feature_readdir)) and
   (supported(feature_opendir)) then
   begin
      //open directory, retrieve filenames, and then close directory
   end
else
   begin
      //Opening, reading, and closing directories is not supported so do
      // something else of abort.
   end

See also 4.8.1 Feature constants, 7.2.58 supported, and 7.3.7 closedir.

---------------------
4.8.4 feature_clrscr:
---------------------
This constant can be used to determine if the current platform supports
the built-in procedure "clrscr".

Example:

if supported(feature_clrscr) then clrscr;

See also 4.8.1 Feature constants, 7.2.58 supported, and 7.3.8 clrscr.

--------------------
4.8.5 feature_delay:
--------------------
This constant can be used to determine if the current platform supports
the built-in procedure "delay".

Example:

if supported(feature_delay) then delay(100);

See also 4.8.1 Feature constants, 7.2.58 supported, and 7.3.11 delay.

---------------------
4.8.6 feature_gotoxy:
---------------------
This constant can be used to determine if the current platform supports
the built-in procedure "gotoxy".

Example:

if not supported(feature_gotoxy) then
   begin
      writeln('gotoxy not supported on the current platform');
      abort
   end;

See also 4.8.1 Feature constants, 7.2.58 supported, and 7.3.26 gotoxy.

------------------------
4.8.7 feature_idispatch:
------------------------
This constant can be used to determine if the current platform supports
accessing COM objects using the IDISPATCH interface.

Example:

program SendEmailWithCDONTS(output);
begin
   obj : object;
begin
   if supported(feature_idispatch) then
      begin
         obj := createobject('CDONTS.NewMail');
         obj.send('from address', 'to address', 'subject', 'body', 1);
         dispose(obj);
      end
   else
      writeln('Can not send email')
end.

See also 4.8.1 Feature constants, 7.2.58 supported,
and 5.6.2 Generic objects.

-------------------
4.8.8 feature_intr:
-------------------
This constant can be used to determine if the current platform supports
calling the built-in procedure "intr".

Example:

if not supported(feature_intr) then
   begin
      writeln('x86 interrupts not supported on the current platform');
      abort
   end;

See also 4.8.1 Feature constants, 7.2.58 supported, and 7.3.30 intr.

-------------------------
4.8.9 feature_keypressed:
-------------------------
This constant can be used to determine if the current platform supports
calling the built-in function "keypressed".

Example:

if not supported(feature_keypressed) then
   begin
      writeln('keypressed not supported on the current platform');
      abort
   end;

See also 4.8.1 Feature constants, 7.2.58 supported,
and 7.2.35 keypressed.

---------------------
4.8.10 feature_mysql:
---------------------
This constant can be used to determine if the current platform supports
MySQL databases.

Example:

program Data(input, output);
var
   conn : connection;

   procedure DisplayError(msg : string);
   begin
      writeln('ERROR:',msg);
      halt
   end;

   function GetConnectionString : string;
   var
      s, sDSN, sUSER, sPassword : string;

      function GetStringValue(sPrompt : string) : string;
      var
         sValue : string;
      begin
         write(sPrompt);
         readln(sValue);
         GetStringValue := sValue
      end;

   begin
      if supported(feature_odbc) then
         begin
            sDSN := GetStringValue('Enter Data Source Name (DSN):');
            sUser := GetStringValue('Enter user id:');
            sPassword := GetStringValue('Enter password:');
            s := 'ODBC;DSN='+sDSN+';user='+sUser+';password='+sPassword;
         end
      else if supported(feature_mysql) then
         begin
            sUser := GetStringValue('Enter user id:');
            sPassword := GetStringValue('Enter password:');
            s := 'MYSQL;user="'+sUser+'";password="'+sPassword+'";socket="/tmp/mysql.sock"';
         end
      else
         DisplayError('No database support detected');
      GetConnectionString := s;
   end;

begin
   new(conn);
   conn.open(GetConnectionString);
   //
   //Add code here to process database
   //
   conn.close;
   dispose(conn);
end.

See also 4.8.1 Feature constants, 7.2.58 supported,
and 5.14.6.1 Connection type.

--------------------
4.8.11 feature_odbc:
--------------------
This constant can be used to determine if the current platform supports
using ODBC to connect to databases.

Example:

program Data(input, output);
var
   conn : connection;

   procedure DisplayError(msg : string);
   begin
      writeln('ERROR:',msg);
      halt
   end;

   function GetConnectionString : string;
   var
      s, sDSN, sUSER, sPassword : string;

      function GetStringValue(sPrompt : string) : string;
      var
         sValue : string;
      begin
         write(sPrompt);
         readln(sValue);
         GetStringValue := sValue
      end;

   begin
      if supported(feature_odbc) then
         begin
            sDSN := GetStringValue('Enter Data Source Name (DSN):');
            sUser := GetStringValue('Enter user id:');
            sPassword := GetStringValue('Enter password:');
            s := 'ODBC;DSN='+sDSN+';user='+sUser+';password='+sPassword;
         end
      else if supported(feature_mysql) then
         begin
            sUser := GetStringValue('Enter user id:');
            sPassword := GetStringValue('Enter password:');
            s := 'MYSQL;user="'+sUser+'";password="'+sPassword+'";socket="/tmp/mysql.sock"';
         end
      else
         DisplayError('No database support detected');
      GetConnectionString := s;
   end;

begin
   new(conn);
   conn.open(GetConnectionString);
   //
   //Add code here to process database
   //
   conn.close;
   dispose(conn);
end.

See also 4.8.1 Feature constants, 7.2.58 supported,
and 5.14.6.1 Connection type.

-----------------------
4.8.12 feature_opendir:
-----------------------
This constant can be used to determine if the current platform supports
the built-in procedure "opendir".

Example:

if (supported(feature_closedir)) and
   (supported(feature_readdir)) and
   (supported(feature_opendir)) then
   begin
      //open directory, retrieve filenames, and then close directory
   end
else
   begin
      //Opening, reading, and closing directories is not supported so do
      // something else of abort.
   end

See also 4.8.1 Feature constants, 7.2.58 supported, and 7.3.35 opendir.

---------------------
4.8.13 feature_popen:
---------------------
This constant can be used to determine if the current platform supports
calling the built-in procedure "popen".

Example:

if not supported(feature_popen) then
   begin
      writeln('popen not supported on the current platform');
      abort
   end;

See also 4.8.1 Feature constants, 7.2.58 supported, and 7.3.38 popen.

-----------------------
4.8.14 feature_readdir:
-----------------------
This constant can be used to determine if the current platform supports
the built-in procedure "readdir".

Example:

if (supported(feature_closedir)) and
   (supported(feature_readdir)) and
   (supported(feature_opendir)) then
   begin
      //open directory, retrieve filenames, and then close directory
   end
else
   begin
      //Opening, reading, and closing directories are not supported so do
      // something else of abort.
   end

See also 4.8.1 Feature constants, 7.2.58 supported, and 7.3.44 readdir.

-----------------------
4.8.15 feature_readkey:
-----------------------
This constant can be used to determine if the current platform supports
calling the built-in function "readkey".

Example:

if not supported(feature_readkey) then
   begin
      writeln('readkey not supported on the current platform');
      abort
   end;

See also 4.8.1 Feature constants, 7.2.58 supported, and 7.2.50 readkey.

-------------------------
4.8.16 feature_rewinddir:
-------------------------
This constant can be used to determine if the current platform supports
the built-in procedure "rewinddir".

Example:

if supported(feature_rewinddir) then rewinddir;

See also 4.8.1 Feature constants, 7.2.58 supported, and 7.3.48 rewinddir.

------------------------------
4.8.17 feature_textbackground:
------------------------------
This constant can be used to determine if the current platform supports
the built-in procedure "textbackground".

Example:

program color(output);
const
   blue = 1;
   white = 15;
begin
   if supported(feature_textbackground) then textbackground(blue);
   if supported(feature_textcolor) then textcolor(white);
   writeln('white on blue');
end.

See also 4.8.1 Feature constants, 7.2.58 supported,
and 7.3.56 textbackground.

-------------------------
4.8.18 feature_textcolor:
-------------------------
This constant can be used to determine if the current platform supports
the built-in procedure "textcolor".

Example:

program color(output);
const
   blue = 1;
   white = 15;
begin
   if supported(feature_textbackground) then textbackground(blue);
   if supported(feature_textcolor) then textcolor(white);
   writeln('white on blue');
end.

See also 4.8.1 Feature constants, 7.2.58 supported, and 7.3.57 textcolor.

----------------------
4.8.19 feature_wherex:
----------------------
This constant can be used to determine if the current platform supports
the built-in function "wherex".

Example:

if supported(feature_wherex) then xpos := wherex;
if supported(feature_wherey) then ypos := wherey;

See also 4.8.1 Feature constants, 7.2.58 supported, and 7.2.70 wherex.

----------------------
4.8.20 feature_wherey:
----------------------
This constant can be used to determine if the current platform supports
the built-in function "wherey".

Example:

if supported(feature_wherex) then xpos := wherex;
if supported(feature_wherey) then ypos := wherey;

See also 4.8.1 Feature constants, 7.2.58 supported, and 7.2.71 wherey.

-----------------------
4.9 FileMode constants:
-----------------------

-------------------------
4.9.1 Filemode constants:
-------------------------
As an extension Irie Pascal supports three integral constants,
which can be used with the built-in procedures "open" and "popen",
to specify the mode a file or pipe should be opened in.

See also 4.1 Constants, 4.9.2 appendmode, 4.9.3 readmode,
4.9.4 writemode, 7.3.34 open, 7.3.38 popen, and 12.15 Extended constants.

-----------------
4.9.2 appendmode:
-----------------
"appendmode" specifies that the file should be opened for writing, and
that all writes will occur at the end of the file. Using "appendmode"
with "popen" is not recomended.

Examples:

   open(file_variable, 'filename', appendmode);

See also 4.9.1 Filemode constants, 4.9.3 readmode, 4.9.4 writemode,
and 7.3.34 open.

---------------
4.9.3 readmode:
---------------
"readmode" specifies that the file or pipe should be opened for reading.
This constant can be combined with "writemode" to specify that
the file or pipe should be opened for both reading and writing.

Examples:

   open(file_variable, 'filename', readmode);

   open(file_variable, 'filename', readmode+writemode);

   open(file_variable, 'filename', readmode or writemode);

See also 4.9.1 Filemode constants, 4.9.2 appendmode, 4.9.4 writemode,
7.3.34 open, and 7.3.38 popen.

----------------
4.9.4 writemode:
----------------
"writemode" specifies that the file or pipe should be opened for writing.
This constant can be combined with "readmode" to specify that
the file or pipe should be opened for both reading and writing.

Examples:

   open(file_variable, 'filename', writemode);

   open(file_variable, 'filename', readmode+writemode);

   open(file_variable, 'filename', readmode or writemode);

See also 4.9.1 Filemode constants, 4.9.2 appendmode, 4.9.3 readmode,
7.3.34 open, and 7.3.38 popen.

--------------------------
4.10 Permission constants:
--------------------------

----------------------------
4.10.1 Permission constants:
----------------------------
As an extension Irie Pascal supports ten built-in integral constants
which can be used with the built-in procedures "mkdir" and "getfilemode"
to specify or identify read, write, and execute/search permissions, as
well as to find out whether a file is a directory.

The constants are

   "dir_bit",
   "usr_r", "usr_w", "usr_x"
   "grp_r", "grp_w", "grp_x"
   "oth_r", "oth_w", "oth_x"

Example:

program AllPermissions(input, output);
var
   s : filename;
   mode : integer;
   isdir : boolean;
begin
   write('Enter filename:');
   readln(s);
   s := fexpand(s);
   getfilemode(s, mode);
   isdir := (mode and dir_bit) <> 0;
   if isdir then
      writeln(s, ' is a directory')
   else
      writeln(s, ' is not a directory');
   write('Owner permissions :');
   if (mode and usr_r) <> 0 then
      write(' Read');
   if (mode and usr_w) <> 0 then
      write(' Write');
   if (mode and usr_x) <> 0 then
      if isdir then
         write(' Search')
      else
         write(' Execute');
   writeln;
   write('Group permissions :');
   if (mode and grp_r) <> 0 then
      write(' Read');
   if (mode and grp_w) <> 0 then
      write(' Write');
   if (mode and grp_x) <> 0 then
      if isdir then
         write(' Search')
      else
         write(' Execute');
   writeln;
   write('Other permissions :');
   if (mode and oth_r) <> 0 then
      write(' Read');
   if (mode and oth_w) <> 0 then
      write(' Write');
   if (mode and oth_x) <> 0 then
      if isdir then
         write(' Search')
      else
         write(' Execute');
   writeln;
end.

See also 4.1 Constants, 4.10.2 dir_bit, 4.10.3 grp_r, 4.10.4 grp_w,
4.10.5 grp_x, 4.10.6 oth_r, 4.10.7 oth_w, 4.10.8 oth_x, 4.10.9 usr_r,
4.10.10 usr_w, 4.10.11 usr_x, 7.3.23 getfilemode, 7.3.31 mkdir,
and 12.15 Extended constants.

---------------
4.10.2 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.

For example the simple program below asks for a filename and
then tests whether the file is a directory:

   program isdirectory(input, output);
   var
      s : filename;
      mode : integer;
      isdir : boolean;
   begin
      write('Enter filename:');
      readln(s);
      s := fexpand(s);
      getfilemode(s, mode);
      isdir := (mode and dir_bit) <> 0;
      if isdir then
         writeln(s, ' is a directory')
      else
         writeln(s, ' is not a directory');
   end.

See also 4.10.1 Permission constants, and 7.3.23 getfilemode.

-------------
4.10.3 grp_r:
-------------
The "grp_r" permission constant specifies that any user belonging to
the same group as the owner of the file or directory has permission to
read the file or directory.

For example the simple program below asks for a filename and then
displays the group permissions for the file.

   program GroupPermissions(input, output);
   var
      s : filename;
      mode : integer;
      isdir : boolean;
   begin
      write('Enter filename:');
      readln(s);
      s := fexpand(s);
      getfilemode(s, mode);
      isdir := (mode and dir_bit) <> 0;
      write('Group permissions :');
      if (mode and grp_r) <> 0 then
         write(' Read');
      if (mode and grp_w) <> 0 then
         write(' Write');
      if (mode and grp_x) <> 0 then
         if isdir then
            write(' Search')
         else
            write(' Execute');
      writeln;
   end.

See also 4.10.1 Permission constants, 7.3.23 getfilemode,
and 7.3.31 mkdir.

-------------
4.10.4 grp_w:
-------------
The "grp_w" permission constant specifies that any user belonging to
the same group as the owner of the file or directory has permission to
read the file or directory.

For example the simple program below asks for a filename and then
displays the group permissions for the file.

   program GroupPermissions(input, output);
   var
      s : filename;
      mode : integer;
      isdir : boolean;
   begin
      write('Enter filename:');
      readln(s);
      s := fexpand(s);
      getfilemode(s, mode);
      isdir := (mode and dir_bit) <> 0;
      write('Group permissions :');
      if (mode and grp_r) <> 0 then
         write(' Read');
      if (mode and grp_w) <> 0 then
         write(' Write');
      if (mode and grp_x) <> 0 then
         if isdir then
            write(' Search')
         else
            write(' Execute');
      writeln;
   end.

See also 4.10.1 Permission constants, 7.3.23 getfilemode,
and 7.3.31 mkdir.

-------------
4.10.5 grp_x:
-------------
The "grp_x" permission constant specifies that any user belonging to
the same group as the owner of the file or directory has permission to
execute the file or search the directory.

For example the simple program below asks for a filename and then
displays the group permissions for the file.

   program GroupPermissions(input, output);
   var
      s : filename;
      mode : integer;
      isdir : boolean;
   begin
      write('Enter filename:');
      readln(s);
      s := fexpand(s);
      getfilemode(s, mode);
      isdir := (mode and dir_bit) <> 0;
      write('Group permissions :');
      if (mode and grp_r) <> 0 then
         write(' Read');
      if (mode and grp_w) <> 0 then
         write(' Write');
      if (mode and grp_x) <> 0 then
         if isdir then
            write(' Search')
         else
            write(' Execute');
      writeln;
   end.

See also 4.10.1 Permission constants, 7.3.23 getfilemode,
and 7.3.31 mkdir.

-------------
4.10.6 oth_r:
-------------
The "oth_r" permission constant specifies that any user not belonging to
the same group as the owner of the file or directory has permission to
read the file or directory.

For example the simple program below asks for a filename and then
displays the file permissions for other users.

   program OtherUsersPermissions(input, output);
   var
      s : filename;
      mode : integer;
      isdir : boolean;
   begin
      write('Enter filename:');
      readln(s);
      s := fexpand(s);
      getfilemode(s, mode);
      isdir := (mode and dir_bit) <> 0;
      write('Other permissions :');
      if (mode and oth_r) <> 0 then
         write(' Read');
      if (mode and oth_w) <> 0 then
         write(' Write');
      if (mode and oth_x) <> 0 then
         if isdir then
            write(' Search')
         else
            write(' Execute');
      writeln;
   end.

See also 4.10.1 Permission constants, 7.3.23 getfilemode,
and 7.3.31 mkdir.

-------------
4.10.7 oth_w:
-------------
The "oth_w" permission constant specifies that any user not belonging to
the same group as the owner of the file or directory has permission to
write to the file or directory.

For example the simple program below asks for a filename and then
displays the file permissions for other users.

   program OtherUsersPermissions(input, output);
   var
      s : filename;
      mode : integer;
      isdir : boolean;
   begin
      write('Enter filename:');
      readln(s);
      s := fexpand(s);
      getfilemode(s, mode);
      isdir := (mode and dir_bit) <> 0;
      write('Other permissions :');
      if (mode and oth_r) <> 0 then
         write(' Read');
      if (mode and oth_w) <> 0 then
         write(' Write');
      if (mode and oth_x) <> 0 then
         if isdir then
            write(' Search')
         else
            write(' Execute');
      writeln;
   end.

See also 4.10.1 Permission constants, 7.3.23 getfilemode,
and 7.3.31 mkdir.

-------------
4.10.8 oth_x:
-------------
The "oth_x" permission constant specifies that any user not belonging to
the same group as the owner of the file or directory has permission to
execute the file or search the directory.

For example the simple program below asks for a filename and then
displays the file permissions for other users.

   program OtherUsersPermissions(input, output);
   var
      s : filename;
      mode : integer;
      isdir : boolean;
   begin
      write('Enter filename:');
      readln(s);
      s := fexpand(s);
      getfilemode(s, mode);
      isdir := (mode and dir_bit) <> 0;
      write('Other permissions :');
      if (mode and oth_r) <> 0 then
         write(' Read');
      if (mode and oth_w) <> 0 then
         write(' Write');
      if (mode and oth_x) <> 0 then
         if isdir then
            write(' Search')
         else
            write(' Execute');
      writeln;
   end.

See also 4.10.1 Permission constants, 7.3.23 getfilemode,
and 7.3.31 mkdir.

-------------
4.10.9 usr_r:
-------------
The "usr_r" permission constant specifies that the owner of the file or
directory has permission to read the file or directory.

For example the simple program below asks for a filename and then
displays the file permissions for the file's owner.

   program OwnerPermissions(input, output);
   var
      s : filename;
      mode : integer;
      isdir : boolean;
   begin
      write('Enter filename:');
      readln(s);
      s := fexpand(s);
      getfilemode(s, mode);
      isdir := (mode and dir_bit) <> 0;
      if isdir then
         writeln(s, ' is a directory')
      else
         writeln(s, ' is not a directory');
      write('Owner permissions :');
      if (mode and usr_r) <> 0 then
         write(' Read');
      if (mode and usr_w) <> 0 then
         write(' Write');
      if (mode and usr_x) <> 0 then
         if isdir then
            write(' Search')
         else
            write(' Execute');
      writeln;
   end.

See also 4.10.1 Permission constants, 7.3.23 getfilemode,
and 7.3.31 mkdir.

--------------
4.10.10 usr_w:
--------------
The "usr_w" permission constant specifies that the owner of the file or
directory has permission to write to the file or directory.

For example the simple program below asks for a filename and then
displays the file permissions for the file's owner.

   program OwnerPermissions(input, output);
   var
      s : filename;
      mode : integer;
      isdir : boolean;
   begin
      write('Enter filename:');
      readln(s);
      s := fexpand(s);
      getfilemode(s, mode);
      isdir := (mode and dir_bit) <> 0;
      if isdir then
         writeln(s, ' is a directory')
      else
         writeln(s, ' is not a directory');
      write('Owner permissions :');
      if (mode and usr_r) <> 0 then
         write(' Read');
      if (mode and usr_w) <> 0 then
         write(' Write');
      if (mode and usr_x) <> 0 then
         if isdir then
            write(' Search')
         else
            write(' Execute');
      writeln;
   end.

See also 4.10.1 Permission constants, 7.3.23 getfilemode,
and 7.3.31 mkdir.

--------------
4.10.11 usr_x:
--------------
The "usr_x" permission constant specifies that the owner of the file
or directory has permission to execute the file or search the directory.

For example the simple program below asks for a filename and then
displays the file permissions for the file's owner.

   program OwnerPermissions(input, output);
   var
      s : filename;
      mode : integer;
      isdir : boolean;
   begin
      write('Enter filename:');
      readln(s);
      s := fexpand(s);
      getfilemode(s, mode);
      isdir := (mode and dir_bit) <> 0;
      if isdir then
         writeln(s, ' is a directory')
      else
         writeln(s, ' is not a directory');
      write('Owner permissions :');
      if (mode and usr_r) <> 0 then
         write(' Read');
      if (mode and usr_w) <> 0 then
         write(' Write');
      if (mode and usr_x) <> 0 then
         if isdir then
            write(' Search')
         else
            write(' Execute');
      writeln;
   end.

See also 4.10.1 Permission constants, 7.3.23 getfilemode,
and 7.3.31 mkdir.

------------------------
4.11 Platform constants:
------------------------

--------------------------
4.11.1 Platform constants:
--------------------------
As an extension Irie Pascal supports several integral constants
which can be compared with the value returned by the built-in function
"platform" to determine the platform your program is running on.

See also 4.1 Constants, 4.11.2 platform_dos, 4.11.3 platform_error,
4.11.4 platform_fbsd, 4.11.5 platform_linux, 4.11.6 platform_os2,
4.11.7 platform_solaris, 4.11.8 platform_solaris_sparc,
4.11.9 platform_win32, 7.2.46 platform, and 12.15 Extended constants.

--------------------
4.11.2 platform_dos:
--------------------
The constant "platform_dos" indicates that the current platform is
DOS (i.e. the interpreter running the application is from the DOS
edition of Irie Pascal).

The following simple program uses the platform constants to
display the current platform.

   program ShowPlatform(output);
   begin
      case platform of
      platform_dos: writeln('DOS');
      platform_os2: writeln('OS/2');
      platform_win32: writeln('Windows');
      platform_linux: writeln('Linux');
      platform_fbsd: writeln('FreeBSD');
      platform_solaris: writeln('Solaris/x86');
      platform_solaris_sparc: writeln('Solaris/Sparc');
      platform_error: writeln('Unknown Platform');
      end
  end.

See also 4.11.1 Platform constants, and 7.2.46 platform.

----------------------
4.11.3 platform_error:
----------------------
The constant "platform_error" indicates that the current platform is
unknown (i.e. an error occured trying to identify the platform).

The following simple program uses the platform constants to
display the current platform.

   program ShowPlatform(output);
   begin
      case platform of
      platform_dos: writeln('DOS');
      platform_os2: writeln('OS/2');
      platform_win32: writeln('Windows');
      platform_linux: writeln('Linux');
      platform_fbsd: writeln('FreeBSD');
      platform_solaris: writeln('Solaris/x86');
      platform_solaris_sparc: writeln('Solaris/Sparc');
      platform_error: writeln('Unknown Platform');
      end
  end.

See also 4.11.1 Platform constants, and 7.2.46 platform.

---------------------
4.11.4 platform_fbsd:
---------------------
The constant "platform_fbsd" indicates that the current platform is
FreeBSD (i.e. the interpreter running the application is from the
FreeBSD edition of Irie Pascal).

The following simple program uses the platform constants to
display the current platform.

   program ShowPlatform(output);
   begin
      case platform of
      platform_dos: writeln('DOS');
      platform_os2: writeln('OS/2');
      platform_win32: writeln('Windows');
      platform_linux: writeln('Linux');
      platform_fbsd: writeln('FreeBSD');
      platform_solaris: writeln('Solaris/x86');
      platform_solaris_sparc: writeln('Solaris/Sparc');
      platform_error: writeln('Unknown Platform');
      end
  end.

See also 4.11.1 Platform constants, and 7.2.46 platform.

----------------------
4.11.5 platform_linux:
----------------------
The constant "platform_linux" indicates that the current platform is
Linux (i.e. the interpreter running the application is from the
Linux edition of Irie Pascal).

The following simple program uses the platform constants to
display the current platform.

   program ShowPlatform(output);
   begin
      case platform of
      platform_dos: writeln('DOS');
      platform_os2: writeln('OS/2');
      platform_win32: writeln('Windows');
      platform_linux: writeln('Linux');
      platform_fbsd: writeln('FreeBSD');
      platform_solaris: writeln('Solaris/x86');
      platform_solaris_sparc: writeln('Solaris/Sparc');
      platform_error: writeln('Unknown Platform');
      end
  end.

See also 4.11.1 Platform constants, and 7.2.46 platform.

--------------------
4.11.6 platform_os2:
--------------------
The constant "platform_os2" indicates that the current platform is
OS/2 (i.e. the interpreter running the application is from the OS/2
edition of Irie Pascal).

The following simple program uses the platform constants to
display the current platform.

   program ShowPlatform(output);
   begin
      case platform of
      platform_dos: writeln('DOS');
      platform_os2: writeln('OS/2');
      platform_win32: writeln('Windows');
      platform_linux: writeln('Linux');
      platform_fbsd: writeln('FreeBSD');
      platform_solaris: writeln('Solaris/x86');
      platform_solaris_sparc: writeln('Solaris/Sparc');
      platform_error: writeln('Unknown Platform');
      end
  end.

See also 4.11.1 Platform constants, and 7.2.46 platform.

------------------------
4.11.7 platform_solaris:
------------------------
The constant "platform_solaris" indicates that the current platform is
Solaris/x86 (i.e. the Solaris/x86 edition of the interpreter is running
the application).

The following simple program uses the platform constants to
display the current platform.

   program ShowPlatform(output);
   begin
      case platform of
      platform_dos: writeln('DOS');
      platform_os2: writeln('OS/2');
      platform_win32: writeln('Windows');
      platform_linux: writeln('Linux');
      platform_fbsd: writeln('FreeBSD');
      platform_solaris: writeln('Solaris/x86');
      platform_solaris_sparc: writeln('Solaris/Sparc');
      platform_error: writeln('Unknown Platform');
      end
  end.

See also 4.11.1 Platform constants, and 7.2.46 platform.

------------------------------
4.11.8 platform_solaris_sparc:
------------------------------
The constant "platform_solaris_sparc" indicates that the current platform
is Solaris/Sparc (i.e. the Solaris/Sparc edition of the interpreter is
running the application).

The following simple program uses the platform constants to
display the current platform.

   program ShowPlatform(output);
   begin
      case platform of
      platform_dos: writeln('DOS');
      platform_os2: writeln('OS/2');
      platform_win32: writeln('Windows');
      platform_linux: writeln('Linux');
      platform_fbsd: writeln('FreeBSD');
      platform_solaris: writeln('Solaris/x86');
      platform_solaris_sparc: writeln('Solaris/Sparc');
      platform_error: writeln('Unknown Platform');
      end
  end.

See also 4.11.1 Platform constants, and 7.2.46 platform.

----------------------
4.11.9 platform_win32:
----------------------
The constant "platform_win32" indicates that the current platform is
Win32 (i.e. the Windows edition of the interpreter is running
the application).

The following simple program uses the platform constants to
display the current platform.

   program ShowPlatform(output);
   begin
      case platform of
      platform_dos: writeln('DOS');
      platform_os2: writeln('OS/2');
      platform_win32: writeln('Windows');
      platform_linux: writeln('Linux');
      platform_fbsd: writeln('FreeBSD');
      platform_solaris: writeln('Solaris/x86');
      platform_solaris_sparc: writeln('Solaris/Sparc');
      platform_error: writeln('Unknown Platform');
      end
  end.

See also 4.11.1 Platform constants, and 7.2.46 platform.

------------------------------
4.12 Recordset type constants:
------------------------------

--------------------------------
4.12.1 Recordset type constants:
--------------------------------
As an extension Irie Pascal supports several integral constants
which can be used when opening a recordset to specify the type
of recordset you want to open.
NOTE: You might not get the type of recordset you ask for, if the
database does not support that type of recordset.

See also 4.1 Constants, 4.12.2 rsdefault, 4.12.3 rsdynamic,
4.12.4 rsforward, 4.12.5 rskeyset, 4.12.6 rsstatic,
5.14.12.1 Recordset type, and 12.15 Extended constants.

-----------------
4.12.2 rsdefault:
-----------------
The constant "rsdefault" specifies that the default type of recordset
should be opened. If you are connected to a database with ODBC or
if you are connected to a MySQL database then a forward type recordset
is opened.

Example:

   rs.open(conn, sSQL, rsdefault);

In the example above
   "rs" is the recordset object that will contain the
          opened recordset.
   "conn" is the connection object containing an open connection
          to the database.
   "sSQL" is a string variable containing the SQL statement
          that defines the recordset.
   "rsdefault" specifies that the default type of recordset
          should be opened.

See also 4.12.1 Recordset type constants, 4.12.4 rsforward,
and 5.14.12.1 Recordset type.

-----------------
4.12.3 rsdynamic:
-----------------
The constant "rsdynamic" specifies that a dynamic recordset should
be opened. Dynamic recordsets are scrollable (i.e. you can move both
forwards and backwards through the records in the recordset). Database
changes (i.e. record insertions, updates, or deletions) are visible
to dynamic recordsets even after the recordset is opened.
NOTE: Irie Pascal does not currently provide a way to move backwards
through a recordset, so you can't take maximum advantage of dynamic
recordsets.
NOTE: If the you are connected to a MySQL database then this constant
is ignored and a forward-only recordset is opened instead.

Example:

   rs.open(conn, sSQL, rsdynamic);

In the example above
   "rs" is the recordset object that will contain the
          opened recordset.
   "conn" is the connection object containing an open connection
          to the database.
   "sSQL" is a string variable containing the SQL statement
          that defines the recordset.
   "rsdynamic" specifies that a dynamic recordset should be opened.

See also 4.12.1 Recordset type constants, and 5.14.12.1 Recordset type.

-----------------
4.12.4 rsforward:
-----------------
The constant "rsforward" specifies that a forward-only recordset should
be opened. Forward-only recordsets, as the name suggests, only allow
you to move forwards. To return to previous record your application
would have to close the recordset, reopen it, and skip to the
record you are interested in. Database changes (i.e. record insertions,
updates, or deletions) are NOT visible to forward-only recordsets after
the recordset is opened.

Example:

   rs.open(conn, sSQL, rsforward);

In the example above
   "rs" is the recordset object that will contain the
          opened recordset.
   "conn" is the connection object containing an open connection
          to the database.
   "sSQL" is a string variable containing the SQL statement
          that defines the recordset.
   "rsforward" specifies that a forward-only recordset should be opened.

See also 4.12.1 Recordset type constants, 4.12.2 rsdefault,
and 5.14.12.1 Recordset type.

----------------
4.12.5 rskeyset:
----------------
The constant "rskeyset" specifies that a keyset recordset should
be opened. Keyset recordsets are scrollable (i.e. you can move both
forwards and backwards through the records in the recordset). Some
database changes (i.e. record updates) are visible to keyset recordsets
after the recordset is opened, but others (i.e. record insertions and
deletions) are not.
NOTE: Irie Pascal does not currently support keyset recordsets, if
you specify this constant then a dynamic record is opened instead,
unless the database is MySQL in which case a forward-only recordset
is opened.

Example:

   rs.open(conn, sSQL, rskeyset);

In the example above
   "rs" is the recordset object that will contain the
          opened recordset.
   "conn" is the connection object containing an open connection
          to the database.
   "sSQL" is a string variable containing the SQL statement
          that defines the recordset.
   "rskeyset" specifies that a keyset recordset should be opened.

See also 4.12.1 Recordset type constants, and 5.14.12.1 Recordset type.

----------------
4.12.6 rsstatic:
----------------
The constant "rsstatic" specifies that a static recordset should
be opened. Static recordsets are scrollable (i.e. you can move both
forwards and backwards through the records in the recordset). Database
changes (i.e. record inserts, updates, and deletions) are NOT visible
to static recordsets after the recordset is opened.
NOTE: Irie Pascal does not currently provide a way to move backwards
through a recordset, so you can not take full advantage of static
recordsets.
NOTE: If the database is MySQL then this constant is ignored and
a forward-only recordset is opened instead.

Example:

   rs.open(conn, sSQL, rsstatic);

In the example above
   "rs" is the recordset object that will contain the
          opened recordset.
   "conn" is the connection object containing an open connection
          to the database.
   "sSQL" is a string variable containing the SQL statement
          that defines the recordset.
   "rsstatic" specifies that a static recordset should be opened.

See also 4.12.1 Recordset type constants, and 5.14.12.1 Recordset type.

--------
5 Types:
--------

----------
5.1 Types:
----------
Types can be defined as groups of values that are related in some way.
For example the type "integer" can be defined as the group of whole number
values between -maxint and +maxint. Every constant, variable, parameter,
and expression in your program is associated with a specific type.
Irie Pascal defines several built-in types that represent commonly
used groupings of values. You can use these built-in types or you
can define your own. You can even redefine the built-in types, but
this is not recommended, because it makes your programs more difficult
to understand. Someone reading your program is likely to assume
that the built-in types have their normal definition.

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 (i.e. structures
that point at themselves e.g. linked lists) to be built.

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

Example
   color = (red, green, blue);

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 |
                     object-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;
   GenericObject = object;

See also 2.8.3 User-defined identifiers, 2.8.1 Identifiers,
5.2 Array types, 5.3 Enumerated types, 5.4 File types, 5.5 List types,
5.6.1 Object types, 5.7 Ordinal types, 5.8 Pointer types,
5.9 Record types, 5.10 Set types, 5.11 String types, 5.12 Subrange types,
5.13 Integral types, 5.14.1 Built-in type identifiers,
and 12.2 Relaxed declarations.

----------------
5.2 Array types:
----------------
Array types define 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. The
number of array elements in an array is fixed, and is equal to the
number of values defined by the array's index type. You can have
arrays of arrays (i.e. an array's component type may itself be an
array type). It is sometimes easier to think about arrays of arrays
as multi-dimensional arrays (i.e. arrays defining a collection of values
with an axis for each array component, where each element is identified
by values from each component array's index type).

Irie Pascal supports fixed length strings as defined in Standard Pascal
(i.e. Fixed length strings, which are simply packed arrays of char,
having a lower bound of one and an upper bound of two or greater). Fixed
length strings have special properties in addition to the properties they
share with other arrays. Normally values of array types can not be compared
to see whether one is less than the other. Fixed length strings can be
compared 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".

NOTE: Irie Pascal also supports variable length string types.

The syntax for defining new 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 array[boolean] of integer

NOTE:
As a shorthand notation a multi-dimensional array type can be defined
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

See also 5.1 Types, 5.11 String types, and 6.2 Array variables.

---------------------
5.3 Enumerated types:
---------------------
Enumerated types define a finite group of ordered values. Each of these
ordered values is associated with an identifier (an enumerated constant)
and has integer type. Enumerated constants are ordered by the sequence
in which they are defined, and they have consecutive ordinal numbers
starting at zero. The built-in function "ord" can be used to retrieve
the ordinal number of an enumerated constant (See 7.1.41 ord).

The syntax for defining new enumerated types is given below:

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

   enumerated-constant-list = enumerated-constant { ',' enumerated-constant }

   enumerated-constant = identifier

Here are some examples of enumerated types

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

In the examples above the first enumerated constant in each type
(i.e. "red", "low", and "married") have the value 0. The second enumerated
constant in each type (i.e. "blue", "medium", and "divorced") have the
value 1. The third enumerated constant in each type has the value 2. And
the fourth enumerated constant in the last type has the value 3.

So for example

   ord(blue) = 1

See also 5.1 Types, 5.7 Ordinal types, 5.12 Subrange types,
5.14.3 boolean type, 7.2.48 pred, 7.2.57 succ, 7.3.10 dec, 7.3.28 inc,
and 8.1 Expressions.

---------------
5.4 File types:
---------------
File type define dynamic collections of persistent values, the values
are persistent in that they remain stored even when your program is not
running. In order to achieve persistence file type values are placed
on external storage devices, and not in memory. As a result accessing
file type values is usually much slower than accessing value of other
types since accessing external storage devices is usually much slower
than accessing memory.

The size of the collection of values defined by a file type (i.e. the
number of values in the collection) is potentially unlimited. File types
do not impose any limit on the size of their collections. In practice
the maximum size of a file type's collection is determined by the amount
of available space on the the external storage device used to store the
collection and/or the operating system that is controlling the storage
device.

In almost all cases the values in a file type's collection have the
same type (called the file's component type). The exception to this
is the special file type named "binary" which has no component type.
File component types can not be file types or types which contain file
types.

File type collections are dynamic because you can increase the size of
a collection by adding values to it. You add values to a file type's
collection using the built-in procedures "put", "write", and "writeln".
You can retrieve values from a file type's collection using the built-in
procedures "get", "read", and "readln".

Before you can add values to or retrieve values from a file type's
collection you have to open the file (i.e. associate the file type's
collection with a named file on the external storage device).

When you have finished adding values to or retrieving values from a
file type's collection you should close the file (i.e. disassociate the
file type's collection from the named file on the external storage device).

The syntax for defining new file types is given below:

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

Here are some examples of file types

   file of integer;
   file of char;

See also 5.1 Types, 5.14.2 binary type, 6.3 File variables, 7.3.20 get,
7.3.39 put, 7.3.61 write, 7.3.62 writeln, 7.3.2 append, 7.3.4 assign,
7.3.34 open, 7.3.6 close, 7.3.47 reset, 7.3.49 rewrite,
and 8.1 Expressions.

---------------
5.5 List types:
---------------
As an extension Irie Pascal supports list types. List types define ordered
collections of values of a single type (called the list's component type).
Each value in a list type's collection is identified by its position in
the collection. Unlike file types the values in a list type's collection
are NOT persistent (i.e. they are not stored when your program is not
running).

The size of the collection of values defined by a list type (i.e. the
number of values in the collection) is potentially unlimited. List types
do not impose any limit on the size of their collections. In practice
the maximum size of a list type's collection is determined by the amount
of memory available to your program.

The syntax for defining new list types is given below:

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

Here are some examples of list types

   list of integer;
   list of char;

Below is a simple example program that uses a list to store and
sort random integer values.

program listexample(output);
var
   l : list of integer;
   i : integer;

   procedure SortList;
   var
      i, temp : integer;
      swapped : boolean;
   begin
       writeln('Sorting...');
      //Bubble sort the list
      repeat
         swapped := false;
         for i := 1 to length(l)-1 do
            begin
               if l[i] > l[i+1] then
                  begin
                     temp := l[i];
                     l[i] := l[i+1];
                     l[i+1] := temp;
                     swapped := true;
                  end
            end;
      until not swapped;
   end;

begin
   randomize;  //initialize random number generator
   new(l);
   //Insert 100 random integer values into the list
   for i := 1 to 100 do
      insert(random(1000), l);
   //Sort the values in the list
   SortList;
   //Output the values in the list
   for i := 1 to length(l) do
      writeln(l[i]);
   dispose(l);
end.

See also 5.1 Types, 6.4 List variables, 7.3.29 insert, 7.3.12 delete,
7.2.36 length, 7.3.33 new, 7.3.13 dispose, and 12.16 Extended types.

-----------------
5.6 Object types:
-----------------

-------------------
5.6.1 Object types:
-------------------
Object types define dynamic collections of values, each of which either
identifies an instance of an object described by the object type or is
the special value "nil" which is guaranteed NOT to identify any instance
of an object. The values in object type collections are stored in
variables, associated with the object type, called object references.
These object references can be used to refer to or access the object
instance identified by the value stored in the object reference.

Object instances have properties (which are similiar to the fields in
records), and methods. Method are functions or procedures that define
what the object can do and also what can be done to the object.

The syntax for accessing an object property is give below

   object-property-access = object-identifier '.' property-reference

   property-reference = property-identifier | '(' property-string ')'

   property-string = string-expression

   object-identifier = identifier

   property-identifier = identifier

where "string-expression" is an expression of type string which
evaluates to the name of the property. The preferred form of a property
reference is just to use the property name, the second form where a
string expression is used is provided for the cases where the property name
is a keyword. You can see this in the cdonts example below in which
the property named "to" could not be specified as

   objMail.to

since "to" is a keyword, instead this proerty is specified using the second
form like so

   objMail.('to')

The syntax for calling object methods is given below:

   function-method-call = object-identifier '.' function-identifier [ actual-parameter-list ]

   procedure-method-call = object-identifier '.' procedure-identifier [ actual-parameter-list ]

   object-identifier = identifier

   function-identifier = identifier

   procedure-identifier = identifier

Irie Pascal does not currently fully support object types, in particular
Irie Pascal does not allow you to define your own object types. You
are restricted to using the built-in object types "connection" and
"recordset", or using the generic object type.

The built-in procedure "new" can be used to create an instance of one
of the built-in object types, and store the value identifying the instance
in an object reference. This also adds the identifying value to the
collection of values defined by the built-in object type associated with
the object reference. The built-in procedure "new" can NOT be used to
create instances of generic object types (See 5.5.1 Generic Objects),
since generic object types do not describe what an object instance "looks"
like ("new" wouldn't know how much memory to allocate).

The built-in function "createobject" can be used to create an instance
of a generic object type, and returns the value identifying the instance.
The value returned by "createobject" is usually stored in a generic
object reference. NOTE: The built-in function "createobject" can NOT
currently be used to create an instance of any of the built-in object types.

The built-in procedure "dispose" should be used to destroy instances of
the built-in object types created with "new", when you have finished
using the instances. This also removes the value identifying the destroyed
instance from the collection of values defined by the built-in object
type.

The built-in procedure "dispose" should also be used to destroy instances
of generic objects created with "createobject". This also removes the value
identifying the destroyed instance from the collection of values defined
by the generic object type.

For example the simple program below illustrates how to use the built-in
procedures "new" and "dispose" with object types.

program Data(input, output);
var
   conn : connection;

   procedure DisplayError(msg : string);
   begin
      writeln('ERROR:', msg);
      halt
   end;

   function GetConnectionString : string;
   var
      s, sDSN, sUSER, sPassword : string;

      function GetStringValue(sPrompt : string) : string;
      var
         sValue : string;
      begin
         write(sPrompt);
         readln(sValue);
         GetStringValue := sValue
      end;

   begin
      if supported(feature_odbc) then
         begin
            sDSN := GetStringValue('Enter Data Source Name (DSN):');
            sUser := GetStringValue('Enter user id:');
            sPassword := GetStringValue('Enter password:');
            s := 'ODBC;DSN='+sDSN+';user='+sUser+';password='+sPassword;
         end
      else if supported(feature_mysql) then
         begin
            sUser := GetStringValue('Enter user id:');
            sPassword := GetStringValue('Enter password:');
            s := 'MYSQL;user="'+sUser+'";password="'+sPassword+'";socket="/tmp/mysql.sock"';
         end
      else
         DisplayError('No database support detected');
      GetConnectionString := s;
   end;

begin
   new(conn);
   conn.open(GetConnectionString);
   //
   //Add code here to process database
   //
   conn.close;
   dispose(conn);
end.

See also 4.6 nil, 5.1 Types, 5.14.6.1 Connection type,
5.14.12.1 Recordset type, 5.6.2 Generic objects, 6.5 Object variables,
8.1 Expressions, and 12.16 Extended types.

----------------------
5.6.2 Generic objects:
----------------------
Generic object types are not any particular object type, but are instead
any object type associated with an instance of an object created with
the built-in function "createobject". Currently "createobject" can only
create instances of COM objects, and only those COM objects which
support late-binding (i.e. the COM objects must export the IDISPATCH
interface, or in other words the COM objects must be OLE automation
servers).

The syntax for defining a new generic object type is given below:

   object-type = 'object' | 'class'

The keywords "object" and "class" can be used interchangably for now,
however in later version of Irie Pascal which will more fully support
Object Pascal these keywords will produce slightly different effects. There
appears to be two specifications for Object Pascal. The first specification
is simplier and uses the keyword "object" and appears to be most popular
on the Mac. While the second specification is more sophisticated and uses
the keyword "class". Later versions of Irie Pascal will attempt to
support both specifications of Object Pascal.

Below is a simple program that uses two generic object references
"objExplorer" and "app" to access some of the COM objects exposes
by Internet Explorer, and to start Internet Explorer and navigate to the
IrieTools website.

   program Explorer;
   var
      objExplorer : object;
      app : object;
   begin
      objExplorer := CreateObject('InternetExplorer.Application');
      app := objExplorer.application;
      app.navigate('http://www.irietools.com', 1, , ,);
      app.quit;
      dispose(app);
      dispose(objExplorer);
   end.

Below is a more useful example program that illustrates how to send
an email using the CDONTS.NewMail COM object that is installed with
Microsoft IIS. You can use a similiar program to send email if your
webserver uses IIS.

   program cdonts;
   const
      NORMAL = 1;
   var 
      objMail : object;
      FromAddress, ToAddress : string;
   begin
      write('Enter the from address:');
      readln(FromAddress);
      write('Enter the to address:');
      readln(ToAddress);
      objMail := CreateObject('CDONTS.NewMail');
      objMail.from := FromAddress;
      objMail.('to') := ToAddress;
      objMail.subject := 'Testing...';
      objMail.Body := 'This is a test message';
      objMail.Importance := NORMAL;
      objMail.Send( , , , , );
      dispose(objMail);
   end.

The program could also be simplified as follows

   program cdonts;
   const
      NORMAL = 1;
   var
      objMail : object;
      FromAddress, ToAddress : string;
   begin
      write('Enter the from address:');
      readln(FromAddress);
      write('Enter the to address:');
      readln(ToAddress);
      objMail := CreateObject('CDONTS.NewMail');
      objMail.Send(FromAddress, ToAddress, 'Testing...', 'This is a test message', NORMAL);
      dispose(objMail);
   end.

See also 5.6.1 Object types, 6.5 Object variables,
4.8.7 feature_idispatch, and 7.2.11 createobject.

------------------
5.7 Ordinal types:
------------------
Ordinal types define discrete groups of ordered values. Each value of
a given ordinal type has a unique predecessor (except the first
value defined by that type). Each value of a given ordinal type has
a unique successor (except the last value defined by that type).

The ordinal types are enumerated types, subrange types and certain
built-in types (i.e. byte, char, integer, and word).

See also 5.1 Types, 5.3 Enumerated types, 5.12 Subrange types,
5.14.3 boolean type, 5.14.4 byte type, 5.14.5 char type,
5.14.10 integer type, 5.14.16 word type, 7.2.48 pred, 7.2.57 succ,
7.3.10 dec, and 7.3.28 inc.

------------------
5.8 Pointer types:
------------------
Pointer types define dynamic collections of values, each of which either
identifies an instance of the pointer type's domain type or is the special
value "nil" which is guaranteed NOT to identify any instance. Instances
of a pointer type's domain type are called identified variables. The
values of a pointer type's collection can be stored in variables,
associated with the pointer type, called pointer variables. The act of
using the value stored in a pointer variable to access the identified
variable is called dereferencing the pointer variable. It is an error to
deference a pointer variable which contains the special value "nil".

A pointer variable can be passed to the built-in procedure "new", which
will create an identified variable of the same type as the pointer
variable's domain type, and store the value identifying the identified
variable in the pointer variable. The value identifying the identified
variable is also added to the collection of values defined by the pointer
variables type. It is an error if an identified variable can not be created
because there is not enough available memory.

A pointer variable can also be passed to the built-in procedure "dispose",
which will destroy the identified variable identified by the value stored
in the pointer variable. The value stored in the pointer variable is also
removed from the collection of values defined by the pointer variable's
type. It is an error to use "dispose" on a pointer variable containing
the special value "nil", or containing a value that is not in the
collection of values defined by the pointer variable's type.

The syntax for defining new pointer types is given below:

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

   domain-type = type-identifier

Here are some examples of pointer types:

   ^integer
   ^real

See also 4.6 nil, 5.1 Types, 6.6 Pointer variables, 7.3.13 dispose,
and 7.3.33 new.

-----------------
5.9 Record types:
-----------------
Record types define collections of values. A record type may be empty
(i.e. defined 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.
In which case 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 defining new 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").

See also 5.1 Types, 6.7 Record variables, and 12.4 Otherwise.

---------------
5.10 Set types:
---------------
Set types define values which are combinations of optional values of the
same ordinal type (called the set's base type). In any combination of
values the same value can not appear more than once. All set type
values include the empty set (i.e. the combination where none of the
optional values are present).

For example the following set type

   set of boolean

defines four values

1. [] - the empty set
2. [false] - the combination containing "false" but not "true"
3. [true] - the combination containing "true" but not "false".
4. [false, true] - the combination containing both "false" and "true".

The syntax for defining new set types is given below:

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

Here are some examples of set types

   set of char
   set of boolean

See also 5.1 Types, 6.8 Set variables, and 8.2.7.1 Set operators.

------------------
5.11 String types:
------------------
As an extension, Irie Pascal supports variable length strings defined
using the built-in type "string". Variable length strings define sequences
of characters. The maximum number of characters allowed in a variable
length string is fixed and is specified when the string type is defined.
Variable length strings defined with "string" are stored as length
prefixed strings (i.e. the actual number of characters in the string
are stored in a byte or integer in front of the string). A byte is
used to store the actual length of the string, if the maximum number of
characters allowed in the string is small enough to be stored in a byte
(i.e. <= 255). An integer is used to store the actual length of the string,
if the maximum number of characters allowed in the string is too big to
fit in a byte (i.e. > 255).

The syntax for defining new string types is given below:

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

   size = integral-constant

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);


In most case it is best to use the built-in type "string" to create
variable length string types. However as an extension, Irie Pascal also
supports variable length strings defined using the built-in type "cstring".
Variable length strings defined with "cstring" are stored in the format
used by the "C" programming language to store strings (i.e. as NULL
terminated sequences of characters). Variable length string types defined
with "cstring" are usful when the values of a variable length string
are going to be passed to or from extern functions/procedures written
in "C". For example the simple "hello world" program uses two variables
of "cstring" types to pass values to the Windows API function
"MessageBoxA". Since most of the Windows API functions are written in "C"
they expect string variables to be in the "C" language format.

program winhello;
const
    NULL_HANDLE = 0;
    CR = 13;

//***************************************************************
// The following two constants are defined by the windows API
//***************************************************************
    MB_OKCANCEL = $00000001;
    MB_ICONEXCLAMATION = $00000030;

type
    MsgBoxRet = (IDNOMEM, IDOK, IDCANCEL, IDABORT, IDRETRY, IDIGNORE,
                 IDYES, IDNO, IDCLOSE, IDHELP );
var
    csText, csCaption : cstring;
    RetVal : MsgBoxRet;

// The following WinAPI function is exported from the windows dll 'user32.dll'
// int MessageBoxA(
//    HWND hWnd,  // handle of owner window
//    LPCTSTR lpText,     // address of text in message box
//    LPCTSTR lpCaption,  // address of title of message box  
//    UINT uType  // style of message box
//   );

// The following external function definition allows the application to
// access the WinAPI function
    function MessageBox(hWnd : word; var lpText, lpCaption : cstring; uint : word) : MsgBoxRet;
     external dll='user32.dll' name='MessageBoxA' stdcall;

begin
    csText := 'Hello world!!'+chr(CR)+'Press Cancel when done';
    csCaption := 'Irie Pascal Windows Hello World Program';
    repeat
       RetVal := MessageBox(NULL_HANDLE, csText, csCaption,
                             MB_OKCANCEL + MB_ICONEXCLAMATION);
    until RetVal = IDCANCEL;
end.

See also 5.1 Types, 5.2 Array types, 5.14.5 char type,
5.14.9 filename type, 6.9 String variables, 7.2.5 concat, 7.2.6 copy,
7.2.7 copyword, 7.2.10 countwords, 7.2.16 fexpand, 7.2.17 filematch,
7.2.23 hex, 7.2.36 length, 7.2.40 lowercase, 7.2.44 paramstr, 7.2.47 pos,
7.2.51 reverse, 7.2.63 trim, 7.2.67 uppercase, 7.2.68 urldecode,
7.3.12 delete, 7.3.29 insert, 7.3.55 str, 7.3.60 val,
8.2.6.1 String operators, and 12.16 Extended types.

--------------------
5.12 Subrange types:
--------------------
Subrange types define a contiguous subset of the values of an ordinal type.
This ordinal type is known as the subrange type's host type and the values
of a subrange type have the same type as its host type.

The syntax for defining new subrange types is give below:

   subrange-type = constant '..' constant

Here are some examples of subrange types:

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

See also 4.1 Constants, 5.1 Types, 5.7 Ordinal types, 7.2.4 chr,
7.2.48 pred, 7.2.57 succ, 7.3.10 dec, and 7.3.28 inc.

--------------------
5.13 Integral types:
--------------------
The Integral types are one of the following types, or subranges of one
of the following types, byte, integer, and word.

See also 5.1 Types, 5.14.4 byte type, 5.14.10 integer type,
and 5.14.16 word type.

-------------------------------
5.14 Built-in type identifiers:
-------------------------------

---------------------------------
5.14.1 Built-in type identifiers:
---------------------------------
Irie Pascal defines several built-in types that represent commonly used
groupings of values. Built-in types are pre-declared for you so that you
can use them without having to declare them. A type identifier is associated
with each built-in type.

See also 5.1 Types, 5.14.2 binary type, 5.14.3 boolean type,
5.14.4 byte type, 5.14.5 char type, 5.14.7 dir type, 5.14.8 error type,
5.14.9 filename type, 5.14.10 integer type, 5.14.11 real type,
5.14.13 registers type, 5.14.14 regtype type, 5.14.15 text type,
5.14.16 word type, 5.14.6.1 Connection type,
and 5.14.12.1 Recordset type.

-------------------
5.14.2 binary type:
-------------------
"binary" is the type identifier for a built-in file type which does not
have a component type (i.e. the built-in file type is an untype file
type). Normally only values of a file's component type can be written
to or read from the file, however this restriction does not apply
to untyped file types. Values of almost any type can be written to and
read from files of untyped file types. Also, because untyped file
types do not have component types than there are no buffer variables
associated with untyped file types.

NOTE: If "f" is a file variable then the file's buffer variable can
be accessed with "f^" or "f@".

For example below is a silly little program that illustrates how
to use "binary" file types.

program silly;
var
   f : binary;
begin
   rewrite(f, 'silly.dat');
   write(f, 100, -67.56, false);
end.

See also 5.4 File types, 5.14.1 Built-in type identifiers,
and 12.16 Extended types.

--------------------
5.14.3 boolean type:
--------------------
"boolean" is the type identifer for a built-in enumerated type with two
values "false" and "true" defined as below:

   boolean = (false, 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 expressions of boolean type. The operators "and",
"or", "not", "and_then", "or_else" operate on expressions of boolean type.

For example below is a simple program that illustrates using the
built-in type "boolean":

program Teenager(input, output);
var
   age : integer;
   teenager : boolean;
begin
   write('How old are you?');
   readln(age);
   teenager := (age >= 13) and (age <= 19);
   if teenager then
      writeln('Congratulations!!! You are a teenager')
   else
      writeln('Sorry. You are not a teenager')
end.

See also 4.7 Boolean Constants, 5.3 Enumerated types, 5.7 Ordinal types,
and 5.14.1 Built-in type identifiers.

-----------------
5.14.4 byte type:
-----------------
"byte" is the type identifier for a built-in type whoose values are
the whole numbers between 0 and 255 (maxbyte). This built-in type is an
extension to Standard Pascal which does not define "byte".

Below is a simple program that writes all possible values of byte
to a file.

program bytes;
var
   f : file of byte;
   b : byte;
begin
   rewrite(f, 'bytes.dat');
   for b := 0 to maxbyte do
      write(f, b)
end.

See also 2.4.1 Whole-numbers, 4.2 maxbyte, 5.7 Ordinal types,
5.13 Integral types, 5.14.1 Built-in type identifiers,
and 12.16 Extended types.

-----------------
5.14.5 char type:
-----------------
"char" is the type identifier for a built-in ordinal type with values of
the current character set.

Below is a simple program that illustrates using "char" to do some
file processing.

(*
This program is used to count the number of vowels and the total number of 
characters in the input file.
NOTE: This program makes use of two features of Irie Pascal
1) If the user does not specify a command-line parameter to match the
program argument 'f' then 'f' is automatically assigned an empty string
as its filename.
2) If a file variable with an empty string as its filename is reset then
the standard input file is associated with the file variable.

The net effect of these two features is that if you run this program and
don't supply a program argument like "ivm vowels" then the program reads
from the standad input file. If you run this program with a program argument
like "ivm vowels filename" then the program will open "filename" and read
from it.
*)
program vowels(f, output);
var
   f : file of char;
   tot, vow : integer;
   c : char;
begin
   reset(f);
   tot := 0;
   vow := 0;
   while not eof(f) do
      begin
         read(f, c);
         case c of
            'a', 'e', 'i', 'o', 'u',
            'A', 'E', 'I', 'O', 'U'
               : vow := vow + 1;
            otherwise
         end;
         tot := tot + 1;
      end;
   writeln('Total characters read = ', tot);
   writeln('Vowels read = ', vow)
end.

See also 2.2 Character literals, 4.3 maxchar, 5.7 Ordinal types,
5.11 String types, 5.14.1 Built-in type identifiers, and 7.2.4 chr.

-----------------------
5.14.6 connection type:
-----------------------

-------------------------
5.14.6.1 Connection type:
-------------------------
"connection" is the type identifier for a built-in object type whoose
values identify instances of connection objects. As the name suggests,
instances of connection objects are used to connect to database engines,
currently connections can only be made via ODBC or to MySQL databases.
The connection object type is an extension to Standard Pascal.

The connection object type has four methods:
See connection.close, connection.execute, connection.open,
and connection.selectdatabase for details.

The connection object type has several properties:
See connection.databasename, connection.dbmsname, connection.dbmsver,
connection.dmver, connection.odbcver, connection.procedures,
connection.readonly, connection.transactions, connection.transsupport
for details.

The built-in procedure "new" is used to create instances of
connection objects, and the built in procedure "dispose" is used to
detroy instances of connection objects.

The simple program below illustrates how to connect to a database
engine using the connection object type.

program Data(input, output);
var
   conn : connection;

   procedure DisplayError(msg : string);
   begin
      writeln('ERROR:',msg);
      halt
   end;

   function GetConnectionString : string;
   var
      s, sDSN, sUSER, sPassword : string;

      function GetStringValue(sPrompt : string) : string;
      var
         sValue : string;
      begin
         write(sPrompt);
         readln(sValue);
         GetStringValue := sValue
      end;

   begin
      if supported(feature_odbc) then
         begin
            sDSN := GetStringValue('Enter Data Source Name (DSN):');
            sUser := GetStringValue('Enter user id:');
            sPassword := GetStringValue('Enter password:');
            s := 'ODBC;DSN='+sDSN+';user='+sUser+';password='+sPassword;
         end
      else if supported(feature_mysql) then
         begin
            sUser := GetStringValue('Enter user id:');
            sPassword := GetStringValue('Enter password:');
            s := 'MYSQL;user="'+sUser+'";password="'+sPassword+'";socket="/tmp/mysql.sock"';
         end
      else
         DisplayError('No database support detected');
      GetConnectionString := s;
   end;

begin
   new(conn);
   conn.open(GetConnectionString);
   //
   //Add code here to process database
   //
   conn.close;
   dispose(conn);
end.

See also 5.14.6.2 connection.close, 5.14.6.3 connection.execute,
5.14.6.4 connection.open, 5.14.6.5 connection.selectdatabase,
5.14.6.6 connection.databasename, 5.14.6.7 connection.dbmsname,
5.14.6.8 connection.dbmsver, 5.14.6.9 connection.dmver,
5.14.6.10 connection.odbcver, 5.14.6.11 connection.procedures,
5.14.6.12 connection.readonly, 5.14.6.13 connection.transactions,
5.14.6.14 connection.transsupport, 5.6.1 Object types, 7.3.13 dispose,
7.3.33 new, 4.8.10 feature_mysql, 4.8.11 feature_odbc,
5.14.1 Built-in type identifiers, 5.14.12.1 Recordset type,
and 12.16 Extended types.

--------------------------
5.14.6.2 connection.close:
--------------------------
The "close" method procedure of the connection object type is used to
close an open connection to a database engine.

For example if you have a connection object reference "conn" with
an open connection to a database then the following call:

   conn.close;

will close the connection.

The syntax for calling the close method of a connection object reference
is given below:

   call-connection-close = connection-object-reference '.' 'close'

See also 5.6.1 Object types, 5.14.6.1 Connection type,
5.14.6.4 connection.open, and 5.14.12.1 Recordset type.

----------------------------
5.14.6.3 connection.execute:
----------------------------
The "execute" method procedure of the connection object type is used to
send an SQL statement to a database engine through an open connection.

For example if you have a connection object reference "conn" with
an open connection to a database then the following call:

   conn.execute('create database test');

will send the SQL statement 'create database test' to the database
engine at the other end of the connection.

The syntax for calling the execute method of a connection object reference
is given below:

   call-connection-execute =
         connection-object-reference '.' 'execute' '(' string-expression ')'

where "string-expression" is an expression of type string that evaluates
to the SQL statement to be executed by the database engine at the other
end of the connection.

See also 5.6.1 Object types, 5.14.6.1 Connection type,
and 5.14.12.1 Recordset type.

-------------------------
5.14.6.4 connection.open:
-------------------------
The "open" method procedure of the connection object type is used to
open a connection to a database engine.

For example the simple program below illustrates how to call the
"open" method. NOTE: The actual connection strings, you will use in
your own programs will probably differ from the one used in the
program below.

program Connect;
var
   conn : connection;
begin
   new(conn); //Create instance of connection object before using it
   if supported(feature_odbc) then
      conn.open('ODBC;DSN=test;user=sa;password=')
   else if supported(feature_mysql) then
      conn.open('MYSQL;user="sa";password="";socket="/tmp/mysql.soc"')
   //
   //Add code here to process database
   //
   conn.close;
   dispose(conn); //Destroy instance of connection object when finished
end.

The syntax for calling the open method of a connection object reference
is given below:

   call-connection-open =
         connection-object-reference '.' 'open' '(' string-expression ')'

where "string-expression" is an expression of type string that evaluates
to the connection string used to connect to the database engine.

Before an attempt is made to actually open a connection the connection
string is processed to determine what kind of connection to open and
what are the parameters to use for the connection. The connection
string is processes as follows:

The connection string must be prefixed by a connection type specifier,
which is separated from the actual connection string by a semi-colon (;).
First the connection type specifier is separated from the connection
string The connection type specifier is compared with ODBC, in such a way
that case is NOT significant, and if there is a match then an ODBC
connection is to be opened. Since case is not significant in this
comparision the connection type specifier could be lowercase (as in odbc),
uppercase (as in ODBC), or any combination of mixed case (like Odbc, OdBc,
odbC etc). If the connection type specifier does not match ODBC then it is
compared with MYSQL, again in such a way that case is NOT significant. If
the connection type specifier matches MYSQL then a MySQL connection is to
be opened. It is an error if the connection string is not prefixed by a
connection type specifier or if the connection type specifier does not
match either ODBC or MYSQL.

Next if an ODBC connection is to be opened then the connection string
must be in one of the following two forms:

   odbc-connection-string =
       odbc-connection-string-1 |
       odbc-connection-string-2 |

   odbc-connection-string-1 =
        dsn-parm ';' uid-parm ';' pwd-parm [';' [driver-specific-text]]

   dsn-parm = 'DSN' '=' name

   uid-parm = 'UID' '=' uid

   pwd-parm = 'PWD' '=' [password]

   odbc-connection-string-2 = name ';' [uid] ';' [password]

where [] indicate optional parameters.

For example  DSN=test;UID=sa;PWD=

When the connection string is in the first form then it is passed, without
further processing, to "SQLDriverConnect" to open the connection.
When the connection string is in the second form then the "name", "id",
and "password" parameters are extracted from the connection string, if
present, and passed to "SQLConnect" to open the connection. NOTE: The first
form of the connection string is the recommended form, support for the
second form is provided for completeness only.

If a MySQL connection is to be opened then the connection string must
be in the following form:

   mysql-connection-string = mysql-parameter-list

   mysql-parameter-list = mysql-parameter ';' mysql-parameter-list | empty

   mysql-parameter =
       mysql-host-parameter |
       mysql-user-parameter |
       mysql-password-parameter |
       mysql-database-parameter |
       mysql-port-parameter |
       mysql-socket-parameter |
       mysql-compress-parameter

   mysql-host-parameter = 'host' '=' '"' host-name '"'

   mysql-user-parameter = 'user' '=' '"' user-name '"'

   mysql-password-parameter = 'password' '=' '"' password '"'

   mysql-database-parameter = 'database' '=' '"' database-name '"'

   mysql-port-parameter = 'port' '=' port-number

   mysql-socket-parameter = 'socket' '=' '"' socket '"'

   mysql-compress-parameter = 'compress' '=' boolean-value

   boolean-value = 'yes' | 'no' | 'true' | 'false'

For example    user="testuser";database="testdb";socket="/tmp/mysql.soc";

The connection parameters are extracted from the connection string
and passed to "mysql_real_connect" to open the connection. NOTE:
"mysql_real_connect" is the MySQL C API function that is used to open
a connection to a MySQL database.

The effect of each of the parameters is described below:

The "mysql-host-parameter" specifies the hostname or IP address of the
MySQL database server. If "mysql-host-parameter" is not specified or if
"host-name" is an empty string or "local-host" then the connection is
opened to the local MySQL server over a UNIX socket.

The "mysql-user-parameter" specifies the username used to connect to
the MySQL database server. If the "mysql-user-parameter" is not specified
or if "user-name" is an empty string then the UNIX login name of the
person running the application is used.

The "mysql-password-parameter" specifies the password of the user who
will be connected to the database server. If the "mysql-password-parameter"
is not specified or if "password" is an empty string then the connection
is rejected if the user actually has a password.

The "mysql-database-parameter" specifies the initial database selected
when the connection is opened. If the "mysql-database-parameter" is not
specified or if "database" is an empty string then no initial database
is selected. In which case you must call the "selectdatabase" method
later on to select a database.

The "mysql-port-parameter" specifies the port used to remotely connect to
a MySQL database server over TCP. If the "mysql-port-parameter" is not
specified or if "port-number" is 0 then the default port is used.

The "mysql-socket-parameter" specifies the filename of the UNIX socket used
to connect to a MySQL database server on the local machine. If the
"mysql-socket-parameter" is not specified or if "socket" is an empty string
then the default socket is used.

The "mysql-compress-parameter" specifies the compression is to be used
when communicating with the MySQL database server. If the
"mysql-compress-parameter" is not specified then compression is not used.

See also 5.6.1 Object types, 5.14.6.1 Connection type,
5.14.6.2 connection.close, and 5.14.12.1 Recordset type.

-----------------------------------
5.14.6.5 connection.selectdatabase:
-----------------------------------
The "selectdatabase" method procedure is used to make a particular
database the default database for an open connection.

For example if you have a connection object reference "conn" with
an open connection to a database then the following call:

   conn.selectdatabase('test');

will make "test" the default database for the connection.

The syntax for calling the selectdatabase method of a connection object
reference is given below:

   call-connection-selectdatabase =
         connection-object-reference '.' 'selectdatabase'
          '(' string-expression ')'

where "string-expression" is an expression of type string that evaluates
to the name of database.

If you want to retrieve the name of the current database for a connection
use the connection object's databasename property

See also 5.6.1 Object types, 5.14.6.1 Connection type,
5.14.6.4 connection.open, and 5.14.6.6 connection.databasename.

---------------------------------
5.14.6.6 connection.databasename:
---------------------------------
The "databasename" property of the connection object type contains the
name of the default database for the connection.

For example if you have a connection object reference "conn" with
an open connection to a database then the following:

   conn.databasename

is equal to the default database for the connection referenced by "conn".

"databasename" is a read-only property of type string.

The syntax for accessing the "databasename" property of a connection object
reference is given below:

   access-databasename-property = 
          connection-object-reference '.' 'databasename'

If you want to change the current database for a connection call the
connection object's "setdatabase" method

See also 5.6.1 Object types, 5.14.6.1 Connection type,
5.14.6.4 connection.open, and 5.14.6.5 connection.selectdatabase.

-----------------------------
5.14.6.7 connection.dbmsname:
-----------------------------
The "dbmsname" property of the connection object type contains the name
of database engine connected to. NOTE: If the connection is to a MySQL
database then this property always constains "MySQL".

For example if you have a connection object reference "conn" with
an open connection to a database then the following:

   conn.dbmsname

is equal to the named of the database engine referenced by "conn".

"dbmsname" is a read-only property of type string.

The syntax for accessing the "dbmsname" property of a connection object
reference is given below:

   access-dbmsname-property = 
          connection-object-reference '.' 'dbmsname'

See also 5.6.1 Object types, 5.14.6.1 Connection type,
and 5.14.6.4 connection.open.

----------------------------
5.14.6.8 connection.dbmsver:
----------------------------
The "dbmsver" property of the connection object type contains the version
of the database engine connected to.

For example if you have a connection object reference "conn" with
an open connection to a database then the following:

   conn.dbmsver

is equal to the version of the database engine referenced by "conn".

"dbmsver" is a read-only property of type string.

The syntax for accessing the "dbmsver" property of a connection object
reference is given below:

   access-dbmsver-property = 
          connection-object-reference '.' 'dbmsver'

See also 5.6.1 Object types, 5.14.6.1 Connection type,
and 5.14.6.4 connection.open.

--------------------------
5.14.6.9 connection.dmver:
--------------------------
The "dmver" property of the connection object type contains the version
of the ODBC driver manager connected to. NOTE: If the connection is to a
MySQL database then this property always constains an empty string ("").

For example if you have a connection object reference "conn" with
an open connection via ODBC then the following:

   conn.dmver

is equal to the version of the ODBC driver manager controlling the
connection referenced by "conn".

"dmver is a read-only property of type string.

The syntax for accessing the "dmver" property of a connection object
reference is given below:

   access-dmver-property = 
          connection-object-reference '.' 'dmver'

See also 5.6.1 Object types, and 5.14.6.1 Connection type.

-----------------------------
5.14.6.10 connection.odbcver:
-----------------------------
The "odbcver" property of the connection object type contains the version
of ODBC that the ODBC driver manager conforms to. NOTE: If the connection
is to a MySQL database then this property always constains an empty string
("").

For example if you have a connection object reference "conn" with
an open connection via ODBC then the following:

   conn.odbcver

is equal to the version of ODBC that the ODBC driver manager conforms to.

"odbcver" is a read-only property of type string.

The syntax for accessing the "odbcver" property of a connection object
reference is given below:

   access-odbcver-property = 
          connection-object-reference '.' 'odbcver'

See also 5.6.1 Object types, and 5.14.6.1 Connection type.

--------------------------------
5.14.6.11 connection.procedures:
--------------------------------
The "procedures" property of the connection object type indicates whether
or not stored procedures are supported by the database engine connected to.

For example if you have a connection object reference "conn" with
an open connection then

   conn.procedures

indicates whether stored procedures are supported by the database engine
referenced by "conn".

"procedures" is a read-only property of type boolean.

The syntax for accessing the "procedures" property of a connection object
reference is given below:

   access-procedures-property = 
          connection-object-reference '.' 'procedures'

See also 5.6.1 Object types, and 5.14.6.1 Connection type.

------------------------------
5.14.6.12 connection.readonly:
------------------------------
The "readonly" property of the connection object type indicates whether
or not the connection to the database engine is readonly.

For example if you have a connection object reference "conn" with
an open connection then

   conn.readonly

indicates whether or not the connection referenced by "conn" is read-only.

"readonly" is a read-only property of type boolean.

The syntax for accessing the "readonly" property of a connection object
reference is given below:

   access-readonly-property = 
          connection-object-reference '.' 'readonly'

See also 5.6.1 Object types, and 5.14.6.1 Connection type.

----------------------------------
5.14.6.13 connection.transactions:
----------------------------------
The "transactions" property of the connection object type indicates
whether or not transactions are supported by the database engine
connected to.

For example if you have a connection object reference "conn" with
an open connection then

   conn.transactions

indicates whether transactions are supported by the database engine
referenced by "conn".

"transactions" is a read-only property of type boolean.

The syntax for accessing the "transactions" property of a connection
object reference is given below:

   access-transactions-property = 
          connection-object-reference '.' 'transactions'

See also 5.14.6.1 Connection type, and 5.14.6.14 connection.transsupport.

----------------------------------
5.14.6.14 connection.transsupport:
----------------------------------
The "transsupport" property of the connection object type indicates
the level of transaction support provided by the database engine
connected to.

For example if you have a connection object reference "conn" with
an open connection then

   conn.transsupport

contains the level of transaction support provided by the database engine
referenced by "conn". The possible values of this property and what
the values mean is given below:

0 - Transactions are not supported
1 - Transactions containing Data Manipulation Language (DML) statements
    are supported. Transactions containing Data Definition Language (DDL)
    statements cause an error. DML statements include SELECT, INSERT,
    UPDATE, DELETE. DDL statements include CREATE, and DROP.
2 - Transactions containing both DML and DDL statements are supported.
3 - Transactions containing DML statements are supported. DDL statements
    encountered in transactions cause the transactions to be committed.
4 - Transactions containing DML statements are supported. DDL statements
    encountered in transactions are ignored.

"transsupport" is a read-only property of type integer.

The syntax for accessing the "transsupport" property of a connection
object reference is given below:

   access-transsupport-property = 
          connection-object-reference '.' 'transsupport'

See also 5.14.6.1 Connection type, and 5.14.6.13 connection.transactions.

----------------
5.14.7 dir type:
----------------
"dir" is the type identifier for a built-in type whoose values are
directory handles. This built-in type is an extension to Standard Pascal.

Below is a simple program that lists all the directories in the
current directory.

program listdir(output);
var
   d : dir;
   filename : string;

   function IsDir(name : filename) : boolean;
   var
      mode : integer;
   begin
      getfilemode(name, mode);
      IsDir := (mode and dir_bit) <> 0;
   end;

begin
   opendir(d, '.');  { Open current directory }
   repeat
      readdir(d, filename);  { Get next file in directory }
      { if the next file exists and it is a directory then list it }
      if (filename <> '') and (IsDir(filename)) then
          writeln(filename);
   until filename = '';
   closedir(d) { Close directory }
end.

See also 5.14.1 Built-in type identifiers, 7.3.7 closedir,
7.3.35 opendir, 7.3.48 rewinddir, 7.3.44 readdir, 5.4 File types,
and 12.16 Extended types.

------------------
5.14.8 error type:
------------------
"error" is the type identifier for a built-in record type which
describes an trappable run-time error. This built-in record type is
an extension to Standard Pascal.

The "error" type is defined as follows:

error = record
           number : integer;
           name : string[16];
           description : string[255];
        end;

where
   "number" is a numeric error code and uniquely identifies the error
   "name" is an alphnumeric error code (not all errors have a "name")
   "description" is text describing the error

When an trappable error occurs it is placed in an "error" record,
and the record is appended to the built-in list variable "errors".

See also 6.10.2 errors, 5.14.1 Built-in type identifiers,
and 12.16 Extended types.

---------------------
5.14.9 filename type:
---------------------
"filename" is the type identifier for a built-in string type which is
the recommended type for variables used to store file and directory names.
This built-in type is an extension to Standard Pascal.

Below is a simple program that lists the names of all the files in the
current directory and uses variables of type "filename" to store
the names of the files.

program listfiles(output);
var
   d : dir;
   filename : string;

   function IsDir(name : filename) : boolean;
   var
      mode : integer;
   begin
      getfilemode(name, mode);
      IsDir := (mode and dir_bit) <> 0;
   end;

begin
   opendir(d, '.');  { Open current directory }
   repeat
      readdir(d, filename);  { Get next file in directory }
      { if the next file exists and it is NOT a directory then list it }
      if (filename <> '') and (not IsDir(filename)) then
          writeln(filename);
   until filename = '';
   closedir(d) { Close directory }
end.

See also 5.11 String types, 5.14.1 Built-in type identifiers,
7.2.12 dirsep, 7.2.16 fexpand, 7.2.17 filematch, 7.3.2 append,
7.3.4 assign, 7.3.34 open, 7.3.38 popen, 7.3.46 rename, 7.3.47 reset,
7.3.49 rewrite, and 12.16 Extended types.

---------------------
5.14.10 integer type:
---------------------
"integer" is the type identifier for a built-in ordinal type whoose values
are whole numbers between -2147483647 and +2147483647 (maxint).

Below is a simple example program that prints the odd numbers between
1 and 24.

program OddNumbers(output);
const
   first = 1;
   last = 24;
var
   i : integer;

   function IsOdd(i : integer) : boolean;
   begin
      IsOdd := (i mod 2) <> 0;
   end;

begin
   for i := first to last do
     if IsOdd(i) then writeln(i);
end.

See also 4.4 maxint, 2.4.1 Whole-numbers, 5.7 Ordinal types,
5.13 Integral types, 5.14.1 Built-in type identifiers, 5.14.16 word type,
and 8.1 Expressions.

------------------
5.14.11 real type:
------------------
"real" is the type identifier for a built-in type whose values are
numbers with fractional parts.

For example the rather pointless program below uses the "real" type
to repeatedly divide a number into thirds.

   program thirds(output);
   const
      initial = 37.6;
      lowest= 0.05;
   var
      value : real;
   begin
      value := initial;
      repeat
         writeln(value, value:12:3);
         value := value / 3
      until value < lowest
   end.

See also 2.5 Real numbers, 5.1 Types, 5.14.1 Built-in type identifiers,
and 8.1 Expressions.

-----------------------
5.14.12 recordset type:
-----------------------

-------------------------
5.14.12.1 Recordset type:
-------------------------
"recordset" is the type identifier for a built-in object type whoose
values identify instances of recordset objects. Instances of recordset
objects are used to retrieve groups of records from open database
connections. The recordset object type is an extension to Standard Pascal.

The recordset object type has four methods:
close, moreresults, movenext, and open.

The recordset object type has two properties:
eof and field.

The code fragment below show a typical use of a recordset. NOTE: The
code fragment is not a complete program and makes the following
assumptions:
1. "conn" is an connection object reference for an open connection object.
2. "conn" is connected to a database with a table named "customer".
3. The customer table has the fields "last_name" and "first_name".

   new(rs);
   rs.open(conn, 'select last_name, first_name from customer', rsforward);
   while not rs.eof
      begin
         writeln(rs.field('last_name'), ', ', rs.field('first_name'));
         rs.movenext;
      end;
   rs.close;
   dispose(rs);

First the code fragment creates an instance of a recordset object.
Next the recordset object is used to open a forward type recordset.
Next the code loops through all the records contained in the recordset
   printing out the contents of the fields "last_name" and "first_name".
Next the recordset is closed.
Finally the instance of the recordset object is destroyed.

See also 5.14.12.2 recordset.close, 5.14.12.3 recordset.moreresults,
5.14.12.4 recordset.movenext, 5.14.12.5 recordset.open,
5.14.12.6 recordset.eof, 5.14.12.7 recordset.field, 5.6.1 Object types,
5.14.1 Built-in type identifiers, 5.14.6.1 Connection type,
and 12.16 Extended types.

--------------------------
5.14.12.2 recordset.close:
--------------------------
The "close" method procedure of the recordset object type is used to
close an open recordset.

For example if you have a recordset object reference "rs" that
refers to an open recordset then the following call:

   rs.close;

will close the recordset.

The syntax for calling the close method of a recordset object reference
is given below:

   call-recordset-close = recordset-object-reference '.' 'close'

See also 5.6.1 Object types, 5.14.12.1 Recordset type,
and 5.14.12.5 recordset.open.

--------------------------------
5.14.12.3 recordset.moreresults:
--------------------------------
The "moreresults" method procedure of the recordset object type is used
to move to the next recordset contained by an open recordset. NOTE:
This method is not to be confused with the "movenext" method which
moves the the next record in the current recordset. This method is
most often used when calling stored procedures that return multiple
recordsets.

For example if you open a recordset like so

   rs.open(conn, 'EXEC procName')

and the stored procedure "procName" returns multiple recordsets then
the recordset object will be poistions at the first record of the
first recordset. The call

   rs.movenext;

would move to the second record in the first recordset, but the call

  rs.moreresults

would move to the first record in the second recordset.

The syntax for calling the moreresults method of a recordset object
reference is given below:

   call-recordset-moreresults =
             recordset-object-reference '.' 'moreresults'

See also 5.6.1 Object types, 5.14.12.1 Recordset type,
and 5.14.12.4 recordset.movenext.

-----------------------------
5.14.12.4 recordset.movenext:
-----------------------------
The "movenext" method procedure of the recordset object type is used
to move to the next record in the current recordset of an open recordset
object

For example if you have a recordset object reference "rs" with
an open recordset then

   rs.movenext

will move to the next record in the recordset.

The syntax for calling the movenext method of a recordset object reference
is given below:

   call-recordset-movenext = recordset-object-reference '.' 'movenext'

See also 5.6.1 Object types, 5.14.12.1 Recordset type,
5.14.12.3 recordset.moreresults, and 5.14.12.6 recordset.eof.

-------------------------
5.14.12.5 recordset.open:
-------------------------
The "open" method procedure of the recordset object type is used to
open a recordset. In order to call this method you need a recordset
object reference, a connection object reference to open connection object
as well as the SQL statement which will return the recordset or recordsets
that will be referenced by the open recordset object.

The code fragment below show a typical use of a recordset. NOTE: The
code fragment is not a complete program and makes the following
assumptions:
1. "conn" is an connection object reference for an open connection object.
2. "conn" is connected to a database with a table named "customer".
3. The customer table has the fields "last_name" and "first_name".

   new(rs);
   rs.open(conn, 'select last_name, first_name from customer', rsforward);
   while not rs.eof
      begin
         writeln(rs.field('last_name'), ', ', rs.field('first_name'));
         rs.movenext;
      end;
   rs.close;
   dispose(rs);

The syntax for calling the open method of a recordset object reference
is given below:

   call-recordset-open =
      recordset-object-reference '.' 'open' '('
        connection-object-reference ','
        SQL-statement
        [',' recordset-type]
      ')'
      
where "SQL-statement" is an expression of type string that evaluates
      to a SQL statement that will return one or more recorsets,
      "recordset-type" is an expression of type integer that evaluates
      to the same value as one of the built-in recordset type constants
      (in most cases you will just use one of the recordset type constants
      directly). If "recordset-type" is not specified then the default
      recordset type is assumed.

See also 5.6.1 Object types, 5.14.12.1 Recordset type,
5.14.12.2 recordset.close, 5.14.12.6 recordset.eof,
and 4.12.1 Recordset type constants.

------------------------
5.14.12.6 recordset.eof:
------------------------
The "eof" property of the recordset object type indicates whether or not
the recordset is currently at end-of-file.

For example if you have a recordset object reference "rs" with
an open recordset then

   rs.eof

indicates whether the current recordset referenced by "rs" is at
end-of-file.

"eof" is a read-only property of type boolean.

It is an error to call the "movenext" method of a recordset object
when the recordset is at end-of-file.

The syntax for accessing the "eof" property of a recordset object reference
is given below:

   access-eof-property = recordset-object-reference '.' 'eof'

See also 5.6.1 Object types, 5.14.12.1 Recordset type,
5.14.12.4 recordset.movenext, and 4.12.1 Recordset type constants.

--------------------------
5.14.12.7 recordset.field:
--------------------------
The "field" property of the recordset object type is used to retrieve
the value of a field of the current record in the current recordset.

For example if you have a recordset object reference "rs" with
an open recordset and the records in the recordset have a field
named "last_name" then

   rs.field('last_name')

constains the contents of the field "last_name" for the current record in
the recordset.

"field" is a read-only property of type variant.

Currently this property is read-only so you can not use it to change
the contents of the record fields (i.e. you can't use this property
to change the database). If you want to change the database call
the "execute" method of the connection object type and pass in
a SQL UPDATE statement.

The syntax for accessing the "field" property of a recordset object
reference is given below:

   access-field-property =
    recordset-object-reference '.' ['field'] '('
     field-name
    ')'

where field-name is an expression of type string that evaluates to
   the name of the field to be accessed.

NOTE: Since this property is used so often you can leave out the
name of the property (i.e. "field"). So for example

   rs.('last_name')

is equivalent to

   rs.field('last_name')

See also 5.6.1 Object types, 5.14.12.1 Recordset type,
and 5.14.6.3 connection.execute.

-----------------------
5.14.13 registers type:
-----------------------
"registers" is the type identifier for a built-in variant record type,
which is used to store the x86 processor registers before and after calls
to the built-in procedure "intr". This type is an extension to
Standard Pascal.

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;

For the simple program below clears the screen by using the built-in
procedure "intr" to call the BIOS INT $10 interrupt.

program cls;
var
   regs : registers;
begin
   fill(regs, 0);
   regs.eax := $0002;
   intr($10, regs)
end.

See also 5.14.1 Built-in type identifiers, 5.14.14 regtype type,
7.3.30 intr, and 12.16 Extended types.

---------------------
5.14.14 regtype type:
---------------------
"regtype" is the type-identifier for a built-in enumerated type used to
build the variant record type "registers".

The built-in enumerated type is defined as follows:

   regtype = (byteregs, wordregs)

See also 5.14.1 Built-in type identifiers, 5.14.13 registers type,
and 12.16 Extended types.

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

See also 5.4 File types, 5.14.1 Built-in type identifiers, 7.2.14 eoln,
7.2.18 filepos, 7.3.45 readln, and 7.3.62 writeln.

------------------
5.14.16 word type:
------------------
"word" is the type identifier for a built-in ordinal type whoose values
are whole numbers between 0 and 4294967295 (maxword).

Below is a simple example program that prints the odd numbers between
1 and 24.

program OddNumbers(output);
const
   first = 1;
   last = 24;
var
   w : word;

   function IsOdd(w : word) : boolean;
   begin
      IsOdd := (w mod 2) <> 0;
   end;

begin
   for w := first to last do
     if IsOdd(w) then writeln(w);
end.

See also 2.4.1 Whole-numbers, 5.7 Ordinal types, 5.13 Integral types,
5.14.1 Built-in type identifiers, 8.1 Expressions,
and 12.16 Extended types.

------------
6 Variables:
------------

--------------
6.1 Variables:
--------------
Variables are typed storage locations (.i.e variables are used to
store values of a particular type). Assignment statements are used
to assign values to variables (i.e. place values inside variables).
The value inside a variable is retrieved when the variable is used in
an expression. Variables that have never been assigned a value are said
to contain undefined values. It is an error to retrieve the value of a
variable containing an undefined value.

Variables must be declared before they can be 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 }

The syntax for assignment statements is given below:

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

The syntax for variable accesses is given below:

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

   entire-variable = variable-identifier

   component-variable = indexed-variable | field-designator

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

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

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

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

   field-designator-identifier = identifier

   object-property-access = object-identifier '.' property-reference

   property-reference = property-identifier | '(' property-string ')'

   property-string = string-expression

   object-identifier = identifier

   property-identifier = identifier

NOTE: The full syntax is given in Appendix A.

See also 2.8.1 Identifiers, 2.8.3 User-defined identifiers, 5.1 Types,
6.2 Array variables, 6.3 File variables, 6.4 List variables,
6.5 Object variables, 6.6 Pointer variables, 6.7 Record variables,
6.8 Set variables, 6.9 String variables,
6.10.1 Built-in variable identifiers, 5.6.1 Object types,
9.3.1 Assignment statement, 8.1 Expressions,
and 12.2 Relaxed declarations.

--------------------
6.2 Array variables:
--------------------
Array variables are used to store values of array type (i.e. collections
of values of the same type). Each member of an array value's collection is
called an array element and is identified by a value of the array's index
type. The number of array elements in an array is fixed, and is equal to
the number of values defined by the array's index type. The storage
locations for each array element are called indexed variables.

The syntax for accessing indexed variables is given below:

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

where "array-variable" is a variable identifier
and "index-expression" is an expression which evaluates to one of the
    values specified by the array's index type (when the indexed variabe
    is part of an array variable).

The syntax for accessing the array variable as a whole is given below:

   array-variable-access = variable-identifier

Here is a simple example program that generates some random numbers,
stores them in an array, sorts the numbers, and then prints the
numbers out.

program sort(output);
const
   max = 20;
var
   numbers : array[1..max] of integer;

   procedure GenerateRandomNumbers;
   var
      i : 1..max;
   begin
      for i := 1 to max do
         numbers[i] := random(100)+1;
   end;

   procedure SortNumbers;
   var
      i : 1..max;
      swapped : boolean;
      temp : integer;
   begin
      repeat
         swapped := false;
         for i := 1 to max-1 do
            if numbers[i] > numbers[i+1] then
               begin
                  temp := numbers[i];
                  numbers[i] := numbers[i+1];
                  numbers[i+1] := temp;
                  swapped := true;
               end;
      until not swapped;
   end;

   procedure PrintNumbers;
   var
      i : 1..max;
   begin
      for i := 1 to max do
         writeln(i, numbers[i]);
   end;

begin
   randomize;
   GenerateRandomNumbers;
   SortNumbers;
   PrintNumbers;
end.

See also 5.1 Types, 5.2 Array types, and 6.1 Variables.

-------------------
6.3 File variables:
-------------------
File variables are used to store values of file types. A seldom used
feature of Pascal is the file buffer associated with most file variable.
File variables for the built-in type "binary" do not have buffer variables,
all other file variables do. Buffer variables contain the next
component to be read from the file, or the next component to be
written to the file.

The syntax for accessing file variables is:

   file-variable-access = variable-identifier

The syntax for accessing the file variables buffer is

   buffer-variable-access = file-variable '^'

he simple example program uses a file variable ("f") to create a
file called "numbers.dat" and write the numbers 1 to 10 to the file.

program numbers;
var
   f : file of integer;
   i : integer;
begin
   assign(f, 'numbers.dat');
   rewrite(f);
   for i := 1 to 10 do
      write(f, i);
end.

See also 5.1 Types, 5.4 File types, 6.1 Variables, 7.3.20 get,
and 7.3.39 put.

-------------------
6.4 List variables:
-------------------
List variables are used to store values of list type (i.e. collections
of values of the same type). Each member of a list value's collection is
called a list element. The number of list elements in an array is unlimited
The storage locations for each list element are called indexed variables.

The syntax for accessing indexed variables is given below:

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

where "list-variable" is a variable identifier
and "index-expression" is an expression which evaluates to the position
    of the indexed variable in the collection.

The syntax for accessing the list variable as a whole is given below:

   list-variable-access = variable-identifier

Here is a simple example program that generates some random numbers,
stores them in a list, sorts the numbers, and then prints the
numbers out.

program sort(output);
const
   max = 20;
var
   numbers : list of integer;

   procedure GenerateRandomNumbers;
   var
      i : 1..max;
   begin
      for i := 1 to max do
         insert(random(100)+1, numbers);
   end;

   procedure SortNumbers;
   var
      i : 1..max;
      swapped : boolean;
      temp : integer;
   begin
      repeat
         swapped := false;
         for i := 1 to max-1 do
            if numbers[i] > numbers[i+1] then
               begin
                  temp := numbers[i];
                  numbers[i] := numbers[i+1];
                  numbers[i+1] := temp;
                  swapped := true;
               end;
      until not swapped;
   end;

   procedure PrintNumbers;
   var
      i : 1..max;
   begin
      for i := 1 to max do
         writeln(i, numbers[i]);
   end;

begin
   randomize;
   new(numbers);
   GenerateRandomNumbers;
   SortNumbers;
   PrintNumbers;
   dispose(numbers);
end.

See also 5.1 Types, 5.5 List types, 5.2 Array types, and 6.1 Variables.

---------------------
6.5 Object variables:
---------------------
Object variables are used to store values of object types. Currently
the only supported object types are:
the built-in object types "connection" and "recordset", and the
generic object type. Values of object types (also called object references)
identify instances of objects. An object variable can be used to access
the object instance identified by the value stored in the variable.

NOTE: The special object value "nil" is guaranteed NOT to identify
any object instance.

See also 4.6 nil, 5.6.1 Object types, 5.6.2 Generic objects,
6.1 Variables, 5.14.6.1 Connection type, and 5.14.12.1 Recordset type.

----------------------
6.6 Pointer variables:
----------------------
Pointer variables are used to store values of pointer types. These values
either identify a variable created using the built-in procedure "new"
or are the special value "nil" which is guaranteed NOT to identify any
variable created using "new". Variables created by the built-in
procedure "new" are called identified variables. The act of using the
value stored in a pointer variable to access the identified variable
is called dereferencing the pointer variable. The built-in procedure
"dispose" should be used to destroy identified variables after you have
finished using them.

The syntax for accessing an identified variable is given below:

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

The syntax for accessing pointer variables is given below:

   pointer-variable-access = variable-identifier

See also 4.6 nil, 5.8 Pointer types, 6.1 Variables, 7.3.13 dispose,
and 7.3.33 new.

---------------------
6.7 Record variables:
---------------------
Record variables are used to store values of record types (i.e.
collections of values of possibly different types). Each member of a
record type's collection is called a field and is identified by a field
specifier, with the possible exception of the variant selector which
sometimes does not have a field specifier.

The syntax for accessing field designators is given below:

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

   field-specifier = field-specifier

   field-designator-identifier = identifier

The syntax for accessing record variables as a whole is given below:

   record-variable-access = variable-identifier

See also 5.9 Record types, and 6.1 Variables.

------------------
6.8 Set variables:
------------------
Set variables are used to store values of set types (i.e. combinations
of optional values of the set's base type).

The following simple example program shows a typical use of set variables
to classify values. The program operates as follows:
First the set variable "letters" is initialized with the set of characters
containing all lowercase and uppercase characters. Next the set
variable "digits" is initialized with the set of characters containing
all the digits. Next the user is prompted to enter a character, and
this character is read in. Finally the character is classified by
checking whether it is a member of "letters", "digits" or none of them.
NOTE: Sets are often used like this as an alternative to a big
case statement.

program classify(input, output);
var
   letters, digits : set of char;
   c : char;
begin
   letters := ['a'..'z', 'A'..'Z'];
   digits := ['0'..'9'];
   write('Enter a character: ');
   read(c);
   if c in letters then
      writeln('You entered a letter')
   else if c in digits then
      writeln('You entered a digit')
   else
      writeln('You entered a symbol')
end.

The syntax for accessing set variables is given below:

   set-variable-access = variable-identifier

See also 5.10 Set types, and 6.1 Variables.

---------------------
6.9 String variables:
---------------------
String variables are used to store values of string types (i.e. sequences
of characters). The maximum number of characters allowed in each sequence
is fixed and is defined when the string type is defined. The individual
characters in a string can be accessed using the syntax given below:

      string-variable '[' index-expression ']'

where "array-variable" is a variable identifier
and "index-expression" is an expression which evaluates to the position
    of a character in the string.

For example if "name" is a string variable containing the string 'Bob'
then

   name[1] accesses the first character in the string (i.e. 'B')

and

   name[2] accesses the second character in the string (i.e. 'o')

and

   name[3] accesses the third character in the string (i.e. 'b')

The syntax for accessing the string variable as a whole is given below:

   string-variable-access = variable-identifier

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.

See also 5.11 String types, and 6.1 Variables.

-----------------------------------
6.10 Built-in variable identifiers:
-----------------------------------

-------------------------------------
6.10.1 Built-in variable identifiers:
-------------------------------------
Irie Pascal defines several built-in variables that contain commonly used
values. Built-in variables are pre-declared for you so that you can use
them without having to declare them. A variable identifier is associated
with each built-in variable.

The built-in variables are:

   errors    exitcode    input    output

See also 6.10.2 errors, 6.10.3 exitcode, 6.10.4 input, 6.10.5 output,
and 6.1 Variables.

--------------
6.10.2 errors:
--------------
"errors" is the variable identifier for a built-in list variable which
stores the list of most recent trappable errors that were detected.
NOTE: This list variable is automatically cleared before each operation
that could cause a trappable error, so don't expect the list of errors
to be maintained indefinately. The operations that can cause trappable
errors are file and database operations.

"errors" is an extension to Standard Pascal.

See also 5.14.8 error type, 6.10.1 Built-in variable identifiers,
and 12.17 Extended variables.

----------------
6.10.3 exitcode:
----------------
"exitcode" is the variable identifier for a built-in integer variable,
whose value is returned to the calling program when your program exits.

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 integer values to it, use it in an expression, pass
it as an argument to a function, etc).

"exitcode" is an extension to Standard Pascal.

See also 6.10.1 Built-in variable identifiers,
and 12.17 Extended variables.

-------------
6.10.4 input:
-------------
"input" is the variable identifier for a built-in file variable,
whoose value is a handle to the standard input stream. The standard
input stream is usually connected to the computer keyboard.

See also 6.10.1 Built-in variable identifiers, 6.10.5 output,
6.3 File variables, 10.1 Program parameters,
and 12.10 Input and Output automatically declared.

--------------
6.10.5 output:
--------------
"output" is the variable identifier for a built-in file variable,
whoose value is a handle to the standard output stream. The standard
output stream is usually connected to the computer display.

See also 6.10.1 Built-in variable identifiers, 6.10.4 input,
6.3 File variables, 10.1 Program parameters,
and 12.10 Input and Output automatically declared.

---------------------------
7 Functions and procedures:
---------------------------

-----------------------------
7.1 Functions and procedures:
-----------------------------
Pascal encourages modular programming (i.e. creating complex programs
from smaller and simpler pieces called 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". This allows modules to be changed without affecting the parts
of the program that use them.

Pascal supports two kinds of modules, "functions" and "procedures".
The only 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.

Sometimes it is useful to create subroutines that accept input data
and/or produce output data. One way to achieve this to use global
variables to store the input and output data. However using global
variables like this can sometimes lead to problems. One problem that
often occurs with global variables is that programs just have too many
of them, and it becomes difficult to keep track of which subroutines use
which global variables and when. Another problem that often occurs with
global variables is that sometimes more than one subroutine will use the
same global variable for different purposes. When this happens subroutines
can become tightly intertwined making it very difficult to change one
subroutine without changing the others.

Another way to create subroutines that accept input data and/or
generate output data is to give each subroutine its own set of
variables to store the data. These variables are called parameters,
and occur in pairs (i.e. for each formal parameter there must be an
actual parameter). When a subroutine is defined, a list of formal
parameters may be specified. Formal parameters are used inside subroutines
to store input and/or output data. When a subroutine is called the caller
must supply an actual parameter for each formal parameter specified by the
subroutine.

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

Value parameters are parameters that are passed by value (i.e. when the
subroutine is called the actual parameter is an expression, and the value
of that 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 parameters that 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 (using
its address) and any changes it makes to the formal parameter will
immediately affect the actual parameter.

Function parameters are 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 formal
parameter to call the function (using its address).

Procedure parameters are 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 formal
parameter to call the procedure (using its address).

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');
      say('Goodbye!');
   end.

The program contains a procedure called "say" which takes a single
value parameter. When the procedure is called for the first time
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. When the procedure is called for the second time the
actual parameter is the expression 'Goodbye!', which is passed into
the formal parameter "message". So "message" now has the value
'Goodbye!'. The call to "writeln" then causes the value of message
(i.e. 'Goodbye!') 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.
The idea is that the forward declaration gives the compiler enough
information to handle calls to the procedure (i.e. the compiler
knows the types and number of parameters the procedure is expecting).

As an extension Irie Pascal supports calling functions and procedures
inside Windows DLLs using the "external" directive.

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

See also 2.8.1 Identifiers, 7.2.1 Built-in functions,
7.3.1 Built-in procedures, 12.5 Relaxed parameter list congruity,
and 12.2 Relaxed declarations.

-----------------------
7.2 Built-in functions:
-----------------------

-------------------------
7.2.1 Built-in functions:
-------------------------
Irie Pascal defines several built-in functions that perform various
tasks. You can call these functions in your programs without having
to declare them. Each built-in function is documented using the
following format:

Purpose: A short description of what the function does.
Parameter(s): Short descriptions of the function parameters, if any.
Syntax: Specifies how the function should be called.
Example: An example or a few examples showing the function being called.
Platforms: Which platforms provide support for the function.
Standard Pascal: Is the function defined by Standard Pascal (Yes or No).
Notes: Any other information about the function.

See also 7.1 Functions and procedures.

----------
7.2.2 abs:
----------
Purpose: Returns the absolute value of a number.
Parameter: A numeric value to be used as input.
Syntax:

   abs-call = 'abs' '(' num ')'

   num = integral-expression | real-expression

Examples:

   abs(-10)  returns  10
   abs(10)   returns  10
   abs(-6.7) returns  6.7
   abs(6.7)  returns  6.7

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

See also 7.2.1 Built-in functions, 5.13 Integral types,
and 5.14.11 real type.

-------------
7.2.3 arctan:
-------------
Purpose: Returns the arctangent of a number.
Parameter: A numeric value to be used as input.
Syntax:

   arctan-call = 'arctan' '(' num ')'

   num = integral-expression | real-expression

Example:   arctan(pi)  returns  1.0
Platforms: All
Standard Pascal: Yes
Notes: The type of the value returned by this function is always real.

See also 7.2.1 Built-in functions, 5.13 Integral types,
and 5.14.11 real type.

----------
7.2.4 chr:
----------
Purpose: Returns the character whose ordinal value is equal to its input.
Parameter: A integral value to be used as input.
Syntax:

   chr-call = 'chr' '(' int ')'

   int = integral-expression

Example:   chr(64)  returns  '@' (assuming the ASCII or ANSI character set).
Platforms: All
Standard Pascal: Yes
Notes: It is an error if there is no character with an ordinal value
       equal to its input.

See also 7.2.1 Built-in functions, 5.13 Integral types, and 7.2.42 ord.

-------------
7.2.5 concat:
-------------
Purpose: Returns a string formed by concatenating its parameters.
Parameters: One of more string or character expressions.
Syntax:

     concat-call = 'concat' '(' s { ',' s } ')'

     s = character-expression | string-expression

Example: concat('abc', '123', '!')  returns  'abc123!'
Platforms: All
Standard Pascal: No
Notes: Characters are converted to strings before the concatenation
       is performed. You can also use the + operator to perform
       string concatenation.

See also 7.2.1 Built-in functions, 5.2 Array types, 5.11 String types,
5.14.5 char type, and 12.18 Extended functions.

-----------
7.2.6 copy:
-----------
Purpose: Returns a copy of a part of or all of a string.
Parameters:
  1. The string to copy from
  2. The position to start copying from
  3. The number of characters to copy
Syntax:

       copy-call = 'copy' '(' s ',' p [ ',' n ')'

       s = character-expression | string-expression

       p = integral-expression

       n = integral-expression

Examples:

    copy('Testing...', 5, 2)     returns    'in'
    copy('Testing...', 7)        returns    'g...'
    copy('Testing...', 1, 1000)  returns    'Testing...'
    copy('Testing...', 50)       returns    ''

Platforms: All
Standard Pascal: No
Notes:
   The first parameter ("s") is the string to copy from.
   The second parameter ("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.
   The third parameter ("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.

See also 7.2.1 Built-in functions, 5.2 Array types, 5.11 String types,
5.14.5 char type, 7.2.7 copyword, 7.3.29 insert,
and 12.18 Extended functions.

---------------
7.2.7 copyword:
---------------
Purpose: Returns a string formed by copying a word from an input string.
Parameters:
  1. The input string
  2. The index of the word to copy
  3. The characters used to deliminate words
Syntax:

   copyword-call = 'copyword' '(' s ',' i [ ',' s2 ] ')'

   s = character-expression | string-expression

   i = integral-expression

   s2 = character-expression | string-expression

Examples:

   copyword('example', 1)                    returns  'example'
   copyword('   example    ', 1)             returns  'example'
   copyword('example', 2)                    returns  ''
   copyword('   another     example   ', 2)  returns  'example'

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

   copyword('1234, name, value', 1, ',')  returns  '1234'
   copyword('1234, name, value', 2, ',')  returns  ' name'
   copyword('1234, name, value', 3, ',')  returns  ' value'

Platforms: All
Standard Pascal: No
Notes:
    The first parameter ("s") is the input string from which the word
        is copied.
    The second parameter ("i") is the number of the word to copy.
        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.
    The third parameter ("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.

See also 5.2 Array types, 5.11 String types, 5.14.5 char type,
7.2.1 Built-in functions, 7.2.6 copy, 7.2.10 countwords, 7.3.29 insert,
and 12.18 Extended functions.

----------
7.2.8 cos:
----------
Purpose: Returns the cosine of a number (expressed in radians).
Parameter: A numeric value.
Syntax:

   cos-call = 'cos' '(' num ')'

   num = integral-expression | real-expression

Example: cos(pi/3)  returns  0.5
Platforms: All
Standard Pascal: Yes
Notes: The type of the value returned by this function is always real.

See also 5.13 Integral types, 5.14.11 real type,
7.2.1 Built-in functions, 7.2.9 cosh, 7.2.53 sin, and 7.2.61 tan.

-----------
7.2.9 cosh:
-----------
Purpose: Returns the hyperbolic cosine of a number.
Parameter: A numeric value
Syntax:

   cosh-call = 'cosh' '(' num ')'

   num = integral-expression | real-expression

Example:   cosh(1)   returns   1.54e01
Platforms: All
Standard Pascal: No
Notes: The type of the value returned by this function is always real.

See also 5.13 Integral types, 5.14.11 real type,
7.2.1 Built-in functions, 7.2.8 cos, 7.2.54 sinh, 7.2.62 tanh,
and 12.18 Extended functions.

------------------
7.2.10 countwords:
------------------
Purpose: Returns the number of words in an input string.
Parameters:
  1. The input string
  2. The characters used to deliminate words
Syntax:

   countwords-call = 'countwords' '(' s [ ',' s2 ] ')'

   s = character-expression | string-expression

   s2 = character-expression | string-expression

Examples:

   countwords('example')  returns  1
   countwords('   example    ')  returns  1
   countwords('   another     example   ')  returns  2

Here is an example using "," as the special character to count fields
in comma-deliminated strings.

   countwords('1234, name, value', ',')  returns  3

Platforms: All
Standard Pascal: No
Notes:
    The first parameter ("s") is the input string whoose words are
        to be counted.
    The second parameter ("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.

See also 5.2 Array types, 5.11 String types, 5.14.5 char type,
7.2.1 Built-in functions, 7.2.6 copy, 7.2.7 copyword, 7.3.29 insert,
and 12.18 Extended functions.

--------------------
7.2.11 createobject:
--------------------
Purpose: Creates an instance of a generic object type and returns
         a value identifying the instance.
Parameter: The name of the object type to create an instance of.
Syntax:

   createobject-call = createobject '(' object-type-name ')'

   object-type-name = string-expression

Example:

   CreateObject('InternetExplorer.Application')

creates an instance of the Internet Explorer Automation object type.
You can use this instance to launch Internet Explorer.

Platforms: Windows only.
Standard Pascal: No
Notes:
   The first parameter ("object-type-name") is a string expression
       that evaluates to the name of a COM object class.

See also 5.6.2 Generic objects, 7.2.1 Built-in functions, 7.3.13 dispose,
7.3.33 new, and 12.18 Extended functions.

--------------
7.2.12 dirsep:
--------------
Purpose: Returns the directory seperator for the current platform.
Parameter: None
Syntax:

   dirsep-call = 'dirsep'

Example: None
Platforms: All
Standard Pascal: No
Notes: On Windows, DOS, OS/2 the value returned is "\".
       On Linux, FreeBSD, Solaris/x86 and Solaris_sparc the value
          returned is "/".

See also 7.2.1 Built-in functions, 7.2.16 fexpand, 7.2.46 platform,
7.2.65 unixplatform, and 12.18 Extended functions.

-----------
7.2.13 eof:
-----------
Purpose: Indicates whether its parameter is at end-of-file.
Parameter: The file variable for the file to be tested for end-of-file.
Syntax:

   eof-call = 'eof' [ '(' f ')' ]

   f = file-variable

Example:

The function below  counts the number of lines in a text file.
The "eof" function is used to determine when the end of the text
file has been reached.

      function CountLines(name : filename) : integer;
      var
         count : integer;
         f : text;
      begin
         count := 0;
         reset(f, name);
         while not eof(f) do
            begin
               readln(f);
               inc(count);
            end;
         CountLines := count;
         close(f)
      end;

Platforms: All
Standard Pascal: Yes
Notes: If the parameter ("f") is omitted then the built-in file variable
          "input" shall be used as the parameter.

See also 5.4 File types, 6.3 File variables, 6.10.4 input,
7.2.1 Built-in functions, 7.2.14 eoln, 7.3.2 append, 7.3.6 close,
7.3.34 open, 7.3.38 popen, 7.3.43 read, 7.3.47 reset, and 7.3.49 rewrite.

------------
7.2.14 eoln:
------------
Purpose: Indicates on whether its parameter is at end-of-line.
Parameter: The text file variable for the file to be tested for end-of-line.
Syntax:

   eoln-call = 'eoln' [ '(' t ')' ]

   t = text-file-variable

Example: None
Platforms: All
Standard Pascal: Yes
Notes: If the parameter ("t") is omitted then the built-in text file
       variable "input" shall be used as the parameter.

See also 5.4 File types, 6.3 File variables, 6.10.4 input,
7.2.1 Built-in functions, 7.2.13 eof, 7.3.2 append, 7.3.6 close,
7.3.34 open, 7.3.38 popen, 7.3.43 read, 7.3.45 readln, 7.3.47 reset,
and 7.3.49 rewrite.

-----------
7.2.15 exp:
-----------
Purpose: Returns the value of "e" raised to a specified power.
Parameter: A numeric value specifying the power to raise "e" to.
Syntax:

   exp-call = 'exp' '(' num ')'

   num = integral-expression | real-expression

Example:  exp(2)   returns   7.389...
Platforms: All
Standard Pascal: Yes
Notes: The type of the value returned by this function is always real.

See also 5.13 Integral types, 5.14.11 real type,
7.2.1 Built-in functions, and 7.2.37 ln.

---------------
7.2.16 fexpand:
---------------
Purpose: Returns the full pathname of a file.
Parameter: The filename whoose full pathname is to be returned.
Syntax:

   fexpand-call = 'fexpand' '(' s ')'

   s = character-expression | string-expression

Example: None
Platforms: All
Standard Pascal: No
Notes: None.

See also 5.4 File types, 5.14.9 filename type, 7.2.1 Built-in functions,
7.2.17 filematch, 7.3.4 assign, 7.3.19 fsplit,
and 12.18 Extended functions.

-----------------
7.2.17 filematch:
-----------------
Purpose: Indicates on whether a filename matches a file specification.
Parameters:
  1. The file specification (which can contain wild-cards)
  2. The filename
Syntax:

   filematch-call = 'filematch' '(' file-spec ',' filename ')'

   file-spec = character-expression | string-expression

   filename = character-expression | string-expression

Examples:

   filematch('file.txt', 'file.txt')  returns  true
   filematch('file.txt', 'otherfile.txt')  returns  false
   filematch('*.txt', 'file.txt')  returns  true
   filematch('*.txt', 'otherfile.txt')  returns  true

   filematch('a?c', 'abc')  returns true
   filematch('a?c', 'agc')  returns true
   filematch('a?c', 'azc')  returns true
   filematch('a?', 'abc')  returns false
   filematch('a?c', 'ab')  returns false
   filematch('?c', 'bc')  returns false
   filematch('??c', 'abc')  returns true
   filematch('a??', 'avd')  returns true

Platforms: All
Standard Pascal: No
Notes:
    The first parameter ("file-spec") is the file specification with
        which the filename is being matched. The file specification may
        contain the following wildcard characters('*' and '?'). The
        character '*' used in the file specification matches any zero
        more characters in the filename. The character '?' used in the
        file specification matches any single character in the filename.
    The second parameter ("filename") is the filename to be matched with
        the file specification. The filename is not tested for validity
        nor does the file have to exist.

See also 5.4 File types, 5.14.9 filename type, 7.2.1 Built-in functions,
7.2.16 fexpand, 7.3.2 append, 7.3.4 assign, 7.3.34 open, 7.3.38 popen,
7.3.47 reset, 7.3.49 rewrite, 7.3.19 fsplit,
and 12.18 Extended functions.

---------------
7.2.18 filepos:
---------------
Purpose: Returns the value of the file position indicator of a file.
Parameter: The file variable for the file whoose file position is to be
           returned.
Syntax:

   filepos-call = 'filepos' '(' f ')'

   f = file-variable

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

       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.

See also 5.4 File types, 6.3 File variables, 7.2.1 Built-in functions,
7.2.13 eof, 7.2.14 eoln, 7.3.2 append, 7.3.6 close, 7.3.34 open,
7.3.43 read, 7.3.45 readln, 7.3.47 reset, 7.3.49 rewrite, 7.3.51 seek,
7.3.61 write, 7.3.62 writeln, and 12.18 Extended functions.

----------------
7.2.19 filesize:
----------------
Purpose: Returns the size of a file.
Parameter: The file variable for the file whoose size is to be returned.
Syntax:

   filesize-call = 'filesize' '(' f ')'

   f = file-variable

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

See also 5.4 File types, 6.3 File variables, 7.2.1 Built-in functions,
7.3.2 append, 7.3.6 close, 7.3.34 open, 7.3.47 reset, 7.3.49 rewrite,
7.3.51 seek, and 12.18 Extended functions.

------------
7.2.20 frac:
------------
Purpose: Returns the fractional part of a real expression.
Parameter: The real expresion whoose fractional part is to be returned.
Syntax:

   frac-call = 'frac' '(' r ')'

   r = real-expression

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

See also 5.14.11 real type, 7.2.1 Built-in functions, 7.2.24 int,
7.2.52 round, and 12.18 Extended functions.

--------------
7.2.21 getenv:
--------------
Purpose: Returns the value of an environment variable.
Parameter: The name of the environment variable to return.
Syntax:

   getenv-call = 'getenv' '(' s ')'

   s = character-expression | string-expression

Example: None
Platforms: All
Standard Pascal: No
Notes:
   The parameter ("s") is the name of the environment variable whoose
       value is to be returned. If no environment variable has a name
       matching "s" then an empty string is returned.

See also 7.2.1 Built-in functions, and 12.18 Extended functions.

--------------------
7.2.22 getlasterror:
--------------------
Purpose: Returns the number of the last trappable error that occured.
Parameter: None
Syntax:

   getlasterror-call = 'getlasterror'

Example: None
Platforms: All
Standard Pascal: No
Notes: When error trapping is enabled your program automatically checks
       for trappable errors after each operation that could cause a
       trappable error. Your program will terminate if a trappable error
       occurs. If you do not want this default behavior you can disable
       error trapping using the built-in function "traperrors" and call
       this function to determine if any errors occurred.

       After this function is called the error number is cleared to zero
       (this prevents the function from returning the same error more than
       once). However because of this, if you need to refer to
       the error number more than once you should store the result
       of the first call in a variable. For example the following is
       incorrect:

          if getlasterror <> 0 then
             case getlasterror of
             1: writeln('Error erasing file');
             2: writeln('Error renaming file');
             3: writeln('File is undefined')
             end

       since the second call to getlasterror will always return 0.
       Instead you should do something like this:

          errnum := getlasterror;
          if errnum <> 0 then
             case errnum of
             1: writeln('Error erasing file');
             2: writeln('Error renaming file');
             3: writeln('File is undefined')
             end

       New applications should use "GetLastError" instead of "IOResult",
       which does the same thing. "IOResult" continues to be supported
       for compatibility reasons only.

See also 6.10.2 errors, 7.2.1 Built-in functions, 7.2.25 ioresult,
7.3.58 traperrors, and 12.18 Extended functions.

-----------
7.2.23 hex:
-----------
Purpose: Returns the hexadecimal representation of its parameter.
Parameter: An integral value.
Syntax:

    hex-call = 'hex' '(' int ')'

    int = integral-expression

Examples:

   hex(10)   returns  'A'
   hex(16)   returns  '10'
   hex(255)  returns  'FF'

Platforms: All
Standard Pascal: No
Notes: None

See also 2.4.3 Hexadecimal whole-numbers, 7.2.1 Built-in functions,
7.3.55 str, and 12.18 Extended functions.

-----------
7.2.24 int:
-----------
Purpose: Returns the integral part of a real value.
Parameter: A real value to be used as input.
Syntax:

   int-call = 'int' '(' r ')'

   r = real-expression

Example:   int(7.234)   returns  7.0
Platforms: All
Standard Pascal: No
Notes: The type of the value returned by this function is always real.

See also 5.13 Integral types, 5.14.11 real type,
7.2.1 Built-in functions, 7.2.64 trunc, 7.2.20 frac, 7.2.52 round,
and 12.18 Extended functions.

----------------
7.2.25 ioresult:
----------------
Purpose: Returns the error number of the last trappable error that occured.
Parameter: None
Syntax:

   ioresult-call = 'ioresult'

Example: None
Platforms: All
Standard Pascal: No
Notes: Use of this function is no longer recommended, new programs
       should use the function "getlasterror" instead.

See also 6.10.2 errors, 7.2.1 Built-in functions, 7.2.22 getlasterror,
7.3.58 traperrors, and 12.18 Extended functions.

---------------
7.2.26 isalpha:
---------------
Purpose: Indicates whether a character is alphabetic.
Parameter: The character to use as input.
Syntax:

   isalpha-call = 'isalpha' '(' c ')'

   c = character-expression

Examples:

    isalpha('a')  returns   true
    isalpha('A')  returns   true
    isalpha('1')  returns   false
    isalpha('@')  returns   false
    isalpha('_')  returns   false

Platforms: All
Standard Pascal: No
Notes: None

See also 5.14.5 char type, 7.2.1 Built-in functions, 7.2.27 isalphanum,
7.2.28 isdigit, 7.2.29 islower, 7.2.31 isprint, 7.2.32 isspace,
7.2.33 isupper, 7.2.34 isxdigit, and 12.18 Extended functions.

------------------
7.2.27 isalphanum:
------------------
Purpose: Indicates whether a character is alphanumeric.
Parameter: The character to use as input.
Syntax:

   isalphanum-call = 'isalphanum' '(' c ')'

   c = character-expression

Examples:

    isalphanum('a')  returns   true
    isalphanum('A')  returns   true
    isalphanum('1')  returns   true
    isalphanum('@')  returns   false
    isalphanum('_')  returns   false

Platforms: All
Standard Pascal: No
Notes: None

See also 5.14.5 char type, 7.2.1 Built-in functions, 7.2.26 isalpha,
7.2.28 isdigit, 7.2.29 islower, 7.2.31 isprint, 7.2.32 isspace,
7.2.33 isupper, 7.2.34 isxdigit, and 12.18 Extended functions.

---------------
7.2.28 isdigit:
---------------
Purpose: Indicates whether a character is a numeric digit.
Parameter: The character to use as input.
Syntax:

   isdigit-call = 'isdigit' '(' c ')'

   c = character-expression

Examples:

    isdigit('a')  returns   false
    isdigit('A')  returns   false
    isdigit('1')  returns   true
    isdigit('@')  returns   false
    isdigit('_')  returns   false

Platforms: All
Standard Pascal: No
Notes: None

See also 2.4.1 Whole-numbers, 5.14.5 char type, 7.2.1 Built-in functions,
7.2.26 isalpha, 7.2.27 isalphanum, 7.2.29 islower, 7.2.31 isprint,
7.2.32 isspace, 7.2.33 isupper, 7.2.34 isxdigit,
and 12.18 Extended functions.

---------------
7.2.29 islower:
---------------
Purpose: Indicates whether a character is a lowercase letter.
Parameter: The character to use as input.
Syntax:

   islower-call = 'islower' '(' c ')'

   c = character-expression

Examples:

    islower('a')  returns   true
    islower('A')  returns   false
    islower('1')  returns   false
    islower('@')  returns   false
    islower('_')  returns   false

Platforms: All
Standard Pascal: No
Notes: None

See also 5.14.5 char type, 7.2.1 Built-in functions, 7.2.26 isalpha,
7.2.27 isalphanum, 7.2.28 isdigit, 7.2.31 isprint, 7.2.32 isspace,
7.2.33 isupper, 7.2.34 isxdigit, and 12.18 Extended functions.

--------------
7.2.30 isnull:
--------------
Purpose: Indicates whether a variant expression is null.
Parameter: The variant expression to use as input.
Syntax:

   isnull-call = 'isnull' '(' v ')'

   v = variant-expression

Example:

The following code fragment uses "isnull" to check the values of
the "last_name" and "first_name" fields to see if they are null, and
if so handle them specially.

   new(rs);
   rs.open(conn, 'select last_name, first_name from customer', rsforward);
   while not rs.eof
      begin
         if isnull(rs.field('last_name')) then
            write('NULL')
         else
            write(rs.field('last_name'));
         write(', ');
         if isnull(rs.field('first_name')) then
            writeln('NULL')
         else
            writeln(rs.field('first_name'))
         rs.movenext;
      end;
   rs.close;
   dispose(rs);

Platforms: All
Standard Pascal: No
Notes: A variant expression is an expression whoose type is not known
       until run-time, when the expression is evaluated and its value is
       determined. Variant expressions currently occur only when you use
       an instance of a recordset object to retrieve a value from a record
       in a database, this is because the compiler does not know the types
       of values stored in database records. So when you retrieve a
       value from a database record the compiler treats that value has
       having variant type (i.e. the compiler generates code to check
       the type of the value at run-time and convert it if necessary,
       and if possible, into values of a usable type). However database
       records can store null values (representing the absence of a value),
       and these values can not be converted into values of a usable type.
       So if you think that a particular value in a database record may
       contain the null value then you should use this function to check
       the value before using it. It is an error to use a null value
       in any way other than passing it into this function.

See also 7.2.1 Built-in functions, 5.14.12.1 Recordset type,
and 12.18 Extended functions.

---------------
7.2.31 isprint:
---------------
Purpose: Indicates whether a character is printable.
Parameter: The character to use as input.
Syntax:

   isprint-call = 'isprint' '(' c ')'

   c = character-expression

Examples:

   isprint('A')     returns   true
   isprint('3')     returns   true
   isprint('+')     returns   true
   isprint(' ')     returns   true
   isprint(chr(10)) returns   false
   isprint(chr(8)) returns    false

Platforms: All
Standard Pascal: No
Notes: The last two examples assume that chr(10) and chr(8) are
       control characters and not printable characters. Whether this
       is true or not depends on the character set being used.

See also 5.14.5 char type, 7.2.1 Built-in functions, 7.2.26 isalpha,
7.2.27 isalphanum, 7.2.28 isdigit, 7.2.29 islower, 7.2.32 isspace,
7.2.33 isupper, 7.2.34 isxdigit, and 12.18 Extended functions.

---------------
7.2.32 isspace:
---------------
Purpose: Indicates whether a character is a whitespace character.
Parameter: The character to use as input.
Syntax:

   isspace-call = 'isspace' '(' c ')'

   c = character-expression

Examples:
   isspace(' ')     returns   true
   isspace(chr(9))  returns   true  (assuming chr(9) is TAB)
   isspace(chr(10)) returns   true  (assuming chr(10) is LINEFEED)
   isspace(chr(13)) returns   true  (assuming chr(13) is CARRIAGE RETURN)
   isspace('A')     returns   false
   isspace('6')     returns   false
   isspace('$')     returns   false

Platforms: All
Standard Pascal: No
Notes:

See also 5.14.5 char type, 7.2.1 Built-in functions, 7.2.26 isalpha,
7.2.27 isalphanum, 7.2.28 isdigit, 7.2.29 islower, 7.2.31 isprint,
7.2.33 isupper, 7.2.34 isxdigit, and 12.18 Extended functions.

---------------
7.2.33 isupper:
---------------
Purpose: Indicates whether a character is an uppercase letter.
Parameter: The character to use as input.
Syntax:

   isupper-call = 'islower' '(' c ')'

   c = character-expression

Examples:

    isupper('a')  returns   false
    isupper('A')  returns   true
    isupper('1')  returns   false
    isupper('@')  returns   false
    isupper('_')  returns   false

Platforms: All
Standard Pascal: No
Notes: None

See also 5.14.5 char type, 7.2.1 Built-in functions, 7.2.26 isalpha,
7.2.27 isalphanum, 7.2.28 isdigit, 7.2.29 islower, 7.2.31 isprint,
7.2.32 isspace, 7.2.34 isxdigit, and 12.18 Extended functions.

----------------
7.2.34 isxdigit:
----------------
Purpose: Indicates whether a character is a hexadecimal digit.
Parameter: The character to use as input.
Syntax:

   isxdigit-call = 'isxdigit' '(' c ')'

   c = character-expression

Examples:

    isxdigit('a')  returns   true
    isxdigit('A')  returns   true
    isxdigit('h')  returns   false
    isxdigit('1')  returns   true
    isxdigit('@')  returns   false
    isxdigit('_')  returns   false

Platforms: All
Standard Pascal: No
Notes: None

See also 2.4.3 Hexadecimal whole-numbers, 5.14.5 char type,
7.2.1 Built-in functions, 7.2.23 hex, 7.2.26 isalpha, 7.2.27 isalphanum,
7.2.28 isdigit, 7.2.29 islower, 7.2.31 isprint, 7.2.32 isspace,
7.2.33 isupper, and 12.18 Extended functions.

------------------
7.2.35 keypressed:
------------------
Purpose: Indicates whether there are unread key presses waiting in
         the keyboard buffer.
Parameter: None
Syntax:

    keypressed-call = 'keypressed'

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

See also 4.8.9 feature_keypressed, 7.2.1 Built-in functions,
7.2.50 readkey, and 12.18 Extended functions.

--------------
7.2.36 length:
--------------
Purpose: Returns the length of a string or list.
Parameter: The list or string variable to be used as input.
Syntax:

   length-call = 'length' '(' s ')' |
                 'length' '(' l ')'

   s = character-expression | string-expression

   l = list-expression

Examples:

    length('')        returns   0
    length('a')       returns  1
    length('hello')   returns  5

And if "l" is a list of integer then

    new(l);
    length(l);         returns  0

and

    new(l);
    insert(1, l);
    insert(78, l);
    insert(45, l);
    insert(3, l);
    length(l);         returns  4

Platforms: All
Standard Pascal: No
Notes:
   When a string is passed to this function then the number of
      characters in the string is returned.
   When a list is passed to this function then the number of elements
      in the list is returned.

See also 5.2 Array types, 5.5 List types, 5.11 String types,
7.2.1 Built-in functions, and 12.18 Extended functions.

----------
7.2.37 ln:
----------
Purpose: Returns the natural logarithm of a numeric value.
Parameter: The numeric value to be used as input.
Syntax:

   ln-call = 'ln' '(' num ')'

   num = integral-expression | real-expression

Examples:

   ln(1)       returns   0.0
   ln(exp(1))  returns   1.0
   ln(100)     returns   4.61

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

See also 5.13 Integral types, 5.14.11 real type,
7.2.1 Built-in functions, 7.2.15 exp, and 7.2.38 log.

-----------
7.2.38 log:
-----------
Purpose: Returns the logarithm to the base 10 of a numeric value.
Parameter: The numeric value to be used as input.
Syntax:

   log-call = 'log' '(' num ')'

   num = integral-expression | real-expression

Examples:

   log(1)    returns   0.0
   ln(10)    returns   1.0
   ln(100)   returns   2.0

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

See also 5.13 Integral types, 5.14.11 real type,
7.2.1 Built-in functions, 7.2.37 ln, and 12.18 Extended functions.

--------------
7.2.39 locase:
--------------
Purpose: Returns the lowercase letter corresponding to a character.
         If there is no corresponding lowercase letter then the character
         is returned unchanged.
Parameter: The character to be converted to lowercase.
Syntax:

   locase-call = 'locase' '(' c ')'

   c = character-expression

Examples:

    locase('a')  returns  'a'
    locase('A')  returns  'a'
    locase('H')  returns  'h'
    locase('1')  returns  '1'
    locase('+')  returns  '+'
    locase('_')  returns  '_'

Platforms: All
Standard Pascal: No
Notes: None.

See also 5.14.5 char type, 7.2.1 Built-in functions, 7.2.40 lowercase,
7.2.66 upcase, 7.2.67 uppercase, and 12.18 Extended functions.

-----------------
7.2.40 lowercase:
-----------------
Purpose: Returns a string formed by converting all uppercase characters
         in an input string to lowercase characters and leaving all other
         characters unchanged.
Parameter: The string to be converted to lowercase.
Syntax:

   lowercase-call = 'lowercase' '(' s ')'

   s = character-expression | string-expression

Examples: lowercase('Hello!!')  returns   'hello!!'
Platforms: All
Standard Pascal: No
Notes: None.

See also 5.2 Array types, 5.11 String types, 5.14.5 char type,
7.2.1 Built-in functions, 7.2.39 locase, 7.2.66 upcase, 7.2.67 uppercase,
and 12.18 Extended functions.

-----------
7.2.41 odd:
-----------
Purpose: Indicates whether a number is odd (i.e. not evenly divisible by 2).
Parameter: The number to use as input.
Syntax:

   odd-call = 'odd' '(' i ')'

   i = integral-expression

Examples:

   odd(0)  return   false
   odd(1)  return   true
   odd(2)  return   false
   odd(-43)  return true
   odd(-44)  return false

Platforms: All
Standard Pascal: Yes
Notes: None.

See also 5.13 Integral types, and 7.2.1 Built-in functions.

-----------
7.2.42 ord:
-----------
Purpose: Returns the ordinal number of an ordinal value.
Parameter: The ordinal value to be used as input.
Syntax:

   ord-call = 'ord' '(' o ')'

   o = ordinal-expression

Examples:

   ord(false)   returns  0
   ord(true)    returns  1
   ord(21)      returns  21
   ord('A')     returns  65 (assuming the ASCII or ANSI character set)

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

See also 5.7 Ordinal types, 7.2.1 Built-in functions, 7.2.4 chr,
7.2.48 pred, and 7.2.57 succ.

------------------
7.2.43 paramcount:
------------------
Purpose: Returns the number of arguments passed to the program.
Parameter: None.
Syntax:

   paramcount-call = 'paramcount'

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 as follows:

    ipc args

and then run it as follow:

    ivm args this is a test

then the output would be

    Number of program arguments = 4

since four arguments were passed to the program
   1. this
   2. is
   3. a
   4. test

Platforms: All
Standard Pascal: No
Notes: None.

See also 7.2.1 Built-in functions, 7.2.44 paramstr,
and 12.18 Extended functions.

----------------
7.2.44 paramstr:
----------------
Purpose: Returns the selected program argument.
Parameter: An integral value that selects the program argument to return.
Syntax:

   paramstr-cal = 'paramstr' '(' i ')'

   i = integral-expression

For example the following is the sample program "args2.pas".

   program args2(output);
   var
      i : integer;
   begin
      for i := -1 to paramcount do
         writeln('Program argument #', i:1, ' is ', '"', paramstr(i), '"')
   end.

If you compile it as follows:

    ipc args2

and then run it as follow:

    ivm args2 this is a test

then the output would be

    Program argument #-1 is "ivm"
    Program argument #0 is "args2"
    Program argument #1 is "this"
    Program argument #2 is "is"
    Program argument #3 is "a"
    Program argument #4 is "test"

Platforms: All
Standard Pascal: No
Notes: If there is no ith program argument an empty string is returned.
       Also the -1th argument is always the name of the interpreter and
       the 0th argument is always the name of the program.

See also 7.2.1 Built-in functions, 7.2.43 paramcount,
and 12.18 Extended functions.

----------
7.2.45 pi:
----------
Purpose: Returns the value of the mathematical constant pi.
Parameter: None.
Syntax:

   pi-call = 'pi'

Example:   pi   returns  3.14
Platforms: All
Standard Pascal: No
Notes: None.

See also 7.2.1 Built-in functions, and 12.18 Extended functions.

----------------
7.2.46 platform:
----------------
Purpose: Returns an integer indicating the platform the program is
         running on.
Parameter: None.
Syntax:

   platform-call = 'platform'

For example the program below uses the "platform" function to
determine which platform it's running on and displays the name of
that platform.

   program ShowPlatform(output);
   begin
      case platform of
      platform_dos: writeln('DOS');
      platform_os2: writeln('OS/2');
      platform_win32: writeln('Windows');
      platform_linux: writeln('Linux');
      platform_fbsd: writeln('FreeBSD');
      platform_solaris: writeln('Solaris/x86');
      platform_solaris_sparc: writeln('Solaris/Sparc');
      platform_error: writeln('Unknown Platform');
      end
   end.

Platforms: All
Standard Pascal: No
Notes: As an extension Irie Pascal supports eight platform constants
       which can be compared with the value returned by this function.

See also 4.11.1 Platform constants, 7.2.1 Built-in functions,
and 12.18 Extended functions.

-----------
7.2.47 pos:
-----------
Purpose: Returns the first occurrence of one string in another, possibly
         after a specified starting position.
Parameters:
  1. The string to search for
  2. The string to be searched
  3. The starting position for the search
Syntax:

   pos-call = 'pos' '(' needle ',' haystack [ ',' start ')'

   needle = character-expression | string-expression

   haystack = character-expression | string-expression

   start = integral-expression

Examples:

   pos('o', 'Hello world')     returns  5
   pos('o', 'Hello world', 1)  returns  5
   pos('o', 'Hello world', 6)  returns  8
   pos('o', 'Hello world', 9)  returns  0

Platforms: All
Standard Pascal: No
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.

See also 5.2 Array types, 5.11 String types, 5.14.5 char type,
7.2.1 Built-in functions, and 12.18 Extended functions.

------------
7.2.48 pred:
------------
Purpose: Returns an ordinal number that is one less its input.
Parameter: The ordinal value to be used as input.
Syntax:

   pred-call = 'pred' '(' o ')'

   o = ordinal-expression

Examples:

   pred(true)    returns  0
   pred(21)      returns  20
   pred('A')     returns  64 (assuming the ASCII or ANSI character set)

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

See also 5.7 Ordinal types, 7.2.1 Built-in functions, 7.2.4 chr,
7.2.42 ord, and 7.2.57 succ.

--------------
7.2.49 random:
--------------
Purpose: Returns a random number.
Parameter: An integral expression that specifies the range of
           numbers within which the random number must fall.
Syntax:

   random-call = 'random' [ '(' i ')' ]

   i = integral-expression

Example: None.
Platforms: All
Standard Pascal: No
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 2.5 Real numbers, 5.13 Integral types, 7.2.1 Built-in functions,
7.3.40 randomize, and 12.18 Extended functions.

---------------
7.2.50 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).
Parameter:
Syntax:

   readkey-call = 'readkey'

Example: None.
Platforms: Windows, DOS, and OS/2
Standard Pascal: No
Notes:
If the key pressed corresponds to a printable character then this
function simply returns the character, however if the keypressed does
not correspond to a printable character (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.

See also 7.2.1 Built-in functions, 7.2.35 keypressed,
and 12.18 Extended functions.

---------------
7.2.51 reverse:
---------------
Purpose: Returns a string created by reversing the characters in an
         input string.
Parameter: The string to be used as input.
Syntax:

   reverse-call = 'reverse' '(' s ')'

   s = character-expression | string-expression

Example:   reverse('Hello!!')   returns  '!!olleH'
Platforms: All
Standard Pascal: No
Notes: None.

See also 5.2 Array types, 5.11 String types, 5.14.5 char type,
7.2.1 Built-in functions, and 12.18 Extended functions.

-------------
7.2.52 round:
-------------
Purpose: Returns the integral value closest to its input.
Parameter: The real value to be used as input.
Syntax:

   round-call = 'round' '(' r ')'

   r = real-expression

Examples:

   round(7.4)  returns  7
   round(7.5)  returns  8
   round(-7.4)  returns -7
   round(-7.5)  returns -8

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

See also 2.5 Real numbers, 5.14.10 integer type,
7.2.1 Built-in functions, 7.2.20 frac, 7.2.24 int, and 7.2.64 trunc.

-----------
7.2.53 sin:
-----------
Purpose: Returns the sine of its input (expressed in radians).
Parameter: A value of numeric type (i.e. byte, integer, word, or real).
Syntax:

   sin-call = 'sin' '(' num ')'

   num = integral-expression | real-expression

Example:   sin(pi/2)  returns  1.0
Platforms: All
Standard Pascal: Yes
Notes:
The type of the value returned by this function is always real.

See also 2.5 Real numbers, 7.2.1 Built-in functions, 7.2.8 cos,
and 7.2.61 tan.

------------
7.2.54 sinh:
------------
Purpose: Returns the hyperbolic sine of its input.
Parameter: A numeric value to be used as input.
Syntax:

   sinh-call = 'sinh' '(' num ')'

   num = integral-expression | real-expression

Example:   sinh(1)   returns  1.18
Platforms: All
Standard Pascal: No
Notes: The type of the value returned by this function is always real.

See also 2.5 Real numbers, 5.13 Integral types, 7.2.1 Built-in functions,
7.2.53 sin, 7.2.9 cosh, 7.2.62 tanh, and 12.18 Extended functions.

-----------
7.2.55 sqr:
-----------
Purpose: Returns the square of its input.
Parameter: A numeric value to be used as input.
Syntax:

   sqr-call = 'sqr' '(' num ')'

   num = integral-expression | real-expression

Examples:

   sqr(1)   returns  1
   sqr(3)   returns  9
   sqr(-5)  returns 25

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

See also 2.5 Real numbers, 5.13 Integral types, 7.2.1 Built-in functions,
and 7.2.56 sqrt.

------------
7.2.56 sqrt:
------------
Purpose: Returns the square-root of its input
Parameter: A numeric value to be used as input.
Syntax:

   sqrt-call = 'sqrt' '(' num ')'

   num = integral-expression | real-expression

Examples:

   sqrt(1)   returns  1.0
   sqrt(9)   returns  3.0
   sqrt(25)  returns 25.0

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

See also 2.5 Real numbers, 5.13 Integral types, 7.2.1 Built-in functions,
and 7.2.55 sqr.

------------
7.2.57 succ:
------------
Purpose: Returns an ordinal number that is one more than its input.
Parameter: The ordinal value to be used as input.
Syntax:

   succ-call = 'succ' '(' o ')'

   o = ordinal-expression

Examples:

   succ(false)   returns  1
   succ(21)      returns  22
   succ('A')     returns  66 (assuming the ASCII or ANSI character set)

See also 5.7 Ordinal types, 7.2.1 Built-in functions, 7.2.4 chr,
7.2.42 ord, and 7.2.48 pred.

-----------------
7.2.58 supported:
-----------------
Purpose: Indicates whether a particular feature is available on the current
         platform.
Paramer: An integral value indicating the feature whoose support is being
         checked.
Syntax:

   supported-call = 'supported' '(' i ')'

   i = integral-expression

Example:   supported(feature_odbc)  returns  true if the current platform
                                    supports ODBC and false otherwise.
Platforms: All
Standard Pascal: No.
Notes: Irie Pascal defines a constant for each feature whoose availability
       can be checked with this function. It is recommended that you use
       one of these predefined constants (as seen in the example above) to
       indicate which feature you want to check the availability of. This
       makes your program easier to read and is probably easier than
       remembering which number corresponds to which feature.

See also 4.8.1 Feature constants, 7.2.1 Built-in functions,
and 12.18 Extended functions.

------------
7.2.59 swap:
------------
Purpose: Returns an integral value calculated by reversing the byte
         ordering of its input.
Parameter: An integral value to use as input
Syntax:

   swap-call = 'swap' '(' i ')'

   i = integral-expression

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

Platforms: All
Standard Pascal: No
Notes: This function is useful for converting integers from little-endian
       to big-endian and vice-versa.

See also 7.2.1 Built-in functions, and 12.18 Extended functions.

--------------
7.2.60 system:
--------------
Purpose: Passes a command to the command processor for execution.
Parameter: A string specifying the command to execute.
Syntax:

   system-call = 'system' '(' s ')'

   s = character-expression | string-expression

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.

Platforms: All
Standard Pascal: No
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.1 Built-in functions, 7.3.15 exec,
and 12.18 Extended functions.

-----------
7.2.61 tan:
-----------
Purpose: Returns the tangent of its input (expressed in radians).
Parameter: A value of numeric type (i.e. byte, integer, word, or real).
Syntax:

   tan-call = 'tan' '(' num ')'

   num = integral-expression | real-expression

Example:   tan(pi/4)  returns  1.0
Platforms: All
Standard Pascal: No
Notes:
The type of the value returned by this function is always real.

See also 7.2.1 Built-in functions, 7.2.8 cos, 7.2.53 sin,
and 7.2.62 tanh.

------------
7.2.62 tanh:
------------
Purpose: Returns the hyperbolic tangent of its input.
Parameter: A value of numeric type (i.e. byte, integer, word, or real).
Syntax:

   tanh-call = 'tanh' '(' num ')'

   num = integral-expression | real-expression

Example:   tanh(1)   returns   0.762
Platforms: All
Standard Pascal: No
Notes: The type of the value returned by this function is always real.

See also 7.2.1 Built-in functions, 7.2.9 cosh, 7.2.54 sinh, 7.2.61 tan,
and 12.18 Extended functions.

------------
7.2.63 trim:
------------
Purpose: Returns a string created by removing all leading and trailing
         spaces from its input.
Parameter: A string to be used as input.
Syntax:

   trim-call = 'trim' '(' s ')'

   s = character-expression | string-expression

Example:   trim(' hello!! ')  returns 'hello!!'
Platforms: All
Standard Pascal: No
Notes: None.

See also 5.2 Array types, 5.11 String types, 5.14.5 char type,
7.2.1 Built-in functions, 7.2.32 isspace, and 12.18 Extended functions.

-------------
7.2.64 trunc:
-------------
Purpose: Returns an integral value formed by removing the fractional
         part of its input.
Parameter: A value of type "real".
Syntax:

   trunc-call = 'trunc' '(' r ')'

   r = real-expression

Example:   trunc(7.234)  returns 7
Platforms: All
Standard Pascal: Yes
Notes: The type of the value returned by this function is always integer.

See also 7.2.1 Built-in functions, 7.2.20 frac, 7.2.24 int,
and 7.2.52 round.

--------------------
7.2.65 unixplatform:
--------------------
Purpose: Indicates whether your program is running on a UNIX-like platform.
Parameter: None.
Syntax:

   unixplatform-call = 'unixplatform'

Example: none.
Platforms: All
Standard Pascal: No.
Notes: This function doesn't actually test the operating system your
       program is running on, instead it tests the edition of the
       interpreter that is running your program. It is assumed for example
       that the Linux version of the interpreter is running under Linux,
       and the Windows version of the interpreter is running under Windows.

See also 7.2.1 Built-in functions, 7.2.46 platform, 7.2.58 supported,
7.2.69 version, and 12.18 Extended functions.

--------------
7.2.66 upcase:
--------------
Purpose: Returns the uppercase letter corresponding to a character.
         If there is no corresponding uppercase letter then the character
         is returned unchanged.
Parameter: The character to be converted to uppercase.
Syntax:

   upcase-call = 'upcase' '(' c ')'

   c = character-expression

Examples:

    upcase('a')  returns  'A'
    upcase('A')  returns  'A'
    upcase('h')  returns  'H'
    upcase('1')  returns  '1'
    upcase('+')  returns  '+'
    upcase('_')  returns  '_'

Platforms: All
Standard Pascal: No
Notes: None.

See also 7.2.1 Built-in functions, 7.2.33 isupper, 7.2.39 locase,
7.2.40 lowercase, 7.2.67 uppercase, and 12.18 Extended functions.

-----------------
7.2.67 uppercase:
-----------------
Purpose: Returns a string formed by converting all lowercase characters
         in an input string to uppercase characters and leaving all other
         characters unchanged.
Parameter: The string to be converted to uppercase.
Syntax:

   uppercase-call = 'uppercase' '(' s ')'

   s = character-expression | string-expression

Examples: uppercase('Hello!!')  returns   'HELLO!!'
Platforms: All
Standard Pascal: No
Notes: None.

See also 7.2.1 Built-in functions, 7.2.33 isupper, 7.2.39 locase,
7.2.40 lowercase, 7.2.66 upcase, and 12.18 Extended functions.

-----------------
7.2.68 urldecode:
-----------------
Purpose: Decodes a URL encoded string and returns the decoded result.
Parameter: The URL encoded string to decode.
Syntax:

   urldecode-call = 'urldecode' '(' s ')'

   s = character-expression | string-expression

Examples:

   urldecode('irie+pascal')           returns   'irie pascal'
   urldecode('%2Fusr%2Flocal%2Fbin')  returns  '/usr/local/bin'

Platforms: All
Standard Pascal: No
Notes: URL 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 for processing GET or POST methods, since these methods
       URL encode strings.

See also 7.2.1 Built-in functions, 7.2.7 copyword, 7.2.10 countwords,
and 12.18 Extended functions.

---------------
7.2.69 version:
---------------
Purpose: Returns the version of the interpreter running your program.
Parameter: None.
Syntax:

   version-call = 'version'

Example:   version  currently returns 5
Platforms: All
Standard Pascal: No
Notes: The version number returned by this function is NOT related
       to the version of Irie Pascal or the operating system version.

       Currently you will probably not need to use this function,
       however this function is provided because each new version of the
       interpreter is likely to add support for new features.  Therefore
       programs in the future may need to know which version of the
       interpreter they are running on to determine whether a particular
       feature is available.

See also 7.2.1 Built-in functions, and 12.18 Extended functions.

--------------
7.2.70 wherex:
--------------
Purpose: Returns the column the cursor/caret is on.
Parameter: None.
Syntax:

   wherex-call = 'wherex'

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

See also 4.8.19 feature_wherex, 7.2.1 Built-in functions, 7.2.71 wherey,
7.3.26 gotoxy, and 12.18 Extended functions.

--------------
7.2.71 wherey:
--------------
Purpose: Returns the row the cursor/caret is on.
Parameter: None.
Syntax:

   wherex-call = 'wherey'

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

See also 4.8.20 feature_wherey, 7.2.1 Built-in functions, 7.2.70 wherex,
7.3.26 gotoxy, and 12.18 Extended functions.

------------------------
7.3 Built-in Procedures:
------------------------

--------------------------
7.3.1 Built-in procedures:
--------------------------
Irie Pascal defines several built-in procedures that perform various
tasks. You can call these procedures in your programs without having
to declare them. Each built-in procedure is documented using the
following format:

Purpose: A short description of what the procedure does.
Parameter(s): Short descriptions of the procedure parameters, if any.
Syntax: Specifies how the procedure should be called.
Example: An example or a few examples showing the procedure being called.
Platforms: Which platforms provide support for the procedure.
Standard Pascal: Is the procedure defined by Standard Pascal (Yes or No).
Notes: Any other information about the procedure.

See also 7.1 Functions and procedures.

-------------
7.3.2 append:
-------------
Purpose: Opens a file for writing at the end of the file, and associates
         a file variable with the opened file.
Parameters:
   1. The file variable for the file to be opened.
   2. The name of the file to open.
Syntax:

   append-call = 'append' '(' f [',' s ] ')'

   f = file-variable

   s = character-expression | string-expression

Example:   append(f, 'file.txt')   opens a file named 'file.txt'.
Platforms: All
Standard Pascal: No
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 procedure "seek".
If a filename ("s") is not specified then the filename used is the
filename assigned with the built-in procedure "assign". If no filename
has been assigned then the standard output file is opened.

See also 7.3.1 Built-in procedures, 7.3.4 assign, 7.3.34 open,
7.3.47 reset, 7.3.49 rewrite, 7.3.51 seek, and 12.19 Extended procedures.

-------------
7.3.3 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.
     When this procedure is not enabled then it does nothing.
     The idea behind this procedure is that you use it during debugging
     to test various conditions, 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 it 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 is using
     this procedure to test normal error conditions that may happen even
     if your program is bug-free (such as out of memory conditions or
     invalid user input).
Parameter: A boolean expression to test.
Syntax:

   assert-call = 'assert' '(' b ')'

   b = boolean-expression

Example: None.
Platforms: All
Standard Pascal: No
Notes: None.

See also 5.14.3 boolean type, 7.3.1 Built-in procedures,
and 12.19 Extended procedures.

-------------
7.3.4 assign:
-------------
Purpose: Assigns a name to a file variable.
Parameters:
   1. The file variable to which the name is to be assigned.
   2. The name to assign.
Syntax:

   assign-call = 'assign' '(' f ',' s ')'

   f = file-variable

   s = character-expression | string-expression

For example to open a file named 'README.TXT' for reading you could use.

    assign(f, 'README.TXT');
    reset(f);

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

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

See also 7.3.1 Built-in procedures, 7.3.2 append, 7.3.34 open,
7.3.47 reset, 7.3.46 rename, 7.3.49 rewrite,
and 12.19 Extended procedures.

------------
7.3.5 chdir:
------------
Purpose: Changes the current directory.
Parameter: The pathname of the directory to change to.
Syntax:

   chdir-call = 'chdir' '(' s ')'

   s = character-expression | string-expression

Example:

   chdir('\irie\samples') changes the current directory to '\irie\samples'

Platforms: All
Standard Pascal: No
Notes: None

See also 5.14.7 dir type, 7.2.12 dirsep, 7.3.1 Built-in procedures,
7.3.31 mkdir, 7.3.50 rmdir, and 12.19 Extended procedures.

------------
7.3.6 close:
------------
Purpose: Closes a file or pipe.
Parameter: A file variable associated with the file or pipe to be closed.
Syntax:

   close-call = 'close' '(' f ')'

   f = file-variable

Example:

      //The function below  counts the number of lines in a text file.
      //The functions opens the file, reads each lines, and then
      //closes the file with the builty-in function "close".
      function CountLines(name : filename) : integer;
      var
         count : integer;
         f : text;
      begin
         count := 0;
         reset(f, name);
         while not eof(f) do
            begin
               readln(f);
               inc(count);
            end;
         CountLines := count;
         close(f)
      end;

Platforms: All
Standard Pascal: No
Notes: The file or pipe must be open before this procedure is called.
       The file or pipe is flushed before it is closed.

See also 5.4 File types, 5.14.6.2 connection.close,
5.14.12.2 recordset.close, 6.3 File variables, 7.2.13 eof,
7.3.1 Built-in procedures, 7.3.2 append, 7.3.7 closedir, 7.3.18 flush,
7.3.34 open, 7.3.35 opendir, 7.3.38 popen, 7.3.47 reset, 7.3.49 rewrite,
and 12.19 Extended procedures.

---------------
7.3.7 closedir:
---------------
Purpose: Closes a directory.
Parameter: A directory variable associated with the directory to be closed.
Syntax:

   closedir-call = 'closedir' '(' d ')'

   d = directory-variable

Example:

   //Below is a simple program that lists all the files in the
   //current directory.
   program listfiles(output);
   var
      d : dir;
      filename : string;
   
   begin
      opendir(d, '.');  // Open current directory
      repeat
         readdir(d, filename);  // Get next file in directory
         if filename <> '' then
            writeln(filename);
      until filename = '';
      closedir(d) // Close directory
   end.

Platforms: All
Standard Pascal: No
Notes: None.

See also 4.8.3 feature_closedir, 5.14.7 dir type, 7.2.46 platform,
7.3.1 Built-in procedures, 7.3.6 close, 7.3.35 opendir, 7.3.44 readdir,
7.3.48 rewinddir, and 12.19 Extended procedures.

-------------
7.3.8 clrscr:
-------------
Purpose: Clears the screen and moves the cursor to the top left corner.
Parameter: None.
Syntax:

   clrscr-call = 'clrscr'

Example: None.
Platforms: Windows and DOS
Standard Pascal: No
Notes: None

See also 4.8.4 feature_clrscr, 7.2.46 platform, 7.2.50 readkey,
7.2.70 wherex, 7.2.71 wherey, 7.3.1 Built-in procedures, 7.3.26 gotoxy,
and 12.19 Extended procedures.

------------
7.3.9 crc32:
------------
Purposes: Computes 32 bit Cyclic Redundancy Check (CRC)
Parameters:
   1. A variable of integer or word type to accumulate the result.
   2. A value of byte or char type to use as the data.
   3. A value of integral type to use as the CRC polynomial.
Syntax:

   crc32-call = 'crc32' '(' accum ',' data [',' poly] ')'

   accum = integer-variable | word-variable

   data = byte-expression | char-expression

   poly = Integral-expression

Example:

   //****************************************************
   // This program uses the built-in procedure crc32
   //  to calculate the 32-bit CRC for a file.
   // Basically the program asks for the name of the file
   // and then it reads the file a character at a time
   // passing each byte to crc32.
   // Finally it calls crc32 4 times with zero to
   //  complete the crc calculation. This is part of
   //  the process of calculating CRCs.
   //****************************************************
   program filecrc(input, output);
   var
      fn : filename;
      f : file of char;
      c : char;
      crc : integer;
   begin
      write('Enter filename: ');
      readln(fn);
      writeln('Calculating CRC...');
      crc := 0;
      reset(f, fn);
      while not eof(f) do
         begin
            read(f, c);
            crc32(crc, c);
         end;

      crc32(crc, 0);
      crc32(crc, 0);
      crc32(crc, 0);
      crc32(crc, 0);

      writeln('CRC for ', fn, ' is ', crc, ' (', hex(crc), ')');
   end.

Platforms: All
Standard Pascal: No
Notes: If you do not specify a CRC polynomial, as in the example above,
       then the default CRC polynonial (i.e. $04C11DB7) is used.

See also 7.3.1 Built-in procedures, and 12.19 Extended procedures.

-----------
7.3.10 dec:
-----------
Purpose: Decrements an ordinal variable by a specified amount or by one.
Parameters:
   1. A variable of ordinal type.
   2. The amount to decrement by.
Syntax:

   dec-call = 'dec' '(' o [',' i ] ')'

   o = ordinal-variable

   i = integral-expression

Examples:

   dec(x)      decrements the variable "x" by 1
   dec(x, 10)  decrements the variable "x" by 10

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

          o := o - i;

See also 5.7 Ordinal types, 5.13 Integral types, 7.2.48 pred,
7.3.1 Built-in procedures, 7.3.28 inc, 8.2.2.3 Subtraction operator,
and 12.19 Extended procedures.

-------------
7.3.11 delay:
-------------
Purpose: Stops the program for a specified number of milli-seconds.
Parameter: An integral value specifying how many milli-seconds to delay.
Syntax:

   delay-call = 'delay' '(' ms ')'

   ms = integral-expression

Example: delay(1000)  delays 1000 milli-seconds (i.e. 1 second).
Platforms: Windows, DOS, OS/2
Standard Pascal: No
Notes: None.

See also 4.8.5 feature_delay, 7.2.46 platform, 7.3.1 Built-in procedures,
7.3.54 sleep, and 12.19 Extended procedures.

--------------
7.3.12 delete:
--------------
Purpose: Deletes components from a list or a string.
Parameters:
   1. A list or string variable from which components are to deleted.
   2. The position to start deleting from.
   3. The number of components to delete.
Syntax:

   delete-call = delete-from-list | delete-from-string

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

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

   l = list-variable

   s = string-variable

   start = integral-expression

   count = integral-expression

Examples:

   delete(l, 1)    deletes all components in the list "l"
   delete(l, 2)    deletes all components except the first one from "l"
   delete(l, 1, 3) deletes the first three components from "l"
   delete(s, 1)    deletes all characters from the string "s"
   delete(s, 2)    deletes all characters except the first one from "s"
   delete(s, 1, 3) deletes the first three characters from "s"

Platforms: All
Standard Pascal: No
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.

See also 5.2 Array types, 5.5 List types, 5.11 String types,
5.14.5 char type, 7.2.6 copy, 7.2.63 trim, 7.3.1 Built-in procedures,
7.3.13 dispose, 7.3.29 insert, and 12.19 Extended procedures.

---------------
7.3.13 dispose:
---------------
Purpose: Destroys a variable, list, or object.
Parameter: The pointer, list, or object variable whoose
          value identifies the variable, list, or object to destroy.
Syntax:

   dispose-call = dispose-pointer | dispose-list | dispose-object

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

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

   dispose-object = 'dispose' '(' obj ')'

   p = pointer-variable

   l = list-variable

   obj = object-variable

Examples: None.
Platforms: All
Standard Pascal: Yes
Notes:
Standard Pascal does not support the "list" type or "object" types and
so does not support using "dispose" on variables of those types.

It is an error to call this procedure if the pointer, list, or object
variable contains the special value "nil" or is undefined.

After calling this procedure the pointer, list, or object variable contains
the undefined value.

See also 6.4 List variables, 6.5 Object variables, 6.6 Pointer variables,
7.2.11 createobject, 7.3.1 Built-in procedures, and 7.3.33 new.

-------------
7.3.14 erase:
-------------
Purpose: Deletes a file.
Parameter: A file variable associated with the file to be deleted.
Syntax:

   erase-call = 'erase' '(' f ')'

   f = file-variable

Example:

   //*************************************************
   // This program removes (i.e. erases) a file
   // First it asks for the name of the file
   // Then it assigns the name to a file variable
   // Finally it calls 'erase' on the file variable
   //************************************************
   program rm(input, output);
   var
      fn : filename;
      f : binary;
   begin
      write('Which file do you want to delete? ');
      readln(fn);
      assign(f, fn);
      erase(f);
   end.

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

See also 5.4 File types, 6.3 File variables, 7.3.1 Built-in procedures,
7.3.4 assign, 7.3.6 close, 7.3.12 delete, and 12.19 Extended procedures.

------------
7.3.15 exec:
------------
Purpose: Passes a command to the command processor for execution.
   1. The name of the command to execute.
   2. The arguments if any to be used by the command.
Syntax:

   exec-call = 'exec' '(' p ',' 'a' ')'

   p = character-expression | string-expression

   a = character-expression | string-expression

Example:

   //***************************************************
   // This program lists all the files ending with .pas
   //  in the current diectory using the built-in
   //  procedure "exec".
   // Basically the program determines whether it is running
   //  under a Unix-like platform or not and passes
   //  the approprate list command to "exec" along
   //  with the "*.pas" argument so that only files
   //  ending with .pas are listed.
   program dirpas(output);
   const
      UnixListCommand = 'ls -l';
      OtherListCommand = 'dir';

   begin
      if UnixPlatform then
         exec(UnixListCommand, '*.pas')
      else
         exec(OtherListCommand, '*.pas');
      if exitcode <> 0 then
         writeln('Error listing directory', exitcode)
   end.

Platforms: All
Standard Pascal: No
Notes: The built-in variable "exitcode" contains the numeric code
       returned by the command processor to indicate whether an
       error occured. Zero means no error occured and any other
       value indicates which particular error occured. The values
       used by command processors to indicate which error occured
       varies is not standardized and so if you are interested in
       knowing which particular error occured you have to know
       which command processor is currently being used and what
       values it uses.

See also 7.2.43 paramcount, 7.2.44 paramstr, 7.2.60 system,
7.3.1 Built-in procedures, and 12.19 Extended procedures.

------------
7.3.16 exit:
------------
Purpose: Terminates the function, procedure, or program in which it is
         used, and optionally returns a value.
Parameter: The value to return.
Syntax:

   exit-call = 'exit' [ '(' e ')' ]

   e = expression

Example:

   //*****************************************************
   // This program is a primitive command processor.
   // It sends each line in the input file to the
   //   command processor.
   program batch(f, output);
   var
      f : text;
      s : string;
      err : integer;
   begin
      writeln('This is a simple command processor');
      writeln('Enter quit when done');
      writeln;
      err := 0;
      reset(f);    (* open input file or standard input file *)
      write('>');
      while not eof(f) do
         begin
            readln(f, s);
            if lowercase(trim(s)) = 'quit' then
               exit;
            writeln('Executing ', s);
            err := system(s);      (* Pass 's' to the command processor *)
            writeln('Error code is ', err);
            if err <> 0 then
               exit(err);
            write('>');
         end;
      exit(err)
   end.

Platforms: All
Standard Pascal: No
Notes:
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 in the main program then "exit" terminates the program.
If used 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 6.10.3 exitcode, 7.1 Functions and procedures,
7.3.1 Built-in procedures, 7.3.27 halt, and 12.19 Extended procedures.

------------
7.3.17 fill:
------------
Purpose: Fills a variable with a specified value.
Parameters:
   1. The variable to fill.
   2. The value to use as filling.
Syntax:

   fill-call = 'fill' '(' v ',' i ')'

   v = variable

   i = integral-expression

Example: None.
Platforms: All
Standard Pascal: No
Notes: None.

See also 5.13 Integral types, 7.2.59 swap, 7.3.1 Built-in procedures,
and 12.19 Extended procedures.

-------------
7.3.18 flush:
-------------
Purpose: Flushes the the buffer assciated with a file or pipe
         (i.e. all data waiting in the buffer to be written is written).
Parameter: A file variable associated with the file or pipe to be flushed.
Syntax:

   flush-call = 'flush' '(' f ')'

   f = file-variable

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

See also 5.4 File types, 7.3.1 Built-in procedures, 7.3.6 close,
7.3.39 put, 7.3.61 write, 7.3.62 writeln, and 12.19 Extended procedures.

--------------
7.3.19 fsplit:
--------------
Purpose: Splits a filename into its component parts.
Parameters:
   1. The filename to be split.
   2. A variable to store the directory part of the filename.
   3. A variable to store the name part of the filename (minus
      the extension.
   4. A variable to store the extension part of the filename.
Syntax:

   fsplit-call = fsplit '(' s ',' [ d ] ',' [ n ] ',' [ e ] ')'

   s = character-expression | string-expression

   d = string-variable

   n = string-variable

   e = string-variable

Examples:

   fsplit('/usr/local/bin/readme.txt', d, n, e) stores
             '/usr/local/bin' in "d" and
             'readme' in "n" and
             '.txt' in "e"

   fsplit('c:\autoexec.bat', d,,) stores 'c:\' in "d"

Platforms: All
Standard Pascal: No
Notes: Although "d", "n", and "e" are optional at least one must
       be specified.

See also 5.14.9 filename type, 7.2.5 concat, 7.2.16 fexpand,
7.2.17 filematch, 7.3.1 Built-in procedures,
and 12.19 Extended procedures.

-----------
7.3.20 get:
-----------
Purpose: Reads the next component from a file into the file's buffer
         variable.
Parameter: A file variable associated with the file to read.
Syntax:

   get-call = 'get' '(' f ')'

   f = file-variable

Example:

   //********************************************************
   //This program is similar to the unix shell command "cat".
   //It uses the built-in procedures "get" and "put" as well
   // as the file buffer's associated with the input and
   // output file to copy the contents of the input file to
   // the output file.
   program cat(f, g);
   var
      f, g : text;
      c : char;
   begin
      reset(f);
      rewrite(g);
      while not eof(f) do
         begin
            c := f^;
            get(f);
            g^ := c;
            put(g);
         end;
      close(g);
      close(f);
   end.

Platforms: All
Standard Pascal: Yes
Notes: This procedure is seldom used since it is usually easier to use
       "read" or "readln".

See also 6.3 File variables, 7.3.1 Built-in procedures, 7.3.39 put,
7.3.43 read, and 7.3.45 readln.

---------------
7.3.21 getdate:
---------------
Purpose: Retrieves the current system date.
Parameters:
   1. Stores the current year
   2. Stores the current month (1 to 12).
   3. Stores the current day of the month (1 to 31)
   4. Stores the current day of the week (0 to 6 counting from Sunday).
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

Example:

    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

Platforms: All
Standard Pascal: No
Notes: None

See also 7.3.22 getfiledate, 7.3.25 gettime, 7.3.1 Built-in procedures,
and 12.19 Extended procedures.

-------------------
7.3.22 getfiledate:
-------------------
Purpose: Returns the date a file was last modified.
Parameters:
   1. Name of the file to test.
   2. Stores the year the file was last modified.
   3. Stores the month the file was last modified (1 to 12)
   4. Stores the day of the month the file was last modified (1 to 31)
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

Example:

    Suppose the file 'c:\irie\readme.txt' was last modified on
       Wednesday September 30, 1998
    then after:

    getfiledate('c:\irie\readme.txt', year, month, day, day_of_week)

    year = 1998
    month = 9
    day = 30

Platforms: All
Standard Pascal: No
Notes: None.

See also 7.3.21 getdate, 7.3.24 getfiletime, 7.3.52 setfiledate,
7.3.1 Built-in procedures, and 12.19 Extended procedures.

-------------------
7.3.23 getfilemode:
-------------------
Purpose: Gets a file's mode.
Parameters:
   1. Name of the file to test.
   2. Stores the file's mode.
Syntax:

   getfilemode-call = 'getfilemode' '(' name ',' mode ')'

   name = character-expression | string-expression

   mode = integer-variable or word-variable

Example:

   //*************************************************************
   //This program uses the built-in procedure "getfilemode" to
   // determine if a file is a directory.
   program isdirectory(input, output);
   var
      s : filename;
      mode : integer;
      isdir : boolean;
   begin
      write('Enter filename:');
      readln(s);
      s := fexpand(s);
      getfilemode(s, mode);
      isdir := (mode and dir_bit) <> 0;
      if isdir then
         writeln(s, ' is a directory')
      else
         writeln(s, ' is not a directory');
   end.

Platforms: All
Standard Pascal: No
Notes:
After calling getfilemode the filemode can be AND'd with the
Permission Constants to determine information about the file.

See also 4.10.1 Permission constants, 7.3.1 Built-in procedures,
and 12.19 Extended procedures.

-------------------
7.3.24 getfiletime:
-------------------
Purpose: Returns the time a file was last modified.
Parameters:
   1. Name of the file to test.
   2. Stores the hour the file was last modified (0 to 23)
   3. Stores the minute the file was last modified (0 to 59)
   4. Stores the second the file was last modified (0 to 61)
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

Example: None.
Platforms: All
Standard Pascal: No
Notes: None.

See also 7.3.22 getfiledate, 7.3.25 gettime, 7.3.53 setfiletime,
7.3.1 Built-in procedures, and 12.19 Extended procedures.

---------------
7.3.25 gettime:
---------------
Purpose: Retrieves the current system time.
Parameters:
   1. Stores the current hour (0 to 23)
   2. Stores the current minute (0 to 59)
   3. Stores the current second (0 to 61)
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

Example:

   //***************************************************
   //This program displays the current system time.
   //The built-in procedure "gettime" is used to
   // retrieve the current system time.
   program time;
   type
      TimePeriod = (am, pm);
   var
      hour, minute, second : integer;
      period : TimePeriod;

      //This function converts an integer to a string
      // and makes sure the string contains at least
      // two digits.
      function Force2Digits(i : integer) : string;
      var
         s : string;
      begin
         str(i:1, s);
         if i < 10 then
            s := '0' + s;
         Force2Digits := s;
      end;

   begin
      gettime(hour, minute, second);
      if hour > 12 then
         begin
            hour := hour - 12;
            period := pm
         end
      else
         period := am;
      write('Time is ');
      write(Force2Digits(hour), ':');
      write(Force2Digits(minute), ':');
      write(Force2Digits(second));
      case period of
      am: writeln(' AM');
      pm: writeln(' PM');
      end;
   end.

Platforms: All
Standard Pascal: No
Notes: None

See also 7.3.21 getdate, 7.3.24 getfiletime, 7.3.1 Built-in procedures,
and 12.19 Extended procedures.

--------------
7.3.26 gotoxy:
--------------
Purpose: Moves the cursor to the specified X, Y position on the screen.
Parameters:
   1. Specifies X coordinate (i.e. column) to move the cursor to.
   2. Specifies Y coordinate (i.e. row) to move the cursor to.
Syntax:

   gotoxy-call = 'gotoxy' '(' x ',' y ')'

   x = integral-expression

   y = integral-expression

Example: gotoxy(1,1)  moves the cursor to the top left-hand corner
                      of the screen.
Platforms: Windows and DOS
Standard Pascal: No
Notes: None

See also 4.8.6 feature_gotoxy, 5.13 Integral types, 7.2.70 wherex,
7.2.71 wherey, 7.3.1 Built-in procedures, and 12.19 Extended procedures.

------------
7.3.27 halt:
------------
Purpose: Terminates the program and optionally returns an integral value
         to the program's caller.
Parameter: The integral value to return.
Syntax:

   halt-call = 'halt' [ '(' i ')' ]

   i = integral-expression

Example:

   //This example program adds the program arguments.
   //The built-in procedure "halt" is used to terminate the program
   //if an argument is found that is not a valid integer.

   program add(output);
   var
      sum, // Stores the total
      i,   // Counts the program arguments
      x,   // Stores the converted program arguments
     err   // Indicates whether or not there was an error *)
      : integer;
   begin
      sum := 0;    // initiaze the sum
      for i := 1 to paramcount do
         begin
            val(paramstr(i), x, err); // Convert program agument into an integer
            if err <> 0 then
               begin
                  writeln(paramstr(i), ' is not a valid integer');
                  halt
               end;
            sum := sum + x
         end;
      writeln('Sum is ', sum)
   end.

Platforms: All
Standard Pascal: No
Notes: If no parameter is specified then zero (0) is returned to the caller.

See also 5.13 Integral types, 6.10.3 exitcode, 7.3.1 Built-in procedures,
7.3.16 exit, and 12.19 Extended procedures.

-----------
7.3.28 inc:
-----------
Purpose: Increments an ordinal variable by a specified amount or by one.
Parameters:
   1. A variable of ordinal type.
   2. The amount to increment by.
Syntax:

   inc-call = 'inc' '(' o [ ',' amount ] ')'

   o = ordinal-variable

   amount = integral-expression

Examples:

   inc(x)      increments the variable "x" by 1
   inc(x, 10)  increments the variable "x" by 10

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

           o := o + amount;

See also 5.7 Ordinal types, 5.13 Integral types, 7.2.57 succ,
7.3.1 Built-in procedures, 7.3.10 dec, 8.2.2.2 Addition operator,
and 12.19 Extended procedures.

--------------
7.3.29 insert:
--------------
Purpose: (A) Inserts a string value into another string or
         (B) Inserts a value into a list.
Parameters (A):
   1. The string value to insert into the destination string.
   2. The string variable containing the destination string.
   3. The position to perform the insertion
        (i.e. where in the destination string).
Parameters (B):
   1. The value to insert into the list (must be assignment compatible
        with the list's component type).
   2. The list variable containing the destination list.
   3. The position to perform the insertion
        (i.e. where in the destination list).
Syntax:

   insert-call = insert-into-string | insert-into-list

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

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

   s1 = character expression | string-expression

   s2 = string-variable

   v = expression

   l = list-variable

   p = integral-expression

Examples:

Here are some examples using "insert" with strings:

Assuming that "x" is a string variable then after:

   x := "ABC";
   insert('DEF', x); //insert 'DEF' at the end of "x"

"x" will contain 'ABCDEF'.

   x := 'ABFGHI';
   insert('CDE', x, 3); //insert 'CDE' at the third position

"x" will contain 'ABCDEFGHI'.


Here is an example program using "insert" with a list:

//*******************************************************************
//The simple program below uses an insertion sort to sort a list of
// integers.
//The program is probably not very useful but it illustrates how
// to use the built-in procedure "insert" on a list.
//*******************************************************************
program intlist(output);
type
   IntList = list of integer;
var
   l : IntList;
   iValue : integer;

   procedure InsertionSort(var l : IntList; iValue : integer);
   var
      i, len : integer;
      inserted : boolean;
   begin (* InsertionSort *)
      inserted := false;
      len := length(l);
      i := 1;
      repeat
         if i <= len then //if we haven't gone past the end of the list
            begin
               if l[i] > iValue then //if we have found the position to insert
                  begin
                     insert(iValue, l, i);
                     inserted := true
                  end
               else //index to next position in the list
                  inc(i)
            end
         else //we have searched the entire list but we haven't found
              //an insertion point, therefore we have to insert at the end
            begin
               insert(iValue, l); //insert value at the end of the list
               inserted := true
            end;
      until inserted;
   end; (* InsertionSort *)

   procedure ShowList(var l : IntList);
   var
      i : integer;
   begin (* ShowList *)
      for i := 1 to length(l) do
        writeln(i, l[i])
   end; (* ShowList *)

begin
   new(l); //create list
   repeat
      write('Enter a integer (use negative vale < 0 to stop) ');
      readln(iValue);
      if iValue >= 0 then
         InsertionSort(l, iValue);
   until iValue < 0;
   ShowList(l);
   dispose(l); //destroy list
end.

Platforms: All
Standard Pascal: No
Notes: If the third parameter (the position to perform the insertion)
        is not specified then the insertion is performed at the end of
        the string or list.

See also 5.2 Array types, 5.5 List types, 5.11 String types,
5.13 Integral types, 5.14.5 char type, 7.2.5 concat, 7.2.36 length,
7.3.1 Built-in procedures, 7.3.2 append, 7.3.12 delete,
and 12.19 Extended procedures.

------------
7.3.30 intr:
------------
Purpose: Executes a x86 processor interrupt.
Parameters:
   1. Integral value indicating which interrupt to generate (0-255).
   2. A variable of the built-in type "registers", which contains
       values to pass into the x86 processor registers before the
       interrupt is generated, and which receives the contents of
       the x86 processor registers after the interrupt is serviced.
Syntax:

   intr-cal = 'intr' '(' intno ',' regs ')'

   into = integral-expression

   regs = registers-variable

Example:

   //For example the following simple program uses interrupt $10
   //to clear the screen.
   program cls;
   var
      regs : registers;
   begin
      fill(regs, 0);
      regs.eax := $0002;
      intr($10, regs)
   end.

Platforms: DOS only
Standard Pascal: No
Notes: None.

See also 4.8.8 feature_intr, 5.14.13 registers type, 7.2.35 keypressed,
7.2.46 platform, 7.2.50 readkey, 7.2.60 system,
7.3.1 Built-in procedures, 7.3.8 clrscr, 7.3.15 exec, 7.3.26 gotoxy,
7.3.32 msdos, and 12.19 Extended procedures.

-------------
7.3.31 mkdir:
-------------
Purpose: Makes a directory
Parameters:
   1. The name of the directory to create.
   2. The permissions for the new directory
Syntax:

   mkdir-call = 'mkdir' '(' name [ ',' permissions ] ')'

   name = character-expression | string-expression

   permissions = integral-expression

Example:

   mkdir('\irie\samples') makes the directory 'samples' in
                           the directory '\irie'

Platforms: All
Standard Pascal: No
Notes: If permissions are specified then the default permissions
       are assuned. You can use the permission constants when specifying
       permissions.

See also 4.10.1 Permission constants, 5.2 Array types, 5.5 List types,
5.11 String types, 5.13 Integral types, 5.14.5 char type,
5.14.7 dir type, 7.2.12 dirsep, 7.3.1 Built-in procedures, 7.3.5 chdir,
7.3.23 getfilemode, 7.3.35 opendir, 7.3.50 rmdir,
and 12.19 Extended procedures.

-------------
7.3.32 msdos:
-------------
Purpose: Executes a call to MSDOS through x86 processor interrupt $21.
Parameters:
   1. A variable of the built-in type "registers", which contains
       values to pass into the x86 processor registers before the
       interrupt is generated, and which receives the contents of
       the x86 processor registers after the interrupt is serviced.
Syntax:

   msdos-cal = 'intr' '(' regs ')'

   regs = registers-variable

Example:

   //For example the following simple program uses
   // MSDOS function $30 to get the MSDOS version number.
   program GetVer(output);
   var
      regs : registers;
   begin
      fill(regs, 0);
      regs.ah := $30;
      regs.al := $00;
      msdos(regs);
      write('MSDOS version is ');
      if regs.al = 0 then
         writeln('1')
      else
         writeln(regs.al:1, '.', regs.ah:1)
   end.

Platforms: DOS only
Standard Pascal: No
Notes: None.

See also 4.8.8 feature_intr, 5.14.13 registers type, 7.2.46 platform,
7.2.60 system, 7.3.1 Built-in procedures, 7.3.15 exec, 7.3.30 intr,
and 12.19 Extended procedures.

-----------
7.3.33 new:
-----------
Purpose: Creates a variable, list, or object.
Parameter: The pointer, list, or object variable to store the value
           identifying the newly created variable, list, or object.
Syntax:

   new-call = new-list | new-pointer | new-object

   new-pointer = 'new' '(' pntr ')'

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

   new-object = 'new' '(' obj ')'

   list = list-variable

   pntr = pointer-variable

   obj = object-variable

Example: None.
Platforms: All
Standard Pascal: No
Notes: Standard Pascal does not support the "list" type or "object" types
       and so does not support using "new" on variables of those types.

See also 6.4 List variables, 6.5 Object variables, 6.6 Pointer variables,
7.2.11 createobject, 7.3.1 Built-in procedures, and 7.3.13 dispose.

------------
7.3.34 open:
------------
Purpose: Opens a file.
Parameter:
   1. The file variable to associate with the open file.
   2. The name of the file to open.
   3. The file mode.
Syntax:

   open-call = 'open' '(' fv ',' name ',' mode ')'

   fv = file-variable

   name = character-expression | string-expression

   mode = integral-expression

Examples:

   open(f, 'filename', readmode);   //this is the same as reset(f, 'filename');
   open(f, 'filename', writemode); //this is the same as rewrite(f, 'filename');
   open(f, 'filename', appendmode); //this is the same as append(f, 'filename');

The following call to "open"

   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 file, before
opening it again for reading and writing.

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

See also 4.9.1 Filemode constants, 5.13 Integral types,
7.3.1 Built-in procedures, 7.3.2 append, 7.3.4 assign, 7.3.35 opendir,
7.3.47 reset, 7.3.49 rewrite, 7.3.51 seek, and 12.19 Extended procedures.

---------------
7.3.35 opendir:
---------------
Purpose: Opens a directory.
Parameters:
   1. The directory variable to associate with the opened directory
   2. The name of the directory to open
Syntax:

   opendir-call = 'opendir' '(' d, name ')'

   d = directory-variable

   name = string-variable

Example:

   //Below is a simple program that lists all the files in the
   //current directory.
   program listfiles(output);
   var
      d : dir;
      filename : string;
   begin
      opendir(d, '.');  // Open current directory
      repeat
         readdir(d, filename);  // Get next file in directory
         if filename <> '' then
            writeln(filename);
      until filename = '';
      closedir(d) // Close directory
   end.

Platforms: All
Standard Pascal: No
Notes: None.

See also 4.8.12 feature_opendir, 5.14.7 dir type, 7.2.46 platform,
7.3.1 Built-in procedures, 7.3.7 closedir, 7.3.34 open, 7.3.44 readdir,
7.3.48 rewinddir, and 12.19 Extended procedures.

------------
7.3.36 pack:
------------
Purpose: Copies some or all of the elements of an unpacked array
         into a packed array.
Parameter:
   1. An unpacked array variable.
   2. An expression that specifies the first element to copy.
   3. A packed array variable.
Syntax:

   pack-call = 'pack' '(' u ',' x ',' p ')'

   u = unpacked-array-variable

   x = expression

   p = packed-array-variable

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"

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

See also 5.2 Array types, 7.2.6 copy, 9.3.2.1 Assignment compatibility,
and 7.3.1 Built-in procedures.

------------
7.3.37 page:
------------
Purpose: Writes a form-feed to a text file.
Parameter: The file variable associated with the text file to page.
Syntax:

   page-call = 'page' '(' t ')'

   t = text-file-variable

Example: None.
Platforms: All
Standard Pascal: Yes
Notes: According to Standard Pascal, this procedure is supposed
       to affect the text file in such a way that subsequent
       output appears on a new page.

See also 5.14.15 text type, and 7.3.1 Built-in procedures.

-------------
7.3.38 popen:
-------------
Purpose: Executes a program and opens a pipe to the program.
Parameters:
   1. The file variable to associate with the open pipe.
   2. The name of the program to execute.
   3. The file mode.
Syntax:

   popen-call = 'popen' '(' fv ',' name ',' mode ')'

   fv = file-variable

   name = character-expression | string-expression

   mode = integral-expression

Examples:

See also 4.8.13 feature_popen, 4.9.1 Filemode constants,
5.13 Integral types, 7.3.1 Built-in procedures, 7.3.6 close, 7.3.34 open,
and 12.19 Extended procedures.

-----------
7.3.39 put:
-----------
Purpose: Writes the contents of a file's buffer variable to the file and
         empties the file's buffer variable leaving it undefined.
Parameter: A file variable associated with the file to write.
Syntax:

   put-call = 'put' '(' f ')'

   f = file-variable

Example:

The example program below uses the built-in procedure "put" to write
a message to the standard output.

   program hello2(output);
   begin
      output^ := 'H';
      put(output);
      output^ := 'e';
      put(output);
      output^ := 'l';
      put(output);
      output^ := 'l';
      put(output);
      output^ := 'o';
      put(output);
      output^ := ' ';
      put(output);
      output^ := 'w';
      put(output);
      output^ := 'o';
      put(output);
      output^ := 'r';
      put(output);
      output^ := 'l';
      put(output);
      output^ := 'd';
      put(output);
      output^ := '!';
      put(output);
      output^ := '!';
      put(output);
   end.

Platforms: All
Standard Pascal: Yes
Notes: If "f" is a file variable then the file's buffer variable can be
       accessed with "f^" or "f@".
       This procedure is seldom used, since it is usually easier to use
       "write" or "writeln".

See also 6.3 File variables, 7.3.1 Built-in procedures, 7.3.20 get,
7.3.61 write, and 7.3.62 writeln.

-----------------
7.3.40 randomize:
-----------------
Purpose: Initializes the random number generator with a seed.
Parameter: The seed used to initialize the random number generator.
Syntax:

   randomize-call = 'randomize' [ '(' i ')' ]

   i = integral-expression

Example:

Here is a simple example program that generates some random numbers,
stores them in an array, sorts the numbers, and then prints the
numbers out. The built-in procedure "randomize" is used to initialize
the random number generator.

   program sort(output);
   const
      max = 20;
   var
      numbers : array[1..max] of integer;

      procedure GenerateRandomNumbers;
      var
         i : 1..max;
      begin
         for i := 1 to max do
            numbers[i] := random(100)+1;
      end;

      procedure SortNumbers;
      var
         i : 1..max;
         swapped : boolean;
         temp : integer;
      begin
         repeat
            swapped := false;
            for i := 1 to max-1 do
               if numbers[i] > numbers[i+1] then
                  begin
                     temp := numbers[i];
                     numbers[i] := numbers[i+1];
                     numbers[i+1] := temp;
                     swapped := true;
                  end;
         until not swapped;
      end;

      procedure PrintNumbers;
      var
         i : 1..max;
      begin
         for i := 1 to max do
            writeln(i, numbers[i]);
      end;

   begin
      randomize; //Initialize random number generator
      GenerateRandomNumbers;
      SortNumbers;
      PrintNumbers;
   end.

Platforms: All
Standard Pascal: No
Notes: If a seed is not specified then the random number generator is
       initialized with a seed derived from the current system date
       and time. Specifying the seed is useful if you want a repeatable
       sequence of random numbers. Or you can just not call "randomize"
       at all in which case the the random number generator generates
       the same sequence of the random numbers, every time your program
       is run.

See also 5.13 Integral types, 7.2.49 random, 7.3.1 Built-in procedures,
and 12.19 Extended procedures.

---------------
7.3.41 rawread:
---------------
Purpose: Reads up to a specified number of characters from a file
         into a character buffer.
Parameters:
   1. A file variable associated with the file to read.
   2. A packed array of char that stores the characters read by
      this procedure.
   3. Specifies the maximum number of characters to read.
   4. An integer or word variable that stores the actual number of
      characters read by this procedure.
Syntax:

   rawread-call = 'rawread' '(' f ',' buffer ',' count ',' actual ')'

   f = file-variable

   buffer = array-variable

   count = integral-expression

   actual = integer-variable or word-variable

Example:

The simple program below copies the contents of an input file into
an output file. It is similar to the UNIX program "cat".
The program uses the built-in procedures "rawread", and "rawwrite"
to perform the I/O.

   program cat(f, g);
   const
      max = 400;
   var
      f, g : text;
      buffer : packed array[1..max] of char;
      actual : integer;
   begin
      reset(f);
      rewrite(g);
      while not eof(f) do
         begin
            rawread(f, buffer, max, actual);
            if actual <> 0 then
               rawwrite(g, buffer, actual, actual);
         end;
      close(g);
      close(f);
   end.

Platforms: All
Standard Pascal: No
Notes: The actual number of characters read by this procedure may be
       less than the maximum number of characters specified if there is
       an I/O error (you can check this by disabling I/O checking and
       using the "getlasterror" function) or if the end-of-file is reached.

See also 5.2 Array types, 5.4 File types, 5.13 Integral types,
7.2.13 eof, 7.2.22 getlasterror, 7.3.1 Built-in procedures, 7.3.34 open,
7.3.42 rawwrite, 7.3.43 read, and 7.3.47 reset.

----------------
7.3.42 rawwrite:
----------------
Purpose: Writes up to a specified number of characters from a character
         buffer to a file.
Parameters:
   1. A file variable associated with the file to write.
   2. A packed array of char that stores the characters to write.
   3. Specifies the maximum number of characters to write.
   4. An integer or word variable that stores the actual number of
      characters written by this procedure.
Syntax:

   rawwrite-call = 'rawwrite' '(' f ',' buffer ',' count ',' actual ')'

   f = file-variable

   buffer = array-variable

   count = integral-expression

   actual = integral-variable

Example:
The simple program below copies the contents of an input file into
an output file. It is similar to the UNIX program "cat".
The program uses the built-in procedures "rawread", and "rawwrite"
to perform the I/O.

   program cat(f, g);
   const
      max = 400;
   var
      f, g : text;
      buffer : packed array[1..max] of char;
      actual : integer;
   begin
      reset(f);
      rewrite(g);
      while not eof(f) do
         begin
            rawread(f, buffer, max, actual);
            if actual <> 0 then
               rawwrite(g, buffer, actual, actual);
         end;
      close(g);
      close(f);
   end.

Platforms: All
Standard Pascal: No
Notes: The actual number of characters written by this procedure may be
       less than the maximum number of characters specified if there is
       an I/O error (you can check this by disabling I/O checking and
       using the "getlasterror" function).

See also 5.2 Array types, 5.4 File types, 5.13 Integral types,
7.2.22 getlasterror, 7.3.1 Built-in procedures, 7.3.34 open,
7.3.41 rawread, 7.3.61 write, and 7.3.62 writeln.

------------
7.3.43 read:
------------
Purpose: This procedure reads data from a file into one or more variables.
Parameters:
   1. The file variable associated with the file to read
      (This parameter may be omitted).
   2. One or more variables to store the data read from the file.
Syntax:

   read-call = 'read' read-parameter-list

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

Example:  read(f, x, y, z)     reads three values from the file associated
                               with "f" into "x", "y", and "z".
Platforms: All
Standard Pascal: Yes
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

See also 4.9.3 readmode, 5.4 File types, 5.11 String types,
5.13 Integral types, 5.14.5 char type, 6.10.4 input, 7.2.13 eof,
7.2.22 getlasterror, 7.2.50 readkey, 7.3.1 Built-in procedures,
7.3.6 close, 7.3.18 flush, 7.3.20 get, 7.3.34 open, 7.3.44 readdir,
7.3.45 readln, 7.3.47 reset, and 7.3.61 write.

---------------
7.3.44 readdir:
---------------
Purpose: Reads a directory (i.e. retrieves the name of the next file in the
         directory).
Parameters:
   1. The directory variable associated with the directory to read.
   2. Stores the filename of the next file in the directory.
Syntax:

   readdir-call = 'readdir' '(' d ',' name ')'

   d = directory-variable

   string-var = string-variable

Example:

The simple program below opens the current directory and then uses
"readdir" to read the names of all the files in the directory, and
then finally closes the directory when done.

   program listdir(output);
   var
      d : dir;
      fn : filename;

   begin
      opendir(d, '.');  { Open current directory }
      repeat
         readdir(d, fn);  { Get next file in directory }
         if fn <> '' then
            writeln(fn);
      until fn = '';
      closedir(d) { Close directory }
   end.

Platforms: All
Standard Pascal: No
Notes: None.

See also 4.8.14 feature_readdir, 5.2 Array types, 5.4 File types,
5.11 String types, 5.14.7 dir type, 5.14.9 filename type,
7.3.1 Built-in procedures, 7.3.7 closedir, 7.3.35 opendir, 7.3.43 read,
7.3.48 rewinddir, and 12.19 Extended procedures.

--------------
7.3.45 readln:
--------------
Purpose: Reads a directory (i.e. retrieves the name of the next file in the
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.
Parameters:
   1. The file variable associated with the file to read
      (This parameter may be omitted).
   2. One or more variables to store the data read from the file.
Syntax:

   readln-call = 'readln' readln-parameter-list

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

Example:

For example the sample program "batch.pas" below is a very primitive
batch processor. It reads lines from a text file using "readln" and
send the lines 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.

Platforms: All
Standard Pascal: Yes
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.

See also 4.9.3 readmode, 5.4 File types, 5.11 String types,
5.13 Integral types, 5.14.5 char type, 5.14.15 text type, 6.1 Variables,
6.10.4 input, 7.2.13 eof, 7.2.14 eoln, 7.2.22 getlasterror,
7.2.50 readkey, 7.3.1 Built-in procedures, 7.3.6 close, 7.3.18 flush,
7.3.20 get, 7.3.34 open, 7.3.44 readdir, 7.3.43 read, 7.3.47 reset,
and 7.3.62 writeln.

--------------
7.3.46 rename:
--------------
Purpose: Changes the name of a file.
Parameters:
   1. The file variable associated with the file to rename.
   2. The new name of the file.
Syntax:

   rename-call = 'rename' '(' f ',' name ')'

   f = file-variable

   name = character-expression | string-expression

Example:

   (* This program renames a single file *)
   program rename;
   var
      f : text;

      procedure syntax;
      begin
         writeln('Renames a file');
         writeln('Syntax: ivm rename old new');
         writeln('  renames a file named ''old'' to ''new''');
         exitcode := 1;
        halt
      end;

   begin
      if paramcount <> 2 then
         syntax;
      assign(f, paramstr(1)); //Specify which file you want to rename
      rename(f, paramstr(2))  //Change the name of the file
   end.

Platforms: All
Standard Pascal: No
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.

See also 5.14.9 filename type, 6.3 File variables, 7.2.16 fexpand,
7.2.17 filematch, 7.3.1 Built-in procedures, 7.3.4 assign,
and 12.19 Extended procedures.

-------------
7.3.47 reset:
-------------
Purpose: Opens a file for reading.
Parameters:
   1. The file variable to associate with the open file.
   2. The name of the file to open.
Syntax:

   reset-call = 'reset' '(' f [ ',' name ] ')'

   f = file-variable

   name = character-expression | string-expression

Example:

(*
This program is used to count the number of vowels and the total number of 
characters in the input file.
NOTE: This program makes use of two features of Irie Pascal
1) If the user does not specify a command-line parameter to match the
    program argument 'f' then 'f' is automatically assigned an empty string
    as it's filename.
2) If a file variable has an empty string as it's filename, and it is
   opened with "reset" then the standard input file is the file opened.

The net effect of these two features is that if you run this program and
don't supply a program argument like

   "ivm vowels"

then the program reads from the standad input file. If you run this program
with a program argument like

   "ivm vowels filename"

then the program will open "filename" and read from it.
*)
program vowels(f, output);
var
   f : file of char;
   tot, vow : integer;
   c : char;
begin
   reset(f);  //Open the input file in readmode.
   tot := 0;  //Initialize total number of chars read so far
   vow := 0;  //Initialize total number of vowels read so far
   while not eof(f) do
      begin
         read(f, c);  //Read character
         case c of
            'a', 'e', 'i', 'o', 'u',
            'A', 'E', 'I', 'O', 'U'
               : vow := vow + 1;
            otherwise //include "otherwise" so that non-vowels don't cause errors.
         end;
         tot := tot + 1;
      end;
   writeln('Total characters read = ', tot);
   writeln('Vowels read = ', vow)
end.

Platforms: All
Standard Pascal: Yes
Notes: If the second parameter (i.e. the name of the file to open) is not
       specified then the name that has been assigned to the file varaible
       is used. If no name has been assigned to the file variable (whether
       using "assign" or using a command-line argument) then the standard
       input stream is the file opened.

See also 4.9.3 readmode, 5.2 Array types, 5.4 File types,
5.11 String types, 5.14.9 filename type, 6.3 File variables,
6.10.4 input, 7.2.13 eof, 7.2.22 getlasterror, 7.3.1 Built-in procedures,
7.3.2 append, 7.3.4 assign, 7.3.6 close, 7.3.18 flush, 7.3.34 open,
7.3.49 rewrite, and 10.1 Program parameters.

-----------------
7.3.48 rewinddir:
-----------------
Purpose: Rewinds a directory so that reading from it starts from the         
         first file.
Parameter: The directory variable associated with the open directory
           to rewind.
Syntax:

   rewind-call = 'rewinddir' '(' d ')'

   d = directory-variable

Example: None.
Platforms: All
Standard Pascal: No
Notes:

See also 4.8.16 feature_rewinddir, 5.14.7 dir type,
7.3.1 Built-in procedures, 7.3.7 closedir, 7.3.35 opendir,
7.3.44 readdir, 10.1 Program parameters, and 12.19 Extended procedures.

---------------
7.3.49 rewrite:
---------------
Purpose: Opens a file for writing.
Parameters:
   1. The file variable to associate with the open file.
   2. The name of the file to open.
Syntax:

   rewrite-call = 'rewrite' '(' f [ ',' name ] ')'

   f = file-variable

   name = character-expression | string-expression

Example:

(**************************************************************************
** This program copies characters from the input file to the output file.
**
** Syntax: ivm type [in [out]]
**    where 'in' is the name of the input file. If 'in' is omitted then
**          the standard input stream is used.
**    and  'out' is the name of the output file. If 'out' is omitted then
**         the standard output stream is used.
*)
program typ(f, out);
var
   f, out : text;
   c : char;
begin
   reset(f);            (* Open "in" or the standard input *)
   rewrite(out);        (* Open "out" or the standard output *)
   while not eof(f) do
      if eoln(f) then
         begin
            readln(f);
            writeln(out)
         end
      else
         begin
            read(f, c);
            write(out, c)
         end
end.

Platforms: All
Standard Pascal: Yes
Notes: If the file exists its contents are deleted. If the file does
       not exist it is created.
       If the second parameter (i.e. the name of the file to open) is not
       specified then the name that has been assigned to the file varaible
       is used. If no name has been assigned to the file variable (whether
       using "assign" or using a command-line argument) then the standard
       output stream is the file opened.

See also 4.9.4 writemode, 5.2 Array types, 5.4 File types,
5.11 String types, 5.14.9 filename type, 6.3 File variables,
6.10.5 output, 7.2.13 eof, 7.2.22 getlasterror,
7.3.1 Built-in procedures, 7.3.2 append, 7.3.4 assign, 7.3.6 close,
7.3.18 flush, 7.3.34 open, 7.3.47 reset, and 10.1 Program parameters.

-------------
7.3.50 rmdir:
-------------
Purpose: Removes (deletes) a directory
Parameter: The pathname of the directory to remove.
Syntax:

   rmdir-call = 'rmdir' '(' name ')'

   name = character-expression | string-expression

Example:

//*************************************************
// This program removes (i.e. erases) a directory
// First it asks for the name of the directory
// Then it calls rmdir to remove the directory
//************************************************
program rd(input, output);
var
   fn : filename;
begin
   write('Which directory do you want to delete? ');
   readln(fn);
   rmdir(fn);
end.

Platforms: All
Standard Pascal: No
Notes: Removing a directory is likely to fail if the directory contains
       files.

See also 5.14.7 dir type, 5.14.9 filename type, 7.2.12 dirsep,
7.3.1 Built-in procedures, 7.3.5 chdir, 7.3.31 mkdir,
and 12.19 Extended procedures.

------------
7.3.51 seek:
------------
Purpose: Moves to a specified position in a file.
Parameters:
   1. A file variable associated with an open file.
   2. An integral value indicating the position in the file to move to.
Syntax:
   seek-call = 'seek' '(' f ',' offset ')'

   f = file-variable

   offset = integral-expression

Example: None.
Platforms: All
Standard Pascal: No
Notes: 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 4.9.3 readmode, 5.13 Integral types, 6.3 File variables,
7.2.13 eof, 7.2.14 eoln, 7.2.18 filepos, 7.2.19 filesize,
7.3.1 Built-in procedures, 7.3.18 flush, 7.3.34 open, 7.3.47 reset,
and 12.19 Extended procedures.

-------------------
7.3.52 setfiledate:
-------------------
Purpose: Sets a file's date (i.e. last modification date).
Parameters:
   1. A string/char value that specifies the name of the file.
   2. An integral value that specifies the year part of the new date.
   3. An integral value that specifies the month part of the new date (1-12).
   4. An integral value that specifies the day part of the new date (1-31).
Syntax:

   setfiledate-call = 'setfiledate' '(' fn ',' year ',' mon ',' day ')'

   fn = string-expression | char-expression

   year = integral-expression

   mon = integral-expression

   day = integral-expression

Example: None.
Platforms: All
Standard Pascal: No
Notes: None.

See also 5.2 Array types, 5.11 String types, 5.13 Integral types,
5.14.5 char type, 5.14.9 filename type, 7.3.1 Built-in procedures,
7.3.53 setfiletime, and 12.19 Extended procedures.

-------------------
7.3.53 setfiletime:
-------------------
Purpose: Sets a files time (i.e. last modification time).
Parameters:
   1. A string/char value that specifies the name of the file.
   2. An integral value that specifies the hour (0 to 23)
   3. An integral value that specifies the minute (0 to 59)
   4. An integral value that specifies the second (0 to 61).
Syntax:

   setfiletime-call = 'setfiletime' '(' fn ',' hour ',' min ',' sec ')'

   fn = string-expression | char-expression

   hour = integral-expression

   min = integral-expression

   sec = integral-expression

Example: None
Platforms: All
Standard Pascal: No
Notes: None

See also 5.2 Array types, 5.11 String types, 5.13 Integral types,
5.14.5 char type, 5.14.9 filename type, 7.3.1 Built-in procedures,
7.3.52 setfiledate, and 12.19 Extended procedures.

-------------
7.3.54 sleep:
-------------
Purpose: Pauses execution of the program for a specified number of seconds.
Parameter: An integral value that specifies the number of seconds to pause.
Syntax:

   sleep-call = 'sleep' '(' sec ')'

   sec = integral-expression

Example: sleep(1)   pauses the program for one (1) second.
Platforms: All
Standard Pascal: No
Notes: None

See also 5.13 Integral types, 7.3.1 Built-in procedures, 7.3.11 delay,
and 12.19 Extended procedures.

-----------
7.3.55 str:
-----------
Purpose: Converts an integral or real value into a string and
         assigns the converted string to a string variable.
Parameters:
   1. The integral value to be converted.
or
   1. The real value to be converted.
   2. An integral value that specifies the maximum width of the
         converted string.
   3. An integral value that specifies the number of digits after
         the decimal point.
   4. A string variable that stores the converted string.

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

Examples:

    str(1034, s)         will store   '   1034'   in "s"
    str(1034:1, s)       will store   '1034'      in "s"
    str(1034:5, s)       will store   ' 1034'     in "s"
    str(7893.678, s)     will store   ' 7.89E+03' in "s"
    str(7893.678:8, s)   will store   '7.89E+03'  in "s"
    str(7893.678:8:3, s) will store   '7893.678'  in "s"

Platforms: All
Standard Pascal: No
Notes: If "width" is omitted then eight is assumed for integral conversion
          and nine is assumed for real conversions.
       If the "width" specified is less than the length of the converted
          string then the converted string is stored in "s" as is without
          any extra passing.
       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.
       The string value is padded on the left if necessary.

See also 5.13 Integral types, 5.14.11 real type, 6.9 String variables,
7.3.1 Built-in procedures, 7.3.60 val, 7.3.61 write, 7.3.62 writeln,
and 12.19 Extended procedures.

----------------------
7.3.56 textbackground:
----------------------
Purpose: Sets the current text background color.
Parameter: An integral value that specifies the text background color.
Syntax:

   textbackground-call = 'textbackground' '(' bc ')'

   bc = integral-expression

Example:
//**************************************************************
// This program uses the built-in procedure "textbackground" to
// change the background color. If you are using Windows try
// running this program and see what happens.
//**************************************************************
program bc(output);
(*$W44-*) //Suppress warning message about "constant defined but no used",
          //since we already know we are not using all of the constants.
const
   black = 0;
   blue = 1;
   green = 2;
   cyan = 3;
   red = 4;
   magenta = 5;
   brown = 6;
   white = 7;
   blinking = 8;
(*$W44+*)
begin
   write('Normal background ');
   textbackground(blue + blinking);
   write('Blinking blue background ');
   textbackground(black);
   writeln('Normal background ');
end.

Platforms: Windows only
Standard Pascal: No
Notes:
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

See also 4.8.17 feature_textbackground, 5.13 Integral types,
7.3.1 Built-in procedures, 7.3.57 textcolor,
and 12.19 Extended procedures.

-----------------
7.3.57 textcolor:
-----------------
Purpose: Sets the current text foreground color.
Parameter: An integral value that specifies the text foreground color.
Syntax:

   textcolor-call = 'textbackground' '(' fc ')'

   fc = integral-expression

Example:

//*************************************************************
// This program uses the built-in procedure textcolor to
// set the screen foreground color.
program fc(output);
(*$W44-*)
const
   black = 0;
   blue = 1;
   green = 2;
   cyan = 3;
   red = 4;
   magenta = 5;
   brown = 6;
   white = 7;
   grey = 8;
   light_blue = 9;
   light_green = 10;
   light_cyan = 11;
   light_red = 12;
   light_magenta = 13;
   yellow = 14;
   high_intensity_white = 15;

(*$W44+*)
begin
   textcolor(white);
   write('White text ');
   textcolor(light_green);
   write('Light green text ');
   textcolor(white);
   writeln('White text ');
end.

Platforms: Windows only
Standard Pascal: No
Notes:
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

See also 4.8.18 feature_textcolor, 5.13 Integral types,
7.3.1 Built-in procedures, 7.3.56 textbackground,
and 12.19 Extended procedures.

------------------
7.3.58 traperrors:
------------------
Purpose: Turns automatic error trapping on or off.
Parameter: A boolean value that indicates whether error trapping should
           be turned on or off.
Syntax:

   trapperrors-call = 'traperrors' '(' b ')'

   b = boolean-expression

Example:

The following simple program asks for the name of a file and
then deterines whether the file exists. It determines whether
the file exists by checking whether the file can be opened for
reading. So technically it is really testing whether the file
file exists AND also if the user has read access to the file.
Anyway the built-in procedure "trapperrors" is used to turn off
error trapping before the program attempts to open the
file (this prevents the normal error trapping procedure from aborting
the program if the file can not be opened). Then the built-in procedure
"getlasterror" is called to determine if an error occured. If an error
occured this program just assumes that the file does not exist.

program DoesFileExist(input, output);
var
   n : filename;

   function FileExists(name : filename) : boolean;
   var
      f : text;
   begin
      traperrors(false);
      reset(f, name);
      FileExists := (getlasterror = 0);
      if FileExists then
         close(f);
      traperrors(true)
   end;

begin
   writeln('Enter filename:');
   readln(n);
   n := trim(n);
   writeln('Does ''', n, ''' exist?:', FileExists(n))
end.

Platforms: All
Standard Pascal: No
Notes: When error trapping is on then if a trappable error occurs,
       your program is automatically terminated, and an error message
       is printed on the screen. When error trapping is off then if a
       trappable error occurs, one or more records of type "error" are
       created and added to the built-in list variable "errors". Each
       error record describes the error that occured (some in more
       detail than others). Also the built-in function "getlasterror"
       will return a non-zero value to indicate which error occured.

       If you want to handle trappable error yourself then turn error
       trapping off (with TrapErrors(false)) before executing code that
       may cause an error. Then call "GetLastError" to determine which
       error if any occured. You will probably want to turn error
       trapping back on with TrapErrors(true).

       The (*$I*) compiler directive also turns error trapping off and on,
       however new applications should use "traperrors" instead.
       Use of the (*I*) compiler directive continues to be supported for
       compatibility reasons only.

See also 5.14.3 boolean type, 6.10.2 errors, 7.2.22 getlasterror,
7.3.1 Built-in procedures, and 12.19 Extended procedures.

--------------
7.3.59 unpack:
--------------
Purpose: Copies some or all of the elements of a packed array into
         an unpacked array.
Parameters:
   1. A packed array to copy from.
   2. An expression that specifies the position of the first element
         in the unpacked array to receive elements from the packed
         array.
   3. An unpacked array.
Syntax:

   unpack-call = 'unpack' '(' p ',' u ',' x ')'

   p = packed-array-variable

   x = expression

   u = unpacked-array-variable

Example:

Suppose you have the following arrays

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

then

   unpack(p, u, 1)

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

Platforms: All
Standard Pascal: Yes
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.

See also 5.2 Array types, 7.3.1 Built-in procedures, 7.3.36 pack,
and 9.3.2.1 Assignment compatibility.

-----------
7.3.60 val:
-----------
Purpose: Converts a string value into an integer, word or real value
         and assigns the converted value to a variable.
Parameters:
   1. The string value to convert.
   2. An integer variable that stores the converted integer value.
or
   2. A word variable that stores the converted word value.
or
   2. A real variable that stores the converted real value.
   3. An integer or word variable that stores the position of the
      first character in "s" that could not be converted
      or zero if all characters where converted.
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

   offset = integer variable | word variable

Examples:

Given integer variables "i" and "x" the following:

    val('123EB', i, x)

will store 123 in "i" and 4 in "x".

Give a real variable "r" and an integer variable "x" the following:

   val('123.45', r, x)

will store 123.45 in "r" and 0 in "x".

Platforms: All
Standard Pascal: No
Notes: None.

See also 5.2 Array types, 5.11 String types, 5.14.5 char type,
5.14.10 integer type, 5.14.11 real type, 7.2.28 isdigit,
7.3.1 Built-in procedures, 7.3.55 str, and 12.19 Extended procedures.

-------------
7.3.61 write:
-------------
Purpose: This procedure writes data from one or more variables into a file
Parameters:
   1. The file variable associated with the file to write
      (This parameter may be omitted).
   2. One or more values to write to the file.
Syntax:

   write-call = 'write' write-parameter-list

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

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

Example:

//***************************************************
//This program displays the current system time.
//The built-in procedure "gettime" is used to
// retrieve the current system time.
program time;
type
   TimePeriod = (am, pm);
var
   hour, minute, second : integer;
   period : TimePeriod;

   //This function converts an integer to a string
   // and makes sure the string contains at least
   // two digits.
   function Force2Digits(i : integer) : string;
   var
      s : string;
   begin
      str(i:1, s);
      if i < 10 then
         s := '0' + s;
      Force2Digits := s;
   end;

begin
   gettime(hour, minute, second);
   if hour > 12 then
      begin
         hour := hour - 12;
         period := pm
      end
   else
      period := am;
   write('Time is ');
   write(Force2Digits(hour), ':');
   write(Force2Digits(minute), ':');
   write(Force2Digits(second));
   case period of
   am: writeln(' AM');
   pm: writeln(' PM');
   end;
end.

Platforms: All
Standard Pascal: Yes
Notes: If the first parameter (the file variable) is not specified
       then the standard output stream is the file written to.
       When this procedure writes to a non-text file then the
       binary value of the write parameters are written to the file.
       When this procedure writes to a text file it first attempts to
       convert the write parameters into text data. In addition when
       writing to a text file the write parameters must be of type
       "boolean", "real", "string", "char", or an "integral type".

See also 4.9.2 appendmode, 4.9.4 writemode, 5.2 Array types,
5.4 File types, 5.11 String types, 5.13 Integral types,
5.14.3 boolean type, 5.14.5 char type, 5.14.10 integer type,
5.14.11 real type, 5.14.15 text type, 6.10.5 output,
7.3.1 Built-in procedures, 7.3.2 append, 7.3.6 close, 7.3.18 flush,
7.3.34 open, 7.3.37 page, 7.3.38 popen, 7.3.39 put, 7.3.42 rawwrite,
7.3.43 read, 7.3.49 rewrite, 7.3.52 setfiledate, 7.3.53 setfiletime,
7.3.55 str, and 7.3.62 writeln.

---------------
7.3.62 writeln:
---------------
Purpose: This procedure writes a line of data from one or more variables
         into a text file
Parameters:
   1. The file variable associated with the file to write
      (This parameter may be omitted).
   2. One or more values to write to the file.
Syntax:

   writeln-call = 'writeln' writeln-parameter-list

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

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

Example:

//****************************************************
// This program uses the built-in procedure crc32
//  to calculate the 32-bit CRC for a file.
// Basically the program asks for the name of the file
// and then it reads the file a character at a time
// passing each byte to crc32.
// Finally it calls crc32 4 times with zero to
//  complete the crc calculation. This is part of
//  the process of calculating CRCs.
//****************************************************
program filecrc(input, output);
var
   fn : filename;
   f : file of char;
   c : char;
   crc : integer;
begin
   write('Enter filename: ');
   readln(fn);
   writeln('Calculating CRC...');
   crc := 0;
   reset(f, fn);
   while not eof(f) do
      begin
         read(f, c);
         crc32(crc, c);
      end;

   crc32(crc, 0);
   crc32(crc, 0);
   crc32(crc, 0);
   crc32(crc, 0);

   writeln('CRC for ', fn, ' is ', crc, ' (', hex(crc), ')');
end.

Platforms: All
Standard Pascal: Yes
Notes: If the first parameter (the file variable) is not specified
       then the standard output stream is the file written to.
       This procedure first attempts to convert the write parameters into
       text data. The write parameters must be of type
       "boolean", "real", "string", "char", or an "integral type".

See also 4.9.2 appendmode, 4.9.4 writemode, 5.2 Array types,
5.4 File types, 5.11 String types, 5.13 Integral types,
5.14.3 boolean type, 5.14.5 char type, 5.14.10 integer type,
5.14.11 real type, 5.14.15 text type, 6.10.5 output,
7.3.1 Built-in procedures, 7.3.2 append, 7.3.6 close, 7.3.18 flush,
7.3.34 open, 7.3.37 page, 7.3.38 popen, 7.3.39 put, 7.3.42 rawwrite,
7.3.45 readln, 7.3.49 rewrite, 7.3.52 setfiledate, 7.3.53 setfiletime,
7.3.55 str, and 7.3.61 write.

--------------------------------------
7.4 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, subrange, and 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, object, 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 to successfully call external functions and procedures you may
need to understand a little bit about Irie Pascal types.
Below is a brief description of Irie Pascal types.

First the simple types:
byte - This is an 8 bit unsigned numeric type.
char - This is an 8 bit non-numeric type.
enumerated (including boolean) - 32 bit numeric type.
integer - 32 bit signed numeric type.
real - 64 bit signed numeric type.
word - 32 bit unsigned numeric 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 complex 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 dimensions are ordered
    by C language compilers.
cstring - These are null terminated sequences of characters (the
          same format used by C programs.
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
DWORD, int, long - integer or word
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 DWORD, int and long parameters:
The C types "DWORD", "int", "unsigned int", "long", and "unsigned 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 wish 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 a 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 a cstring by
reference.

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 convention should be used
   (This is the default).
and
   "cdecl" specifies that the cdecl calling convention should be used

See also 2.8.4.2 external, 4.8.2 feature_calldll,
and 7.1 Functions and procedures.

--------------
8 Expressions:
--------------

----------------
8.1 Expressions:
----------------
Expressions describe a sequence of operations to be performed on one
or more operands that result in a single value of a particular type.
The operations to be performed are specified by operators.

The syntax for expressions is given below:

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

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

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

   simple-expression = term { adding-operator term }

   shift-operator = 'shl' | shr'

   term = factor { multiplying-operator factor }

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

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

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

   sign = '+' | '-'

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

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


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

   function-method-call = object-identifier '.' function-identifier [ actual-parameter-list ]

   object-property-access = object-identifier '.' property-reference

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

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

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

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

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

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

   character-code = digit-sequence

   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.

   entire-variable = variable-identifier

   component-variable = indexed-variable | field-designator

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

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

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

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

   omitted-parameter =

   property-reference = property-identifier | '(' property-string ')'

   property-string = string-expression

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

   decimal-whole-number = digit-sequence

   digit-sequence = digit { digit }

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

   hexadecimal-whole-numbers = '$' hex-digit-sequence

   hex-digit-sequence = hex-digit { hex-digit }

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

   binary-whole-numbers = '%' bit-sequence

   bit-sequence = bit { bit }

   bit = '0' | '1'

   fractional-part = digit-sequence

   exponent = 'e' | 'E'

   scale-factor = [ sign ] digit-sequence

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

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

   field-specifier = field-identifier

See also 8.2.1 Operators, 8.3 Compatible Types, 4.1 Constants, 5.1 Types,
and 6.1 Variables.

--------------
8.2 Operators:
--------------

----------------
8.2.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. Operators with the same precedence are performed
left to right. Parantheses can be used to control the order in which
operations are performed by grouping operations that should be
performed first.

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

So for example with the expression below

   2 + 3 - 1

the addition would be performed before the subtraction. This is
because "+" and "-" have the same precedence and so the operations
are performed from left to right.

However since "*" has a higher precedence then with the expression below

   2 + 3 * 1

the multiplication is performed before the addition. Using the same
example above you can force the addition to be performed first by using
parentheses like so:

   (2 + 3) * 1

For more complicated expressions you can use nested parentheses, in
which case the operatings enclosed in the inner-most parentheses
are performed first. So for example given

   2 + (4 - 1) * (4 div (2 + 2))

the first operation performed is 2 + 2 which yields 4, resulting in

   2 + (4 - 1) * (4 div 4)

Now we have two nested parentheses at the same level so which operation
is performed first? Well operations at the same level of precedence are
performed left to right so the (4 - 1) is performed next resulting in

   2 + 3 * (4 div 4)

Next the 4 div 4 is performed resulting in

   2 + 3 * 1

Next the 3 * 1 is performed resulting in

   2 + 3

which results in the integer value 5

See also 8.2.2.1 Arithmetic operators, 8.2.3.1 Equality operators,
8.2.4.1 Relational operators, 8.2.5.1 Boolean operators,
8.2.6.1 String operators, 8.2.7.1 Set operators,
and 8.2.8.1 Bitwise operators.

---------------------------
8.2.2 Arithmetic operators:
---------------------------

-----------------------------
8.2.2.1 Arithmetic operators:
-----------------------------
The arithmetic operators are:

   + - * / div mod

and perform addition, unary plus, subtranction, unary minus,
multiplication, division, and moduls on numeric operands.

See also 8.2.2.2 Addition operator, 8.2.2.3 Subtraction operator,
8.2.2.4 Multiplication operator (real numbers),
8.2.2.5 Division operator (real numbers), 8.2.2.6 div operator,
8.2.2.7 mod operator, and 8.2.1 Operators.

--------------------------
8.2.2.2 Addition operator:
--------------------------
When the + operator has two operands of integral type or "real" type then
it performs 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".

For example:

   0 + 4    results in  4
   1 + 4    results in  5
   2 + 4    results in  6
   -1 + 4   results in  3
   1 + -4   results in -3
   -1 + -4  results in -5
   -4 + 4   results in  0
   4 + -4   results in  0

   -1.0 + 4   results in 3.0
   -1.0 + 4.0 results in 3.0
   4 + 4.5    results in 8.5
   4.0 + 4.5  results in 8.5

When the + operator has one operand of integral type or "real" type then
it performs unary-plus and the result of the operation has the same type
as the operand. NOTE: Unary plus in fact has no effect, the result of
the operation is the value of the operand.

For example:

   +4    results in   4
   +78   results in  78
   +9.8  results in 9.8

See also 5.13 Integral types, 5.14.11 real type,
8.2.2.3 Subtraction operator, 8.2.6.2 Concatenation,
8.2.7.2 Set union operator, and 8.2.2.1 Arithmetic operators.

-----------------------------
8.2.2.3 Subtraction operator:
-----------------------------
When the - operator has two operands of integral type or "real" type then
it performs 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".

For example:

   0 - 4    results in  -4
   1 - 4    results in  -3
   2 - 4    results in  -2
   -1 - 4   results in  -5
   1 - -4   results in 5
   -1 - -4  results in 3
   -4 - 4   results in  -8
   4 - -4   results in  8

   2 - 4.5    results in -2.5
   2.0 - 4.5  results in -2.5
   -4.5 - 2   results in -2.5
   -4.5 - 2.0 results in -2.5

When the - operator has only one operand of integral type or "real" then
it performs unary-minus. The result of this operation has the same type
and magnitude as its operand but the opposite sign.

For example:

  -4      results in -4
  -4.5    results in -4.5
  -(-4)   results in 4
  -(-4.5) results in 4.5

See also 5.13 Integral types, 5.14.11 real type,
8.2.2.2 Addition operator, 8.2.2.1 Arithmetic operators,
and 8.2.7.3 Set difference  operator.

-----------------------------------------------
8.2.2.4 Multiplication operator (real numbers):
-----------------------------------------------
When the * operator has two operands of integral type or "real" type then
it perform 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".

For example

   2 * 2       results in 4
   -2 * -2     results in 4
   -2 * 2      results in -4
   2 * 2.0     results in 4.0
   2.0 * 2.0   results in 4.0
   -2 * 2.0    results in -4.0

See also 5.13 Integral types, 5.14.11 real type,
8.2.2.5 Division operator (real numbers), 8.2.2.1 Arithmetic operators,
and 8.2.7.4 Set intersection operator.

-----------------------------------------
8.2.2.5 Division operator (real numbers):
-----------------------------------------
The / operator takes two operands and performs 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".

For example

    2   /  4    results in   0.5
    2.0 /  4.0  results in   0.5
   -2.0 /  4.0  results in  -0.5
    2.0 / -4.0  results in  -0.5
   -2.0 / -4.0  results in   0.5

See also 5.13 Integral types, 5.14.11 real type,
8.2.2.4 Multiplication operator (real numbers),
8.2.2.1 Arithmetic operators, 8.2.2.6 div operator,
and 8.2.2.7 mod operator.

---------------------
8.2.2.6 div operator:
---------------------
The "div" operator takes two operands and performs integral division. Both
operands must be of integral type. The result of the operation is of
integral type (note: The remainder from the division is discarded).

For example

   0 div 4    results in  0
   1 div 4    results in  0
   2 div 4    results in  0
   3 div 4    results in  0
   4 div 4    results in  1
   7 div 4    results in  1
   8 div 4    results in  2
   -4 div 4   results in -1
   7 div -4   results in -1
   -8 div -4  results in  2

See also 5.13 Integral types, 8.2.2.1 Arithmetic operators,
8.2.2.4 Multiplication operator (real numbers),
8.2.2.5 Division operator (real numbers), and 8.2.2.7 mod operator.

---------------------
8.2.2.7 mod operator:
---------------------
The "mod" operator takes two operands and performs modulus. Both operands
must be of integral type. The result of the operation is of integral type.
The modulus operation is defined by Standard Pascal (ISO/IEC 7185)
as follows:

"A term of the form i mod j shall be an error if j is zero or negative,
otherwise, the value of i mod j shall be that value if (i-(k*j)) for
integral k such that 0 <= i mod j < j".

Irie Pascal implements the "mod" operator according to the definition
given above. What does the definition really mean? Well in the simple
case where the operands are positive then the result of the operation
is the remainder left over after dividing the left operand by the right
operand. This is the most common use of the "mod" operator, but you
should be aware that this does not hold when the left operand is negative.
You also need to be aware that the right operand must be greater than zero.

For example if you run the program below:

   program mods(output);
   var
      i : -3..3;
      j : 1..3;
   begin
      for i := -3 to 3 do
         for j := 1 to 3 do
            writeln(i:1, ' mod ', j:1, ' = ', i mod j : 1);
   end.

you will get the following output

  -3 mod 1 = 0
  -3 mod 2 = 1
  -3 mod 3 = 0
  -2 mod 1 = 0
  -2 mod 2 = 0
  -2 mod 3 = 1
  -1 mod 1 = 0
  -1 mod 2 = 1
  -1 mod 3 = 2
   0 mod 1 = 0
   0 mod 2 = 0
   0 mod 3 = 0
   1 mod 1 = 0
   1 mod 2 = 1
   1 mod 3 = 1
   2 mod 1 = 0
   2 mod 2 = 0
   2 mod 3 = 2
   3 mod 1 = 0
   3 mod 2 = 1
   3 mod 3 = 0

See also 5.13 Integral types, 8.2.2.1 Arithmetic operators,
8.2.2.4 Multiplication operator (real numbers),
8.2.2.5 Division operator (real numbers), and 8.2.2.6 div operator.

-------------------------
8.2.3 Equality operators:
-------------------------

---------------------------
8.2.3.1 Equality operators:
---------------------------
The equality operators are

   = <>

and take two operands which are compared for equality.

See also 8.2.3.2 Is equal operator, 8.2.3.3 Is not equal operator,
and 8.2.1 Operators.

--------------------------
8.2.3.2 Is equal 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.

For example

   23 =   23    results in true
  -23 =  -23    results in true
   23 = 23.0    results in true
 23.0 =   23    results in true
   23 =  -23    results in false
    2 =    3    results in false
    3 =    2    results in false

See also 4.1 Constants, 6.1 Variables, 8.2.3.3 Is not equal operator,
8.2.4.2 Is less than operator, 8.2.4.3 Is less than or equal operator,
8.2.4.4 Is greater than operator,
8.2.4.5 Is greater than or equal operator, 8.2.3.1 Equality operators,
and 8.2.7.5 in operator.

------------------------------
8.2.3.3 Is not equal 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 "false" otherwise.

For example

   23 <>   23    results in false
  -23 <>  -23    results in false
   23 <> 23.0    results in false
 23.0 <>   23    results in false
    2 <>    3    results in true
    3 <>    2    results in true

See also 8.2.3.2 Is equal operator, 8.2.4.2 Is less than operator,
8.2.4.3 Is less than or equal operator, 8.2.4.4 Is greater than operator,
8.2.4.5 Is greater than or equal operator, 8.2.3.1 Equality operators,
and 8.2.7.5 in operator.

---------------------------
8.2.4 Relational operators:
---------------------------

-----------------------------
8.2.4.1 Relational operators:
-----------------------------
The relational operators are:

   < <= > >=

With numeric operands the relational operators compare the values
of the operands.

For operands of string type the relational operators compare
the lexical ordering of the operands.

For operands of "set" types the relational operators (<= and >= only)
test whether one operand is a subset of the other.

See also 8.2.4.2 Is less than operator,
8.2.4.3 Is less than or equal operator, 8.2.4.4 Is greater than operator,
8.2.4.5 Is greater than or equal operator, 8.2.1 Operators,
5.11 String types, and 5.10 Set types.

------------------------------
8.2.4.2 Is less than 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, and "false" otherwise.

For example

   23 <   23    results in false
  -23 <  -23    results in false
   23 < 23.0    results in false
 23.0 <   23    results in false
    2 <    3    results in true
    2 <   -3    results in false
   -2 <   -3    results in false
    3 <    2    results in false
   -3 <    2    results in true
   -3 <   -2    results in true

For operands of string type the < operator compares the lexical ordering
of the operands.

For example:

  "abc" < "abc"  results in false
  "abc" < "abcd" results in true
  "abc" < "ab"   results in false
  "abc" < "abd"  results in true
  "abc" < "aac"  results in false
  "abc" < "b"    results in true

See also 8.2.4.3 Is less than or equal operator,
8.2.4.4 Is greater than operator,
8.2.4.5 Is greater than or equal operator, 8.2.3.2 Is equal operator,
8.2.3.3 Is not equal operator, 4.1 Constants, and 6.1 Variables.

---------------------------------------
8.2.4.3 Is less than or equal operator:
---------------------------------------
When the <= operator has two numeric operands then it compares their
values. 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.

For example:

   23 <=   23    results in true
  -23 <=  -23    results in true
   23 <= 23.0    results in true
 23.0 <=   23    results in true
    2 <=    3    results in true
    2 <=   -3    results in false
   -2 <=   -3    results in false
    3 <=    2    results in false
   -3 <=    2    results in true
   -3 <=   -2    results in true

For operands of string type the <= operator compares the lexical ordering
of the operands.

For example:

  "abc" <= "abc"  results in true
  "abc" <= "abcd" results in true
  "abc" <= "ab"   results in false
  "abc" <= "abd"  results in true
  "abc" <= "aac"  results in false
  "abc" <= "b"    results in true

When the <= operator has two operands of "set" type then it tests
for set inclusion. The result of this operation is "true" if all the
members of the left operand are in the right operand, and "false"
otherwise.

For example:

   ['a', 'b', 'c'] <= ['a']            returns false
   ['a', 'b', 'c'] <= ['a', 'b']       returns false
   ['a', 'b', 'c'] <= ['a', 'b', 'c']  returns true
   ['a']           <= ['a', 'b', 'c']  returns true
   ['a', 'b']      <= ['a', 'b', 'c']  returns true
   []              <= ['a']            return true
   ['a']           <= []               return false

See also 8.2.4.2 Is less than operator, 8.2.4.4 Is greater than operator,
8.2.4.5 Is greater than or equal operator, 8.2.3.2 Is equal operator,
8.2.3.3 Is not equal operator, 4.1 Constants, 6.1 Variables,
5.11 String types, 5.10 Set types, and 8.2.7.5 in operator.

---------------------------------
8.2.4.4 Is greater than 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, and "false" otherwise.

For example

   23 >   23    results in false
  -23 >  -23    results in false
   23 > 23.0    results in false
 23.0 >   23    results in false
    2 >    3    results in false
    2 >   -3    results in true
   -2 >   -3    results in true
    3 >    2    results in true
   -3 >    2    results in false
   -3 >   -2    results in false

For operands of string type the > operator compares the lexical ordering
of the operands.

For example:

  "abc" > "abc"  results in false
  "abc" > "abcd" results in false
  "abc" > "ab"   results in true
  "abc" > "abd"  results in false
  "abc" > "aac"  results in true
  "abc" > "b"    results in false

See also 8.2.4.2 Is less than operator,
8.2.4.3 Is less than or equal operator,
8.2.4.5 Is greater than or equal operator, 8.2.3.2 Is equal operator,
8.2.3.3 Is not equal operator, 4.1 Constants, and 6.1 Variables.

------------------------------------------
8.2.4.5 Is greater than or equal operator:
------------------------------------------
When the >= operator has two numeric operands then it compares their
values. 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.

For example:

   23 >=   23    results in true
  -23 >=  -23    results in true
   23 >= 23.0    results in true
 23.0 >=   23    results in true
    2 >=    3    results in false
    2 >=   -3    results in true
   -2 >=   -3    results in true
    3 >=    2    results in true
   -3 >=    2    results in false
   -3 >=   -2    results in false

For operands of string type the >= operator compares the lexical ordering
of the operands.

For example:

  "abc" >= "abc"  results in true
  "abc" >= "abcd" results in false
  "abc" >= "ab"   results in true
  "abc" >= "abd"  results in false
  "abc" >= "aac"  results in true
  "abc" >= "b"    results in false

When the >= operator has two operands of "set" type then it tests
for set inclusion. The result of this operation is "true" if all the
members of the right operand are in the left operand, and "false"
otherwise.

For example:

   ['a', 'b', 'c'] >= ['a']            returns true
   ['a', 'b', 'c'] >= ['a', 'b']       returns true
   ['a', 'b', 'c'] >= ['a', 'b', 'c']  returns true
   ['a']           >= ['a', 'b', 'c']  returns false
   ['a', 'b']      >= ['a', 'b', 'c']  returns false
   []              >= ['a']            return false
   ['a']           >= []               return true

See also 8.2.4.2 Is less than operator,
8.2.4.3 Is less than or equal operator, 8.2.4.4 Is greater than operator,
8.2.3.2 Is equal operator, 8.2.3.3 Is not equal operator, 4.1 Constants,
6.1 Variables, 5.11 String types, 5.10 Set types,
and 8.2.7.5 in operator.

------------------------
8.2.5 Boolean operators:
------------------------

--------------------------
8.2.5.1 Boolean operators:
--------------------------
The boolean operators are:

   and, and_then, or, or_else, xor, not

and perform AND, OR, XOR (exclusive or), and NOT

See also 8.2.5.2 not operator, 8.2.5.3 and operator,
8.2.5.4 and_then operator, 8.2.5.5 or operator, 8.2.5.6 or_else operator,
8.2.5.7 xor operator, and 8.2.1 Operators.

---------------------
8.2.5.2 not operator:
---------------------
When the "not" operator has one operand of type "boolean" then it
performs boolean NOT. The result of this operation is "true" if the value
of the operand is "false", and the result this operation is "false" if the
value of the operand is "true".

For example

   not true   results in "false"
   not false  results in "true"

See also 5.14.3 boolean type, 8.2.5.7 xor operator,
and 8.2.5.1 Boolean operators.

---------------------
8.2.5.3 and operator:
---------------------
When the "and" operator has operands of type "boolean" then it performs
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 can be
used to enable/disable short-circuit evaluation.

For example

   false and false   results in false
   false and true    results in false
   true  and false   results in false
   true  and true    results in true

See also 5.14.3 boolean type, 8.2.5.4 and_then operator,
8.2.5.5 or operator, and 8.2.5.1 Boolean operators.

--------------------------
8.2.5.4 and_then operator:
--------------------------
As an extension Irie Pascal supports the "and_then" operator, which takes
two boolean operands and performs 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". Short-circuit evaluation is
ALWAYS 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").

For example

   false and_then false   results in false
   false and_then true    results in false
   true  and_then false   results in false
   true  and_then true    results in true

The differences between the "and_then" operator and the "and" operator are:
   1. "and_then" can not be used to perform bitwise AND
   2. short-circuit evaluation is always used when evaluating "and_then"

See also 5.14.3 boolean type, 8.2.5.3 and operator,
8.2.5.6 or_else operator, 8.2.5.1 Boolean operators,
and 12.12 and_then operator.

--------------------
8.2.5.5 or operator:
--------------------
When the "or" operator has operands of type "boolean" then it performs
boolean OR. The result of the operation is of type "boolean" and is equal
to "true" if 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 can be used to enable/disable
short-circuit evaluation.

For example:

   false or false   results in false
   false or true    results in true
   true  or false   results in true
   true  or true    results in true

See also 5.14.3 boolean type, 8.2.5.6 or_else operator,
8.2.5.7 xor operator, 8.2.5.3 and operator,
and 8.2.5.1 Boolean operators.

-------------------------
8.2.5.6 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", and is equal to "true" if either operand
is "true", and "false" if both operands are "false". Short-circuit
evaluation is ALWAYS 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").

For example

   false or_else false   results in false
   false or_else true    results in true
   true  or_else false   results in true
   true  or_else true    results in true

The differences between the "or_else" operator and the "or" operator are:
   1. "or_else" can not be used to perform bitwise OR
   2. short-circuit evaluation is always used when evaluating this operator.

See also 5.14.3 boolean type, 8.2.5.4 and_then operator,
8.2.5.5 or operator, 8.2.5.7 xor operator, 8.2.5.1 Boolean operators,
and 12.13 or_else operator.

---------------------
8.2.5.7 xor operator:
---------------------
As an extension Irie Pascal supports the "xor" operator, which when
used with operands of type "boolean" performs 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", or
both operands are "true".

For example:

   false xor false   results in false
   false xor true    results in true
   true  xor false   results in true
   true  xor true    results in false

See also 5.14.3 boolean type, 8.2.5.5 or operator,
8.2.5.6 or_else operator, 8.2.5.3 and operator,
and 8.2.5.1 Boolean operators.

-----------------------
8.2.6 String operators:
-----------------------

-------------------------
8.2.6.1 String operators:
-------------------------
The only string operator is "+" which performs string concatenation.

See also 8.2.6.2 Concatenation, and 8.2.1 Operators.

----------------------
8.2.6.2 Concatenation:
----------------------
As an extension Irie Pascal supports using the "+" operator to perform
string concatenation. When the "+" operator has two operands of "string"
or "char" types then it performs string concatenation. Any operands of
type "char" are converted to type "string" before being concatenated.

For example:

   'Hello' + ' ' + 'world' + '!!'   results in 'Hello world!!'

See also 5.11 String types, 5.14.5 char type, 8.2.2.2 Addition operator,
8.2.7.2 Set union operator, and 8.2.6.1 String operators.

--------------------
8.2.7 Set operators:
--------------------

----------------------
8.2.7.1 Set operators:
----------------------
The set operators are:

   + - * in

and perform set union, difference, intersection, and membership.

See also 8.2.7.2 Set union operator, 8.2.7.3 Set difference  operator,
8.2.7.4 Set intersection operator, and 8.2.7.5 in operator.

---------------------------
8.2.7.2 Set union operator:
---------------------------
When the "+" operator has operands of type set then it performs set
union (i.e. the result of the operation is a set with all the members
from both operands).

For example:

   ['a', 'e'] + ['a', 'c', 'z'] results in ['a', 'c', 'e', 'z']

To see this try the example program below:

   program setu(output);
   type
      letter = 'a'..'z';
   var
      s : set of letter;
      c : letter;
   begin
      s := ['a', 'e'] + ['a', 'c', 'z'];
      for c := 'a' to 'z' do
         if c in s then
            writeln(c)
   end.

See also 8.2.7.3 Set difference  operator,
8.2.7.4 Set intersection operator, 8.2.7.5 in operator,
8.2.4.3 Is less than or equal operator,
8.2.4.5 Is greater than or equal operator, 8.2.7.1 Set operators,
5.10 Set types, 8.2.2.2 Addition operator, and 8.2.6.2 Concatenation.

---------------------------------
8.2.7.3 Set difference  operator:
---------------------------------
When the "-" operator has operands of type set then it performs set
difference (i.e. the result of the operation is a set with those members
which are in the left operand but not in the right operand).

For example:

   ['a', 'b', 'c', 'd'] - ['a', 'j'] results in ['b', 'b', 'c', 'd']

To see this try the example program below:

   program setd(output);
   type
      letter = 'a'..'z';
   var
      s : set of letter;
      c : letter;
   begin
      s := ['a', 'b', 'c', 'd'] - ['a', 'j'];
      for c := 'a' to 'z' do
         if c in s then
            writeln(c)
   end.

See also 8.2.7.2 Set union operator, 8.2.7.4 Set intersection operator,
8.2.7.5 in operator, 8.2.4.3 Is less than or equal operator,
8.2.4.5 Is greater than or equal operator, 8.2.7.1 Set operators,
5.10 Set types, and 8.2.2.3 Subtraction operator.

----------------------------------
8.2.7.4 Set intersection operator:
----------------------------------
When the "*" operator has operands of type set then it performs set
intersection (i.e. the result of the operation is a set whose members
are those members common to both operands).

For example

   ['a', 'b', 'c', 'd'] * ['a', 'c', 'j', 'z']  results in ['a', 'c']

To see this try the example program below:

   program seti(output);
   type
      letter = 'a'..'z';
   var
      s : set of letter;
      c : letter;
   begin
      s := ['a', 'b', 'c', 'd'] * ['a', 'c', 'j', 'z'];
      for c := 'a' to 'z' do
         if c in s then
            writeln(c)
   end.

See also 8.2.7.2 Set union operator, 8.2.7.3 Set difference  operator,
8.2.7.5 in operator, 8.2.4.3 Is less than or equal operator,
8.2.4.5 Is greater than or equal operator, 8.2.7.1 Set operators,
5.10 Set types, and 8.2.2.4 Multiplication operator (real numbers).

--------------------
8.2.7.5 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.

For example:

   'a'    in  ['a', 'b', 'c']    returns true
   'b'    in  ['a', 'b', 'c']    returns true
   'c'    in  ['a', 'b', 'c']    returns true
   'd'    in  ['a', 'b', 'c']    returns false
   'e'    in  ['a', 'b', 'c']    returns false
   'a'    in  []                 returns false

See also 5.7 Ordinal types, 5.10 Set types, 8.2.7.2 Set union operator,
8.2.7.3 Set difference  operator, 8.2.7.4 Set intersection operator,
8.2.4.3 Is less than or equal operator,
8.2.4.5 Is greater than or equal operator, and 8.2.7.1 Set operators.

------------------------
8.2.8 Bitwise operators:
------------------------

--------------------------
8.2.8.1 Bitwise operators:
--------------------------
The bitwise operators are:

   not and or xor shl shr

and perform bitwise NOT, AND, XOR, shift left, and shift right.

See also 8.2.8.2 not operator (bitwise), 8.2.8.3 and operator (bitwise),
8.2.8.4 or operator (bitwise), 8.2.8.5 xor operator (bitwise),
8.2.8.6 shl operator, 8.2.8.7 shr operator, and 12.14 Bitwise operators.

-------------------------------
8.2.8.2 not operator (bitwise):
-------------------------------
When the "not" operator has one operand of integral type then it
performs bitwise NOT (i.e. the result of the operation is calculated
by flipping all the bits in the operand). NOTE: This use of the
"not" operator is an extension to Standard Pascal.

For example

   not 1      //results in -2
              //Since not 1 = not %00000000000000000000000000000001
              // which results in %11111111111111111111111111111110
              // or -2

See also 8.2.5.2 not operator, 8.2.8.5 xor operator (bitwise),
8.2.8.1 Bitwise operators, and 5.13 Integral types.

-------------------------------
8.2.8.3 and operator (bitwise):
-------------------------------
When the "and" operator has operands of integral type then it
performs bitwise AND. The result of the operation is of integral type,
and has its bits set as follows:
  each bit is one (1) in the result if and only if the bits in the
    corresponding position in both operands are one.
NOTE: This use of the "and" operator is an extension to Standard Pascal.

For example

   %11100 and %10111  results in %10100

NOTE: Binary whole numbers are used in the example above so that you can
clearly see the individual bits in the operands and the result. The
example above could have been written as

   28 and 23   results in  20

which is the same thing but is probably not be as clear.

See also 8.2.8.4 or operator (bitwise), 8.2.5.3 and operator,
8.2.8.1 Bitwise operators, and 5.13 Integral types.

------------------------------
8.2.8.4 or operator (bitwise):
------------------------------
When the "or" operator has operands of integral type then it
performs bitwise OR. The result of the operation is of integral type
and has its bits set as follows:
  each bit is one (1) in the result if and only if one of bits in the
    corresponding position in the operands is one (1).

NOTE: This use of the "or" operator is an extension to Standard Pascal.

For example:

   %11100 or %10111  results in %11111

NOTE: The example uses binary whole numbers so that you can clearly see
the individual bits in the operands and the result. The example above
could have been written as

   28 or 23   results in  31

which is the same thing but it might not be as clear.

See also 8.2.8.3 and operator (bitwise), 8.2.5.5 or operator,
8.2.8.1 Bitwise operators, and 5.13 Integral types.

-------------------------------
8.2.8.5 xor operator (bitwise):
-------------------------------
When the "xor" operator has operands of integral type then it performs
bitwise exclusive or. The result of the operation is of integral type
and has its bits set as follows:
  each bit is one (1) in the result if and only if one of bits in the
    corresponding position in the operands is one (1) but not both.

For example:

   %11100 xor %10111  results in %01011

NOTE: The example uses binary whole numbers so that you can clearly see
the individual bits in the operands and the result. The example above
could have been written as

   28 xor 23   results in  11

which is the same thing but it might not be as clear.

See also 8.2.8.4 or operator (bitwise), 8.2.5.7 xor operator,
8.2.8.1 Bitwise operators, and 5.13 Integral types.

---------------------
8.2.8.6 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 of integral type, and is equal to the value of 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.
NOTE: Bit-shifting left by N bits is the same as multiplying by 2 raised
to the Nth power.

For example:

   %11100 shl 3  results in %11100000

NOTE: The example uses binary whole numbers so that you can clearly see
the individual bits in the operands and the result. The example above
could have been written as

   28 shl 3   results in 224

which is the same thing but it might not be as clear.

See also 8.2.8.7 shr operator,
8.2.2.4 Multiplication operator (real numbers),
8.2.8.1 Bitwise operators, and 5.13 Integral types.

---------------------
8.2.8.7 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 of integral type and is equal to the value of 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.
NOTE: Bit-shifting right by N bits is the same as dividing by 2 raised
to the Nth power.

For example:

   %11100 shr 3  results in %00011

NOTE: The example uses binary whole numbers so that you can clearly see
the individual bits in the operands and the result. The example above
could have been written as

   28 shr 3   results in 3

which is the same thing but it might not be as clear.

See also 8.2.8.6 shl operator, 8.2.2.6 div operator,
8.2.8.1 Bitwise operators, and 5.13 Integral types.

---------------------
8.3 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.

See also 5.1 Types, and 8.1 Expressions.

-------------
9 Statements:
-------------

---------------
9.1 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.

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 |
              procedure-method-call |
              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

See also 3.1 Labels, 9.2 Empty statement, 9.3.1 Assignment statement,
9.4 Procedure statement, 9.5 Goto statement, 9.6 Compound statement,
9.7 If statement, 9.8 Case statement, 9.9 Repeat statement,
9.10 While statement, 9.11 For statement, 9.12 With statement,
and 9.13 Procedure method call.

--------------------
9.2 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 =

See also 9.1 Statements.

-------------------------
9.3 Assignment statement:
-------------------------

---------------------------
9.3.1 Assignment statement:
---------------------------
Assignments statements specify that an expression is to be evaluated and
the result stored in a variable or an object property. The value produced
from evaluating the expression must be assignment compatible with the type
of the variable or property.

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 |
             object-property-access

   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 '@'

   object-property-access = object-identifier '.' property-reference

   property-reference = property-identifier | '(' property-string ')'

   property-string = string-expression

See also 5.6.1 Object types, 6.1 Variables, 8.1 Expressions,
9.1 Statements, and 9.3.2.1 Assignment compatibility.

-------------------------------
9.3.2 Assignment compatibility:
-------------------------------

---------------------------------
9.3.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.

See also 9.3.1 Assignment statement.

-----------------------------------------------------
9.3.2.2 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).

See also 9.3.2.1 Assignment compatibility.

--------------------------------------------------------
9.3.2.3 Assignnment 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).

See also 9.3.2.1 Assignment compatibility.

---------------------------------------------
9.3.2.4 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]".

See also 9.3.2.1 Assignment compatibility.

------------------------------------------------------------
9.3.2.5 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).

See also 9.3.2.1 Assignment compatibility.

--------------------------------------------
9.3.2.6 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".

See also 9.3.2.1 Assignment compatibility.

----------------------------
9.3.2.7 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").

See also 9.3.2.1 Assignment compatibility.

------------------------
9.4 Procedure statement:
------------------------
"Procedure" statements specify that a procedure is to be executed and
that zero, one or more arguments 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.

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 =

   object-property-access = object-identifier '.' property-reference

   property-reference = property-identifier | '(' property-string ')'

   property-string = string-expression

   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 } ')' ]

See also 7.1 Functions and procedures, and 9.1 Statements.

-------------------
9.5 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

See also 3.1 Labels, and 9.1 Statements.

-----------------------
9.6 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 }

See also 9.1 Statements.

-----------------
9.7 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

See also 5.14.3 boolean type, 8.1 Expressions, 9.8 Case statement,
and 9.1 Statements.

-------------------
9.8 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 1024 values
or less 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

See also 4.1 Constants, 5.7 Ordinal types, 8.1 Expressions,
9.7 If statement, 9.1 Statements, and 12.4 Otherwise.

---------------------
9.9 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

See also 5.14.3 boolean type, 8.1 Expressions, 9.5 Goto statement,
9.10 While statement, 9.11 For statement, and 9.1 Statements.

---------------------
9.10 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

See also 5.14.3 boolean type, 8.1 Expressions, 9.5 Goto statement,
9.9 Repeat statement, 9.11 For statement, and 9.1 Statements.

-------------------
9.11 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. "For" statments can count upwards to 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

See also 5.7 Ordinal types, 8.1 Expressions, 9.5 Goto statement,
9.9 Repeat statement, 9.10 While statement, and 9.1 Statements.

--------------------
9.12 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 }

See also 5.9 Record types, and 9.1 Statements.

---------------------------
9.13 Procedure method call:
---------------------------
"Procedure" method calls specify that an object's procedure method is to
be executed and that zero, one or more arguments are to be passed into
the procedure. When procedure methods are executed, program execution is
transferred to the first statement in the procedure method's statement
block. After the execution of a procedure method, program execution resumes
with the statement after the procedure method call.

For example:

Below is an example program that illustrates how to send an email using
the CDONTS.NewMail COM object that is installed with Microsoft IIS.
You can use a similiar program to send email if your webserver uses IIS.
This program also has call to the "Send" procedure method of the
"objMail" object.

   program cdonts;
   const
      NORMAL = 1;
   var
      objMail : object;
      FromAddress, ToAddress : string;
   begin
      write('Enter the from address:');
      readln(FromAddress);
      write('Enter the to address:');
      readln(ToAddress);
      objMail := CreateObject('CDONTS.NewMail');
      objMail.Send(FromAddress, ToAddress, 'Testing...',
                   'This is a test message', NORMAL);
      dispose(objMail);
   end.


The syntax for calling object methods is given below:

   procedure-method-call = object-identifier '.' procedure-identifier [ actual-parameter-list ]

   object-identifier = identifier

   procedure-identifier = identifier

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

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

   object-property-access = object-identifier '.' property-reference

   property-reference = property-identifier | '(' property-string ')'

   property-string = string-expression

   omitted-parameter =

See also 5.6.1 Object types, 7.1 Functions and procedures,
and 9.1 Statements.

----------------------
10 Program Parameters:
----------------------

------------------------
10.1 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".

See also 5.4 File types, 5.11 String types, 6.1 Variables, 6.10.4 input,
6.10.5 output, 7.2.43 paramcount, 7.2.44 paramstr, 7.3.15 exec,
and 12.10 Input and Output automatically declared.

--------------
11 Appendix A:
--------------

-------------------------
11.1 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

   binary-whole-numbers = '%' bit-sequence

   bit-sequence = bit { bit }

   bit = '0' | '1'

   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

   character-code = digit-sequence

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

   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-number |
              character-literal |
              string-literal |
              constant-identifier

   constant-declaration = identifier '=' constant

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

   control-variable = variable-identifier

   decimal-whole-number = digit-sequence

   declarative-part = { declaration }

   declaration =
             label-declaration-group |
             constant-declaration-group |
             type-declaration-group |
             variable-declaration-group |
             function-declaration |
             procedure-declaration

   digit-sequence = digit { digit }

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

   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 =

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

   entire-variable = variable-identifier

   exponent = 'e' | 'E'

   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

   fractional-part = digit-sequence

   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-method-call = object-identifier '.' function-identifier [ actual-parameter-list ]

   function-parameter-specification = function-heading

   goto-statement = 'goto' label

   hexadecimal-whole-numbers = '$' hex-digit-sequence

   hex-digit-sequence = hex-digit { hex-digit }

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

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

   identifier = letter { letter | digit }

   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 } ';'

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

   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 |
                     object-type |
                     string-type

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

   object-identifier = identifier

   object-property-access = object-identifier '.' property-reference

   object-type = 'object' | 'class'

   omitted-parameter =

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

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

   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.

   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-method-call = object-identifier '.' procedure-identifier [ actual-parameter-list ]

   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

   property-identifier = identifier

   property-reference = property-identifier | '(' property-string ')'

   property-string = string-expression

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

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

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

   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

   scale-factor = [ sign ] digit-sequence

   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 = integral-constant

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

   statement-part = compound-statement

   statement-sequence = statement { ';' statement }

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

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

   string-literal = empty-string | other-string

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

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

   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 = whole-number |
                       real-number |
                       character-literal |
                       constant-identifier |
                       'nil'

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

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

   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

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

   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 } ')'

See also 1.2 Grammar notation.

--------------
12 Appendix B:
--------------

-------------------------------------------------------
12.1 Extensions to Pascal as specified by ISO/IEC 7185:
-------------------------------------------------------
Extensions are additions to the Pascal that do not invalidate any
program that would be valid without the extension. The exception to
this rule is that extensions may add new keywords to Pascal which
would invalidate programs that used those keywords as normal identifiers.

Irie Pascal supports a number of extensions to Standard Pascal.
Some of these extensions were added for compatibility with Turbo Pascal
or Extended Pascal, while others are specific to Irie Pascal.

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

--------------------------
12.2 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 for local
declarations 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.

See also 3.1 Labels, 4.1 Constants, 5.1 Types, 6.1 Variables,
7.1 Functions and procedures,
and 12.1 Extensions to Pascal as specified by ISO/IEC 7185.

---------------------
12.3 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.

See also 4 Constants, 5.8 Record, and 9.7 Case Statement.

See also 12.1 Extensions to Pascal as specified by ISO/IEC 7185.

---------------
12.4 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'

See also 5.9 Record types, 9.8 Case statement,
and 12.1 Extensions to Pascal as specified by ISO/IEC 7185.

--------------------------------------
12.5 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.

See also 7.1 Functions and procedures,
and 12.1 Extensions to Pascal as specified by ISO/IEC 7185.

----------------------------------
12.6 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.

See also 3.1 Labels,
and 12.1 Extensions to Pascal as specified by ISO/IEC 7185.

--------------------------------
12.7 Underscores in identifiers:
--------------------------------
Irie Pascal supports identifiers which contain and/or start with
underscores ("_"). So for example the following are valid
identifiers:

   _name
   last_name
   _all_names_

See also 2.8.1 Identifiers,
and 12.1 Extensions to Pascal as specified by ISO/IEC 7185.

-----------------------------------
12.8 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

See also 2.4.4 Binary whole-numbers,
and 12.1 Extensions to Pascal as specified by ISO/IEC 7185.

----------------------------------------
12.9 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.

See also 2.4.3 Hexadecimal whole-numbers,
and 12.1 Extensions to Pascal as specified by ISO/IEC 7185.

----------------------------------------------
12.10 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.

For example the following program:

  program hello;
  begin
     writeln('Hello!!')
  end.

is equivalent to

  program hello(output);
  begin
     writeln('Hello!!')
  end.

See also 6.10.4 input, 6.10.5 output, 10.1 Program parameters,
and 12.1 Extensions to Pascal as specified by ISO/IEC 7185.

-----------------------------
12.11 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'

See also 2.2 Character literals, 2.3 String literals,
and 12.1 Extensions to Pascal as specified by ISO/IEC 7185.

------------------------
12.12 and_then operator:
------------------------
The "and_then" operator is similar to the "and" operator except that
short-circuit evaluation is always used for the "and_then" operator
regardless of the setting of the "sc" compiler option.

See also 8.2.5.4 and_then operator,
and 12.1 Extensions to Pascal as specified by ISO/IEC 7185.

-----------------------
12.13 or_else operator:
-----------------------
The "or_else" operator is similar to the "or" operator except that
short-circuit evaluation is always used for the "or_else" operator
regardless of the setting of the "sc" compiler option.

See also 8.2.5.6 or_else operator,
and 12.1 Extensions to Pascal as specified by ISO/IEC 7185.

------------------------
12.14 Bitwise operators:
------------------------
Irie Pascal defines several operators that manipulate bits.

   not, and, or, xor, shl, shr

See also 8.2.8.1 Bitwise operators,
and 12.1 Extensions to Pascal as specified by ISO/IEC 7185.

-------------------------
12.15 Extended constants:
-------------------------
Irie Pascal defines a number of built-in constants which are
not part of Standard Pascal.

   maxbyte, maxchar, maxword

   Feature Constants:
   feature_calldll, feature_closedir, feature_clrscr,
   feature_delay, feature_gotoxy, feature_idispatch,
   feature_intr, feature_keypressed, feature_mysql,
   feature_odbc, feature_opendir, feature_popen,
   feature_readdir, feature_readkey, feature_rewinddir,
   feature_textbackground, feature_textcolor, feature_wherex,
   feature_wherey

   FileMode Constants:
   appendmode, readmode, writemode

   Permission Constants:
   dir_bit,
   grp_r grp_w, grp_x,
   oth_r, oth_w, oth_x,
   usr_r, usr_w, usr_x

   Platform Constants:
   platform_dos, platform_error, platform_fbsd,
   platform_linux, platform_os2, platform_solaris,
   platform_solaris_sparc, platform_win32

   Recordset Type Constants:
   rsdefault, rsdynamic, rsforward,
   rskeyset, rsstatic

See also 4.2 maxbyte, 4.3 maxchar, 4.5 maxword, 4.8.1 Feature constants,
4.9.1 Filemode constants, 4.10.1 Permission constants,
4.12.1 Recordset type constants,
and 12.1 Extensions to Pascal as specified by ISO/IEC 7185.

---------------------
12.16 Extended types:
---------------------
Irie Pascal defines a number of built-in types which are not part
of Standard Pascal.

   list, class, object, string, binary, byte, dir, error,
   filename, registers, regtype, word, connection, recordset

See also 5.5 List types, 5.6.1 Object types, 5.11 String types,
5.14.2 binary type, 5.14.4 byte type, 5.14.7 dir type, 5.14.8 error type,
5.14.9 filename type, 5.14.13 registers type, 5.14.14 regtype type,
5.14.16 word type, 5.14.6.1 Connection type, 5.14.12.1 Recordset type,
and 12.1 Extensions to Pascal as specified by ISO/IEC 7185.

-------------------------
12.17 Extended variables:
-------------------------
Irie Pascal defines a number of built-in variables which are not part
of Standard Pascal.

   errors        exitcode

See also 6.10.2 errors, 6.10.3 exitcode,
and 12.1 Extensions to Pascal as specified by ISO/IEC 7185.

-------------------------
12.18 Extended functions:
-------------------------
Irie Pascal defines a number of built-in functions which are not part
of Standard Pascal.

   concat, copy, copyword, cosh, countwords, createobject,
   dirsep, fexpand, filematch, filepos, filesize, frac,
   getenv, getlasterror, hex, int, ioresult, isalpha,
   isalphanum, isdigit, islower, isnull, isprint, isspace,
   isupper, isxdigit, keypressed, length, log, locase,
   lowercase, paramcount, paramstr, pi, platform, pos,
   random, readkey, reverse, sinh, supported, swap, system,
   tanh, trim, unixplatform, upcase, uppercase, urldecode,
   version, wherex, wherey

See also 7.2.5 concat, 7.2.6 copy, 7.2.7 copyword, 7.2.9 cosh,
7.2.10 countwords, 7.2.11 createobject, 7.2.12 dirsep, 7.2.16 fexpand,
7.2.17 filematch, 7.2.18 filepos, 7.2.19 filesize, 7.2.20 frac,
7.2.21 getenv, 7.2.22 getlasterror, 7.2.23 hex, 7.2.24 int,
7.2.25 ioresult, 7.2.26 isalpha, 7.2.27 isalphanum, 7.2.28 isdigit,
7.2.29 islower, 7.2.30 isnull, 7.2.31 isprint, 7.2.32 isspace,
7.2.33 isupper, 7.2.34 isxdigit, 7.2.35 keypressed, 7.2.36 length,
7.2.38 log, 7.2.39 locase, 7.2.40 lowercase, 7.2.43 paramcount,
7.2.44 paramstr, 7.2.45 pi, 7.2.46 platform, 7.2.47 pos, 7.2.49 random,
7.2.50 readkey, 7.2.51 reverse, 7.2.54 sinh, 7.2.58 supported,
7.2.59 swap, 7.2.60 system, 7.2.62 tanh, 7.2.63 trim,
7.2.65 unixplatform, 7.2.66 upcase, 7.2.67 uppercase, 7.2.68 urldecode,
7.2.69 version, 7.2.70 wherex, 7.2.71 wherey,
and 12.1 Extensions to Pascal as specified by ISO/IEC 7185.

--------------------------
12.19 Extended procedures:
--------------------------
Irie Pascal defines a number of built-in procedures which are not part
of Standard Pascal.

   append, assert, assign, chdir, close, closedir,
   clrscr, crc32, dec, delay, delete, erase, exec,
   exit, fill, flush, fsplit, getdate, getfiledate,
   getfilemode, getfiletime, gettime, halt, inc,
   insert, intr, mkdir, msdos, open, opendir, popen,
   randomize, rawread, rawwrite, readdir, rename,
   rewinddir, rmdir, seek, setfiledate, setfiletime,
   sleep, str, textbackground, textcolor, traperrors,
   val

See also 7.3.2 append, 7.3.3 assert, 7.3.4 assign, 7.3.5 chdir,
7.3.6 close, 7.3.7 closedir, 7.3.8 clrscr, 7.3.9 crc32, 7.3.11 delay,
7.3.12 delete, 7.3.14 erase, 7.3.15 exec, 7.3.16 exit, 7.3.17 fill,
7.3.18 flush, 7.3.19 fsplit, 7.3.21 getdate, 7.3.22 getfiledate,
7.3.23 getfilemode, 7.3.24 getfiletime, 7.3.25 gettime, 7.3.27 halt,
7.3.28 inc, 7.3.29 insert, 7.3.30 intr, 7.3.31 mkdir, 7.3.32 msdos,
7.3.34 open, 7.3.35 opendir, 7.3.38 popen, 7.3.40 randomize,
7.3.41 rawread, 7.3.42 rawwrite, 7.3.44 readdir, 7.3.46 rename,
7.3.48 rewinddir, 7.3.50 rmdir, 7.3.51 seek, 7.3.52 setfiledate,
7.3.53 setfiletime, 7.3.54 sleep, 7.3.55 str, 7.3.56 textbackground,
7.3.57 textcolor, 7.3.58 traperrors, 7.3.60 val,
and 12.1 Extensions to Pascal as specified by ISO/IEC 7185.

