Copyright (c) 1998, 1999 Stuart King. All rights reserved. Welcome to the Irie Pascal Programmer's Reference Manual ----------------- Table Of Contents ----------------- 1 Introduction 1.1 Grammar Notation 2 Lexical Elements 2.1 Character Literals 2.2 String Literals 2.3 Integers 2.3.1 Decimal Integers 2.3.2 Hexadecimal Integers 2.3.3 Binary Integers 2.4 Reals 2.5 Special Symbols 2.6 Reserved Words 2.7 Identifiers 2.7.1 Directives 2.7.2 Built-in Identifiers 2.7.3 User Defined Identifiers 2.8 Comments 3 Labels 4 Constants 4.1 Boolean 4.2 MaxChar 4.3 MaxInt 4.4 Nil 4.5 Permission 4.6 Platform 4.7 FileMode 4.8 dir_bit 5 Types 5.1 Enumerated Types 5.2 Subrange Types 5.3 Pointer Types 5.4 Array Types 5.5 String Types 5.6 Record Types 5.7 Set Types 5.8 File Types 5.9 List Types 5.10 Type Identifiers 5.10.1 boolean 5.10.2 char 5.10.3 dir 5.10.4 filename 5.10.5 integer 5.10.6 real 5.10.7 text 6 Variables 6.1 Pointer Variables 6.2 Array Variables 6.3 String Variables 6.4 Record Variables 6.5 List Variables 7 Functions And Procedures 7.1 Built-in Functions 7.1.1 abs 7.1.2 arctan 7.1.3 chr 7.1.4 concat 7.1.5 copy 7.1.6 cos 7.1.7 cosh 7.1.8 eof 7.1.9 eoln 7.1.10 exp 7.1.11 fexpand 7.1.12 filepos 7.1.13 filesize 7.1.14 frac 7.1.15 getenv 7.1.16 hex 7.1.17 int 7.1.18 ioresult 7.1.19 isalpha 7.1.20 isalphanum 7.1.21 isdigit 7.1.22 islower 7.1.23 isprint 7.1.24 isspace 7.1.25 isupper 7.1.26 isxdigit 7.1.27 length 7.1.28 ln 7.1.29 log 7.1.30 locase 7.1.31 lowercase 7.1.32 odd 7.1.33 ord 7.1.34 paramcount 7.1.35 paramstr 7.1.36 pi 7.1.37 platform 7.1.38 pos 7.1.39 pred 7.1.40 random 7.1.41 reverse 7.1.42 round 7.1.43 sin 7.1.44 sinh 7.1.45 sqr 7.1.46 sqrt 7.1.47 succ 7.1.48 swap 7.1.49 system 7.1.50 tan 7.1.51 tanh 7.1.52 trim 7.1.53 trunc 7.1.54 upcase 7.1.55 uppercase 7.2 Built-in Procedures 7.2.1 append 7.2.2 assert 7.2.3 assign 7.2.4 chdir 7.2.5 close 7.2.6 closedir 7.2.7 dec 7.2.8 delete 7.2.9 dispose 7.2.10 erase 7.2.11 exec 7.2.12 exit 7.2.13 flush 7.2.14 fsplit 7.2.15 get 7.2.16 getdate 7.2.17 getfiledate 7.2.18 getfilemode 7.2.19 getfiletime 7.2.20 gettime 7.2.21 halt 7.2.22 inc 7.2.23 insert 7.2.24 mkdir 7.2.25 new 7.2.26 open 7.2.27 opendir 7.2.28 pack 7.2.29 page 7.2.30 put 7.2.31 randomize 7.2.32 rawread 7.2.33 rawwrite 7.2.34 read 7.2.35 readdir 7.2.36 readln 7.2.37 rename 7.2.38 reset 7.2.39 rewinddir 7.2.40 rewrite 7.2.41 rmdir 7.2.42 seek 7.2.43 setfiledate 7.2.44 setfiletime 7.2.45 sleep 7.2.46 str 7.2.47 unpack 7.2.48 val 7.2.49 write 7.2.50 writeln 8 Expressions 8.1 Operators 8.1.1 Not Operator 8.1.2 * Operator 8.1.3 / Operator 8.1.4 Div Operator 8.1.5 Mod Operator 8.1.6 And Operator 8.1.7 And_Then Operator 8.1.8 + Operator 8.1.9 - Operator 8.1.10 Or Operator 8.1.11 Or_Else Operator 8.1.12 Xor Operator 8.1.13 shl Operator 8.1.14 shr Operator 8.1.15 = Operator 8.1.16 <> Operator 8.1.17 < Operator 8.1.18 <= Operator 8.1.19 > Operator 8.1.20 >= Operator 8.1.21 In Operator 8.2 Compatible types 9 Statements 9.1 Empty Statement 9.2 Assignment Statement 9.2.1 Assignment Compatibility 9.2.1.1 Assignment compatibility with array indexing 9.2.1.2 Assignment compatibility with value parameters 9.2.1.3 Assignment compatibility with "read" 9.2.1.4 Assignment compatibility with assignment statements 9.2.1.5 Assignment compatibility with "for" 9.2.1.6 Transfer procedures 9.3 Procedure Statement 9.4 Goto Statement 9.5 Compound Statement 9.6 If Statement 9.7 Case Statement 9.8 Repeat Statement 9.9 While Statement 9.10 For Statement 9.11 With Statement 10 Program parameters Appendix A. Irie Pascal Grammar Appendix B. Extensions to Pascal as specified by ISO/IEC 7185 B.1 Relaxed declarations B.2 Constant ranges B.3 Otherwise B.4 Relaxed parameter list congruity B.5 Non-numeric statement labels B.6 Underscores in identifiers B.7 Binary integer constants B.8 Hexadecimal integer constants B.9 Input and Output automatically declared B.10 Double-quoted literals B.11 and_then operator B.12 or_else operator B.13 Bitwise operators B.13.1 shl operator B.13.2 shr operator B.13.3 and (Bitwise) operator B.13.4 or (Bitwise) operator B.13.5 not (Bitwise) operator B.13.6 xor (Bitwise) operator B.14 Extended constants B.14.1 maxchar B.14.2 usr_r B.14.3 usr_w B.14.4 usr_x B.14.5 grp_r B.14.6 grp_w B.14.7 grp_x B.14.8 oth_r B.14.9 oth_w B.14.10 oth_x B.14.11 dir_bit B.14.12 platform_dos B.14.13 platform_os2 B.14.14 platform_win32 B.14.15 platform_linux B.14.16 platform_fbsd B.14.17 platform_error B.14.18 appendmode B.14.19 readmode B.14.20 writemode B.15 Extended types B.15.1 dir B.15.2 filename B.15.3 list B.15.4 string B.16 Extended variables B.16.1 exitcode ---------------- 1 Introduction ---------------- This is the Irie Pascal Programmer's Reference Manual, and describes the Irie Pascal language. This manual is not a tutorial and does not attempt to teach programming. If you are new to programming or new to Pascal you may need additional information. Fortunately there are many excellent books which teach programming in Pascal. If you decide to purchase a Pascal book, you should look for one that covers Standard Pascal. For information on how to install and use Irie Pascal, see the Irie Pascal User's Manual which should accompany this manual. -------------------- 1.1 Grammar Notation -------------------- Context-free grammars are often used to define the syntax of programming languages because they produce short and precise definitions. A context-free grammar breaks the syntax of a complex language into a number of simpler elements called non-terminal symbols. The syntax of each non-terminal symbol is defined by a production. Each production consists of a non-terminal symbol followed by some sort of assignment operator, and then followed by a sequence of special symbols, terminal symbols and non-terminal symbols. The special symbols are used to describe how the other symbols can be combined. The terminals symbols are literal text that can occur in the language being defined. The full context-free grammar takes the form of a sequence of productions for all the non-terminal symbols in the language. The context-free grammar used in this manual has the following notation. The equal sign is used as the assignment operator in productions to separate the non-terminal symbol being defined from it's definition. The special symbols are |, {}, [], and (). The | symbol is used to separate alternatives (i.e. the grammar allows either the symbols on it's left-hand side or the symbols on it's right-hand side). The {} symbols are used to enclose symbols that can be repeated zero, one, or more times. The [] symbols are used to enclose optional symbols (i.e. the grammar allows the enclosed symbols to either occur once or not occur at all). The () symbols are used to group symbols that are evaluated together. The terminal symbols are enclosed in single quotes ('') to distinguish them For example here are the productions that define the syntax for identifiers. identifier = letter { letter | digit } letter = 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j' | 'k' | 'l' | 'm' | 'n' | 'o' | 'p' | 'q' | 'r' | 's' | 't' | 'u' | 'v' | 'w' | 'x' | 'y' | 'z' | 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M' | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z' | '_' digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' The productions mean: An identifier is a letter followed by zero or more letter or digits. A letter is a lower-case letter or an upper-case letter or an underscore. A digit is one of the decimal numerals. The complete grammar for Irie Pascal is given in Appendix A. -------------------- 2 Lexical Elements -------------------- This chapter describes the elements that make up programs. ---------------------- 2.1 Character Literals ---------------------- A character literal is a character enclosed in single quotes (') or as an extension in double quotes ("). Two single quotes together can be used to represent single quotes in character literals enclosed in single quotes. Two double quotes together can be used to represent double quotes in character literals enclosed in double quotes. So "'" and '''' are both character literals containing single quotes. And """" and '"' are both character literals containing double quotes. Character literals are case-sensitive so 'X' is not equal to 'x'. The syntax for character literals is as follows character-literal = ''' string-element-one ''' | '"' string-element-two '"' string-element-one = '''' | printable-character string-element-two = '""' | printable-character printable-character = any character (including a space) that has a visual representation. NOTE: The production for printable-character doesn't follow the usual notation because 1) its tedious to write out every possible printable character and 2) the definition for a printable character depends on the character set being used. Here are some examples of valid character literals: 'A' '+' ' ' '''' '"' "A" "+" " " "'" """" ------------------- 2.2 String Literals ------------------- A string literal is a sequences of zero, two or more characters enclosed in single quotes (') or as an extension in double quotes. Literals with one character are character literals not string literals. Two single quotes together can be used to represent single quotes in string literals enclosed in single quotes. Two double quotes together can be used to represent double quotes in string literals enclosed in double quotes. So "Don't" and 'Don''t' are both string literals containing Don't. String literals are case-sensitive, so 'Hello' is not equal to 'HELLO'. There is no explicit limit on the length of string literals but since string literals can not span more than one line, then the limit on the length of a line (400) implicitly limits the length of string literals. The syntax for string literals is as follows string-literal = empty-string | other-string empty-string = '''' | '""' other-string = ''' string-element-one string-element-one {string-element-one ''' | '"' string-element-two string-element-two {string-element-two '"' string-element-one = '''' | printable-character string-element-two = '""' | printable-character printable-character = any character (including a space) that has a visual representation. NOTE: The production for printable-character doesn't follow the usual notation because 1) its tedious to write out every possible printable character and 2) the definition for a printable character depends on the character set being used. Here are some examples of valid string literals: '' ' ' 'Don''t' 'Say "Hello"' '!@#$%^&*()' "" " " "Don't" "Say ""Hello""" "!@#$%^&*()" ------------ 2.3 Integers ------------ Integers are whole numbers (i.e. numbers with no fractional part). Leading zeroes are not significant in integers. The syntax for integers is integer = decimal-integer | hexadecimal-integer | binary-integer Irie Pascal supports integers with values between -2147483647 and +2147483647 ---------------------- 2.3.1 Decimal Integers ---------------------- A decimal integer is a base 10 whole number. The syntax for decimal integers is as follows: decimal-integer = [sign] digit { digit } sign = [ '+' | '-' ] digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' Here are some examples of valid decimal integers 100 -0 +7453 000005 -------------------------- 2.3.2 Hexadecimal Integers -------------------------- As an extension Irie Pascal supports hexadecimal (base 16) integers. The syntax for hexadecimal integers is as follows: hexadecimal-integer = [sign] '$' hex-digit { hex-digit } sign = [ '+' | '-' ] digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' hexdigit = digit | 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'A' | 'B' | 'C' | 'D' | 'E' | 'F' Here are some examples of valid hexadecimal integers $64 -$0 +$FF -$000ab4 --------------------- 2.3.3 Binary Integers --------------------- As an extension Irie Pascal supports binary (base 2) integers. The syntax for binary integers is as follows: binary-integer = [sign] '%' bit { bit } sign = [ '+' | '-' ] bit = '0' | '1' Here are some examples of valid binary integers %01100110 -%0 +%11111111 --------- 2.4 Reals --------- Reals are numbers with fractional parts. Leading zeroes are not significant in reals. The syntax for reals is as follows real = [sign] unsigned-real sign = [ '+' | '-' ] unsigned-real = digit-sequence '.' fractional-part [ exponent scale-factor ] | digit-sequence exponent scale-factor digit-sequence = digit { digit } fractional-part = digit-sequence exponent = 'e' | 'E' scale-factor = [ sign ] | digit-sequence Here are some examples of real numbers: -1.23456e2 which is equal to -123.456 -1.23456e02 which is also equal to -123.456 009863434455e-07 which is equal to 986.3434455 7e-1 which is equal to 0.7 Irie Pascal supports reals with values between about 1e308 and about -1e308 ------------------- 2.5 Special Symbols ------------------- Special symbols have special meanings to the compiler. The syntax for special symbols is given below: special-symbol = '+' | '-' | '*' | '/' | '=' | '<>' | '<' | '<=' | '>' | '>=' | '(' | ')' | '[' | ']' | '(.' | '.)' | ':=' | '.' | ',' | ';' | '..' | '^' | '@' ------------------ 2.6 Reserved Words ------------------ Keywords have pre-defined and fixed meanings to the compiler. The case of keywords is usually not significant so although the syntax below uses all lowercase letters for keywords the compiler will by default recognize keywords regardless of the case of the letters. NOTE: There is a compiler option (-p) that will make identifiers and keywords case-sensitive. The syntax for keywords is given below: keywords := 'and' | 'and_then' | 'array' | 'begin' | 'case' | 'const' | 'div' | 'do' | 'downto' | 'else' | 'end' | 'file' | 'for' | 'function' | 'goto' | 'if' | 'in' | 'label' | 'list' 'mod' | 'nil' | 'not' | 'of' | 'or' | 'or_else' | 'otherwise' | 'packed' | 'procedure' | 'program' | 'record' | 'repeat' | 'set' | 'shl' | 'shr' | 'then' | 'to' | 'type' | 'until' | 'var' | 'while' | 'with' | 'xor' Attempts to declare an identifier with the same name as a keyword will be rejected by the compiler. --------------- 2.7 Identifiers --------------- Identifiers are sequences of letters and digits that start with a letter. As an extension, Irie Pascal also supports identifiers that contain and/or start with underscores (_). By default identifiers are not case-sensitive so x and X are normally considered to be the same identifier. NOTE: There is a compiler option (-p) that will make keywords and identifiers case-sensitive. Some programmers prefer case-sensitive languages since these consider identifiers that differ only in case to be different identifiers. This is often used to allow strongly related identifiers to have the same "spelling" (i.e. differ only in case). For example consider the code fragment below. type STUDENT = record name : string; address : string; grade : integer; end; var student : STUDENT; The use of the same "spelling" for the variable "student" and it's type "STUDENT" emphasize the connection between the two. You should use this compiler option with caution (or not at all) since this feature of Irie Pascal is not supported by many (if any) other Pascal compilers. The syntax for identifiers is given below: identifier = letter { letter | digit } letter = 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j' | 'k' | 'l' | 'm' | 'n' | 'o' | 'p' | 'q' | 'r' | 's' | 't' | 'u' | 'v' | 'w' | 'x' | 'y' | 'z' | 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M' | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z' | '_' digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' ----------------- 2.7.1 Directives ----------------- Directives are special identifiers that can be used to give the compiler extra information about a declaration. The compiler recognizes directives only at specific points in a declaration, and this recognition is not affected by and does not affect, any meaning the directive's identifier may have outside of these specific points. So for example the "forward" directive is recognized even if the identifier "forward" has been declared to have some other meaning, and the use of the "forward" directive does not affect any meaning that "forward" has been declared to have. NOTE: Irie Pascal currently supports only the "forward" directive (see "7 Functions and Procedures" for more information). --------------------------- 2.7.2 Built-in Identifiers --------------------------- Built-in identifiers are automatically declared by the compiler. Unlike keywords, you can declare identifiers with the same name as built-in identifiers, if you do then your declaration will override the declaration made by the compiler. So for example the following declaration type boolean = (no, yes); will override the declaration given by the compiler type boolean = (false, true); Some built-in identifiers are extensions and are therefore only declared when extensions are enabled. ------------------------------- 2.7.3 User Defined Identifiers ------------------------------- User defined identifiers are created and bound to program entities using declarations. You can then reference the entities using the identifiers. Identifiers can be bound to the following kinds of entities: Labels, Constants, Types, Variables, Procedures, and Functions. ------------ 2.8 Comments ------------ Comments are sequences of characters enclosed in { or (* and } or *) Comments are treated like spaces by the compiler and therefore have no effect on your program except possible to separate identifiers (e.g. the compiler treats i(* comment *)j like two separate identifiers i j and not a single identifier ij). By default comments can not be nested (i.e. by default comments can not contain other comments). So comments like (* outer (* inner comment *) comment *) will be terminated at the first close comment marker, like below (* outer (* inner comment *) the last part comment *) will not be treated as part of the comment and will cause a syntax error. There is a compiler option (-nc) that causes the compiler to support nested comments. When this compiler option is enabled the compiler recognizes the end of comments only when the number of close comment markers matches the number of open comment markers. So the example comment above will terminate only after the second *). Both open comment markers (* and { are considered to be equivalent, and both close comment markers *) and } are considered to be equivalent. So attempting to trick the compiler into accepting nested comments with something like (* outer { inner comment } comment *) will not work. Nested comments are disabled by default since in Standard Pascal comments do not nest. ---------- 3 Labels ---------- Labels are markers which you can place in front of statements so that the statements can be referenced by "goto" statements. Labels can be digit sequences or as an extension identifiers. Leading zeroes are not significant in labels which are digit sequences, so "009" and "9" are the same label. Labels must be declared (in a label declaration group) before they can be used. The syntax for label declaration groups is given below: label-declaration-group = 'label' label { ',' label } ';' label = digit-sequence | identifier ------------- 4 Constants ------------- Constants can be character literals, string literals, integers, reals, or constant identifiers. Character and string literals, integers, and reals have already been described in previous sections (See "2.1 Character Literals", "2.2 String Literals", "2.3 Integers", and "2.4 Reals"). Constant identifiers are identifiers that have been bound to a constant using a constant declaration. Constant declarations must be placed in constant declaration groups. The syntax for constant declaration groups is given below: constant-declaration-group = 'const' constant-declaration ';' { constant-declaration ';' } constant-declaration = identifier '=' constant constant = integer | real | character-literal | string-literal | constant-identifier Here is an example of a constant definition group: const Space = ' '; message = 'Hello'; first = 1; last = 10; DaysInYear = 365.25; minint = -maxint; ----------- 4.1 Boolean ----------- Irie Pascal supports two built-in enumerated constants "false" and "true" which are associated with the built-in type "boolean". The ordinal value of "false" is zero and the ordinal value of "true" is one. ----------- 4.2 MaxChar ----------- As an extension Irie Pascal supports the built-in character constant "maxchar" which is equal to the largest character value supported by Irie Pascal. ---------- 4.3 MaxInt ---------- Irie Pascal supports the built-in integer constant "maxint" which is equal to the largest supported integer value. ------- 4.4 Nil ------- Irie Pascal supports a built-in constant "nil" associated with all pointer types, this constant can be assigned to any pointer variable to indicate that the variable doesn't point anywhere. Any pointer variable can also be compared with "nil". -------------- 4.5 Permission -------------- As an extension Irie Pascal supports nine built-in integer constants which can be used with the built-in procedures "mkdir" and "getfilemode" to specify or identify read, write, and execute permissions. Three constants "usr_r", "usr_w", and "usr_x" specify or identify user read, write, and execute permissions respectively (i.e. permissions associated with the file or directories owner). Three constants "grp_r", "grp_w", and "grp_x" specify or identify group read, write, and execute permissions respectively (i.e. permissions associated with users belonging to the file or directories owner's group). Three constants "oth_r", "oth_w", and "oth_x" specify or identify other read, write, and execute permissions respectively (i.e. permissions associated with users who do not belong to the file or directory owner's group). ------------ 4.6 Platform ------------ As an extension Irie Pascal supports four integer constants "platform_dos", "platform_os2", "platform_win32", and "platform_linux" which can be compared with the value returned by the built-in function "platform" to determine the platform your program is running on. ------------ 4.7 FileMode ------------ As an extension Irie Pascal supports three integer constants "readmode", "writemode", and "appendmode" which can be used with the built-in "open" procedure to specify the mode the file should be opened in. See also "7.2.26 open". ----------- 4.8 dir_bit ----------- As an extension Irie Pascal supports the integer constant "dir_bit", which can be AND'd with "mode" returned by "getfilemode" to determine if a file is a directory. --------- 5 Types --------- Types specify sets of valid values, and every constant, variable and function return value is associated with a specific type. Most types must be defined before they can be used, the exceptions to this rule are pointer types. Pointer types are allowed to be used before they are defined to allow self-referencing structures (such as linked lists) to be built. Irie Pascal supports the following types: enumerated types, subrange types, pointer types, array types, string types, record types, set types, file types, list types, type-identifiers Type identifiers are identifiers that have been bound to a type using a type declaration. Type declarations must be placed in type declaration groups. The syntax for type declaration groups is given below: type-declaration-group = 'type' identifier '=' type-declaration ';' { type-declaration ';' } type-declaration = identifier '=' type-denoter type-denoter = type-identifier | new-type type-identifier = identifier new-type = new-ordinal-type | new-structured-type | new-pointer-type new-ordinal-type = enumerated-type | subrange-type new-structured-type = [ 'packed' ] array-type | [ 'packed' ] record-type | [ 'packed' ] set-type | [ 'packed' ] file-type | [ 'packed' ] list-type | string-type new-pointer-type = '^' domain-type | '@' domain-type domain-type = type-identifier Here is an example of a type declaration group: type symbols = record name : string; value : integer; end; SymbolTable = list of symbols; color = (red, green, blue); cardinal = 0..maxint; IntegerList = array[1..100] of integer; characters = set of char; -------------------- 5.1 Enumerated Types -------------------- Enumerated types specify a finite set of ordered values. Each of these ordered values is associated with an identifier (a enumerated constant) and has integer type. The syntax for enumerated types is given below: enumerated-type = '(' identifier-list ')' identifier-list = identifier { ',' identifier } Here are some examples of enumerated types (red, blue, green) (low, medium, high) (married, divorced, widowed, single) ------------------ 5.2 Subrange Types ------------------ Subrange types specify a contiguous subset of an ordinal type. This ordinal type is known as the host type and the values of a subrange type have the same type as it's host type. The syntax for subrange types is give below: subrange-type = constant '..' constant Here are some examples of subrange types: -100..+100 true..true 'a'..'z' ----------------- 5.3 Pointer Types ----------------- Pointer types specify the special value "nil" and a set of values identifying variables associated with them. The built-in procedure "new" creates a pointer variable and associates it with the variables type. The built-in procedure "dispose" destroys a pointer variable and disassociates it from the variables type. The syntax for pointer types is given below: pointer-type = '^' domain-type | '@' domain-type domain-type = type-identifier Here are some examples of pointer types: ^integer ^real --------------- 5.4 Array Types --------------- Array types specify collections of values of the same type (called the array's component type) and associates an index type with the collections. Each member of an array's collection is called an array element and is identified by a value of the array's index type. An array's component type may itself be an array, and the component type of the component type may also be an array. It is sometimes easier to think about an array of arrays as a multi-dimensional array (i.e. an array specifying a collection with an axis for each array component, where each element is identified by values from each component arrays index type). Packed arrays of char having a lower bound of one and an upper bound of two or greater are fixed length strings and have special properties. Normally values of array types can be tested for equality and inequality but can not be tested to see whether one is less than the other. Fixed length strings can be tested not only for equality and inequality but also can be tested to see whether one is less than the other. Fixed length strings unlike other arrays can also be read from and written to text files as a unit using the built-in procedures "read", "readln", "write", and "writeln". The syntax for array types is given below array-type = 'array' '[' index-type-list ']' 'of' component-type index-type-list = index-type { ',' index-type } index-type = ordinal-type ordinal-type = enumerated-type | subrange-type | ordinal-type-identifier component-type = type-denoter Here are some examples of array types: array[1..10] of real array[char] of boolean array[-456..-450] of integer NOTE: As a shorthand notation a multi-dimensional array type can be created by listing the index types of each of the component arrays. In other words array[1..10, char, boolean] of integer is a shorthand notation for array[1..10] of array[char] of array[boolean] of integer ---------------- 5.5 String Types ---------------- As an extension Irie Pascal supports variable length strings using the built-in type "string". Variable length strings specify collections of characters whose length does not exceed a maximum value. The syntax for string types is given below: string-type = 'string' | 'string' '[' size ']' | 'string' '(' size ')' size = integer where size is an integer constant, between 1 and 1048576, which specifies the maximum length of the string. If size is not specified the maximum length used is 255. For example to create a variable length string type called "name" with a maximum length of 80 use name = string[80]; or name = string(80); To create a variable length string type called 'address' with a maximum length of 255 use address = string; or address = string[255]; or address = string(255); ---------------- 5.6 Record Types ---------------- Record types specify collections of values. A record type may be empty (i.e. specify a collection with no values). Each member of a record type's collection is called a field and is identified by a field identifier, with the possible exception of the variant selector which sometimes does not have a field identifier. Each member in a record's collection has a particular type (which can be a record type). Sometimes groups of fields in a record type are mutually exclusive. You can use a variant part in a record type to specify mutually exclusive groups of fields (these mutually exclusive groups are called variants). Each variant part contains a variant selector, the value of the variant selector determines which variant if any is active. The syntax for record types is given below: record-type = 'record' field-list 'end' field-list = fixed-part ';' variant-part [ ';' ] | fixed-part [ ';' ] | variant-part [ ';' ] | empty fixed-part = record-section { ';' record-section } record-section = id-list ':' type-denoter id-list = identifier { ',' identifier } variant-part = 'case' variant-selector 'of' variant-body variant-selector = [ identifier ':' ] ordinal-type-identifier variant-body = variant-list [ [;] variant-part-completer ] | variant-part-completer variant-list = variant { ';' variant } variant = case-constant-list ':' '(' field-list ')' case-constant-list = case-specifier { ',' case-specifier } case-specifier = case-constant [ '..' case-constant ] case-constant = ordinal-constant variant-part-completer = 'otherwise' '(' field-list ')' Here are some examples of valid record types: record end record ; end The record types above are empty. record name : string; grade : integer; end The record type above has two fields which are identified by "name" of type "string" and "grade" of type "integer". Given the type below type clothes = (shoe, pants, shirt); the following record type is valid record price : real; case kind : clothes of shoe : ( size : integer; ); pants : ( waist, length : integer ); shirt : ( neck : integer; sleeve : integer ) end and contain seven fields "price", "kind", "size", "waist", "length", "neck", and "sleeve". The fields "price" and "kind" are always present and the value of the field "kind" determine which of the variants if any is present. The variants are ("size") and ("waist" and "length") and ("neck" and "sleeve"). ------------- 5.7 Set Types ------------- Set types specify combination of values of the same ordinal type (called the set's base type). The same value can not appear more than once. A set can be empty (i.e. have no values). The syntax for set types is given below: set-type = 'set' 'of' ordinal-type Here are some examples of set types set of char set of boolean -------------- 5.8 File Types -------------- File types specify collections of values that are persistent (i.e. they remain stored when your program is not running) and have the same type (called the file's component type). File component types can not be file types or types which contain file types. The syntax for file types is given below: file-type = 'file' 'of' component-type -------------- 5.9 List Types -------------- As an extension Irie Pascal supports list types. List types are ordered collections values of a single type (called the list's component type). Each member of a list's collection is identified by it's position in the list. The syntax for list types is given below: list-type = 'list' 'of' component-type --------------------- 5.10 Type Identifiers --------------------- A type identifier is an identifier that is bound to a type with a type definition. The following built-in type identifiers are supported by Irie Pascal: boolean, char, integer, real, filename, text, dir -------------- 5.10.1 boolean -------------- "boolean" is a built-in enumerated type with two values "false" and "true". The ordinal value of "false" is zero and the ordinal value of "true" is one. The conditional statement "if" and the looping statements "while" and "repeat/until" use boolean expressions. The operators "and", "or", "not", "and_then", "or_else" operate on boolean expressions. ----------- 5.10.2 char ----------- "char" is a built-in ordinal type with values of the current character set. ---------- 5.10.3 dir ---------- As an extension Irie Pascal supports the built-in type "dir" whose values are directory handles (See also "7.2.27 opendir", "7.2.35 readdir", "7.2.39 rewinddir", and "7.2.6 closedir"). --------------- 5.10.4 filename --------------- As an extension Irie Pascal supports the built-in string type "filename" which is the recommended type for variables used to store file and directory names. -------------- 5.10.5 integer -------------- "integer" is a built-in ordinal type whose values are whole numbers (see also "2.3 Integers"). ----------- 5.10.6 real ----------- "real" is a built-in type whose values are numbers with fractional parts (see also "2.4 Reals"). ----------- 5.10.7 text ----------- "text" is a built-in file type whose values are sequences of lines. A line is a sequence of characters and every lines in a "text" file is terminated by an end-of-line character except possibly the last line. ------------- 6 Variables ------------- Variables are typed storage locations, and store values of their types. Variables must be declared before they are used. Variable identifiers are identifiers that have been bound to a variable using a variable declaration. Variable declarations must occur in variable declaration groups. The syntax for variable declaration groups is given below: variable-declaration-group = 'var' variable-declaration { ';' variable-declaration } variable-declaration = identifier-list ':' type-denoter identifier-list = identifier { ',' identifier } --------------------- 6.1 Pointer Variables --------------------- Pointer variables store either the special value "nil" or a reference to another variable. The built-in procedure "new" is used to create variables referenced by pointer variables. The built-in procedure "dispose" is used to destroy variables referenced by pointer variables. ------------------- 6.2 Array Variables ------------------- Array elements can be accessed using the notation ArrayName[Index] where "ArrayName" is the name of the array variable and "Index" is an expression whose value is one of the values specified by the array's index type (see also "5.4 Array Types"). You can use either this notation ArrayName[Index1][Index2]...[IndexN] or this notation ArrayName[Index1, Index2,...IndexN] to access array elements in multi-dimensional array variables. -------------------- 6.3 String Variables -------------------- The individual characters in a string variable can be accessed using array notation. For example if "name" is a string variable then name[2] accesses the second character in the string stored in "name". You can use the following built-in procedures and functions to manipulate variables of string types: concat, copy, length, lowercase, pos, reverse, trim, uppercase, delete, insert, str, val You can use the "+" operator to perform string concatenation. For example here is a hello world program using string concatenation. program good(output); begin writeln('hello' + ' ' + 'world' + '!') end. -------------------- 6.4 Record Variables -------------------- Record variable fields can be accessed using the following notation RecordName.FieldName where "RecordName" is the name of the record variable and "FieldName" is the name of the field. ------------------ 6.5 List Variables ------------------ You can use the following built-in procedures and functions with variables of list types: new, dispose, insert, delete, length You can access the components of a list variable just like an array variable. The syntax is list-variable '[' integer-expression ']' where integer-expression is an expression of integer type that specifies the position in the list of the component being accessed. For example if "i" is an integer and "lv" is a list variable the statement below will write each component of "lv". for i := 1 to length(lv) do writeln(lv[i]) ---------------------------- 7 Functions And Procedures ---------------------------- Pascal encourages modular programming (i.e. creating a complex program from smaller and simpler modules). Ideally these modules should resemble so called "black boxes" where the implementation details about how a module performs its work is kept hidden inside the module, the user of a module only needs to know "what" the module does and not "how". Pascal supports two kinds of modules, "functions" and "procedures". The difference between functions and procedures is that functions return a value to their callers and are used in expressions, while procedures do not return a value to their callers and are used in procedure statements. Since functions and procedures are so similar the generic term subroutine will be used to refer to both. The recommended way of passing information into and out of subroutines is by use of parameters. Subroutines may have a list of formal parameters, these formal parameters are used by the subroutine to access information passed into it. When the subroutine is called the caller must supply an actual parameter for each formal parameter in the subroutine. The actual parameter is the information being passed into or out of the subroutine. Irie Pascal supports four kinds of parameters (value parameters, variable parameters, function parameters, and procedure parameters). Value parameters are passed by value (i.e. when the subroutine is called the actual parameter is an expression, and the value of the expression passed into the formal parameter). The subroutine can use the formal parameter to access the value passed to it but any changes it makes to the formal parameter will not affect the actual parameter. Variable parameters are passed by reference (i.e. when the subroutine is called the actual parameter is a variable, and a reference to this variable is passed into the formal parameter). The subroutine can use the formal parameter to access the variable (via the reference) and any changes it makes to the formal parameter will immediately affect the actual parameter. Function parameters are references to functions (i.e. when the subroutine is called the actual parameter is a function, and a reference to this function is passed into the formal parameter). The subroutine can use the formal parameter to call the function. Procedure parameters are references to procedures (i.e. when the subroutine is called the actual parameter is a procedure, and a reference to this procedure is passed into the formal parameter). The subroutine can use the formal parameter to call the procedure. For example here is an example of a simple program with a procedure. program simple(output); procedure say (message : string); begin writeln(message) end; begin say('Hello world') end. The program contains a procedure called "say" which takes a single value parameter. When the procedure is called "say('Hello world')" the actual parameter is the expression 'Hello world' which is passed into the formal parameter "message". So "message" now has the value 'Hello world'. When writeln is used the value of "message" (i.e. 'Hello world') is 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 syntax for function and procedure declarations is given below: function-declaration = function-heading ';' directive | function-identification ';' function-block | function-heading ';' function-block procedure-declaration = procedure-heading ';' directive | 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 = 'forward' result-type = type-identifier ---------------------- 7.1 Built-in Functions ---------------------- Irie Pascal supports the following built-in functions. --------- 7.1.1 abs --------- Purpose: Returns the absolute value of its input. Syntax: abs-call = 'abs' '(' num ')' num = integer-expression | real-expression Standard Pascal: Yes Example: abs(-10) is equal to 10 Notes: The type of the value returned by this function is always the same as the type of its input. ------------ 7.1.2 arctan ------------ Purpose: Returns the arctangent of its input Syntax: arctan-call = 'arctan' '(' num ')' num = integer-expression | real-expression Standard Pascal: Yes Notes: The type of the value returned by this function is always real. --------- 7.1.3 chr --------- Purpose: Returns the character whose ordinal value is equal to its input. Syntax: chr-call = 'chr' '(' num ')' num = integer-expression Standard Pascal: Yes Notes: ------------ 7.1.4 concat ------------ Purpose: Returns a string formed by concatenating its input. Syntax: concat-call = 'concat' '(' s { ',' s } ')' s = character-expression | string-expression Standard Pascal: No Notes: For example you could do something like message := concat('Hello', ' ', 'world', '!'); to make message equal to 'Hello world!' You can also concatenate strings and characters using the "+" operator like message := 'Hello' + ' ' + 'world' + '!'; ---------- 7.1.5 copy ---------- Purpose: Returns a string formed by copying from an input string starting from a specified position. Syntax: copy-call = 'copy' '(' s ',' p [ ',' n ')' s = character-expression | string-expression p = integer-expression n = integer-expression Standard Pascal: No Notes: "s" is the source of characters "p" specifies the position from which to start copying characters "n" specifies the number of characters to copy. If "n" is omitted or is greater than the number of characters in "s" from "p" to the end, then all characters in "s" starting from "p" to the end are copied. For example copy('Testing...', 5, 2) is equal to 'in' and copy('Testing...', 7) is equal to 'g...' and copy('Testing...', 1, 1000) is equal to 'Testing...' --------- 7.1.6 cos --------- Purpose: Returns the cosine of its input (expressed in radians). Syntax: cos-call = 'cos' '(' num ')' num = integer-expression | real-expression Standard Pascal: Yes Notes: The type of the value returned by this function is always real. ---------- 7.1.7 cosh ---------- Purpose: Returns the hyperbolic cosine of its input. Syntax: cosh-call = 'cosh' '(' num ')' num = integer-expression | real-expression Standard Pascal: No Notes: The type of the value returned by this function is always real. --------- 7.1.8 eof --------- Purpose: Returns "true" or "false" depending on whether its input (which is a file variable) is at end-of-file. Syntax: eof-call = 'eof' [ '(' f ')' ] f = file-variable If "f" is omitted then the built-in file variable "input" shall be used as input to this function. Standard Pascal: Yes Notes: ---------- 7.1.9 eoln ---------- Purpose: Returns "true" or "false" depending on whether its input (which is a file variable) is at end-of-line. Syntax: eoln-call = 'eoln' [ '(' t ')' ] t = text-file-variable If "t" is omitted then the built-in text file variable "input" shall be used as input to this function. Standard Pascal: Yes Notes: ---------- 7.1.10 exp ---------- Purpose: Returns the value of "e" raised to the power of its input. Syntax: exp-call = 'exp' '(' num ')' num = integer-expression | real-expression Standard Pascal: Yes Notes: The type of the value returned by this function is always real. -------------- 7.1.11 fexpand -------------- Purpose: Returns the full pathname of its input (which is a filename). Syntax: fexpand-call = 'fexpand' '(' s ')' s = character-expression | string-expression Standard Pascal: No Notes: -------------- 7.1.12 filepos -------------- Purpose: Returns the value of the file position indicator of a file. Syntax: filepos-call = 'filepos' '(' f ')' f = file-variable Standard Pascal: No Notes: This function returns an integer value. The file variable "f" must be open. For a text file variable the value of the file position indicator may not be equal to the number of characters read/written so far. For a binary file the value of the file position indicator is equal to the number of characters read/written so far. --------------- 7.1.13 filesize --------------- Purpose: Returns the size of a file. Syntax: filesize-call = 'filesize' '(' f ')' f = file-variable Standard Pascal: No Notes: This function returns an integer value. The file variable "f" must be open. ----------- 7.1.14 frac ----------- Purpose: Returns the fractional part of a real expression. Syntax: frac-call = 'frac' '(' r ')' r = real-expression Standard Pascal: No Notes: For example frac(7.234) is equal to 0.234 The type of the value returned by this function is always real. ------------- 7.1.15 getenv ------------- Purpose: Returns the environment variable specified by its input. Syntax: genenv-call = 'getenv' '(' s ')' s = character-expression | string-expression Standard Pascal: No Notes: If a string matching "s" can not be found in the environment list then an empty string is returned. ---------- 7.1.16 hex ---------- Purpose: Returns the hexadecimal representation of its input as a string. Syntax: hex-call = 'hex' '(' i ')' i = integer-expression Standard Pascal: No Notes: For example hex(16) is equal to '10'. ---------- 7.1.17 int ---------- Purpose: Returns the integer part of a real expression. Syntax: int-call = 'int' '(' r ')' r = real-expression Standard Pascal: No Notes: For example int(7.234) is equal to 7.0 The type of the value returned by this function is always real. --------------- 7.1.18 ioresult --------------- Purpose: Returns the error code of the last input/output operation. Syntax: ioresult-call = 'ioresult' Standard Pascal: No Notes: By default (when I/O checking is enabled) your program automatically checks for errors after each I/O operation and terminates with an error message if any errors are detected. If you do not want this default behavior you can disable I/O checking (either globally using the "i" compiler option or locally using the "i" compiler directive) and call this function to determine if any I/O errors occurred. (See "Appendix F" of the "Irie Pascal Users Manual" for a list of the error codes returned by this function. This function resets the error code to zero after it is called, so if you call this function twice after an I/O operation then the second call will always return 0. If you need to refer to the error code more than once you can save the error code into a variable. For example: errcode := IOResult; if errcode <> 0 then case errcode of 1: writeln('Error erasing file'); 2: writeln('Error renaming file'); 3: writeln('File is undefined') end -------------- 7.1.19 isalpha -------------- Purpose: Returns "true" or "false" depending on whether its input is a alphabetic character. Syntax: isalpha-call = 'isalpha' '(' c ')' c = character-expression Standard Pascal: No Notes: ----------------- 7.1.20 isalphanum ----------------- Purpose: Returns "true" or "false" depending on whether its input is a alphanumeric character. Syntax: isalphanum-call = 'isalphanum' '(' c ')' c = character-expression Standard Pascal: No Notes: -------------- 7.1.21 isdigit -------------- Purpose: Returns "true" or "false" depending on whether its input is a digit character. Syntax: isdigit-call = 'isdigit' '(' c ')' c = character-expression Standard Pascal: No Notes: -------------- 7.1.22 islower -------------- Purpose: Returns "true" or "false" depending on whether its input is a lower case letter. Syntax: islower-call = 'islower' '(' c ')' c = character-expression Standard Pascal: No Notes: -------------- 7.1.23 isprint -------------- Purpose: Returns "true" or "false" depending on whether its input is a printable character. Syntax: isprint-call = 'isprint' '(' c ')' c = character-expression Standard Pascal: No Notes: -------------- 7.1.24 isspace -------------- Purpose: Returns "true" or "false" depending on whether its input is a white space character. Syntax: isspace-call = 'isspace' '(' c ')' c = character-expression Standard Pascal: No Notes: -------------- 7.1.25 isupper -------------- Purpose: Returns "true" or "false" depending on whether its input is an upper case letter. Syntax: isupper-call = 'isupper' '(' c ')' c = character-expression Standard Pascal: No Notes: --------------- 7.1.26 isxdigit --------------- Purpose: Returns "true" or "false" depending on whether its input is a hexadecimal digit character. Syntax: isxdigit-call = 'isxdigit' '(' c ')' c = character-expression Standard Pascal: No Notes: ------------- 7.1.27 length ------------- Purpose: Returns the length of its input. Syntax: length-call = 'length' '(' v ')' v = list-variable | string-variable Standard Pascal: No Notes: --------- 7.1.28 ln --------- Purpose: Returns the natural logarithm of its input. Syntax: ln-call = 'ln' '(' num ')' num = integer-expression | real-expression Standard Pascal: Yes Notes: The type of the value returned by this function is always real. ---------- 7.1.29 log ---------- Purpose: Returns the logarithm to the base 10 of its input. Syntax: log-call = 'log' '(' num ')' num = integer-expression | real-expression Standard Pascal: Yes Notes: The type of the value returned by this function is always real. ------------- 7.1.30 locase ------------- Purpose: Returns the lowercase letter corresponding to its input. If there is no lowercase letter corresponding to its input then its input is returned. Syntax: locase-call = 'locase' '(' c ')' c = character-expression Standard Pascal: No Notes: ---------------- 7.1.31 lowercase ---------------- Purpose: Returns a string formed by converting all lower case characters in its input to upper case characters and leaving all other characters unchanged. Syntax: lowercase-call = 'lowercase' '(' s ')' s = string-expression Standard Pascal: No Notes: ---------- 7.1.32 odd ---------- Purpose: Returns "true" or "false" depending on whether its input is an odd number. Syntax: odd-call = 'odd' '(' i ')' i = integer-expression Standard Pascal: Yes Notes: ---------- 7.1.33 ord ---------- Purpose: Returns the ordinal value of its input. Syntax: ord-call = 'ord' '(' o ')' o = ordinal-expression Standard Pascal: Yes Notes: The type of the value returned by this function is always integer. ----------------- 7.1.34 paramcount ----------------- Purpose: Returns the number of arguments passed to the program. Syntax: paramcount-call = 'paramcount' Standard Pascal: No Notes: For example the following is the sample program "args.pas". program args(output); begin writeln('Number of program arguments =', paramcount) end. If you compile it and run it as follows ipc args ivm args this is a test then the output would be Number of program arguments = 4 --------------- 7.1.35 paramstr --------------- Purpose: Returns the ith program argument string where i is its input. Syntax: paramstr-cal = 'paramstr' '(' i ')' i = integer-expression Standard Pascal: No Notes: If there is no ith program argument an empty string is returned. --------- 7.1.36 pi --------- Purpose: Returns the value of the mathematical constant pi. Syntax: pi-call = 'pi' Standard Pascal: No Notes: --------------- 7.1.37 platform --------------- Purpose: Returns an integer indicating the platform the program is running on. Syntax: platform-call = 'platform' Standard Pascal: No Notes: As an extension Irie Pascal supports four integer constants "platform_dos", "platform_os2", "platform_win32", and "platform_linux" which can be compared with the value returned by this function. ---------- 7.1.38 pos ---------- Purpose: Searches for one string in another. Syntax: pos-call = 'pos' '(' needle ',' haystack [ ',' start ')' needle = character-expression | string-expression haystack = character-expression | string-expression start = integer-expression 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. For example pos('o', 'Hello world') is equal to 5 pos('o', 'Hello world', 1) is equal to 5 pos('o', 'Hello world', 6) is equal to 8 pos('o', 'Hello world', 256) is equal to 0 ----------- 7.1.39 pred ----------- Purpose: Returns an ordinal value that is one less than its input. Syntax: pred-call = 'pred' '(' o ')' o = ordinal-expression Standard Pascal: Yes Notes: The type of the value returned by this function is always the same as the type of its input. ------------- 7.1.40 random ------------- Purpose: Returns a pseudo-random number. Syntax: random-call = 'random' [ '(' i ')' ] i = integer-expression 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 integer value between 1 and "i"-1. See also "7.2.31 randomize". -------------- 7.1.41 reverse -------------- Purpose: Returns a string created by reversing the characters in its input. Syntax: reverse-call = 'reverse' '(' s ')' s = character-expression | string-expression Standard Pascal: No Notes: For example reverse('Hello') is equal to 'olleH' ------------ 7.1.42 round ------------ Purpose: Returns the integer value closes to its input. Syntax: round-call = 'round' '(' r ')' r = real-expression Standard Pascal: Yes Notes: For example round(7.234) is equal to 7. The type of the value returned by this function is always integer. ---------- 7.1.43 sin ---------- Purpose: Returns the sine of its input (expressed in radians). Syntax: sin-call = 'sin' '(' num ')' num = integer-expression | real-expression Standard Pascal: Yes Notes: The type of the value returned by this function is always real. ----------- 7.1.44 sinh ----------- Purpose: Returns the hyperbolic sine of its input. Syntax: sinh-call = 'sinh' '(' num ')' num = integer-expression | real-expression Standard Pascal: No Notes: The type of the value returned by this function is always real. ---------- 7.1.45 sqr ---------- Purpose: Returns the square of its input Syntax: sqr-call = 'sqr' '(' num ')' num = integer-expression | real-expression Standard Pascal: Yes Notes: The type of the value returned by this function is always the same as the type of its input. ----------- 7.1.46 sqrt ----------- Purpose: Returns the square-root of its input Syntax: sqrt-call = 'sqrt' '(' num ')' num = integer-expression | real-expression Standard Pascal: Yes Notes: The type of the value returned by this function is always real. ----------- 7.1.47 succ ----------- Purpose: Returns an ordinal value that is one more than its input. Syntax: succ-call = 'succ' '(' o ')' o = ordinal-expression Standard Pascal: Yes Notes: The type of the value returned by this function is always the same as the type of its input. ----------- 7.1.48 swap ----------- Purpose: Returns an integer value calculated by reversing the byte ordering of its input. Syntax: swap-call = 'swap' '(' i ')' i = integer-expression Standard Pascal: No Notes: For example assuming 32 bit little endian integers then 256 is stored in four bytes as follows: 0 0 1 0 So swap(256) results in the following integer: 0 1 0 0 which is equal to 65536 ------------- 7.1.49 system ------------- Purpose: Passes its input to the command processor, which will attempt to execute it as a command. Syntax: system-call = 'system' '(' s ')' s = string-expression Standard Pascal: No 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.11 Exec". For example the sample program "batch.pas" below is a very primitive batch processor. It sends each line in the input file to the command processor to be executed. program batch(f, output); var f : text; s : string; err : integer; begin reset(f); (* open input file or standard input file *) while not eof(f) do begin readln(f, s); writeln('Executing ', s); err := system(s); (* Pass 's' to the command processor *) writeln('Error code is ', err) end end. ---------- 7.1.50 tan ---------- Purpose: Returns the tangent of its input (expressed in radians). Syntax: tan-call = 'tan' '(' num ')' num = integer-expression | real-expression Standard Pascal: No Notes: The type of the value returned by this function is always real. ----------- 7.1.51 tanh ----------- Purpose: Returns the hyperbolic tangent of its input. Syntax: tanh-call = 'tanh' '(' num ')' num = integer-expression | real-expression Standard Pascal: No Notes: The type of the value returned by this function is always real. ----------- 7.1.52 trim ----------- Purpose: Returns a string created by removing all leading and trailing spaces from its input. Syntax: trim-call = 'trim' '(' s ')' s = string-expression Standard Pascal: No Notes: For example trim(' hello ') is equal to 'hello' ------------ 7.1.53 trunc ------------ Purpose: Returns an integer value formed by removing the fractional part of its input. Syntax: trunc-call = 'trunc' '(' r ')' r = real-expression Standard Pascal: Yes Notes: For example trunc(7.234) is equal to 7. The type of the value returned by this function is always integer. ------------- 7.1.54 upcase ------------- Purpose: Returns the uppercase letter corresponding to its input. If there is no uppercase letter corresponding to its input then its input is returned. Syntax: upcase-call = 'upcase' '(' c ')' c = character-expression Standard Pascal: No Notes: ---------------- 7.1.55 uppercase ---------------- Purpose: Returns a string formed by converting all upper case characters in its input to lower case characters and leaving all other characters unchanged. Syntax: uppercase-call = 'uppercase' '(' s ')' s = string-expression Standard Pascal: No Notes: ----------------------- 7.2 Built-in Procedures ----------------------- Irie Pascal supports the following built-in procedures. ------------ 7.2.1 append ------------ Purpose: Opens a file for writing at the end of the file, and associates a file variable with the opened file. Syntax: append-call = 'append' '(' f [',' s ] ')' f = file-variable s = filename Standard Pascal: No Notes: If the file does not exist it is created. If the file exists its contents are preserved. In either case all writes occur at the end of the file. If a filename ("s") is specified then the filename is assigned to the file variable before the file is opened (the file must be closed). After the file is opened all writes will occur at the end of the file regardless of calls to the built-in seek procedure (See "7.2.40 rewrite", "7.2.3 assign", "7.2.38 reset", and "7.2.42 seek"). ------------ 7.2.2 assert ------------ Purpose: This procedure is based on the C language macro of the same name. The assert procedure can be enabled/disabled using the -A compiler option. When enabled this procedure evaluates its input, which is a boolean expression and aborts the program if the expression evaluates to false. If the expression evaluates to true nothing happens. The idea behind this procedure is that you use it during debugging to verify that the variables in your program have the values you expect, and after your program is debugged you don't have to search your program and remove the calls to this procedure, instead you just disable this procedure using a compiler option. A common mistake in using this procedure is to test normal error conditions (such as out of memory or invalid user input). Syntax: assert-call = 'assert' '(' b ')' b = boolean-expression Standard Pascal: No Notes: ------------ 7.2.3 assign ------------ Purpose: Assigns a name to a file variable. Syntax: assign-call = 'assign' '(' f ',' name ')' f = file-variable name = character-expression | string-expression Standard Pascal: No Notes: The file variable "f" must be closed. For example to open a file named 'README.TXT' for reading use assign(f, 'README.TXT'); reset(f); You can't use this function to rename a file, use the "rename" procedure if you want to do that. ----------- 7.2.4 chdir ----------- Purpose: Changes the current directory. Syntax: chdir-call = 'chdir' '(' name ')' name = character-expression | string-expression Standard Pascal: No Notes: "name" specifies the name of the directory that is to be the new current directory. ----------- 7.2.5 close ----------- Purpose: Flushes and then closes a file. Syntax: close-call = 'close' '(' f ')' f = file-variable Standard Pascal: No Notes: -------------- 7.2.6 closedir -------------- Purpose: Closes a directory. Syntax: closedir-call = 'closedir' '(' d ')' d = directory-variable Standard Pascal: No Notes: Irie Pascal allows you to open, read, rewind, and close directories (See also "7.2.27 opendir", "7.2.35 readdir", "7.2.39 rewinddir"). --------- 7.2.7 dec --------- Purpose: Decrements an ordinal variable by a specified amount or by one. Syntax: dec-call = 'dec' '(' o [',' i ] ')' o = ordinal-variable i = integer-expression 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; ------------ 7.2.8 delete ------------ Purpose: Deletes components from a list or a string. Syntax: delete-call = delete-list | delete-string delete-list = 'delete' '(' l ',' start [',' count ] ')' delete-string = 'delete' '(' s ',' start [ ',' count ] ')' l = list-variable start = integer-expression count = integer-expression s = string-variable 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. ------------- 7.2.9 dispose ------------- Purpose: Releases memory allocated using "new". Syntax: dispose-call = dispose-pointer | dispose-list dispose-pointer = 'dispose' '(' p ')' dispose-list = 'dispose' '(' l ')' p = pointer-variable l = list-variable Standard Pascal: Yes Notes: After the call to dispose the pointer variable or list variable is undefined. ------------ 7.2.10 erase ------------ Purpose: Deletes a file. Syntax: erase-call = 'erase' '(' f ')' f = file-variable Standard Pascal: No Notes: The file must be closed and have a name associated with it. ----------- 7.2.11 exec ----------- Purpose: Executes a program. Syntax: exec-call = 'exec' '(' p ',' 'a' ')' p = character-expression | string-expression a = character-expression | string-expression Standard Pascal: No Notes: "p" specifies the program to execute. "a" specifies the arguments (if any) to be passed to the program (see also "7.1.49 system", "7.1.34 paramcount" and "7.1.35 paramstr"). The code returned by the program if any is stored in the built-in variable "exitcode". ----------- 7.2.12 exit ----------- Purpose: Terminates the function/procedure/program in which it is used, and optionally returns a value. Syntax: exit-call = 'exit' [ '(' e ')' ] e = expression Standard Pascal: No Notes: "i" if specifies is the value to be returned by the function or program If used in a function then "exit" terminates the function. If used in a function named "f" then "exit(e)" is equivalent to f := e; exit If used in a procedure then "exit" terminates the procedure. If used in a procedure then "exit(x)" is an error since you can not return a value from a procedure. If used not in a function or procedure but in the main program then "exit" terminates the program. If used not in a function or procedure but in the main program then "exit(e)" is equivalent to: ExitCode := e; exit (i.e. the program is terminated with "e" as the exit code). See also "7.2.21 halt". ------------ 7.2.13 flush ------------ Purpose: Flushes the a file's buffers (i.e. all data waiting to be written to the file is written). Syntax: flush-call = 'flush' '(' f ')' f = file-variable Standard Pascal: No Notes: The file associated with "f" must be open. ------------- 7.2.14 fsplit ------------- Purpose: Splits a filename into its component parts. Syntax: fsplit-call = fsplit '(' s ',' [ d ] ',' [ n ] ',' [ e ] ')' s = character-expression | string-expression d = string-variable n = string-variable e = string-variable Standard Pascal: No Notes: "s" specifies the filename to be split. "d" specifies a variable to store the directory part of the filename. "n" specifies a variable to store the name part of the filename (minus the extension. "e" specifies a variable to store the extension part of the filename. Although "d", "n", and "e" are optional at least one must be specified. ---------- 7.2.15 get ---------- Purpose: Reads the next component in a file into the file variable's buffer. Syntax: get-call = 'get' '(' f ')' f = file-variable Standard Pascal: Yes Notes: -------------- 7.2.16 getdate -------------- Purpose: Retrieves the current system date. Syntax: getdate-call = 'getdate' '(' year ',' month ',' day ',' day_of_week ')' year = integer-variable month = integer-variable day = integer-variable day_of_week = integer-variable Standard Pascal: No Notes: "year" stores the current year "month" stores the current month (1 to 12). "day" stores the current day of the month (1 to 31) "day_of_week" stores the current day of the week (0 to 6 counting from Sunday). Suppose the current system date is Wednesday September 30, 1998 then after GetDate(year, month, day, day_of_week) year = 1998 month = 9 day = 30 day_of_week = 3 ------------------ 7.2.17 getfiledate ------------------ Purpose: Returns the date a file was last modified. Syntax: getfiledate-call = 'getfiledate' '(' name ',' year ',' month ',' day ')' name = character-expression | string-expression year = integer-variable month = integer-variable day = integer-variable Standard Pascal: No Notes: "name" is the name of the file to test. "year" stores the year the file was last modified. "month" stores the month the file was last modified (1 to 12) "day" stores the day of the month the file was last modified (1 to 31) ------------------ 7.2.18 getfilemode ------------------ Purpose: Gets a file's mode. Syntax: getfilemode-call = 'getfilemode' '(' name ',' mode ')' name = character-expression | string-expression mode = integer-variable Standard Pascal: No Notes: "name" is the name of the file to test. "mode" stores the file mode. After the call "mode" can be AND'd with the following built-in constants to determine information about the file: The constants "usr_r", "usr_w", and "usr_x" can be AND'd with "mode" to determine the user read, write, and execute permissions for the file. The constants "grp_r", "grp_w", and "grp_x" can be AND'd with "mode" to determine the group read, write, and execute permissions for the file. The constants "oth_r", "oth_w", and "oth_x" can be AND'd with "mode" to determine the read, write, and execute permissions for persons other than the files owner who are not part of the file owner group. The "dir_bit" constant can be AND'd with "mode" to determine if the file really is a directory. ------------------ 7.2.19 getfiletime ------------------ Purpose: Returns the time a file was last modified. Syntax: getfiletime-call = 'getfiletime' '(' name ',' hour ',' min ',' sec ')' name = character-expression | string-expression hour = integer-variable min = integer-variable sec = integer-variable Standard Pascal: No Notes: "name" is the name of the file to test. "hour" stores the hour the file was last modified (0 to 23) "min" stores the minute the file was last modified (0 to 59) "sec" stores the second the file was last modified (0 to 61) -------------- 7.2.20 gettime -------------- Purpose: Retrieves the current system time. Syntax: gettime-call = 'gettime' '(' hour ',' min ',' sec ')' hour = integer-variable min = integer-variable sec = integer-variable Standard Pascal: No Notes: "hour" stores the current hour (0 to 23) "min" stores the current minute (0 to 59) "sec" stores the current second (0 to 61) ----------- 7.2.21 halt ----------- Purpose: Terminates the program and optionally returns an integer value to the program's caller. Syntax: halt-call = 'halt' [ '(' i ')' ] i = integer-expression Standard Pascal: No Notes: "i" if specified is the value returned by the program. ---------- 7.2.22 inc ---------- Purpose: Increments an ordinal variable by a specified amount or by one. Syntax: inc-call = 'inc' '(' o [ ',' amount ] ')' o = ordinal-variable amount = integer-expression 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; ------------- 7.2.23 insert ------------- Purpose: Inserts a component into a string or a list. Syntax: insert-call = insert-list | insert-string insert-list = 'insert' '(' v ',' l [ ',' p ] ')' insert-string = 'insert' '(' s1 ',' s2 [ ',' p ] ')' v = expression l = list-variable s1 = character expression | string-expression s2 = string-variable Standard Pascal: No Notes: "v" is the component to insert into the list "l", and must be assignment compatible with the list's component type. "l" is the list variable to insert into. "s1" s the component to insert into the string "s2". "s2" is the string variable to insert into. "p" if specified indicates the position to perform the insertion. If "p" is omitted the insertion is performed at the end of the string or list. ------------ 7.2.24 mkdir ------------ Purpose: Makes a directory Syntax: mkdir-call = 'mkdir' '(' name ')' name = character-expression | string-expression Standard Pascal: No Notes: "name" is the name of the directory to create. ---------- 7.2.25 new ---------- Purpose: Initializes a list or creates a variable for a pointer. Syntax: new-call = new-list | new-pointer new-list = 'new' '(' l ')' new-pointer = 'new' '(' p ')' l = list-variable p = pointer-variable Standard Pascal: Yes Notes: ----------- 7.2.26 open ----------- Purpose: Open a file. Syntax: open-call = 'open' '(' fv ',' name ',' mode ')' fv = file-variable name = character-expression | string-expression mode = integer-expression Standard Pascal: No Notes: "name" is the name of the file to open. "mode" is the file mode. You can use the built-in constants "readmode", "writemode", and "appendmode" to specify the file mode. The "readmode" and "writemode" constants can be added or or'd together to specify that the file be opened for both reading and writing. For example open(f, "test.txt", readmode+writemode); will open the file "test.txt" for both reading and writing. It is an error if the file "test.txt" does not exist. If you wish to create a new file for reading and writing you must create it first with "rewrite" or using "open" with "writemode" only, and then close the filee, before opening it again for reading and writing. See also "7.2.1 append", "7.2.38 reset", "7.2.40 rewrite". -------------- 7.2.27 opendir -------------- Purpose: Opens a directory. Syntax: opendir-call = 'opendir' '(' d ')' d = directory-variable Standard Pascal: No Notes: Irie Pascal allows you to open, read, rewind, and close directories (See "7.2.6 closedir", "7.2.35 readdir", and "7.2.39 rewinddir"). ----------- 7.2.28 pack ----------- Purpose: Copies some or all of the contents of an unpacked array into a packed array. Syntax: pack-call = 'pack' '(' u ',' x ',' p ')' u = unpacked-array-variable x = expression p = packed-array-variable where "u" is an unpacked array and "x" is an expression that is assignment compatible with the index type of "u" and specifies the first element of "u" to copy. and "p" is a packed array Standard Pascal: Yes Notes: The elements of "u" and "a" must have the same type. For example suppose you have the following arrays p : packed array[1..10] of integer; u : array[-10..10] of integer; then pack(u, 1, p) copies elements 1 to 10 of "u" into elements 1 to 10 of "p". Or in a more complicated example pack(u, 9, p) copies elements 9 to 10 of "u" into elements 1 to 2 of "p" ----------- 7.2.29 page ----------- Purpose: This procedure is supposed to affect a text file in such a way that subsequent output to the file appears on a new page. Syntax: page-call = 'page' '(' t ')' t = text-file-variable Standard Pascal: Yes Notes: Currently this procedure simply writes a form-feed to the text file. ---------- 7.2.30 put ---------- Purpose: Writes the contents of a file's buffer to a file and empties the file's buffer leaving it undefined. Syntax: put-call = 'put' '(' f ')' f = file-variable Standard Pascal: Yes Notes: If "f" is a file variable then the file's buffer can be accessed with "f^" or "f@". ---------------- 7.2.31 randomize ---------------- Purpose: Initializes the random number generator with a seed. Syntax: randomize-call = 'randomize' [ '(' i ')' ] i = integer-expression Standard Pascal: No Notes: "i" if specified is the seed used to initialize the random number generator. If "i" is omitted then the random number generated is initialized with a seed derived from the current system date and time. Specifying "i" is useful if you want a repeatable sequence of random numbers. -------------- 7.2.32 rawread -------------- Purpose: Reads up to a specified number of characters into a character buffer. Syntax: rawread-call = 'rawread' '(' f ',' buffer ',' count ',' actual ')' f = file-variable buffer = array-variable count = integer-expression actual = integer-variable Standard Pascal: No Notes: "buffer" must be a packed array of char variable and stores the characters read by this procedure. "count" specifies the maximum number of characters to read. "actual" stores the actual number of characters read by this procedure. "actual" may be less than "count" if there was an I/O error (you can check for this by disabling I/O checking and using the IOResult function) or if end of file was reached. --------------- 7.2.33 rawwrite --------------- Purpose: Writes up to a specified number of characters from a character buffer to a file. Syntax: rawwrite-call = 'rawwrite' '(' f ',' buffer ',' count ',' actual ')' f = file-variable buffer = array-variable count = integer-expression actual = integer-variable Standard Pascal: No Notes: "buffer" must be a packed array of char variable and stores the characters to be written by this procedure. "count" specifies the maximum number of characters to write. "actual" stores the actual number of characters written by this procedure. "actual" may be less than "count" if there was an I/O error (you can check for this by disabling I/O checking and using the IOResult function). ----------- 7.2.34 read ----------- Purpose: This procedure reads data from a file into one or more variables. Syntax: read-call = 'read' read-parameter-list read-parameter-list = '(' [ file-variable ',' ] variable-access { ',' variable-access } ')' Standard Pascal: Yes 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, integer, char, or subrange of integer. -------------- 7.2.35 readdir -------------- Purpose: Reads a directory (i.e. retrieves the name of a file in the directory). Syntax: readdir-call = 'readdir' '(' d ',' name ')' d = directory-variable name = string-variable where "d" is a directory variable (i.e. a variable of the built-in type "dir"). Standard Pascal: No Notes: "d" is the directory variable associated with the directory to read. "name" stores the filename of the next file in the directory. See also "7.2.6 closedir", "7.2.27 opendir", and "7.2.39 rewinddir". ------------- 7.2.36 readln ------------- Purpose: This procedure reads a line of data from a text file into one or more variables. Any data left on the line after the read is ignored. Syntax: readln-call = 'readln' readln-parameter-list readln-parameter-list = [ '(' ( file-variable | variable-access ) { ',' variable-access } ')' ] Standard Pascal: Yes 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, integer, char, or subrange of integer. ------------- 7.2.37 rename ------------- Purpose: Renames the file a file. Syntax: rename-call = 'rename' '(' f ',' name ')' f = file-variable name = character-expression | string-expression Notes: This procedure changes the name of the file associated with the file variable "f" to "name". This is more than just changing the name associated with the file variable, the actual name of the file is changed. ------------ 7.2.38 reset ------------ Purpose: Opens a file for reading. Syntax: reset-call = 'reset' '(' f [ ',' name ] ')' f = file-variable name = character-expression | string-expression Standard Pascal: Yes Notes: If "name" is specified then "name" is assigned to the file variable before the file is opened (the file must be closed). See also "7.2.1 append", "7.2.40 rewrite", "7.2.3 assign", and "7.2.42 seek". ---------------- 7.2.39 rewinddir ---------------- Purpose: Rewinds a directory so that reads start with the first file in the directory. Syntax: rewind-call = 'rewinddir' '(' d ')' d = directory-variable Standard Pascal: No Notes: See also "7.2.6 closedir", "7.2.27 opendir", and "7.2.35 readdir". -------------- 7.2.40 rewrite -------------- Purpose: Opens a file for writing. Syntax: rewrite-call = 'rewrite' '(' f [ ',' name ] ')' f = file-variable name = character-expression | string-expression Standard Pascal: Yes Notes: If the file exists it's contents are deleted. If the file does not exist it is created. If a filename ("n") is specified then the filename is assigned to the file variable before the file is opened (the file must be closed). See also "7.2.1 append", "7.2.3 assign", "7.2.38 reset", and "7.2.42 seek". ------------ 7.2.41 rmdir ------------ Purpose: Removes (deletes) a directory Syntax: rmdir-call = 'rmdir' '(' name ')' name = character-expression | string-expression Standard Pascal: No Notes: "name" is the name of the directory to delete. ----------- 7.2.42 seek ----------- Purpose: Sets the position indicator for a file. Syntax: seek-call = 'seek' '(' f ',' offset ')' f = file-variable offset = integer-expression Standard Pascal: No Notes: "offset" specifies the new position indicator for the file. The file associated with "f" must be open. ------------------ 7.2.43 setfiledate ------------------ Purpose: Sets a files date (i.e. last modification date). Syntax: setfiledate-call = 'setfiledate' '(' f ',' year ',' mon ',' day ')' f = file-variable year = integer-expression mon = integer-expression day = integer-expression Standard Pascal: No Notes: "year" specifies the year. "mon" specifies the month (1 to 12) "day" specifies the day (1 to 31). ------------------ 7.2.44 setfiletime ------------------ Purpose: Sets a files time (i.e. last modification time). Syntax: setfiletime-call = 'setfiletime' '(' f ',' hour ',' min ',' sec ')' f = file-variable hour = integer-expression min = integer-expression sec = integer-expression Standard Pascal: No Notes: "hour" specifies the hour (0 to 23) "min" specifies the minute (0 to 59) "sec" specifies the second (0 to 61). ------------ 7.2.45 sleep ------------ Purpose: Pauses execution of the program for a specified number of seconds. Syntax: sleep-call = 'sleep' '(' i ')' i = integer-expression Standard Pascal: No Notes: "i" specifies the number of seconds to sleep. ---------- 7.2.46 str ---------- Purpose: Converts an integer or real expression into a string and assigns the converted string to a variable. Syntax: str-call = str-integer | str-real str-integer = 'str' '(' i [':' width] ',' s ')' str-real = 'str' '(' r [ ':' width [ ':' frac ] ] ',' s ')' i = integer-expression width = integer-expression s = string-variable r = real-expression frac = integer-expression Standard Pascal: No Notes: "i" specifies the integer to convert "s" stores the converted string. "width" specifies the maximum width of the converted string "frac" specifies the number of digits after the decimal point. If "width" is omitted then eight is assumed for integer conversion and nine is assumed for real conversions. If "frac" is omitted then the real expression is converted into a string in exponential form. If "frac" is present then the real expression is converted into a string in fixed form. For example str(1034:6, s) will store ' 1034' in "s" str(3.1:8, s) will store '3.1E+001' in "s" str(-3.14:6:2, s) will store ' -3.14' in "s" The string value is padded on the left if necessary. ------------- 7.2.47 unpack ------------- Purpose: Copies some or all of the elements of a packed array into an unpacked array. Syntax: unpack-call = 'unpack' '(' p ',' u ',' x ')' p = packed-array-variable x = expression u = unpacked-array-variable Standard Pascal: Yes Notes: "x" must be assignment compatible with the index type of "u" and specifies the position in "u" to receive the first array element. The elements of "u" and "a" must have the same type. For example suppose you have the following arrays p : packed array[1..10] of integer; u : array[-10..10] of integer; then unpack(p, u, 1) copies elements -10 to -1 of "p" into elements 1 to 10 of "u". ---------- 7.2.48 val ---------- Purpose: Converts a string expression into an integer or real value and assigns the converted value to a variable. Syntax: val-call = val-integer | val-real val-integer = 'val' '(' s ',' i ',' offset ')' val-real = 'val' '(' s ',' r ',' offset ')' s = character-expression | string-expression i = integer-variable r = integer-variable Standard Pascal: No Notes: "i" stores the converted integer value "r" stores the converted real value "offset" stores the position of the first character in "s" that could not be converted or zero if all characters where converted. For example given integer variables "i" and "x" the following statement val('123EB', i, x) will store 123 in "i" and 4 in "x". ------------ 7.2.49 write ------------ Purpose: This procedure writes data from one or more variables into a file Syntax: write-call = 'write' write-parameter-list write-parameter-list = '(' [ file-variable ',' ] write-parameter { ',' write-parameter } ')' write-parameter = expression [ ':' expression [ ':' expression ] ] Standard Pascal: Yes Notes: When this procedure writes to a non-text file then the write-parameters are simply expressions, and the binary value of the expressions are written to the file. When this procedure writes to a text file it first attempts to convert the binary data stored in the variables into text data. In addition when writing to a text file the variables in the variable list must must be of type boolean, real, string, integer, subrange of integer, or char. -------------- 7.2.50 writeln -------------- Purpose: This procedure writes a line of data from one or more variables into a text file Syntax: writeln-call = 'writeln' writeln-parameter-list writeln-parameter-list = [ '(' ( file-variable | write-parameter ) { ',' write-parameter } ')' ] write-parameter = expression [ ':' expression [ ':' expression ] ] Standard Pascal: Yes Notes: When this procedure writes to a text file it first attempts to convert the binary data stored in the variables into text data. In addition when writing to a text file the variables in the variable list must must be of type boolean, real, string, integer, subrange of integer, or char. ------------- 8 Expressions ------------- Expressions specify a sequence of operations to be performed that result in a single value of a particular type. The syntax for expressions is given below: expression = shift-expression [ relational-operator shift-expression] shift-expression = simple-expression [ shift-operator simple-expression] simple-expression = term { adding-operator term } term = factor { multiplying-operator factor } factor = [sign] unsigned-constant | [sign] variable-access | [sign] '(' expression ')' | function-designator | 'not' factor | set-constructor sign = '+' | '-' unsigned-constant = unsigned-integer | unsigned-real | character-string | constant-identifier | 'nil' variable-access = entire-variable | component-variable | identified-variable | buffer-variable entire-variable = variable-identifier component-variable = indexed-variable | field-designator indexed-variable = array-variable '[' index-expression { ',' index-expression } ']' field-designator = record-variable '.' field-specifier | field-designator-identifier field-specifier = field-identifier identified-variable = pointer-variable '^' | pointer-variable '@' buffer-variable = file-variable '^' | file-variable '@' set-constructor = '[' [ member-designator { ',' member-designator } ] ']' member-designator = expression [ '..' expression ] function-designator = function-identifier [ actual-parameter-list ] actual-parameter-list = '(' actual-parameter { ',' actual-parameter } ')' actual-parameter = expression | variable-access | procedure-identifier | function-identifier omitted-parameter omitted-parameter = relational-operator = '=' | '<>' | '<' | '<=' | '>' | '>=' | 'in' shift-operator = 'shl' | shr' adding-operator = '+' | '-' | 'or' | 'or_else' | 'xor' multiplying-operator = '*' | '/' | 'div' | 'mod' | 'and' | 'and_then' ------------- 8.1 Operators ------------- Below is a table of all the operators supported by Irie Pascal in order of decreasing precedence. All operators on the same line have the same precedence. ----------------------------- not ----------------------------- * / div mod and and_then ----------------------------- + - or or_else xor ----------------------------- shl shr ----------------------------- = <> < <= > >= in ----------------------------- ------------------ 8.1.1 Not Operator ------------------ The "not" operator takes a single operand and specifies one of two operations depending on the type of the operand. If the operand is of type boolean then the "not" operator specifies a boolean NOT (i.e if the value of the operand is true the result of the operation is false and if the value of the operand is false the result of the operation is true). If the operand is of type integer then the "not" operator specifies a bitwise NOT (i.e. the result of the operation is calculated by flipping all the bits in the operand). ---------------- 8.1.2 * Operator ---------------- The "*" operator takes two operands and specifies one of two operations depending on the type of the operands. If the operands are of type integer or real then the "*" operator specifies multiplication. If both operands are of type integer then the result of the operation is of type integer. If both operands are of type real then the result of the operation is of type real. If one operand is of type integer and the other is of type real then the integer operand is converted to real before the multiplication is performed and the result of the operation is of type real. If the operands are set-types then the "*" operator specifies set intersection (i.e. the result of the operation is a set whose members are those members common to both operands). ---------------- 8.1.3 / Operator ---------------- The "/" operator takes two operands and specifies division. The type of the operands must be integer or real, and the integer operands are first converted to real before the division is performed. The result of the operation is of type real. ------------------ 8.1.4 Div Operator ------------------ The "div" operator takes two operands and specifies division. The type of the operands must both be of type integer. The result of the operation is of type integer (note: The remainder from the division is discarded). ------------------ 8.1.5 Mod Operator ------------------ The "mod" operator takes two operands and specifies modulus. The type of the operands must both be of type integer. When the operands are positive then the result of the operation is the remainder from dividing the left operand by the right operand. The result of the operation is of type integer. ------------------ 8.1.6 And Operator ------------------ The "and" operator takes two operands and specifies one of two operations depending on the type of the operands. If the operands are of type boolean then the "and" operator specifies boolean AND. The result of the operation is of type boolean and is equal to true of both operands are true, and false if either operand is false. By default short circuit evaluation is used when performing the boolean AND (i.e. The left operand is evaluated first and if it is false then the right operand is not evaluated because the result of the operation must be false). The "-sc" compiler option that can be used to enable/disable short-circuit evaluation. If the operands are of type integer then the "and" operator specifies bitwise AND. The result of the operation is of type integer. ----------------------- 8.1.7 And_Then Operator ----------------------- As an extension Irie Pascal supports the "and_then" operator, which takes two boolean operands and specifies boolean AND. The result of the operation is of type boolean. The difference between this operator and the "and" operator is that this one can not be used to perform bitwise AND and short circuit evaluation is always used when evaluating this operator. ---------------- 8.1.8 + Operator ---------------- The "+" operator takes one or two operands and specifies one of three operations depending on the type of the operands. If there is only one operand and it is of type integer or real then this operator specifies unary-plus and in fact has no effect. If there are two operands and they are of type integer or real then the "+" operator specifies addition. If both operands are of type integer then the result of the operation is of type integer. If both operands are of type real then the result of the operation is of type real. If one operand is of type integer and the other is of type real then the integer operand is converted to real before the addition is performed and the result of the operation is of type real. If there are two operands and they are of set type then the "+" operator specified set union (i.e. the result of the operation is a set with all the members from either operand). As an extension Irie Pascal supports the use of the "+" to specify string concatenation where there are two operands and they are of type string or char. ---------------- 8.1.9 - Operator ---------------- The "-" operator takes one or two operands and specifies one of two operations depending on the type of the operands. If there is only one operand and it is of type integer or real then this operator specifies unary-minus and specifies unary-minus. The result of this operation has the same type as it's operand and has the same magnitude as it's operand but the opposite sign. If there are two operands and they are of type integer or real then the "-" operator specifies subtraction. If both operands are of type integer then the result of the operation is of type integer. If both operands are of type real then the result of the operation is of type real. If one operand is of type integer and the other is of type real then the integer operand is converted to real before the subtraction is performed and the result of the operation is of type real. If there are two operands and they are of set type then the "-" operator specified set difference (i.e. the result of the operation is a set with those members are in the left operand but not in the right operand). ------------------ 8.1.10 Or Operator ------------------ The "or" operator takes two operands and specifies one of two operations depending on the type of the operands. If the operands are of type boolean then the "or" operator specifies boolean OR. The result of the operation is of type boolean and is equal to true of either operand is true, and false if both operands are false. By default short circuit evaluation is used when performing the boolean OR (i.e. The left operand is evaluated first and if it is true then the right operand is not evaluated because the result of the operation must be true). The "-sc" compiler option that can be used to enable/disable short-circuit evaluation. If the operands are of type integer then the "or" operator specifies bitwise OR. The result of the operation is of type integer. ----------------------- 8.1.11 Or_Else Operator ----------------------- As an extension Irie Pascal supports the "or_else" operator, which takes two boolean operands and specifies boolean OR. The result of the operation is of type boolean. The difference between this operator and the "or" operator is that this one can not be used to perform bitwise OR and short circuit evaluation is always used when evaluating this operator. ------------------- 8.1.12 Xor Operator ------------------- As an extension Irie Pascal supports the "xor" operator, which takes two operands and specifies one of two operations depending on the type of the operands. If the operands are of type boolean then the "xor" operator specifies boolean XOR. The result of the operation is of type boolean and is equal to true if one but not both operands are true, and false if both operands are false. If the operands are of type integer then the "xor" operator specifies bitwise XOR. The result of the operation is of type integer. ------------------- 8.1.13 shl Operator ------------------- As an extension Irie Pascal supports the "shl" operator, which takes two operands of type integer and specifies bit-shift left. The result of the operation is the left operand shifted left by the number of bits specified by the right operand. The right operand must be greater than or equal to zero. ------------------- 8.1.14 shr Operator ------------------- As an extension Irie Pascal supports the "shr" operator, which takes two operands of type integer and specifies bit-shift right. The result of the operation is the left operand shifted right by the number of bits specified by the right operand. The right operand must be greater than or equal to zero. ----------------- 8.1.15 = Operator ----------------- The "=" operator takes two operands and compares them for equality. If one operand is of type integer and the other is of type real then the integer operand is converted to real before the comparison is made. The result of this operation is of type boolean and is true if the operands are equal and false otherwise. ----------------- 8.1.16 <> Operator ----------------- The "<>" operator takes two operands and compares them for equality. If one operand is of type integer and the other is of type real then the integer operand is converted to real before the comparison is made. The result of this operation is of type boolean and is true if the operands are not equal and true otherwise. ----------------- 8.1.17 < Operator ----------------- The "<" operator takes two operands and compares them. If one operand is of type integer and the other is of type real then the integer operand is converted to real before the comparison is made. The result of this operation is of type boolean and is true if the left operand is less than the right operand. ------------------ 8.1.18 <= Operator ------------------ The "<=" operator takes two operands and specifies one of two operations depending on the type of the operands. The operands are simple types or string types then this operator compares them. If one operand is of type integer and the other is of type real then the integer operand is converted to real before the comparison is made. The result of this operation is of type boolean and is true if the left operand is less than or equal to the right operand. If the operands are set types then the "<=" operator specifies set inclusion. The result of this operation is true if all the members of the left operand are in the right operand. ----------------- 8.1.19 > Operator ----------------- The ">" operator takes two operands and compares them. If one operand is of type integer and the other is of type real then the integer operand is converted to real before the comparison is made. The result of this operation is of type boolean and is true if the left operand is greater than the right operand. ------------------ 8.1.20 >= Operator ------------------ The ">=" operator takes two operands and specifies one of two operations depending on the type of the operands. The operands are simple types or string types then this operator compares them. If one operand is of type integer and the other is of type real then the integer operand is converted to real before the comparison is made. The result of this operation is of type boolean and is true if the left operand is greater than or equal to the right operand. If the operands are set types then the ">=" operator specifies set inclusion. The result of this operation is true if all the members of the right operand are in the left operand, and is false otherwise. ------------------ 8.1.21 In Operator ------------------ The "in" operator takes two operands, the left operand is of set type and the right operands of ordinal type. The result of this operation is of type boolean and is true if the right operand is a member of the left operand, and is false otherwise. -------------------- 8.2 Compatible types -------------------- Irie Pascal implements the type compatibility rules defined by Standard Pascal (ISO/IEC 7185), and adds one more to support variable length string types. The first four rules below are taken from ISO/IEC 7185 and the last one is the one added to support variable length string types. Types T1 and T2 shall be designated compatible if any of the following statements is true: 1. T1 and T2 are the same type. 2. T1 is a subrange of T2, or T2 is a subrange of T1, or both T1 and T2 are subranges of the same host type. 3. T1 and T2 are set-types of compatible base-types, and either both T1 and T2 are designated packed or neither T1 nor T2 is designated packed. 4. T1 and T2 are fixed-length-string-types with the same number of components. 5. Either T1 is a variable-length-string-type and T2 is a variable-length-string-type, or T1 is a variable-length-string-type and T2 is a fixed-length-string-type, and the number of components in T2 is less than or equal to the maximum length of T1, or T1 is a variable-length-string-type and T2 is the char-type or T2 is a variable-length-string-type and T1 is a fixed-length-string-type, and the number of components in T1 is less than or equal to the maximum length of T2, or T2 is a variable-length-string-type and T1 is the char-type. ------------ 9 Statements ------------ The statements in a program specify the specific actions that the program can perform. Programs perform their actions (or run) by executing the statements that they contain. Pascal programs begin executing at the first statement in the main program block. Program execution generally flows from left to right and top to bottom, however there are a number of statements which can alter this flow of execution. Statements can be grouped in a number of ways. For example statements can be separated into two groups, simple statement and structured statements, where simple statements are statements that do not contain other statements, while structured statements are statements that do contain other statements. Other groups of statements include conditional statements and repetitive statements. Conditional statements allow programs to make decisions (i.e. they test a particular condition and change the flow of execution depending on the result). Repetitive statements allow the program to loop (i.e. execute one or more statements repeatedly). Labels can be placed in front of statements to mark them as targets for "goto" statements. As an extension Irie Pascal allows labels to be identifiers as well as sequences of digits. See also "3 Labels". The syntax for statements is given below: statement = [ label ':' ] ( simple-statement | structured-statement ) label = digit-sequence | identifier simple-statement = empty-statement | assignment-statement | procedure-statement | goto-statement structured-statement = compound-statement | conditional-statement | repetitive-statement | with-statement compound-statement = 'begin' statement-sequence 'end' statement-sequence = statement { ';' statement } conditional-statement = if-statement | case-statement repetitive-statement = repeat-statement | while-statement | for-statement ------------------- 9.1 Empty Statement ------------------- Empty statements don't do anything and are usually created when Pascal syntax requires a statement to exist but you don't specify one. For example if you write begin end then technically according to Pascal syntax there must be a statement between the "begin" and the "end", and since there is nothing there the empty statement is said to exist there. Empty statements also commonly occur when statements sequences have a trailing semi-colon. In Pascal the semi-colon is used as a statement separator and not a statement terminator so the following statement sequence a; b; actually contains three statements, the statement "a", the statement "b" and an empty statement following "b". Since a semi-colon follows "b" then it must separate "b" from another statement. The syntax for the empty statement is given below: empty-statement = ------------------------ 9.2 Assignment Statement ------------------------ Assignments statements specify that an expression is to be evaluated and the result stored in a variable. The value produced from evaluating the expression must be assignment compatible with the type of the variable (See "9.2.1 Assignment Compatibility" for details). For example x := 1+1 is a simple example. When this statement is executed the expression "1+1" is evaluated, and the value "2" is placed in the variable "x". The syntax for the assignment statement is given below: assignment-statement = variable-access ':=' expression variable-access = entire-variable | component-variable | identified-variable | buffer-variable entire-variable = variable-identifier component-variable = indexed-variable | field-designator indexed-variable = array-variable '[' index-expression { ',' index-expression } ']' field-designator = record-variable '.' field-specifier | field-designator-identifier field-specifier = field-identifier identified-variable = pointer-variable '^' | pointer-variable '@' buffer-variable = file-variable '^' | file-variable '@' See "8 Expression" for the syntax of expressions. ------------------------------ 9.2.1 Assignment Compatibility ------------------------------ Irie Pascal implements the assignment compatibility rules defined by Standard Pascal (ISO/IEC 7185), and adds one more to support variable length string types. The first five rules below are taken from ISO/IEC 7185 and the last one is the one added to support variable length string types. A value "V" of type T2 is assignment compatible with a type T1 if any of the following is true: 1. T1 and T2 are the same type, and that type is not a file type or a type which contains a file type. 2. T1 is the real-type and T2 is the integer-type. 3. T1 and T2 are compatible ordinal-types, and V is in the closed interval specified by T1. 4. T1 and T2 are compatible set-types, and all the members of V are in the closed interval specified by the base-type of T1. 5. T1 and T2 are fixed length string types with the same length. 6. T1 is a variable length string type and either T2 is a variable length string type or T2 is a fixed length string type or T2 is a char-type. In addition the length of V must not be greater then the maximum length of T1. ---------------------------------------------------- 9.2.1.1 Assignment compatibility with array indexing ---------------------------------------------------- The value of an index-expression shall be assignment compatible with the index-type of the array variable. For example given: var x : array[1..10] of integer; and x[i] := 20; then "i" (the value of the index-expression) shall be assignment compatible with "1..10" (the index-type of the array variable). ------------------------------------------------------ 9.2.1.2 Assignment compatibility with value parameters ------------------------------------------------------ When passing a parameter by value the actual-parameter shall be assignment compatible with the type of the formal-parameter. For example given: function IsDigit(c : char) : Boolean; begin if c in ['0'..'9'] then IsDigit := true else IsDigit := false end; and while not IsDigit(key) do read(key) then "key" (the actual-parameter in IsDigit(key) shall be assignment compatible with "char" (the type of the formal-parameter). -------------------------------------------- 9.2.1.3 Assignment compatibility with "read" -------------------------------------------- When using the built-in procedure "read" to store an input value into a variable the input value shall be assignment compatible with the type of the variable to which it is stored. For example given: var s : string[40]; and read(s); then the value read in by "read(s)" must be assignment compatible with "string[40]". ----------------------------------------------------------- 9.2.1.4 Assignment compatibility with assignment statements ----------------------------------------------------------- The value of the expression on the right-hand side of an assignment statement shall be assignment compatible with the type of the left-hand side (i.e. either the variable or the function-identifier on the left-hand side). For example given: var age : 0..100; and age := v; then "v" (the right-hand side of the assignment statement) shall be assignment compatible the "0..100" (the type of the left-hand side of the assignment statement). ------------------------------------------- 9.2.1.5 Assignment compatibility with "for" ------------------------------------------- The initial value and the final value in a for-statement shall be assignment compatible with the type of the control variable if the statement of the for-statement is executed (See "9.10 For Statement"). For example given: for i := low to high do writeln(i); then "low" (the initial value) and "high" (the final value) shall be assignment compatible with the type of "i" (the control variable) if "writeln(i)" is executed. NOTE: "writeln(i)" will get executed unless "low" is greater than "high". --------------------------- 9.2.1.6 Transfer procedures --------------------------- In the statement pack(a,i,z) and unpack(z,a,i) the value of "i" shall be assignment compatible with the index-type of "a". For example given: var a : array[1..100] of real; z : packed array[1..100] of real; i : integer; and pack(a,i,z) or unpack(z,a,i) then "i" shall be assignment compatible with "1..100" (the index-type of "a"). ----------------------- 9.3 Procedure Statement ----------------------- Procedure statements specify that a procedure is to be executed and that a list of arguments if any are to be passed into the procedure. When procedures are executed program execution is transferred to the first statement in the procedure's statement block. After the execution of a procedure program execution resumes with the statement after the procedure call (See "7 Functions And Procedures"). For example writeln('1 + 1 = ', 1+1) is a simple example. When this statement is executed the parameters "'1+1'" and "1+1" are passed into the procedure and then it is executed. In this case the "writeln" procedure prints the parameters to the standard output stream. The syntax for procedure statements is given below: procedure-statement = procedure-identifier ( [ actual-parameter-list ] | read-parameter-list | readln-parameter-list | write-parameter-list | writeln-parameter-list ) procedure-identifier = identifier actual-parameter-list = '(' actual-parameter { ',' actual-parameter } ')' actual-parameter = expression | variable-access | procedure-identifier | function-identifier | omitted-parameter omitted-parameter = read-parameter-list = '(' [ file-variable ',' ] variable-access { ',' variable-access } ')' readln-parameter-list = [ '(' ( file-variable | variable-access ) { ',' variable-access } ')' ] write-parameter-list = '(' [ file-variable ',' ] write-parameter { ',' write-parameter } ')' write-parameter = expression [ ':' expression [ ':' expression ] ] writeln-parameter-list = [ '(' ( file-variable | write-parameter ) { ',' write-parameter } ')' ] ------------------ 9.4 Goto Statement ------------------ Goto statements specify that program execution is to be transferred to the statement prefixed by the goto statement's label. Standard (ISO/IEC 7185) Pascal describes the rules governing the use of goto statements as follows: A label, if any, of a statement S shall be designated as prefixing S. The label shall be permitted to occur in a goto-statement G if and only if any of the following three conditions is satisfied. a) S contains G. b) S is a statement of a statement-sequence containing G. c) S is a statement of the statement-sequence of the compound-statement of the statement-part of a block containing G. To fully understand these rules you will probably need a copy of the Standard (ISO/IEC 7185) but the fully 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 until the block containing the statement referred to be the goto statement is reached. So for example if the main program calls a procedure A, and procedure A calls procedure B, and procedure B calls procedure C, and a goto statement in procedure C transfers execution back to procedure A then procedures C and B are terminated. Below is a simple program illustrating the use of the goto statement program ten(output); label loop; var count : integer; begin count := 1; loop: writeln(count); count := count + 1; if count <= 10 then goto loop end. NOTE: The label "loop" used in this program is declared before it is used (which is a requirement for all labels). The syntax for goto statements is given below: goto-statement = 'goto' label label = digit-sequence | identifier ---------------------- 9.5 Compound Statement ---------------------- Compound statements are used to group a number of statements into a single statement. When a compound statement is executed, program execution is transferred to the first statement in the statement group and generally continues left to right, top to bottom unless diverted by one of the statements executed. You usually use compound statements when Pascal syntax says that only one statement is allowed at a particular point but you want to put more than one, so you put the statements in a compound statement and Pascal syntax is happy because the compound statement is a single statement. For example look at the program fragment below: write('Do you want to continue'); readln(answer); if (answer = 'n') or (answer = 'N') then begin writeln('Program terminated by user'); halt end here we want to write a message to the screen and stop if the user answers "n" or "N", but this requires two statements and the then part of an if statement allows only a single statement. The solution as you can see is just to put the two statements into a compound statement. The syntax for compound statements is given below: compound-statement = 'begin' statement-sequence 'end' statement-sequence = statement { ';' statement } ---------------- 9.6 If Statement ---------------- If statements conditionally execute one or two statements. If statements contain a boolean expression, a "then-part", and may optionally contain an "else-part". When an if statement is executed the boolean expression is evaluated and what happens next depends on the result of the evaluation. If the expression is evaluated and found to be true then the statement in the "then-part" is executed, and program execution resumes at the statement after the if statement. If the expression is evaluated and found to be false then if an "else-part" is present the statement in the "else-part" is executed and program control resumes at the statement after the if statement, if an else part is not present then program execution is transferred immediately to the statement after the if statement. For example if x > y then writeln('x is greater than y') else writeln('x is NOT greater than y') is an if statement. When this statement is executed the boolean expression "x > y" is evaluated and if true the statement "writeln('x is greater than y')" is executed, and if the boolean expression is false the statement "writeln('x is NOT greater than y')" is executed. The syntax for if statements is given below: if-statement = 'if' boolean-expression then-part [ else-part ] then-part = 'then' statement else-part = 'else' statement ------------------ 9.7 Case Statement ------------------ Case statements conditionally execute one, two, or more statements. Case statements contain an ordinal expression, zero, one or more case list elements, and optionally a case statement completer. Case list elements contain one or more constants and a statement. Case statement completers contain a statement sequence. When a case statement is executed the ordinal expression is evaluated and the value used to conditionally execute either the statement in one of the case list elements or the statement sequence in the case statement completer. If the expression evaluates to a value equal to one of the constants in a case list element then the statement in that case list element is executed. If the expression evaluates to a value that is not equal to one of the constants in a case list element then the statement sequence in the case statement completer is executed (if there is no case statement completer then this is an error). After executing either the statement in the case list element or the statement sequence in the case statement completer program execution resumes at the statement after the case statement. Constant ranges can be used to specify a number of contiguous constants (for example 1..5 is the same as 1, 2, 3, 4, 5). No two case list elements can contain the same constant, so case x of 1, 2, 3 : write('1 to 3'); 2 : write('2'); end is an error since both case list elements contain "2". For example the program fragment below shows an ordinal type and a procedure with a case statement. type DayOfWeek = (monday, tuesday, wednesday, thursday, friday, saturday, sunday); procedure WriteDayOfWeek(day : DayOfWeek); begin case day of monday: write('monday'); tuesday: write('tuesday'); wednesday: write('wednesday'); thursday: write('thursday'); friday: write('friday'); saturday: write('saturday'); sunday: write('sunday'); end end; When the case statement is executed the ordinal expression "day" is evaluated and if it is equal to "tuesday" for example then since the second case list element contains a constant equal to "tuesday" then the statement in the second case list element is executed (i.e. write('tuesday')). Below is a slightly more complex example. program example(input, output); var c : char; begin write('Enter a digit :'); readln(c); case c of '0'..'9' : writeln('OK'); 'a'..'z', 'A'..'Z' : writeln('That is a letter'); otherwise writeln('What is that?'); end end. When the case statement is executed the ordinal expression "c" is evaluated and the value used as follows: If the value is a digit then the statement in the first case list element is executed. If the value is a letter then the statement in the second case list elements is executed. If the value is not a digit or a letter then the statement sequence in the case statement completer is executed. Due to an implementation limit Irie Pascal handles case statements differently depending on the type of the ordinal expression. If the ordinal expression in the case statement has a type with less than or equal to 1024 values then Irie Pascal implements the case statement using a jump table and the rule that no two case list elements can have the same constant is enforced. In addition with the table implementation the ordinal expression is evaluated only once. If the ordinal expression in the case statement has a type with more than 1024 values then Irie Pascal implements the case statement as a series of if statements and the rule that no two case list elements can have the same constant is NOT enforced. In addition with the if statement implementation the ordinal expression is evaluated once for each case list element until a match is found. In practice the only integer expression are likely to have types with ranges greater than 1024. You could create an enumerated type with more than 1024 values but that is unlikely. The syntax for case statements is given below: case-statement = 'case' case-index case-body [ ';' ] 'end' case-index = ordinal-expression case-body = case-list-elements [ [ ';' ] case-statement-completer ] | case-statement-completer case-list-elements = case-list-element { ';' case-list-element } case-list-element = case-constant-list ':' statement case-constant-list = case-specifier { ',' case-specifier } case-specifier = case-constant [ '..' case-constant ] case-constant = ordinal-constant case-statement-completer = 'otherwise' statement-sequence -------------------- 9.8 Repeat Statement -------------------- Repeat statements are used to repeatedly execute one or more statements in a loop. Repeat statements contain a statement sequence and a loop condition. When a repeat statement is executed the statement sequence is executed as long as the loop condition is satisfied. The loop condition is tested after the statement sequence is executed so the statement sequence will always be executed at least once. The loop condition is a boolean expression and is satisfied as long as the expression evaluates to false. Usually the statement sequence will perform some action that will eventually cause the loop condition to fail and thus terminate the loop. It is also possible to use a goto statement to terminate the loop. For example below is a very simple program which illustrates the use of the repeat statement. program ten(output); var count : 1..11; begin count := 1; repeat writeln(count); count := count + 1 until count > 10 end. The syntax for repeat statements is given below repeat-statement = 'repeat' statement-sequence 'until' boolean-expression ------------------- 9.9 While Statement ------------------- While statements are used to repeatedly execute a statement in a loop. While statements contain a statement and a loop condition. When a while statement is executed the statement is executed as long as the loop condition is satisfied. The loop condition is tested before the statement is executed so it is possible that the statement not be executed at all. The loop condition is a boolean expression and is satisfied as long as the expression evaluates to true. Usually the statement will perform some action that will eventually cause the loop condition to fail and thus terminate the loop. It is also possible to use a goto statement to terminate the loop. For example below is a very simple program which illustrates the use of the while statement. program ten(output); var count : 1..11; begin count := 1; while count <= 10 do begin writeln(count); count := count + 1; end end. The syntax for while statements is given below while-statement = 'while' boolean-expression 'do' statement ------------------ 9.10 For Statement ------------------ For statements are used to repeatedly execute a statement in a loop, while at the same time counting each loop iteration. For statements contain a control variable, an initial value, a final value, and a statement. There are two kind of for statements, one kind counts upwards, and the other kind counts downwards. For statements that count upwards are executed as follows: First 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 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 is used in the read-parameter-list or the readln-parameter-list. A for statement "threatens" the control variable if it uses the same control variable. The syntax for the for statement is given below: for-statement = 'for' control-variable ':=' initial-value ('to' | 'downto') final-value 'do' statement control-variable = variable-identifier initial-value = ordinal-expression final-value = ordinal-expression ------------------- 9.11 With Statement ------------------- With statements allow the fields of a record variable to be accessed without specifying the record-variable each time. With statements contain a record variable list and a statement. When a with statement is executed the statement it contains is executed, however the fields in the record variable can be accessed using the field identifier alone. For example give the following type and variable type student = record name : string; address : string; grade : integer; end; var s : student; then with s do begin name := 'John'; address := 'main street'; grade := 20; end is equivalent to begin s.name := 'John'; s.address := 'main street'; s.grade := 20; end Since some record types can contain other record types you can have nested with statements like with record1 do with record2 do with record3 do statement or you can use the following shorthand with record1, record2, record3 do statement The syntax for the with statement is given below: with-statement = 'with' record-variable-list 'do' statement record-variable-list = record-variable { ';' record-variable } --------------------- 10 Program parameters --------------------- Program parameters are identifiers which appear after the program name (placed between parentheses). In addition to appearing after the program name, most program parameters must also appear in a global variable declaration. Two special program parameters "input" and "output" are the exceptions to this rule. The appearance of the two special program parameters, after the program name, automatically declares them as two special file variables which reference the standard-input and standard-output streams. You can use program parameters to access command-line arguments passed to your program (see also extended procedures "paramcount" and "paramstr"). For example suppose you want to write a program to append two files together, writing the appended files to a third file, then you might write a program similar to the sample program below. (********************************************************************** ** This program appends two files together, writing the appended files ** out to a third file. *) program append(in1, in2, out, output); type char_file = file of char; var in1 : char_file; (* first input file *) in2 : char_file; (* second input file *) out : char_file; (* output file *) (*************************************************************** ** PURPOSE: Writes copies the contents of one file into another. ** ARGUMENTS: ** 'f' - the input file ** 'g' - the output file ** NOTES: It is up to the caller to open and close the files. *) procedure WriteFile(var f, g: char_file); var c : char; begin while not eof(f) do begin read(f, c); write(g, c) end end; (********************************************** ** PURPOSE: Writes a help screen and then halts *) procedure syntax; begin writeln('Appends two files together and writes the output to a third file'); writeln('Syntax'); writeln(' ivm append in1 in2 out'); writeln('where "in1" is the first input file'); writeln('and "in2" is the second input file'); writeln('and "out" is the output file'); halt end; begin if paramcount <> 3 then syntax; rewrite(out); reset(in1); WriteFile(in1, out); close(in1); reset(in2); WriteFile(in2, out); close(in2) close(out); end. The first thing to notice about this program is the line below: program append(in1, in2, out, output); Here four program parameters are being used "in1", "in2", "out", and "output". The first program parameter "in1" accesses the first command-line argument The second program parameter "in2" accesses the second command-line argument. The third program parameter "out" accesses the third command-line argument. The fourth program parameter "output" declares the special file variable which references the standard-output stream, and has nothing to do with command-line arguments. "output" does not have to be the last program parameter, it can be used in the first, or second or any position. Since "output" does not access any command-line arguments it can appear in any position (not just the fourth and last position) without disturbing the command-line arguments accessed by the other program parameters. In other words all of the following are equivalent program append(output, in1, in2, out); or program append(in1, output, in2, out); or program append(in1, in2, output, out); or program append(in1, in2, out, output); And in each of the four cases "in1" accesses the first command-line argument and "in2" accesses the second command-line argument and "out" accesses the third command-line argument. The second thing to notice about the program are the following lines. var in1 : char_file; (* first input file *) in2 : char_file; (* second input file *) out : char_file; (* output file *) Here the program parameters (except for "output") appear in global variable declarations as required. They are declared to be variables of type "char_file" which has been declared to be "file of char". Now since they are declared to be file variables it means that the command-line arguments accessed specify the names of the external files associated with the file variables. What this means is that if the file variables are opened (using "reset", "rewrite", or "append") then the external file which is opened is the one specified by the command-line argument accessed. For example if the program is run with the line ivm append x.txt y.txt a:\z.txt then when "in1" is opened the file "x.txt" is opened and when "in2" is opened the file "y.txt" is opened and when "out" is opened the file "a:\z.txt" is opened. The final thing to notice about the program are the following lines. if paramcount <> 3 then syntax; These lines cause the procedure "syntax" to be called if the number of command-line arguments is not 3. These lines are intended to prevent problems if the user does not enter 3 command-line arguments. Suppose for example that this program was run with no command-line arguments. The first program argument "in1" will access the first command-line argument which does not exist so the empty string will specify the external file associated with this file variable. Similarly the empty string will specify the external files associated with the file variables "in2" and "out". You might ask what happens if you open a file variable associated with an external file specified by an empty string? Well, if you open such a file variable for reading (with "reset") then the external file opened is the standard input stream. If you open such a file for writing (with "rewrite" or "append") then the external file opened is the standard output stream. I didn't want this effect when I wrote the sample program above so I inserted the lines if paramcount <> 3 then syntax; to avoid this. So far I have described how file-type program parameters are handled. You can also use string-type program parameters. They also access the command-line arguments, but in a different way. The command-line argument accessed is simply assigned to the string-type program parameter. If you use program parameters other than file-type or string-type then the command-line argument is ignored. The compiler will issue a warning, that the command-line argument has an invalid type, but otherwise do nothing. For example look at this rather strange program. program strange(f, s1, dummy, s2); var f : text; s1, s2 : string; dummy : real; begin rewrite(f); writeln(f, s1); writeln(f, s2) end. If you compile it you will get some warnings but ignore them. If you run the program with ivm strange out.txt first skip second then the first program parameter "f" will access "out.txt", and since "f" is a file-type program argument when "rewrite" is used on "f" the file "out.txt" will be opened for writing. The second program parameter "s1" will access "first", and since this is a string-type program argument then "first" will be assigned to "s1". The third program parameter "dummy" is not a file-type or string-type program parameter so the third command-line argument "skip" will be ignored. The fourth program parameter "s2" will access "second", and since this is a string-type program argument then "second" will be assigned to "s2". So the effect of the following three lines rewrite(f); writeln(f, s1); writeln(f, s2) is that a text file "out.txt" is opened and two lines are written to it. The first line will be "first" and the second will be "second". ------------------------------- Appendix A. Irie Pascal Grammar ------------------------------- The start symbol for this grammar is "program". actual-parameter = expression | variable-access | procedure-identifier | function-identifier omitted-parameter actual-parameter-list = '(' actual-parameter { ',' actual-parameter } ')' adding-operator = '+' | '-' | 'or' | 'or_else' | 'xor' array-type = 'array' '[' index-type-list ']' 'of' component-type assignment-statement = variable-access ':=' expression block = declarative-part statement-part buffer-variable = file-variable '^' | file-variable '@' case-body = case-list-elements [ [ ';' ] case-statement-completer ] | case-statement-completer case-constant = ordinal-constant case-constant-list = case-specifier { ',' case-specifier } case-index = ordinal-expression case-list-element = case-constant-list ':' statement case-list-elements = case-list-element { ';' case-list-element } case-specifier = case-constant [ '..' case-constant ] case-statement = 'case' case-index case-body [ ';' ] 'end' case-statement-completer = 'otherwise' statement-sequence component-type = type-denoter component-variable = indexed-variable | field-designator compound-statement = 'begin' statement-sequence 'end' conditional-statement = if-statement | case-statement constant = integer | real | character-literal | string-literal | constant-identifier constant-declaration = identifier '=' constant constant-declaration-group = 'const' constant-declaration ';' { constant-declaration ';' } control-variable = variable-identifier declarative-part = { pre-declaration } { sub-block-declaration } domain-type = type-identifier else-part = 'else' statement empty-statement = entire-variable = variable-identifier expression = shift-expression [ relational-operator shift-expression] factor = [sign] unsigned-constant | [sign] variable-access | [sign] '(' expression ')' | function-designator | 'not' factor | set-constructor field-designator = record-variable '.' field-specifier | field-designator-identifier field-designator-identifier = identifier field-list = fixed-part ';' variant-part [ ';' ] | fixed-part [ ';' ] | variant-part [ ';' ] | empty field-specifier = field-identifier file-type = 'file' 'of' component-type final-value = ordinal-expression fixed-part = record-section { ';' record-section } for-statement = 'for' control-variable ':=' initial-value ('to' | 'downto') final-value 'do' statement function-designator = function-identifier [ actual-parameter-list ] goto-statement = 'goto' label identified-variable = pointer-variable '^' | pointer-variable '@' identifier-list = identifier { ',' identifier } if-statement = 'if' boolean-expression then-part [ else-part ] indexed-variable = array-variable '[' index-expression { ',' index-expression } ']' index-type = ordinal-type index-type-list = index-type { ',' index-type } initial-value = ordinal-expression label = digit-sequence | identifier label-declaration-group = 'label' label { ',' label } ';' list-type = 'list' 'of' component-type member-designator = expression [ '..' expression ] multiplying-operator = '*' | '/' | 'div' | 'mod' | 'and' | 'and_then' new-ordinal-type = enumerated-type | subrange-type new-pointer-type = '^' domain-type | '@' domain-type new-structured-type = [ 'packed' ] array-type | [ 'packed' ] record-type | [ 'packed' ] set-type | [ 'packed' ] file-type | [ 'packed' ] list-type | string-type new-type = new-ordinal-type | new-structured-type | new-pointer-type omitted-parameter = ordinal-type = new-ordinal-type | ordinal-type-identifier pre-declaration = label-declaration-group | constant-declaration-group | type-declaration-group | variable-declaration-group procedure-identifier = identifier procedure-statement = procedure-identifier ( [ actual-parameter-list ] | read-parameter-list | readln-parameter-list | write-parameter-list | writeln-parameter-list ) program = 'program' program-name [ '(' program-args ')' ] ';' block '.' program-args = identifier-list read-parameter-list = '(' [ file-variable ',' ] variable-access { ',' variable-access } ')' readln-parameter-list = [ '(' ( file-variable | variable-access ) { ',' variable-access } ')' ] record-section = identifier-list ':' type-denoter record-type = 'record' field-list 'end' record-variable-list = record-variable { ';' record-variable } relational-operator = '=' | '<>' | '<' | '<=' | '>' | '>=' | 'in' repeat-statement = 'repeat' statement-sequence 'until' boolean-expression repetitive-statement = repeat-statement | while-statement | for-statement 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 = integer statement = [ label ':' ] ( simple-statement | structured-statement ) statement-part = compound-statement statement-sequence = statement { ';' statement } string-type = 'string' | 'string' '[' size ']' | 'string' '(' size ')' structured-statement = compound-statement | conditional-statement | repetitive-statement | with-statement term = factor { multiplying-operator factor } then-part = 'then' statement type-declaration = identifier '=' type-denoter type-declaration-group = 'type' identifier '=' type-declaration ';' { type-declaration ';' } type-denoter = type-identifier | new-type type-identifier = identifier unsigned-constant = unsigned-integer | unsigned-real | character-string | constant-identifier | 'nil' variable-access = entire-variable | component-variable | identified-variable | buffer-variable variable-declaration = identifier-list ':' type-denoter variable-declaration-group = 'var' variable-declaration { ';' variable-declaration } variant = case-constant-list ':' '(' field-list ')' variant-body = variant-list [ [;] variant-part-completer ] | variant-part-completer variant-list = variant { ';' variant } variant-part = 'case' variant-selector 'of' variant-body variant-part-completer = 'otherwise' '(' field-list ')' variant-selector = [ identifier ':' ] ordinal-type-identifier while-statement = 'while' boolean-expression 'do' statement with-statement = 'with' record-variable-list 'do' statement writeln-parameter-list = [ '(' ( file-variable | write-parameter ) { ',' write-parameter } ')' ] write-parameter = expression [ ':' expression [ ':' expression ] ] write-parameter-list = '(' [ file-variable ',' ] write-parameter { ',' write-parameter } ')' ------------------------------------------------------------- Appendix B. Extensions to Pascal as specified by ISO/IEC 7185 ------------------------------------------------------------- Irie Pascal supports a number of extensions to Standard Pascal. Some of these extensions were added for compatibility with Turbo Pascal and Extended Pascal, while others were added because I thought they might be useful. Extensions can be enabled/disabled using the -E compiler option. ------------------------ B.1 Relaxed declarations ------------------------ Standard Pascal requires that all declarations/definitions of the same kind must be made together in a single group and that the groups must appear in a specific order. The order required by Standard Pascal is: Label declaration group Constant definition group Type definition group Variable declaration group sub-block declaration group When "relaxed declarations" is enabled there can be more than one of each kind of group and groups can appear in any order except that the sub-block declaration group must be last. So if "relaxed declarations" is enabled then the following program is legal, program summing(output); const first = 1; last = 100; type num = first..last; var i : num; type atype = array[first..last] of integer; var a : atype; sum : integer; begin sum := 0; for i := first to last do begin sum := sum + i; a[i] := sum end; for i := last downto first do writeln(i, a[i]); end. even though it has two type definition groups "type num = first..last;" and "type atype = array[first..last] of integer;" and two variable declaration groups "var i : num;" and "var a : atype; sum : integer;" In Standard Pascal or with "relaxed declarations" disabled you would have to combine these groups so you would have the following program summing(output); const first = 1; last = 100; type num = first..last; atype = array[first..last] of integer; var i : num; a : atype; sum : integer; begin sum := 0; for i := first to last do begin sum := sum + i; a[i] := sum end; for i := last downto first do writeln(i, a[i]); end. ------------------- B.2 Constant ranges ------------------- You can use constant ranges to specify a number of consecutive case constants. To use a constant range you specify the first constant, and the last constant, separated by '..' as follows: first..last You could use the constant range 1..5 to specify the following constants 1, 2, 3, 4, 5 For example suppose "c" is a char variable and you want to use a case statement to write the word "Letter" if "c" contains a letter, and the word "Digit" if "c" contains a digit, then you could specify each constant individually as follows: case c of 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' : write('Letter'); '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' : write('Digit'); end; Or you could use constant ranges like the following: case c of 'a'..'z', 'A'..'Z' : write('Letter'); '0'..'9' : write('Digit'); end; Constant ranges can be used in case statements, like in the example above, and in variant records. ------------- B.3 Otherwise ------------- You can use the keyword "otherwise" in case statements and variant records to specify "all values that haven't been used yet". You can also use "else" instead of "otherwise" (this feature was added in order to improve compatibility with Turbo Pascal). For example in the following variant record type character = record case c : char of 'a'..'z', 'A'..'Z' : (vowel : Boolean); '0'..'9' : (value : integer); otherwise (); end; when "otherwise" is used, the following values have already been specified 'a'..'z', 'A'..'Z', and '0'..'9' so otherwise specifies all character values except 'a'..'z', 'A'..'Z', and '0'..'9' ------------------------------------ B.4 Relaxed parameter list congruity ------------------------------------ Standard Pascal says the following parameter lists (VAR a, b : integer) and (VAR c : integer; VAR d : integer) are not congruous even though the individual parameters are congruous because Standard Pascal compares formal parameter sections. So in the example above the parameter lists are not congruous for two reasons: 1) The first parameter list has one formal parameter section "VAR a, b : integer" while the second parameter list has two formal parameter section "VAR c : integer" and "VAR d : integer" 2) The individual parameter sections are not congruous (i.e.. "VAR a, b : integer" is not congruous with "VAR c : integer") Irie Pascal checks for parameter list congruity by comparing the individual parameters without regard to the formal-parameter-sections. So the example above would be considered congruous since "a" and "c" are both integer variable parameters and "b" and "d" are both integer variable parameters Parameter list congruity becomes important when passing functions/procedures since the parameter list of the actual function/procedure parameter must be congruous with the parameter list of the corresponding formal function/procedure parameter. Relaxed parameter list congruity can not be disabled. -------------------------------- B.5 Non-numeric statement labels -------------------------------- Irie Pascal supports non-numeric statement labels. For example in the following program "loop" is used as a statement label. program name(output); label loop; var i : integer; begin i := 1; loop: writeln(i); i := i + 1; if i <= 20 then goto loop; end. ------------------------------ B.6 Underscores in identifiers ------------------------------ Irie Pascal supports identifiers which contain and/or start with underscores ("_"). ---------------------------- B.7 Binary integer constants ---------------------------- Binary integer constants begin with "%", and are followed by one or more binary digits. The following are examples of valid binary constants %0 %1 %01110101010101010111101 The following are not valid binary constants %2 % %151 %g --------------------------------- B.8 Hexadecimal integer constants --------------------------------- Hexadecimal integer constants begin with "$", and are followed by one or more hexadecimal digits. The following are examples of valid hexadecimal integer constants $9 $A123 $ffff The following is not a valid hexadecimal integer constant $abgd since "g" is not a hexadecimal integer constants. ------------------------------------------- B.9 Input and Output automatically declared ------------------------------------------- Standard (ISO/IEC 7185) Pascal specifies that whenever the required identifiers "Input" and "Output" are referenced in a program that they must by declared (i.e. appear as program parameters). However because some Pascal compilers do not enforce this requirement many Pascal programs do not meet this specification. In order to allow Irie Pascal to compile these programs without requiring the user to insert "Input" and "Output" into the program parameter list, I decided that by default Irie Pascal should automatically declare Input and Output. --------------------------- B.10 Double-quoted literals --------------------------- You can use double quotation marks to form character and string literals. For example you could use "Hello world" instead of 'Hello world' Double-quoted literals can be useful if you want to create literals with single quotes in them since you don't have to use two single quotes to represent one single quote. For example you could use "Don't go away" which is equivalent to 'Don''t do away' ---------------------- B.11 and_then operator ---------------------- The "and_then" operator is similar to the "and" operator except that short-circuit evaluation is always used for "and_then" regardless of the setting of the "sc" compiler option. See "8.1.7 And_Then Operator" for more information. --------------------- B.12 or_else operator --------------------- The "or_else" operator is similar to the "or" operator except that short-circuit evaluation is always used for "or_else" regardless of the setting of the "sc" compiler option. See "8.1.11 Or_Else Operator" for more information. ---------------------- B.13 Bitwise operators ---------------------- Irie Pascal defines several bitwise operators. ------------------- B.13.1 shl operator ------------------- The "shl" operator performs a left bit-shift, and returns the result of this bit-shift. The left operand is the integer to be shifted, and the right operand, which is also an integer, specifies the number of bits to shift. For example 4 shl 2 is equal to 16, since 4 shifted left by 2 bits is 16. ------------------- B.13.2 shr operator ------------------- The "shr" operator performs a right bit-shift, and returns the result of this bit-shift. The left operand is the integer to be shifted, and the right operand, which is also an integer, specifies the number of bits to shift. For example 4 shr 2 is equal to 1, since 4 shifted right by 2 bits is 1. ----------------------------- B.13.3 and (Bitwise) operator ----------------------------- The bitwise "and" operator takes two integer operands and produces an integer result. A bit in the result is 1 if the bit in the corresponding position in the left operand is 1 AND the bit in the corresponding position in the right operand is 1. Otherwise the result bit is 0. For example 5 and 3 = 1 Since 101 (which is 5 in binary) and 011 (which is 3 in binary) --------- = 001 --------- NOTE: Bit zero is 1 in the result since bit zero is one in both the left and right operands. All other bits are zero. ---------------------------- B.13.4 or (Bitwise) operator ---------------------------- The bitwise "or" operator takes two integer operands and produces an integer result. A bit in the result is 1 if the bit in the corresponding position in the left operand is 1 OR the bit in the corresponding position in the right operand is 1 OR both bits are 1. Otherwise the result bit is 0. For example 5 or 3 = 7 Since 101 (which is 5 in binary) or 011 (which is 3 in binary) --------- = 111 --------- ----------------------------- B.13.5 not (Bitwise) operator ----------------------------- The bitwise "not" operator takes an integer operand and produces an integer result. A bit in the result is 1 if the bit in the corresponding position in the operand is 0. A bit in the result is 0 if the bit in the corresponding position in the operand is 1. For example not 1 = -2 Since not 00000000 00000000 00000000 00000001 = 1 ----------------------------------------- 11111111 11111111 11111111 11111110 = -2 ----------------------------- B.13.6 xor (Bitwise) operator ----------------------------- The bitwise "xor" operator takes two integer operands and produces an integer result. A bit in the result is 1 either the bit in the corresponding position in the left operand is 1 OR the bit in the corresponding position in the right operand is 1, but not both. Otherwise the result bit is 0. For example 5 xor 3 = 6 Since 101 (which is 5 in binary) xor 011 (which is 3 in binary) --------- = 110 --------- ----------------------- B.14 Extended constants ----------------------- Irie Pascal defines a number of built-in constants which are not part of Standard Pascal. The constants are referred to here as extended constants. -------------- B.14.1 maxchar -------------- Irie Pascal defines "maxchar" which is a built-in character constant, whose value is the maximum character value allowed. Syntax: maxchar ------------ B.14.2 usr_r ------------ Irie Pascal defines "usr_r" which is a built-in integer constant. You can use this constant with the "mkdir" procedure to specify that the directory owner has read permission. You can also "or" this constant with a file mode to determine if the file owner has read permission. Syntax: usr_r ------------ B.14.3 usr_w ------------ Irie Pascal defines "usr_w" which is a built-in integer constant. You can use this constant with the "mkdir" procedure to specify that the directory owner has write permission. You can also "or" this constant with a file mode to determine if the file owner has write permission. Syntax: usr_w ------------ B.14.4 usr_x ------------ Irie Pascal defines "usr_x" which is a built-in integer constant. You can use this constant with the "mkdir" procedure to specify that the directory owner has execute permission. You can also "or" this constant with a file mode to determine if the file owner has execute permission. Syntax: usr_x ------------ B.14.5 grp_r ------------ Irie Pascal defines "grp_r" which is a built-in integer constant. You can use this constant with the "mkdir" procedure to specify that the directory owner's group has read permission. You can also "or" this constant with a file mode to determine if the file owner's group has read permission. Syntax: grp_r ------------ B.14.6 grp_w ------------ Irie Pascal defines "grp_w" which is a built-in integer constant. You can use this constant with the "mkdir" procedure to specify that the directory owner's group has write permission. You can also "or" this constant with a file mode to determine if the file owner's group has write permission. Syntax: grp_w ------------ B.14.7 grp_x ------------ Irie Pascal defines "grp_x" which is a built-in integer constant. You can use this constant with the "mkdir" procedure to specify that the directory owner's group has execute permission. You can also "or" this constant with a file mode to determine if the file owner's group has execute permission. Syntax: grp_x ------------ B.14.8 oth_r ------------ Irie Pascal defines "oth_r" which is a built-in integer constant. You can use this constant with the "mkdir" procedure to specify that (the world) everyone has read permission. You can also "or" this constant with a file mode to determine if (the world) everyone has read permission. Syntax: oth_r ------------ B.14.9 oth_w ------------ Irie Pascal defines "oth_w" which is a built-in integer constant. You can use this constant with the "mkdir" procedure to specify that (the world) everyone has write permission. You can also "or" this constant with a file mode to determine if (the world) everyone has write permission. Syntax: oth_w ------------- B.14.10 oth_x ------------- Irie Pascal defines "oth_x" which is a built-in integer constant. You can use this constant with the "mkdir" procedure to specify that (the world) everyone has execute permission. You can also "or" this constant with a file mode to determine if (the world) everyone has execute permission. Syntax: oth_x --------------- B.14.11 dir_bit --------------- Irie Pascal defines "dir_bit" which is a built-in integer constant. You can "or" this constant with a file mode to determine if the file is a directory. Syntax: dir_bit -------------------- B.14.12 platform_dos -------------------- Irie Pascal defines "platform_dos" which is a built-in integer constant. You can compare this constant with the value returned by the "platform" function to determine if your program is running under dos. -------------------- B.14.13 platform_os2 -------------------- Irie Pascal defines "platform_os2" which is a built-in integer constant. You can compare this constant with the value returned by the "platform" function to determine if your program is running under OS/2. ---------------------- B.14.14 platform_win32 ---------------------- Irie Pascal defines "platform_win32" which is a built-in integer constant. You can compare this constant with the value returned by the "platform" function to determine if your program is running under WIN32. ---------------------- B.14.15 platform_linux ---------------------- Irie Pascal defines "platform_linux" which is a built-in integer constant. You can compare this constant with the value returned by the "platform" function to determine if your program is running under Linux. --------------------- B.14.16 platform_fbsd --------------------- Irie Pascal defines "platform_fbsd" which is a built-in integer constant. You can compare this constant with the value returned by the "platform" function to determine if your program is running under FreeBSD. ---------------------- B.14.17 platform_error ---------------------- Irie Pascal defines "platform_error" which is a built-in integer constant. You can compare this constant with the value returned by the "platform" function to determine if the call to "platform" failed. ------------------ B.14.18 appendmode ------------------ Irie Pascal defines "appendmode" which is a built-in integer constant. You can use this constant with the "open" function to specify that the file should be opened in append mode. ---------------- B.14.19 readmode ---------------- Irie Pascal defines "readmode" which is a built-in integer constant. You can use this constant with the "open" function to specify that the file should be opened for reading (i.e. input). You can combine (with "+" or "or") this constant with "writemode" to specify that the file should be opened for both reading and writing. ----------------- B.14.20 writemode ----------------- Irie Pascal defines "writemode" which is a built-in integer constant. You can use this constant with the "open" function to specify that the file should be opened for writing (i.e. output). You can combine (with "+" or "or") this constant with "readmode" to specify that the file should be opened for both reading and writing. ------------------- B.15 Extended types ------------------- Irie Pascal defines a number of extended types (i.e. built-in types that are not a part of Standard Pascal). ---------- B.15.1 dir ---------- Irie Pascal defines a type identifier called "dir" which is the type of directory variables, which are used in the directory manipulation procedures. See "7.2.6 closedir", "7.2.27 opendir", "7.2.35 readdir", and "7.2.39 rewinddir". --------------- B.15.2 filename --------------- Irie Pascal defines a type identifier called "filename" which is the string type most suitable for variables used to store filenames. Syntax: filename For example to declare a variable to store filenames use var name : filename; NOTE: You can also use string types such as var name : packed array[1..N] of char; or name : string; But I recommend you use "filename" since this type is likely to be the most suitable type for storing filenames. ----------- B.15.3 list ----------- Irie Pascal defines a new keyword "list" in order to provide support for lists. To create a list type use the syntax below. Syntax: [packed] list of Type where "Type" is the type of the components in the list. If you use "packed" then the list is likely to be more efficient in terms of memory but less efficient in terms of speed. You must use "new" to initialize a list variable before you use it. The syntax is: new(list-variable) You can use "dispose" to release the memory used by a list variable after you have finished with it. The syntax is: dispose(list-variable) You can use "insert" to add components to a list variable. You can use "delete" to remove components from a list variable. You can use the "length" function to determine the number of components in a list variable. You can access the components of a list variable just like an array variable. The syntax is lv '[' p ']' where "lv" is the list variable being accessed "p" is the position of the component being accessed For example if "i" is an integer and "lv" is a list variable then the statement below will write each component of "lv". for i := 1 to length(lv) do writeln(lv[i]) ------------- B.15.4 string ------------- Standard Pascal considers packed arrays of char with a lower bound of 1 to be strings. However these are fixed length strings (i.e.. the only text that can be assigned to these strings is text of exactly the same length as the length of the array). Irie Pascal supports variable length strings using a new type "string". For example to create a variable length string type called "name" with a maximum length of 80 use name = string[80]; or name = string(80); To create a variable length string type called "address" with a maximum length of 255 use address = string; or address = string[255]; or address = string(255); The advantage of variable length strings is that any string can be assigned to them, whether fixed or variable length, as long as the length of the string being assigned does not exceed the string's maximum length. Even characters can be assigned to variable length strings. You can use the "+" operator to perform string concatenation. ----------------------- B.16 Extended variables ----------------------- Irie Pascal defines one extended variable (i.e. a built-in variable that is not a part of Standard Pascal). --------------- B.16.1 exitcode --------------- Irie Pascal defines "exitcode" which is a built-in integer variable, whose value is returned to the calling program when your program exits. Syntax: exitcode For example suppose you want to return a value of 1 from your program (perhaps to indicate that your program detected an error) then you can use the following code exitcode := 1; halt; NOTE: You can treat "exitcode" like any other integer variable (i.e. you can assign to it, use it in an expression, pass it as an argument to a function, etc). END