Pascal Macro Compiler Release 1.01
User Manual - August 16, 2005



1. PASCAL MACRO COMPILER



     The Pascal Macro Compiler is a program for generating Pascal language
programs.  The use of the Pascal Macro Language and the Pascal Macro
Compiler can ease and speed the task of writing and maintaining correct and
efficient Pascal programs.

     This manual assumes that the reader is already familiar with the
Pascal programming language and the use of at least one Pascal language
compiler.

     Some current Pascal compilers have rudimentary macro features, such as
the compiler directives $DEFINE, $IFDEF and $ENDIF.  The compiler writers
recognized the need for macro capabilities.  These existing macro features
provide a very limited means for tailoring the compiler output.

     The Pascal Macro Compiler is a full-featured code generator offering
not just the IF construct, but FOR, WHILE and REPEAT constructs, variables,
arrays, strings, types, functions and procedures, type conversion, include
files, a library of compile-time functions, and more.  These powerful macro
features allow the user to generate any desired Pascal code:  expressions,
declarations, statements, procedures, units, or entire software
applications.



TABLE OF CONTENTS


1. PASCAL MACRO COMPILER
  1.1. What is a macro language?
  1.2. Advantages
  1.3. The macro compiler
  1.4. Objectives
  1.5. Language overview
  1.6. Statement overview

2. MACRO LANGUAGE SYNTAX
  2.1. Comments
  2.2. Identifiers
  2.3. Constants
  2.4. Macro Variables
  2.5. Arrays
  2.6. Subscripts
  2.7. Substrings
  2.8. Types
  2.9. Expressions
    2.9.1. Arithmetic expressions
    2.9.2. Boolean expressions
    2.9.3. String expressions
    2.9.4. Code expressions
  2.10. Procedures and functions
    2.10.1. Scope
    2.10.2. Arguments and parameters
    2.10.3. Function return values
    2.10.4. Forward declarations

3. MACRO LANGUAGE EXECUTABLE STATEMENTS
  3.1. Macro assignment statement
    3.1.1. Integer macro variables
    3.1.2. Boolean macro variables
    3.1.3. String macro variables
    3.1.4. Code macro variables
    3.1.5. Type conversion
  3.2. Macro IF statement
  3.3. Macro FOR statement
  3.4. Macro WHILE statement
  3.5. Macro BEGIN and END statements
  3.6. Macro REPEAT and UNTIL statements
  3.7. Macro Procedure Call statement
    3.7.1. Code parameters
    3.7.2. Code variables and function values
  3.8. Macro CONTINUE, BREAK, EXIT and HALT statements
  3.9. Pascal statements
    3.9.1. Generated code
    3.9.2. Terminating code expressions

4. INVOKING THE MACRO COMPILER
  4.1. Macro statement
  4.2. Macro compiler Include files

5. MACRO COMPILER DIRECTIVES
  5.1. %I Include directive
  5.2. %LL Line length directive

6. COMPILER LIMITS

7. MACRO COMPILER LIBRARY
  7.1. Integer functions
    7.1.1. _Abs
    7.1.2. _Even
    7.1.3. _Max
    7.1.4. _Min
    7.1.5. _Odd
    7.1.6. _Sqr
    7.1.7. _Sqrt
  7.2. Character functions
  7.3. String functions
    7.3.1. _Caps
    7.3.2. _Clean
    7.3.3. _Delete
    7.3.4. _Insert
    7.3.5. _Length
    7.3.6. _LoCase
    7.3.7. _Pad
    7.3.8. _Pos
    7.3.9. _Subst
    7.3.10. _UpCase
  7.4. Random numbers
    7.4.1. _Random
    7.4.2. _Randomize
    7.4.3. _RandSet
  7.5. Output functions
    7.5.1. _Col
    7.5.2. _Line

8. PROGRAMMING NOTES

Appendix A. DOS BASICS
  A.1. Starting DOS
  A.2. Sizing the DOS window
  A.3. Directories
  A.4. Current directory
  A.5. Working with directories
  A.6. Identifying files
  A.7. File operations



1.1. What is a macro language?


     A macro language is a high-level language that can be used to generate
code in a lower-level language.  An ordinary compiler takes statements in
some high-level language such as Pascal or Fortran and compiles them into
the low-level machine language.  A macro compiler takes statements in its
macro language and compiles them into statements in a target language such
as Pascal or Fortran.

    An ordinary compiler deals with values, such as numbers or character
strings.  A macro compiler deals with values and also with elements of the
target language.  That is, a macro compiler can take elements of the target
language and generate expressions, statements, functions, and even entire
programs in the target language.



1.2. Advantages


    The Pascal Macro Compiler can help achieve many goals.  It can speed up
the process of writing a program by requiring fewer statements, and
possibly shorter statements.  It can make the generated program easier to
read and maintain by working at a higher level.  It can make the generated
program more efficient by eliminating many function and procedure calls.

    The macro compiler can aid in creating multiple versions of Pascal
procedures and functions.  For example, the strong typing in Pascal makes
it difficult to write a general-purpose sort program that will work with
any type of array.  The macro language makes it easy to create a specific
sort program for each type of array that needs sorting from a general model
of a sort procedure.  (A model sort generator is distributed with the
Pascal Macro Compiler.)

    The macro compiler can be used to initialize complex data structures.
The code used to initialize the structures will be executed during the
macro compilation, and therefore need not be a part of the executable
program.  For example, if a chess-playing program needed a table giving all
of the possible moves for each type of chess piece from each square on the
chessboard, the macro compiler could create this table during the macro
compilation.  This could speed up the chess-playing program since it would
no longer need to test whether a prospective move went past the edge of the
board.

    The macro compiler can speed up the execution of a program by using
in-line code in place of selected procedure and function calls, or by
unrolling chosen loops.  It can eliminate the need for some run-time
procedures by doing the calculations at compile time.

     The macro compiler can make it easier to create multiple versions of a
program.  For example, suppose a program needed messages, menus and user
inputs in English, French, Spanish and German.	The macro compiler could
easily create four separate versions, instead of having one version that
contained all four sets of messages and screens, and repeatedly had to
select among them.  Similarly, the macro compiler could create separate
versions of a program for Windows, Unix and Macintosh environments.  When a
change is needed in the program, it can be made just once in the macro
source, and all of the versions will change simultaneously.

     The macro compiler can make it easier to work with different Pascal
compilers, which may have differing features, or use different keywords for
the same purpose.  For example, a project may use one Pascal compiler for
Windows, and a different one for Unix or Linux platforms.  Or, a program
library might be written for use by many organizations that use diverse
Pascal compilers.  The macro compiler can make it possible to have just one
set of source code for all of the different compilers.

     The macro compiler can avoid repetition of complicated expressions.
For example, the mathematical expression for the determinant of a 4x4
matrix contains 24 terms with a total of 96 factors.  This expression could
be written just once in the macro compiler, which would then generate the
correct expression for each matrix in the Pascal program.

     The macro compiler can support mapping of names.  For example, if
several procedures were written using the same data structure, but using
different names for its components, the macro language can be used to
generate the correct field names for each procedure.  This makes it easier
to integrate programs written by different software groups.

     The macro compiler can be used to personalize the syntax of Pascal
programs.  For example, if you would prefer to say

     STEP x FROM 1 UPTO 100 START

or, perhaps

     FUR x := 1 BIS 100 TUN

instead of

     FOR x := 1 TO 100 DO

this is easy to accomplish using the macro compiler.



1.3. The macro compiler


     The Pascal Macro Compiler is a program that converts Pascal macro
source code into Pascal language code.	The Pascal Macro Compiler operates
as a separate phase prior to the Pascal language compiler.  It reads the
macro language source code from a macro source file and writes the
resulting Pascal language statements to a Pascal source file.

     The Pascal macro compiler is not integrated into any particular Pascal
language compiler.  It can be used with any Pascal language compiler.  A
large organization might use different Pascal language compilers for
different projects, but might use the same Pascal Macro Compiler with all
of them.

     The Pascal Macro Compiler can be used with some of the Pascal language
files in a project, but not others, as desired.  There is no need to
convert older Pascal language programs in order to use the macro compiler.
The macro compiler could be used for newer components of a project, leaving
the older parts unchanged.  (However, when desired, conversion of an older
program is easy.  Simply insert

     %Macro name; %Begin

at the start of the file, and place

     %End.

at the end.)

     The output of the macro compiler can be an entire Pascal program, or
it can be some smaller piece, such as a single function or procedure, a
data structure, or simply any sequence of Pascal language statements.  The
pieces can be collected to form the entire Pascal program by using the
Pascal include directive, {$I filename}.



1.4. Objectives


     The Pascal Macro Compiler handles two types of statements, macro
statements and Pascal language statements.  Pascal language statements are
the statements of the Pascal language, such as variable declarations,
assignment statements, conditional statements, looping statements,
procedure and function definitions, and so forth.  These are the statements
that are compiled into machine language for execution.	(In some older
Pascal compilers they were compiled into token strings for interpretation.)

     The macro statements are statements in the Pascal Macro Language that
will be compiled by the Pascal Macro Compiler into Pascal language
statements.  The Pascal Macro Language was designed with the following
objectives.

     (1) Macro statements should have a syntax that is as close to the
syntax of Pascal statements as possible.

     (2) No special character should be required to distinguish variable
names or other identifiers in the macro language from identifiers in
Pascal.

     (3) Macro statements and Pascal statements should be allowed to mix
freely.  It should not be necessary to isolate the macro source code from
the Pascal source code in separate files or in separate blocks or sections
of the source file.

     (4) It should not be necessary to use a command, such as
emit(thiscode), to cause the macro compiler to produce a piece of code.

     (5) Existing Pascal programs should not require any extensive
rewriting in order to convert them for using the macro compiler.

     (6) If the user desires, it should be possible to produce
natural-looking Pascal code, with natural line feeds, indentations, use of
blanks and comments, as though the code had been written by a person.

     To meet these goals, the following rules have been adopted for the
macro language.

     (1) The Pascal Macro Language will use a subset of the statement types
used in the Pascal language.  Only one new statement type, macro, and one
new data type, code, have been added.

     (2) Identifiers in the macro language have the same syntax as
identifiers in the Pascal language.  However, the macro compiler uses the
convention that library functions in the macro language begin with an
underscore _ to distinguish them from the corresponding library functions
in Pascal, for example _length and length.

     (3) In the body of the main macro program, or in the body of any macro
function or procedure, Pascal language statements can be mixed freely with
the executable macro language statements.  The Pascal statements can be of
any type; they are not restricted to executable statements.

     (4) There is no Emit function, nor any equivalent function.  To
produce a piece of Pascal code, you simply write that code in the macro
program.

     (5) An existing Pascal program requires little conversion to use the
macro compiler.  All that is needed is to place

     %macro programname; %begin

at the start of the file, and

     %end.

at the end of the file.

      (6) The Pascal Macro Compiler preserves line feeds, indentations,
comments and other features of the Pascal statements so that it is possible
to produce natural-looking code.  This is useful for debugging macros,
displaying the resulting Pascal program for publication, or for using the
resulting Pascal code as the source code for a project.  The macro language
also has library functions _line and _col to skip lines and to generate
code in the desired columns.



1.5. Language overview


     A Pascal Macro Language file takes the same form as a Pascal program
file.  There are macro variable declarations, macro functions and
procedures, and a main body of macro language statements enclosed within a
%Begin-%End block.  The overall structure of a macro program is

     %macro programname;
       macro variable declarations
       macro procedure and function declarations
     %begin
       Pascal statements and executable macro statements
     %end.



1.6. Statement overview


     Macro statements are preceded by the macro character %.  The following
statement types are defined for the Pascal Macro Language.  A simple
example is provided for each type of statement.

Macro	    begins the outermost macro procedure
End.	    ends the outermost macro procedure
	      %Macro macname;
		declarations
	      %Begin
		main body of macro procedure
	      %End.
Var	    defines macro variables.
	      %Var  x: integer;
Procedure   starts a macro procedure.
	      %Procedure s (x: integer); ...
Function    starts a macro function.
	      %Function f (x: integer): boolean; ...
Assignment  assigns a value to a macro variable.
	      %x := y + z;
If	    starts an If conditional statement.
	      %If  x=0	then  A  else  B;
For	    starts a For loop.
	      %For  n := 1 to 10  do
While	    starts a While loop.
	      %While  t > 0  do
Repeat	    starts a Repeat loop.
Until	    ends a Repeat loop.
	      %Repeat  A  %until  B;
Begin	    starts a block of code.
End	    ends a block of code.
	      %Begin  %x:=y;  p:=p+1;  %End;
Pascal	    generates Pascal code
	      circum := diameter * 3.14159;

Notice that macro statements always begin with the macro character % while
Pascal statements never begin with %.  In the %Begin-%End example above,
the statement p:=p+1; is a Pascal statement.



2. MACRO LANGUAGE SYNTAX



     This chapter describes the syntax of the macro language.  The macro
language has been designed to be as close to the Pascal language as
possible.  However, they are still two distinct programming languages, and
differences should be expected and noted.

     The macro language contains only a subset of the features of the
Pascal language.  It is important to recognize that this does not in any
way restrict the Pascal code that can be generated.  For example, the macro
language does not include any real or floating point data types, but the
generated code may use these data types freely.



2.1. Comments


     Comments may be used in the macro language source file anywhere that a
blank can be used.  Comments may be enclosed in { } braces, or between
(* and *).  For example, these are valid comments

     {Here is a comment}
     (* Here is another *)

The Macro Compiler also supports comments in the style of the Ada
programming language.  These comments begin with -- and are terminated by
the end of the line.  Here is an example

    %repeat		-- Start the main loop
      %FindNext;	-- Find the next item



2.2. Identifiers


     Identifiers are used in the macro language for the names of language
keywords, variables, data arrays, procedures, functions, and similar
purposes.  An identifer may consist of 1 to 255 letters, digits and
underscores.  The first character in an identifier must be a letter.  Both
upper and lower case letters may be used.  Some examples of valid
identifers are

     n	       K41___c_ 	    Procedure
     X2        FederalIncomeTax     ErrorSTOP_16
     index     stack_Limit	    SquareRoot

     No distinction is made between upper and lower case letters.  Thus
index, Index and INDEX are equivalent, and may be used interchangeably.  It
is a common practice to capitalize the first letter of each word when an
identifier is a multiword phrase, for example MessageCode or EndOfFile.

     Pascal language keywords and macro language keywords such as
Procedure, While and Div are reserved for the compilers and should not be
used as names of variables, functions, etc.



2.3. Constants


     The Pascal macro language has three types of constants, integer
constants, boolean constants and string constants.  Integer constants are
represented as strings of decimal digits with optional + or - signs.
Integer constants may be in the range -2,147,483,648 to +2,147,483,647.
Boolean constants are represented as true or false.  All of the following
are valid integer or boolean constants

     0	 -12   51894   +1312958374   true   False

     String constants may be represented as quoted strings of 0 to 255
characters, such as

     'This is a string constant'

or #n where n is an integer from 0 to 255.  The constant #n is a string
constant of length 1.  For example, #65 is equivalent to 'A'.  The starting
and ending quote marks are not part of the string, and do not count in its
length.  Thus 'ABC' has length 3, and '' has length 0.  The string '' is
called the empty string.  A string constant can be written as a
concatenation of quoted strings and #nn character codes, for example

     #91 'count' #93

which is equivalent to '[count]'.

     A quote mark can be represented in a quoted string by two quotes, for
example

     'Cap''n Kidd''s ship isn''t coming'

     A quoted string must be contained on a single line in the macro
program.  This is a safety feature of the Pascal Macro Compiler.  It helps
to prevent unpaired and mispaired quotes, which otherwise may be difficult
to diagnose, since the resulting error message could refer to a point in
the program several lines past the actual error.

     If a string constant is longer than one line, it can be broken into as
many pieces as needed, with each piece enclosed in quote marks on its own
line.

     %bigstring := 'This is a really long string that needs to '
		   'be split into several separate lines in the '
		   'macro source file.';



2.4. Macro Variables


     Macro variables are used to hold values during the macro compilation.
These values may be changed by assigning new values to the variables.
Variables may be tested using conditional statements such as If and While.
Macro variables must be declared before they can be used.  They are
declared using the macro Var statement.  The format is

     %Var declarationlist

The declaration list consists of one or more declarations, each followed by
a semicolon, like this

     declaration; declaration; declaration;

Each declaration consists of one or more variable names separated by
commas, a colon, and then the variable type.

     variable: type;
     variable, variable: type;
     variable, variable, variable: type;

The valid types are integer, boolean, string and code.  For example,

     %var  a,b,rate,time: integer;
	   done, error: boolean;
	   header:string;
	   Name_1, Name_2 : string[16];
	   ProgSeg: code;

     For string variables, a length may be specified in brackets, for
example ModelName[24] indicates that the model name may be up to 24
characters.  The length may be any unsigned integer value from 1 to 255.
If no length is given, the default length is 255 characters.

     The macro compiler checks that each macro variable name is not one of
the macro language reserved keywords, namely AND, BEGIN, CASE, DIV, DO,
DOWNTO, ELSE, END, FALSE, FUNCTION, IF, MOD, NOT, OR, PROCEDURE, REPEAT,
SHL, SHR, THEN, TO, TRUE, UNTIL, VAR, WHILE, XOR. It is generally unsafe to
give a macro variable the same name as a Pascal language keyword, or a
variable in the generated Pascal code.	The macro compiler does not make
this check, however, as reserved keywords vary among different compilers,
and release versions of those compilers.

     For a general-purpose macro file that will be used in several
different programs or projects, it may be advisable to use some special
prefix or suffix that will distinguish the macro variables from Pascal
variables, procedure names, type names, etc.  For example, macro variables
in a macro function called MyMac might be named like this:

     mymac_index, mymac_length, mymac_filename

     Macro variable declarations cannot be made inside a %Begin-%End block.
They may, however, appear between outer procedure and function
declarations, or after procedure and function declarations, but before the
main program logic.

     Macro variable declarations made inside a macro procedure or function
are local to that procedure or function.  All other macro variables are
global to the entire file, starting from the point where they are declared
until the end of the file.  Macro variable declarations made inside a macro
procedure or function must appear between the procedure header and the
%Begin statement.



2.5. Arrays


     The macro compiler supports arrays of variables.  The format for
declaring an array is

     %Var  variables: array[low..high] of type;

Here variables means one or more macro variable names separated by commas,
low and high are integer constants specifying the lower and upper bounds of
the array, and type is any one of the four macro variable types, integer,
boolean, string or code.  The lower bound must be less than or equal to the
upper bound.  The types string and code may have lengths specified.

     An array may have any number of dimensions, as

     %Var  name1: array[Lo1..Hi1] of type;
	   name2: array[Lo1..Hi1,Lo2..Hi2] of type;
	   name3: array[Lo1..Hi1,Lo2..Hi2,Lo3..Hi3] of type;
	   etc.

Some examples of array declarations are

     %var
	length, width, height: array[1..100] of integer;
	months: array[1..12] of string[9];
	bitstring: array[0..63] of boolean;
	stellar:  array[-1..1,-1..1,-1..1, 1..16] of boolean;



2.6. Subscripts


     An element in an array can be specified by using subscripts.  The
format is

     arrayname[sub1]
     arrayname[sub1,sub2]
     arrayname[sub1,sub2,sub3]
     etc.

where arrayname is the name of the array, and the subscripts sub1, sub2,
sub3, etc. are integer expressions.  The value of each subscript must be
between the lower and upper bounds for the corresponding dimension of the
array.	For example, if the array is declared

     %var  bonus: array[1..4,0..31] of boolean;

and the macro program contains a reference to this array

     bonus[mm,nn]

then mm must be between 1 and 4, and nn must be between 0 and 31,
inclusive.

     Each array element is a variable of the array type.  For example an
element of an integer array is an integer variable, and may be used any
place that an integer variable is allowed, for instance as a loop variable,
like

     %for  ix[3] := 1 to 100  do

     When an array has more than one dimension, using some of the
subscripts can produce an array of fewer dimensions.  For example,

     %Var
	matrix: array[1..16,1..32] of integer;
	tensor: array[1..8,1..16,1..32] of integer;
     %matrix := tensor[i];

is a valid assignment that transfers a 16x32 block of integers.

     The Pascal Macro Compiler also supports the use of multiple subscripts
for arrays with more than one dimension, such as

     arr[i][j]

This is exactly equivalent to

     arr[i,j]



2.7. Substrings


     Characters in a string variable can be selected by using a substring.
The format is

     stringvar[charpos]

to specify a single character in the string at the position charpos, or

     stringvar[first..last]

to specify a range of characters, from the position first through the
position last.  Here stringvar is a macro variable of type string, and
charpos, first and last are integer expressions.  The value of charpos must
be between 1 and the string length, the value of first must be between 1
and the string length, and the value of last must be between first-1 and
the string length.

     When last=first-1 the substring denotes the empty string.  This can be
useful when for making insertions into a string without replacing any of
the existing characters.  For example

     %string1[1:0] := newstuff;

would insert newstuff at the start of string1, leaving the rest of string1
unchanged.

     Characters within an array of strings can be specified by giving the
array subscript(s) and then the substring within that array element.  For
example

     stringarray1[sub,charpos]
     stringarray2[sub1,sub2,first..last]

It is also permissible to specify the subscripts and substrings separately.
The two array references above are equivalent to

     stringarray1[sub][charpos]
     stringarray2[sub1,sub2][first..last]



2.8. Types


     A data type or structure type may be given a name.  These names may
then be used as types for variables and parameters.  Type names are
declared using the macro Type statement, which has the format

     %Type  typelist

where typelist consists of one or more type declarations followed by
semicolons, for example

     typedeclaration; typedeclaration; typedeclaration;

Each type declaration has the form

     typename = datatype

The type name is any unique identifier, and the data type may be a simple
data type (integer, boolean, string or code), a user-defined data type, or
an array of such data types.  The following is a valid type statement

     %Type
	size = integer;
	switch = boolean;
	name = string[24];
	progseg = code;
	list = array[1..100] of size;
	names = array[1..64] of name;
	matrix = array[1..100] of list;



2.9. Expressions


     The Pascal Macro Compiler provides 4 types of expressions, arithmetic
expressions, boolean expressions, string expressions and code expressions.


2.9.1. Arithmetic expressions

     Arithmetic expressions are formed from integer variables, integer
constants and integer functions using the operators

     +	  Addition
     -	  Subtraction
     *	  Multiplication
     div  Integer division (the result is truncated towards 0)
     mod  Modulus (or remainder)
     shl  Shift left
     shr  Shift right

Here are some examples

     3 + 5	is  8
     10 - 3	is  7
     5 * 7	is  35
     20 div 3	is  6
     23 mod 5	is  3
     5 shl 3	is  40
     100 shr 2	is  25

     Arithmetic expressions are evaluated by first performing the
multiplicative operations

     * div mod shl shr

left to right, then performing the additive operations

     + -

left to right.


2.9.2. Boolean expressions

     Boolean expressions, also known as logical expressions, are formed
from boolean variables, boolean constants, boolean functions and
comparisons using the boolean operators

     not  Unary not
     and  Boolean and
     or   Boolean or
     xor  Exclusive-or

Boolean expressions are evaluated by applying all NOT operators first, then
all AND operators, then OR and XOR operators left to right.

     The macro compiler also supports boolean operations on integer
variables.  In this case, the boolean operation is performed bitwise on the
32 bits of the integer operands.  The result of the operation is an
integer.

     Comparisons are formed from two integer expressions, two boolean
expressions, or two string expressions using the comparison operators

     =	 Equal
     <>  Unequal
     <	 Less than
     >	 Greater than
     <=  Less than or equal
     >=  Greater than or equal

The result of a comparison is a boolean value.	For example, the result of
the comparison

     3 + 4 = 6

would be the boolean value false.

     Boolean values may be compared using only the = and <> operators.	For
example, x=y will be true if x and y are both true or both false.

     In arithmetic and boolean expressions parentheses may be used to
change the order of operations.  The inner expression, inside the
parentheses, is evaluated first, before the outer expression is evaluated.
For example,

     3 - 4 + 5	   would produce   4
     (3 - 4) + 5   would produce   4
     3 - (4 + 5)   would produce   -6
     3 + 4 * 5	   would produce   23
     (3 + 4) * 5   would produce   35.

     true or false and false	 would produce	 true
     true or (false and false)	 would produce	 true
     (true or false) and false	 would produce	 false


2.9.3. String expressions

     String expressions are formed from string constants, string variables
and string functions either by writing the terms in succession, or by using
the string concatenation operator +.  The terms in a string expression will
be concatenated from left to right.  For example, the string expressions

     'Hello'   ', '   'world!'
 or
     'Hello' + ', ' + 'world!'

would produce the string

     'Hello, world!'

     Blanks, control characters and comments before, between and after the
terms in a string expression are ignored.  For example,

     'Today is ' DayName[day] ', '   {Day of the week}
     Month[mon] ' ' IntStr[date]     {Month and day}

might produce

     'Today is Friday, July 10'

     When a string expression is used in an assignment statement, or is
used as a parameter of a macro function or procedure, any string variables
or string functions in the string expression are evaluated.  The result of
evaluating a string expression must be a string of 0 to 255 characters.


2.9.4. Code expressions

     Code expressions are formed from macro variables, macro functions and
Pascal language elements such as variables, keywords and operators.  The
terms in a code expression are written in succession, or the % operator may
be used to indicate concatenation.  If the terms are written in succession,
then any blanks between the terms are part of the expression.  If the %
concatenation operator is used, then the blanks are omitted.

     For example, suppose that aa is a code variable that currently
contains Count and bb is an integer variable that currently contains 2.
Then

     aabb	 would produce	   aabb
     aa bb	 would produce	   Count 2
     aa   bb	 would produce	   Count   2
     aa%bb	 would produce	   Count2
     aa % bb	 would produce	   Count2
     aa+bb	 would produce	   Count+2

     Macro variables and macro functions of all types may be used in code
expressions.  When the code expression is evaluated, they will be converted
into their character representations.  For example, an integer variable
containing the integer 2 would be converted into the character 2, as in the
previous example.  Macro variables used in code expressions may have
subscripts and substrings.

     Macro variables and macro functions are not evaluated when they appear
in code expressions in assignment statements, or as parameters to macro
functions or procedures.  Macro variables and macro functions are evaluated
only when they appear in Pascal statements.



2.10. Procedures and functions


     Macro procedures and functions are defined in the declaration section
of a macro program.  That is, they are placed following the %Macro
statement, but before the %Begin statement for the main body of the
program.  Procedure and function declarations can be freely mixed with
variable declarations.

     The general format of a procedure or function declaration is

     header
       declarations
     %begin
       body
     %end;

A procedure or function header may have any of these forms

     %Procedure  pname;
     %Procedure  pname (parameters);
     %Function	fname: ftype;
     %Function	fname (parameters): ftype;

     The procedure or function name, pname or fname, may be any identifier
that is not a macro compiler reserved keyword.	For example, Review,
check_stat, and OverSize are valid names.  The function type, ftype, may be
integer, boolean, string or code.

     The parameter list consists of one or more parameter names with their
types.	For example,

     parm1: type1
     parm1: type1; parm2: type2
     parm1: type1; parm2: type2; parm3: type3
       etc.

When two or more consecutive parameters have the same type, they may be
combined by separating the parameter names with commas.  For example,

     parm1,parm2: type1; parm3,parm4,parm5: type2; parm6: type3

     Parameter names may be any identifier except macro compiler reserved
keywords.  The parameter types may be any of the four variable types,
integer, boolean, string or code, or any type defined by the user with a
Type declaration.  For example,

     %Procedure Power (height, length, width: integer;
		       mass, force, time: integer;
		       Uname, Cname: string;
		       power_formula: code;
		       torsion: tensor);

Note that the length of a string parameter cannot be specified.  The length
is always the default length of 255 characters.

     The declaration section of a procedure or function definition can
contain declarations for any variables, types, procedures or functions that
it may use.  The format is the same as for the declaration section of the
main macro program.  The declared variables, types, procedures and
functions are internal to the procedure or function where they are
declared.  That is, they are not known and cannot be used outside of that
procedure or function.	They may be used in any statements in the body of
the procedure or function.  The procedure or function that contains these
declarations is called the outer procedure or function.


2.10.1. Scope

     The body of a procedure or function consists of one or more executable
statements or Pascal statements.  These may contain references to its
parameters, variables and internal procedures and functions, as well as
those of any outer procedures or functions.

     For example, if procedure A contains procedure B and function C, then
procedure A may refer to its own parameters and variables, and it may call
procedure B and function C.  However, procedure A cannot refer to the
parameters or internal variables of procedure B or function C.

     Procedure B may refer to its own parameters and variables, as well as
the parameters and variables of procedure A, and it may call procedure A
and function C.  However, procedure B cannot refer to the parameters or
internal variables of function C.

     Function C may refer to its own parameters and variables, as well as
the parameters and variables of procedure A, and it may call procedure A
and procedure B.  However, function C cannot refer to the parameters or
internal variables of procedure B.


2.10.2. Arguments and parameters

     When a procedure or function is called, the values for each of its
parameters must be given.  These values are called the arguments of the
procedure or function call.  Each argument may be given as an expression of
the same type as the corresponding parameter.  For example, if the first
parameter has type integer, then the first argument in the call must be an
integer expression.  If the second parameter had type string, then the
second argument must be a string expression.  And so forth.  Here is an
example of a procedure header and a corresponding call

     %procedure warn (custno: integer; custname,action: string);

     %warn (curr-1, first last, ' will be deleted');

     Each time the procedure or function is called, each parameter is set
to the value of the corresponding argument.  The effect is the same as if
the parameter were set to the argument value by an assignment statement.
For example, if function Volume had the header

     %function Volume (length, width, height: integer): integer;

then a valid call to Volume could be

     %newvol := Volume (len, wid+2, ht+4);

When this call to the Volume function is executed, length will be set to
len, width will be set to wid+2, and height will be set to ht+4, just as
though there had been 3 assignment statements

     %length := len;
     %width := wid+2;
     %height := ht+4;

Within the Volume function an assignment to length can change the value of
length, but will not affect the value of len in the calling procedure.


2.10.3. Function return values

     The basic difference between a procedure and a function is that a
function returns a value to the calling procedure.  This value may be used
in expressions in the calling procedure, as illustrated above.	Within the
body of the function the return value may be set by making an assignment to
the function name.  For example, the function Volume could be defined as

     %function Volume (length, width, height: integer): integer;
     %begin
       %Vol := length * width * height;
     %end;

In the call above, if len, wid and ht all had the value 1, then length,
width and height would all be set to the values 1, 3 and 5, respectively.
Volume would return the value 15, so newvol would be set to 15;

     In the Pascal Macro Language the function value may be used in
expressions within the function body in the same way that any ordinary
variable would be used.  For example, if volume is an integer function, the
following would be valid

     %if  double
	  then	%volume := volume * 2;

The use of the function name, without a function parameter list, does not
cause a recursive call to the function.  Rather, the function name volume
in the expression volume*2 is treated as an ordinary variable.  The value
of volume will be the last value assigned to it in an assignment statement.

     Note, however, that this feature prevents a function that has no
parameters from calling itself recursively.


2.10.4. Forward declarations

     The Pascal Macro Compiler allows functions and procedures to call one
another recursively.  Normally a procedure or function can call only
procedures or functions that have previously been declared, because it is
necessary for the compiler to check the parameters on each call.  When two
or more functions or procedures call each other, there is a problem about
which one to declare first.  Each one needs all the others to come before.

     The Pascal Macro Compiler solves this problem by allowing forward
declarations.  This technique splits the declaration of a function or
procedure into two parts, one part defining the parameters and return
value, and the other part containing all of the declarations and executable
statements.  In the parameter declaration, instead of declarations and the
%Begin-%End block, the keyword forward is used to indicate that the other
parts will be declared later.  For example,

     %Procedure Sample (m,n: integer); forward;
     %Function AnyFunc: integer; forward;

     (other procedure and function declarations)

     %Procedure Sample;
	(declaration section of Sample)
     %Begin
	(executable section of Sample)
	(may include calls to AnyFunc)
     %End;

     %Function AnyFunc;
	(declaration section of AnyFunc)
     %Begin
	(executable section of AnyFunc)
	(may include calls to Sample)
     %End;

Note that the keyword forward does not take a % sign, and that the
declaration for the executable portion of the procedure or function does
not have a parameter list.  In this example, the second parts of the
declarations for Sample and AnyFunc could be given in either order.



3. MACRO LANGUAGE EXECUTABLE STATEMENTS



     The Pascal Macro Language has the following statements and control
structures.

     assignment      Causes a variable to be set to a given value.
     if-then-else    Causes a statement or block to be executed
		     if a condition is true.
     for	     Causes a statement or block to be executed a
		     number of times.
     while	     Causes a statement or block to be executed
		     repeatedly while a condition remains true.
     repeat-until    Causes a block of statements to be executed
		     repeatedly until a condition becomes true.
     begin-end	     Bounds a block of statements.
     procedure call  Causes a procedure to be executed.
     continue	     Skips to the end of a block.
     break	     Leaves a block.
     exit	     Leaves a procedure or function.
     halt	     Leaves the program.
     pascal	     Generates Pascal code.



3.1. Macro assignment statement


     The macro assignment statement has the format

     %variable := expression;

The variable on the left is called the receiver, and the expression on the
right is called the value, or the source expression.  The effect of the
assignment is to evaluate the source expression and store this value in the
receiver location.  If the receiver is an element of an array or a string
variable, then subscript and substring notation may be used to indicate
where in the receiver string the value will be stored.	For example

     %var  namelist: array[1..20] of string[8];
     %namelist[n,1..2] := 'Mc';

     There are four types of macro variables, integer, boolean, string and
code.  The type of the receiver variable determines whether an assignment
to that variable is evaluated immediately, or evaluated later.	Assignments
to integer, boolean and string macro variables are evaluated immediately.
Assignments to code macro variables are not evaluated until the code
variable is used in a Pascal statement, or passed back from a function of
type code.


3.1.1. Integer macro variables

     Integer macro variables are always 32-bit signed integers in the range
-2,147,483,648 to +2,147,483,647.

     When an assignment is made to an integer macro variable, the right
side of the assignment must be an arithmetic expression whose terms are all
integer constants or macro variables of type integer.  The expression is
evaluated immediately, and the value is assigned to the receiver.  Valid
arithmetic operations are

     + - * div mod shl shr

Division is integer division, so that 20 div 3 would be evaluated as 6.
Mod indicates the modulus or remainder operation.  For example, 20 mod 3
would be evaluated as 2.  The shift operations shl and shr, shift left and
shift right, respectively double or halve the the value of the left operand
for each position shifted.  Thus x shl 1 is the same as x*2, x shl 2 is the
same as x*4, x shl 3 is x*8, etc.	Similarly x shr 1 is x div 2, x shr 2 is
x div 4, etc.  Parentheses may be used to group operations.

     The operations *, div, mod, shl, and shr are performed first, left to
right, and then the operations + and - are performed left to right on the
resulting values.  In the expression 2+4*5 div 6-7+8 the term 4*5 div 6
would be evaluated first as (4*5) div 6 which has the value 3.  Then the
expression 2+3-7+8 would be evaluated left to right giving the value 6.


3.1.2. Boolean macro variables

     Boolean macro variables can take the values TRUE and FALSE.

     When an assignment is made to a boolean macro variable, the right side
of the assignment must be a boolean expression whose terms are all boolean
constants, macro variables of type boolean, or comparison expressions.

     The expression is evaluated immediately, and the value is assigned to
the receiver.  Valid boolean operations are

     and or xor not

The not operation is a unary operation and has highest precedence.  That
is, it is performed first.  The and operations are then performed, and
finally or and xor operations are performed left to right.  Parentheses may
be used to group operations.  The expression

     a or b and not c xor d

would be evaluated as

     (a or (b and (not c))) xor d


3.1.3. String macro variables

     String macro variables take the value of strings of 0 to 255
characters.  If no length is specified when the string variable is
declared, the default length is 255 characters.

     When an assignment is made to a string macro variable, the right side
of the assignment must be a string expression whose terms are all string
constants and macro variables or macro functions of type string.  The
expression is evaluated immediately, and the value is assigned to the
receiver.  If the string is longer than the receiver, it is truncated to
fit.

     There are two string operations, concatenation and substring.
Concatenation is indicated either by the + string operator, or by simply
writing two or more string constants, string variables or string functions
in sequence with one or more blanks separating them.  For example the
following is a valid string assignment

     %result := 'Start' able+baker 'Finish';

where result is a macro string variable, and able and baker are either
macro string variables or macro string functions.  Note that if start and
finish happen to be the names of macro variables, their values will not be
substituted into the quoted strings.  For example

     %able := #91 'first';
     %baker := ',' 'last' #93;
     %start := 'Begin';
     %result := 'Start' able + baker 'Finish';

would cause result to have the value

     'Start[first,last]Finish'

     A substring is indicated by giving the range of characters within the
string in brackets

     stringvar[first..last]

where stringvar is a macro variable of type string, first is the first
character position in the substring and last is the last character position
in the substring.  The values first and last are integer expressions.  For
example if alpha is a macro string variable with the value 'ABCDEFGHIJ'
then alpha[3..5] is 'CDE'.  If a single character in the string is wanted,
only first needs to be specified.  Thus name[5] is the same as name[5..5].

     If the length of a string expression is different from the length of
the receiving substring in an assignment statement, the receiver is
shortened or lengthened accordingly.  For example,

     %string1 := 'ABCDEFGHIJ';
     %string2 := 'ABCDEFGHIJ';
     %string1[4..6] := 'z';
     %string2[4..6] := 'zebra';

results in string1 containing 'ABCzGHIJ' and string2 containing
'ABCzebraGHIJ'.

     The substring operations are performed first and then the
concatenation operations are performed left to right on the resulting
values.  Thus

     %able := 'abcdeghij';
     %baker := '123456789';
     %result := able baker[4..6];

would cause result to contain 'abcdefghij456'.

     The last character position in a string can be indicated in a
substring by the * operator.  Thus the string assignment

     %mystring := mystring[2..*];

would cause the first character of mystring to be deleted.  The expression
mystring[*] would be the last character in mystring.


3.1.4. Code macro variables

     Code macro variables take the value of code expressions.  A code
expression may be any sequence of macro variables, macro functions and
Pascal language elements.  The expression is terminated by the first
semicolon which is not contained within comment braces { } or within a
quoted string ' '.  The semicolon is not part of the expression.  Every
character, starting with the first non-blank character after the assignment
operator := up to, but not including the closing semicolon, is part of the
code value, including all blanks, tabs, carriage returns, comments, macro
variables, macro functions, and Pascal language elements.

     The expression assigned to a code variable is not evaluated at the
time of the assignment.  Rather the expression is evaluated later, when the
code variable appears in a Pascal statement in the macro program, or in the
value of a code function.  When a code variable appears in a Pascal
statement or code function value all of its macro variables and macro
function references are replaced by their current values.  If these contain
any macro variables or functions, those are also replaced by their current
values until all macro references have been resolved.  For example, the
macro statements

     %bump := name := name * 1.5   {Increase 50%};
     %name := xlength;
     bump;
     %name := ywidth;
     bump;

would generate the Pascal code

     xlength := xlength * 1.5	{Increase 50%};
     ywidth := ywidth * 1.5   {Increase 50%};

Similarly,

     %sizetest := if  rangecheck  then	goodsize;
     %rangecheck := heightcheck and widthcheck;
     %goodsize := writeln ('The size is valid');
     %heightcheck := ((height > 0) and (height <= maxheight));
     %widthcheck := ((width > 0) and (width <= maxwidth));
     sizetest;

would generate

     if  ((height > 0) and (height <= maxheight)) and
	 ((width > 0) and (width <= maxwidth))
	 then  writeln ('The size is valid');

Notice that rangecheck and goodsize were not yet set when sizetest was set.

     Care must be taken to avoid an infinite recursion when expanding a
code variable.	For example, if index is a code variable then the
statements

     %index := index+1;
     n := index;

would give n := index+1; which gives n := index+1+1; which gives
n := index+1+1+1;  ad infinitum.

     If it is necessary to concatenate two elements in a code expression,
with no blank separating them, the % operator can be used to specify
concatenation.	For example,

     %copy := copy_record(old_%name,new_%name);
     %name := Customer;
     copy;

would produce the Pascal code

     copy_record(old_Customer,new_Customer);


3.1.5. Type conversion

     Values can be converted from any variable type to any other variable
type by using an explicit conversion assignment.  The syntax is

     %macvar := %type expression;

Here macvar is a macro variable which will contain the converted value,
type is any of the four macro variable types, integer, boolean, string or
code, and expression gives the value to be converted.  The type specified
must be the type of the expression.  For example, if UnitID is a string
variable, then

     %UnitID := %integer 21934;

would set UnitID to the string value '21934'.

     The expression must contain a value which can be converted to the same
type as the receiver.  For example, if the receiver is an integer variable,
then the expression must evaluate to a signed or unsigned string of decimal
digits in the range -2147483648 to +2147483647.

     The following table shows the permissible values.

       \			EXPRESSION
 MACVAR  \    integer	   boolean	string	       code
	  ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
 integer  ³No conversion³0 if FALSE ³Digits with  ³Digits with	³
	  ³		³1 if TRUE  ³optional sign³optional sign³
	  ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄ´
 boolean  ³FALSE if 0	³No	    ³Must contain ³Must contain ³
	  ³TRUE if not 0³conversion ³TRUE or FALSE³TRUE or FALSE³
	  ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄ´
 string   ³Any value	³Any value  ³No conversion³Any value	³
	  ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄ´
 code	  ³		       No conversion			³
	  ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

     When the assignment receiver is a code variable, no conversion is
performed, since a code expression may contain variables of any type.



3.2. Macro IF statement


     The macro IF statement can have either of two forms,

     %if  condition  then  action1;
     %if  condition  then  action1  else  action2;

The condition may be any boolean expression.  The actions, action1 and
action2, may be any macro statement or Pascal statement.  If the action is
a Pascal statement, then it must be terminated by either a ; or a %;
combination.  For example, the following are valid if statements,

    %if  xflag	then  %operator := '*';
    %if  xflag	then  %operator := '*'
		else  %operator := '/';

    %if  (precision < 10) or (iterations < 1000)
	 then  IntegrateSingle (curve, low, high);
	 else  IntegrateDouble (curve, low, high);

    %if  (precision < 10) or (iterations < 1000)
	 then  {$I \code\single\mathpack.pas}%;
	 else  {$I \code\double\mathpack.pas};

     If the condition is true, the macro compiler performs action1.  If the
condition is false, and an ELSE clause is given, then the macro compiler
performs action2.



3.3. Macro FOR statement


     The macro FOR statement can take either of two forms,

     %for  macvar := low to high  do  action;
     %for  macvar := high downto low  do  action;

Here macvar must be an integer macro variable, low and high are integer
macro expressions, and action is any executable macro statement or Pascal
statement.  The semicolon of the FOR terminates the action.  Macvar is
called the loop variable, low is called the lower bound, and high is called
the upper bound of the loop.

     The first type of macro FOR statement is executed by first assigning
the value of low to the loop variable, macvar.  This value is compared to
the value of high.  If the value of macvar is less than or equal to high,
then the action is performed, and the value of macvar is increased by 1.
Then the loop repeats.	If the new value of macvar is less than or equal to
the upper bound, then the action is performed and macvar is increased by 1
again.	The action is repeated until the value of macvar exceeds the upper
bound.	Then the statement following the FOR statement is executed.

     The second type of macro FOR statement is executed by first assigning
the value of high to the loop variable, macvar.  This value is compared to
the value of low.  If the value of macvar is greater than or equal to low,
then the action is performed, and the value of macvar is decreased by 1.
Then the loop repeats.	If the new value of macvar is greater than or equal
to the lower bound, then the action is performed and macvar is decreased by
1 again.  The action is repeated until the value of macvar is less than the
lower bound.  Then the statement following the FOR statement is executed.



3.4. Macro WHILE statement


     The macro WHILE statement is used to execute a given statement while
some condition holds true.  The format is

     %while  condition	do  statement;

Here condition is any boolean expression and statement can be either a
macro statement or a Pascal statement.	A series of statements can be
executed by enclosing them in a %Begin-%End block.

     The condition is evaluated.  If it is true, then the statement is
executed, and the condition is evaluated again.  The statement continues to
be executed until the condition becomes false.	The statement needs to make
some change that eventually makes the condition false, or else the
statement will be executed indefinitely.



3.5. Macro BEGIN and END statements


     The macro BEGIN and END statements are used to enclose a block of
statements.  For example,

     %begin
       statement;
       statement;
	 ...
     %end;

The block of statements is then treated as a single statement in the Then
or Else clauses of an If statement, or the Do clause of a While statement.
For example,

     %if  hour > 24
	  then	%begin
		  day := day + 1;
		  hour := hour - 24;
		%end;



3.6. Macro REPEAT and UNTIL statements


     The macro REPEAT and UNTIL statements are used to repeat a block of
statements until a given condition becomes true.  The format is

     %repeat
       statement;
       statement;
	 ...
     %until  condition;

Here, condition is any boolean expression.

     The block of statements is executed, and then the condition is
evaluated.  If the condition is true, execution continues with the next
statement following the Until statement.  Otherwise the block of statements
is executed again and the condition is evaluated again.  This continues
until the condition becomes true.

     The block of statements must make the condition become true
eventually, or else the block of statements will be executed indefinitely.



3.7. Macro Procedure Call statement


     A macro procedure can be called, or invoked, with the procedure call
statement.  The statement has two forms, depending upon whether or not the
procedure was declared with a parameter list.  The formats are

     %procname;
     %procname (arg1, arg2, ...);

Here procname is the name of the procedure as it was defined in the
procedure declaration.

     The arguments arg1, arg2, etc., are macro language expressions, which
must agree in type with the corresponding formal parameters in the
procedure declaration.	For example, if the procedure had been declared as

     %Procedure  work (count:integer; line:string);

in the procedure call

     %Work (xxx, yyy)

the argument xxx must be an integer expression, and the argument yyy must
be a string expression.


3.7.1. Code parameters

     If a formal parameter of a function or procedure has been declared
with type code the value of a corresponding argument must be a code
expression.  Since commas and parentheses are used to delimit the arguments
in the procedure call, some limits must be placed on the use of commas and
parentheses in the code expression.

     Commas and parentheses may be used freely in any comments or quoted
literals in the code expression.  Outside of comments and quoted literals,
any parentheses or brackets in the code expression must be properly paired.
Any commas within these paired parentheses or brackets are taken as part of
the code expression.  Commas and parentheses outside of comments, quoted
literals, and paired parentheses and brackets are taken as separating the
expressions in the argument list.  The following is an example of a valid
argument list containing four code expressions

     (x[1,2], func(a,b,c[0,0]), x or y {x,y}, 'Y=yes, N=no')

     A valid value for a code parameter is the null or empty value.  This
is indicated by immediately writing a comma or right parenthesis to end the
code parameter.  For example, the second and fourth arguments in this
procedure call are null.

     myproc (able,,charlie,);

The called procedure or function can test for an omitted code parameter
using the %If statement.  For example,

     %Procedure Royal (crown,sceptre,throne: code);
     %Begin
       %if  crown  then action1 else action2;
     %End;

If crown is given in a call to Royal, then action1 will be taken, but if
crown is omitted then action2 will be taken.  For example, action2 would be
taken if the procedure were called using

     Royal (, new_sceptre, old_throne);

     The same method can be used to test if a code variable has been
assigned a null value.	For example,

     %mycode :=;
     %if  mycode  then	%proc1	else  %proc2;

Since the code variable mycode has a null value, proc2 will be called.

     Note that an omitted parameter and a parameter that has a null value
are NOT the same thing.  Using the procedure Royal defined above

     %mycode :=;
     %Royal (mycode, x, y);

will cause action1 to be taken, since crown has not been omitted, but been
given as mycode.

     Similarly, note that a blank is a valid value for a code variable.
Thus, in the call

     %Royal ( , n, t);

the parameter crown will be set to one blank, so it has not been omitted.
In this case action1 will be taken.


3.7.2. Code variables and function values

     When an assignment is made to a code variable, the value expression is
not evaluated immediately.  Rather, it is evaluated at the time the code
variable is used in a Pascal statement.  Each time the variable occurs in a
Pascal statement it is newly evaluated.  Any variables or functions
appearing in the expression are given their current values.

     If the assignment is in an inner procedure, but the assignment is made
to a code variable in an outer procedure, it may be impossible to evaluate
the expression.  This is because the values of the procedure parameters and
variables exist only while the procedure is being executed.  After the
inner procedure finishes, the values of its variables no longer exist.
Therefore an assignment to an external variable of type code is not
allowed.

     For the same reason, an assignment to the value of a code function
cannot be evaluated later.  Instead of disallowing code functions, the
macro compiler evaluates the code expression when the function finishes.
The value of the code expression is converted to a character string, and
this string becomes the value of the code function.  This means that the
value of a code function cannot be longer than 255 characters.



3.8. Macro CONTINUE, BREAK, EXIT and HALT statements


     The execution of a loop, procedure or program can be shortened by the
use of the CONTINUE, BREAK, EXIT and HALT statements.

     The CONTINUE and BREAK statements are used in %Begin-%End blocks and
%Repeat-%Until blocks.	When a CONTINUE statement is reached, the remaining
statements in the block are skipped, and control is transferred to the end
of the block.  If the block is a %Repeat-%Until block, or if the block is
contained in a %For-Do or %While-Do construct, then the terminating
condition of the loop is tested.  If the terminating condition is not true,
then the next iteration of the loop occurs, otherwise the loop ends.  For
example,

     %for  n := 1 to 10  do
       %begin
	  %x := x + 1;	  {This statement is executed 10 times}
	  %if  n > 6
	       then  %continue;
	  %y := y + 1;	  {This statement is executed 6 times}
       %end;

     When a BREAK statement is reached, the remaining statements in the
block are skipped, and control is transferred to the statement following
the end of the block.  There are no further iterations of the loop.  For
example,

     %n := 0;
     %while  n <= 10  do %begin
	%n := n + 1;
	%x := x * 2;	{This statement is executed 7 times}
	%if  n > 6
	     then  %break;
	%y := y * 3;	{This statement is executed 6 times}
     %end;

     The EXIT statement is used in macro procedures and functions.  When an
EXIT statement is reached, the remaining statements in the procedure or
function are skipped and control is transferred to the %End statement.	For
example,

     %Function SquareRoot (n: integer): integer;
     %begin
	%SquareRoot := -1;   {In case of a negative value}
	%if  n < 0	     {Test for a valid input}
	     then  %exit;    {No.  Skip the calculation}
	  ...  {Calculate the square root}
     %end;

     The HALT statement may be used anywhere in a macro program.  When a
HALT statement is reached, execution of the program is terminated, and all
blocks are exited.  For example,

     %Procedure  ProcessMessage;
     %begin
	%if  messagecount = 0	{Any messages left?}
	     then  %halt;	{No.  Quit, we're done}
	  ...  {Handle the next message}
     %end;



3.9. Pascal statements


     Pascal statements in a macro program may be any statements in the
Pascal language, including declarations, executable statements, and Pascal
compiler directives.  Pascal statements may appear in the main body of the
macro program, as well as in the body of any macro procedure or function.
That is, they appear between the initial %Begin and the final %End of the
main program or any procedure or function.  Pascal statements cannot appear
in the declaration portion of a macro program, procedure or function.  For
example, Var statements and %Var statements cannot be mixed together.

     The Pascal statements in a macro program are written to the output
file.  The resulting Pascal code consists of all the Pascal statements that
occur during the execution of the macro program.  A single Pascal statement
may produce many statements in the resulting Pascal program if it is
contained within a loop or a macro procedure.

     Pascal statements are formed from Pascal language elements, macro
variables and macro functions by writing them in order.  Pascal language
elements include Pascal keywords such as While, Pascal operators such as +,
Pascal variable names such as FlowRate, and Pascal comments such as {Done}.
Macro variables and functions of all types may be used.  Each time a Pascal
statement is encountered the macro variables and macro functions will be
replaced by their current values in string form.

     The terms in a Pascal statement are simply listed in order.  Since the
+ operator is a Pascal language element, it cannot be used as a macro
concatenation operator in a Pascal statement.  Instead, the % operator can
be used to indicate concatenation.  The terms are concatenated from left to
right.	For example, the following are all valid Pascal statements

     distance := rate * time;
     if  price < 0  then  Error ('Invalid price');
     Var  length, height, width: real;	{Outer dimensions}
     while  size%n < limit%n  do  Adjust(position%n);
     array[1..10,1..10,1..10] of integer;
     ready or offline;

     The first semicolon ; that is not inside a comment or quoted string
terminates the Pascal statement.  The ending semicolon is part of the
Pascal statement, as well as any comments and control characters on the
same line.  The combination end. also terminates a Pascal statement.

     The final semicolon may be excluded by preceding it with a %.	For
example, the statements

     sum := amt1 %;
     %for  n := 2 to 7	do + amt%n %;
     ;

would generate

     sum := amt1 + amt2 + amt3 + amt4 + amt5 + amt6 + amt7;

     When a Pascal statement ends with %; any comments or control
characters following on the same line are ignored.  If it is desired to
produce a line feed, but not a semicolon, then the %; may be placed on the
following line, for example

     %if  condition
	  then	pascalcode1
     %;
	  else	pascalcode2;

The _Line function may also be used to skip to the next line, for example

     %if  condition
	  then	pascalcode1 _line%;
	  else	pascalcode2;


3.9.1. Generated code

     Comments that appear inside a macro statement are taken as macro
comments.  They do not become part of the generated Pascal code.  A comment
that appears after a macro statement and is contained entirely on the same
line is also considered part of the macro statement.

     Comments that appear in Pascal statements are considered part of the
Pascal program, and are included in the generated Pascal language.  A
comment that appears after a Pascal statement and is contained entirely on
the same line is also considered part of the Pascal statement.	For
example, the comments in the following statements are considered part of
the Pascal code.

     x := x + 1   {Increase x};
     x := x + 1;  {Increase x}
     %incr := x := x + 1   {Increase x};

     Comments that precede a statement are considered part of the following
statement.  If the following statement is a Pascal statement, then the
comment will become part of the resulting Pascal code.	If the following
statement is a macro statement, then the comment will not be part of the
generated code.  If it is desired to make the comment part of the output
code, then it should be followed by %; which is a null Pascal statement.
If a carriage return is needed after the comment, then the %; should be
placed on the following line, or the _Line function should be used.

     The macro compiler will not substitute macro variables or function
references that appear inside of comments or quoted strings.  Concatenation
can be used to have macro variables or function references substituted
inside comments or quoted strings, for example

     %procedure bump (item: code);
     %begin
       item := item + 1';  {Increase' item'}' %;
     %end;

Then  Bump(count)  would generate

     count := count + 1;  {Increase count}


3.9.2. Terminating code expressions

     Code expressions may appear in several different contexts within a
macro program.	The rules for terminating a code expression, and the rules
concerning treatment of comments, depend on where the code expression is
used.

     A Pascal statement is a code expression that appears as a separate
statement in a macro program.  In a Pascal statement a code expression
begins with the first character of the statement, and it ends with either ;
or %; If it ends with ; then any complete comment on the same line, and the
carriage return and line feed are part of the expression.  If it terminates
with %; then anything following the %; belongs to the next statement.

     In an assignment statement where the receiver is a code variable, or
where the %code keyword indicates a code expression, the code expression
begins with the first character after the assignment operator := or the
conversion operator %code.  (If %code is followed by one or more blanks,
the first blank is not part of the code expression.)  The code expression
is terminated by the semicolon ; that ends the assignment statement.  The
semicolon and any further characters on the same line are not part of the
code expression.

     In a Then clause of an If statement the code expression begins with
the first character following Then and one blank.  The code expression is
terminated by either a semicolon or the keyword Else.  The semicolon and
any subsequent characters are not part of the code expression.	The keyword
Else and one blank preceding the keyword are not part of the code
expression.  For example, in the statement

     %if ready then resume else quit;

the code expression consists of the single word resume with no preceding or
following blanks.

     In an Else clause of an If statement the code expression begins with
the first character following Else and one blank.  The code expression is
terminated by a semicolon.  The semicolon and any subsequent characters are
not part of the code expression.

     In a parameter of a macro function or procedure a code expression
begins with the first character following the left parenthesis or comma.
The code expression is terminated by the first comma or right parenthesis
that is not contained within a comment, a quoted string, or paired
parentheses or brackets.  In the following examples of parameters the last
comma on each line terminates the code expression

     a + b,
     power[m,n],
     Rate1 {State tax, pct} + Rate2 {Federal tax, pct},
     ErrorMessage (24, 'Missing , or )', console),

When a code expression is used as a function or procedure parameter any
brackets or parentheses it may contain must be paired correctly.  Thus
odd[3)  would not be valid as a code parameter.	However, odd[3) could
appear in a Pascal statement, or a code expression in a macro assignment
statement.



4. INVOKING THE MACRO COMPILER



     The Pascal Macro Compiler operates on each macro language source file
independently.	The Macro Compiler is called with the macro command on the
MSDOS command line.  It has three formats

     macro
     macro infile
     macro infile outfile

If the files are not given, the macro compiler will prompt for them.  The
file specifiers infile and outfile have the form

     drive: path filename .ext

The filename is required, and the drive, path and extension are all
optional.  There cannot be any spaces between the drive, the path, the
filename and the file type extension, if they are present.

     The drive can be any drive on your system, such as a, b, c, etc.  The
path is a DOS directory path, such as

     pas\
     \project\library\PascalSource\

     The file names infile and outfile may be any valid MSDOS file name,
such as myprog or temperature-calc.  Some examples of file specifiers are

     myprog
     c:pas\myprog.mac
     \project\library\PascalSource\temperature

     The default filetype extension for Pascal Macro Language source code
is mac.	If no filetype extension is given for the input file, the filetype
mac will be used.  The default filetype extension for the resulting Pascal
code is pas.  If no filetype extension is given for the output file, the
filetype pas will be used.

     If the output file is not specified, then the output file will have
the same drive, path and filename as the input file, and the filetype
extension will be pas.  For example, the command

     macro \macsource\neutron

would cause the macro source code to be read from the file
\macsource\neutron.mac and the generated Pascal code to be written to the
file \macsource\neutron.pas.

     The Pascal Macro Compiler can be used for any file that contains
Pascal code such as program files, include files and unit files.

     IMPORTANT:  If you use the same file for the macro input file and the
macro output file, then the macro output will overwrite the macro source
file, and the source code will be lost.



4.1. Macro statement


     Some Pascal compilers will call the Pascal Macro Compiler
automatically.	These compilers use the %macro statement at the start of
the file to identify that the file contains macro statements.  The Pascal
compiler may require that the %macro statement appears at the start of the
file, with no preceding comments.  The Macro Compiler itself does not have
any such restrictions.



4.2. Macro compiler Include files


     A large macro program can be split into several smaller files.  Any
meaningful part of the program, such as a procedure, or group of related
procedures, can be placed in a separate file, called an Include file.
Similarly, macro source code that is used by several different macro
programs can be placed in macro Include files.

     Each Include file can be read back into the macro program by using the
macro include directive

     {%I macfile}

where macfile is a file specifier, as above.  The sequence {%I must be
written solidly, with no intervening blanks, as {%i or {%I.  If no filetype
extension is given, the filetype mac is assumed.

     When the macro compiler is run, the include directive will be replaced
by the contents of the Include file.  The macro statements and Pascal
language statements in the macro Include file will be treated as though
they were in the macro source file itself at the point where the include
directive appeared.

     Up to 200 macro source files are allowed, including the main file and
all include files.  Each file may be included only once.



5. MACRO COMPILER DIRECTIVES






5.1. %I Include directive


     The Include directive causes macro source code to be read from an
alternate file.  During macro compilation the included source code is
placed in the macro program at the point where the Include directive
appeared.  An Include directive may be placed anywhere in a macro source
file between the %macro statement and the %end. statement except inside a
comment or a quoted literal.

     The format of the Include directive is either of

     {%I filename}
     {%I filename.filetype}

The filename may include a drive and/or a path.  If the path is omitted,
the source is read from the current directory.	If the file type is
omitted, the file type defaults to MAC.	An example of an Include directive
is

     {%I c:\source\macro\sortgen.inc}

This would cause the file sortgen.inc to be read into the macro program
from the directory \source\macro\ on the c: drive during the macro
compilation.

     An included file may itself contain Include directives.  To prevent
infinite looping, the macro compiler maintains a list of all source files.
This imposes a limit of 200 files altogether.

     Each macro source file must have a unique filename.filetype
combination.  You could not, for example, use two include files
old\survey.mac and new\survey.mac in the same macro program.  You could,
however, have two include files named survey.old and survey.new.	The macro
compiler compares file names to prevent loading the same source file more
than once.



5.2. %LL Line length directive


     The line length directive sets the maximum line length for the
generated Pascal code.	This could be the same as the maximum input line
length for whichever Pascal compiler(s) will be used to compile the
generated program.  The format is

     {%LL len}

where len is a positive integer.  There cannot be any spaces between
{ and %.

     If no %LL directive appears in the macro program, the default line
length of 120 is used.	The output line length should be specified only
once in any macro program.  If more than one %LL directive appears, then
the line length specified in the last such directive will be used, and that
line length will be used throughout the macro program.

     The %LL directive may appear anywhere in the macro program where a
blank could appear, except inside a comment or a quoted string.  However,
note that if the directive appears in a Pascal statement then it will
become part of the generated Pascal code.  It is therefore recommended that
the %LL directive be placed in the declaration section of the macro
program.

     The macro compiler will split an oversized line after the last blank
or tab, if any.  If the line contains no blanks or tabs, then the line will
be split after len characters.



6. COMPILER LIMITS



     The Pascal Macro Compiler has a number of fixed-size tables that place
certain limits on each macro program.  It is important to note, however,
that this need not limit the size of the Pascal program that can be
generated, since the Pascal program can be divided into Units and Include
files which can be generated separately.

     The following table details the limits on each individual macro
compilation.  In some cases, ways are described to work around the limits.
We solicit feedback concerning which limits are the most serious, and we
may increase table sizes or make other adjustments to relieve these limits.

     FILE NAME  The maximum length for a fully qualified file name, which
may include drive, path, name and extension is 80 characters.  If file
names longer than this are used, the user could either move the source
files into a directory closer to the macro compiler, or copy the macro
compiler into a directory closer to the source files.

     PROGRAM BUFFER  The program buffer holds all of the macro source code
for one macro compilation, both the main file and all included files.  The
size of the program buffer is 200,000 characters.  If the source code is
longer than this, the user could eliminate any unused Include files, or the
user could compile a temporary copy of the source code in which large
comment blocks have been removed.

     FILE LIST  The file list contains the names of all of the source files
and Include files used for one macro compilation.  The size of the file
list is 200 entries.  If more files than this are used, the user could
combine some files.

     NAME TABLE	The name table has one entry for each name of a declared
variable, type, procedure and parameter, and two entries for each declared
function.  The size of the name table is 5,000 names.  If more names than
this are used, the user could try to identify and remove names that are not
referenced in the macro program, or could use the same variable in several
different places.

     TYPE TABLE	The type table has one entry for each distinct data type
and each distinct set of array bounds.	The type table is compressed so
that, for example, all scalar integer variables share the same type table
entry.	The size of the type table is 500 types.  If more distinct types
than this are used, the user could make more variables the same size.  For
example, if there were string variables of length 20, 22 and 24, they could
all be declared as string[24].

     FUNCTION/PROCEDURE STACK  The function/procedure stack contains one
entry for each nested procedure or function declaration.  This limits how
deeply function and procedure definitions can be nested, but it does not
limit how deeply calls can be nested, nor does it limit how many functions
and procedures can be declared.  The size of the function/procedure stack
is 10 entries.	If procedure and function declarations are nested more
deeply than this, the user can move some function or procedure declarations
outside of their containing function or procedure.

     FUNCTION/PROCEDURE LIST  The function/procedure list contains one
entry for each procedure and function declaration.  The size of the
function/procedure list is 200 entries.  If more procedures and functions
are declared, the user can try to identify and remove any that are not used
in a given maco program.

     PARENTHESIS/BRACKET STACK  The parenthesis/bracket stack contains one
entry for each unmatched left parenthesis or left bracket in a macro
expression during parsing.  It limits the depth to which parentheses and
brackets can be nested, but it does not limit the total number of
parentheses and brackets in a macro expression, or the depth of nested
parentheses and brackets in a code expression.	The size of the
parenthesis/bracket stack is 25 entries.  There are separate
parenthesis/bracket stacks for macro expressions and for code expressions.
When a code expression contains a macro expression, such as in a function
argument or a subscript, it is possible to achieve nesting deeper than 25
levels.  If parentheses and brackets are nested more deeply than this, the
user may assign temporary variables to hold portions of the expression,
then use these variables in a less-nested version of the expression.

     BEGIN/REPEAT STACK	The begin/repeat stack contains one entry for each
unmatched Begin or Repeat statement during the parsing of a macro program.
It limits the depth to which Begin and Repeat statements can be nested, but
it does not limit the total number of Begin and Repeat statements in any
function or procedure.	The size of the begin/repeat stack is 100 entries.
If Begin and Repeat statements are nested more deeply than this, the user
can create a procedure to hold a portion of the nested blocks.
     Note that If, For and While statements are not, themselves, nested.
It is the Begin and Repeat blocks contained in these statements that are
nested.

     TOKEN LIST	The token list contains a representation of the executable
code in a macro program.  There is about one token for each statement,
variable reference, constant, function, and delimiter in the macro program.
The size of the token list is 50,000 tokens.  If more executable code than
that is used, the user could divide the program to be generated into
smaller parts and collect the separate generated parts using Pascal $I
include statements.

     EXECUTION STACK  The execution stack contains one entry for each
nested procedure or function call.  This limits the depth of procedure and
function calls, and therefore can prevent the macro program from infinite
recursion.  It does not limit the number of calls that can be made during
execution, nor does it limit the number of distinct functions and
procedures.  The size of the execution stack is 100 entries.  If deeper
recursion than that is used, the user can replace some recursions by
iterated loops, can achieve recursion by using a stack, or can combine some
functions so that fewer calls are needed.

     STRING DATA  The string data area contains the names of all declared
variables, types, functions, procedures and parameters, all string
constants, storage for all variables and arrays during execution, and
intermediate values created while evaluating expressions.  The size of the
string data is 1,000,000 characters.  If more storage than that is used,
the user can reduce array sizes, reduce the depth of recursive calling, or
break the generated Pascal program into smaller units.



7. MACRO COMPILER LIBRARY



     The Pascal Macro Compiler provides a library of useful functions and
procedures to ease the task of writing macro programs.

     All library function and procedure names begin with the underscore _
character to distinguish them from Pascal functions and procedures that may
have the same name.  For example, _length gives the length of a character
string.  In a code expression length(aa) would refer to the length of the
Pascal string variable aa, and would be part of the generated code.  But
_length(bb) would refer to the length of the macro string variable bb, and
would generate the current length of that variable as an integer constant.
Thus,

     %bb := 'answer';
     len := length(aa) + _length(bb);

would generate

     len := length(aa) + 6;



7.1. Integer functions


     The Pascal Macro Compiler provides two integer constants and a number
of integer functions.  The integer constants are

     MaxInt = +2,147,483,647
     MaxNeg = -2,147,483,648

These are the largest positive and negative integers that the macro
compiler supports.


7.1.1. _Abs

     _Abs(n) produces the absolute value of the integer n.  If n is
positive, the value is n, and if n is negative, the value is -n.  For
example, _abs(3-10) produces 7.	The value of n must be between -231+1 and
231-1.


7.1.2. _Even

     _Even(n) returns true if the integer n is even, and false otherwise.
For example _even(3*5) gives false.


7.1.3. _Max

     _Max(n1,n2,n3,...) returns the largest integer in the list of integers
n1, n2, etc.  For example,

     _max (99)		    produces   99,
     _max (5, 10)	    produces   10,
     _max (-12, -14, -16)   produces  -12.


7.1.4. _Min

     _Min(n1,n2,n3,...) returns the smallest integer in the list of
integers n1, n2, etc.  For example,

     _min (99)		    produces   99,
     _min (5, 10)	    produces	5,
     _min (-12, -14, -16)   produces  -16.


7.1.5. _Odd

     _Odd(n) returns true if the integer n is odd, and false otherwise.
For example _odd(3*5) gives true.


7.1.6. _Sqr

     _Sqr(n) returns the square of the integer n.  For example _sqr(12)
gives 144.  The square cannot be larger than 2,147,483,647 so n must be in
the range -46,340 to +46,340.


7.1.7. _Sqrt

     _Sqrt(n) returns the integer part of the square root of the integer n.
For example _sqrt(144) gives 12 and _sqrt(143) gives 11.	The integer n
cannot be negative.



7.2. Character functions


     The character functions generate characters in the compiler output.

     _Comma    produces a comma ,
     _LBrace   produces a left brace {
     _LParen   produces a left parenthesis (
     _Pct      produces a percent sign %
     _Quote    produces a quote '
     _RBrace   produces a right brace }
     _RParen   produces a right parenthesis )
     _Semi     produces a semicolon ;

     These character functions can be useful where writing the character
would alter the output.  For example, macro variables and functions are not
evaluated inside of comments or quoted strings.  The character functions
can be used to produce comments or quoted strings in the generated code
where macro variables and functions will be evaluated.	Thus,

     %name :=power;
     name := name * 2;	   _lbrace Double the name _rbrace %;

would generate

     power := power * 2;     { Double the power }



7.3. String functions




7.3.1. _Caps

     _Caps(str) produces a character string where each word in the
character string str is capitalized.  The first letter in the string, and
every letter following a blank, tab, or other control character is set to
upper case.  Characters other than letters 'a' through 'z' are not changed.
For example,

     _caps ('The rain in Spain falls mainly on the plain')

produces

     'The Rain In Spain Falls Mainly On The Plain'


7.3.2. _Clean

     _Clean(str) produces a clean copy of the character string str in which
certain control characters have been replaced by blanks.  The control
characters Null, Tab, Line Feed, Form Feed, Carriage Return, End of File
and Escape are all replaced by blanks.	Writing any of those characters to
the screen, to a printer, or to a file might have an undesired effect.


7.3.3. _Delete

     _Delete(st,n,len) produces a string in which len characters starting
at position n in the character string st have been deleted.  For example,

     _delete ('Rally all good citizens', 11, 5);

produces

     'Rally all citizens'

     The _delete function is not strictly needed in the macro language,
since the same effect can be obtained using substring notation in a more
efficient way.	The statement

     %str := _delete (str, n, len);

is equivalent to

     %str[n..n+len-1] := '';


7.3.4. _Insert

     _Insert(st1,st2,n) produces a string in which string st1 has been
inserted into string st2 starting at position n.	For example,

     _insert ('Bonnie ', 'My lies over the ocean', 4)

produces

     'My Bonnie lies over the ocean'

     The _insert function is not strictly needed in the macro language,
since the same effect can be obtained using substring notation in a more
efficient way.	The statement

     %lock := _insert (key, lock, n);

is equivalent to

     %lock[n..n-1] := key;


7.3.5. _Length

     _Length(str) gives the length of string str.  For example,
_length('hello') gives 5.


7.3.6. _LoCase

     _LoCase(str) converts the character string str to lower case.  For
example, _locase('LoCase') gives 'locase'.


7.3.7. _Pad

     _Pad(str,fill,len) pads the string str with the string fill to the
length len.  Str may be any string, fill may be any non-empty string, and
len must be an integer from 0 to 255.  The result string is formed by
appending as many copies of fill as needed to str until the string length
equals len.  The last copy of fill may be truncated, if needed to make the
result length exactly len.  If str is longer than len characters, the
result is a copy of str truncated to len characters.

     _pad('', ' ', 20)          produces  '                    '
     _pad('Philosopy',' .',20)  produces  'Philosophy . . . . .'
     _pad('', '....|, 22)       produces  '....|....|....|....|..'


7.3.8. _Pos

     _Pos(fish,sea) finds the first occurrence of the character string fish
within the character string sea.  It gives the character position where the
first appearance of fish begins.  If fish is not found in sea, then the
function returns 0.  For example,

     _pos ('tuna', 'A man of unfortunate circumstance.')

gives the value 15.


7.3.9. _Subst

     _Subst(old,new,str) produces a character string in which the string
new is substituted for each occurrence of the string old within the string
str.  For example,

     _subst ('man', 'person', 'Manny''s our man in Germany.')

would produce the string 'Manny''s our person in Gerpersony'.  Note that no
substitution is made for 'Man' in 'Manny' since the 'M' is upper case.

     The string will be scanned as often as needed until all possible
substitutions have been performed, or the length would become greater than
255.  For example, _subst('rat','tag','ararat') would produce 'atagag'
since the first substitution results in 'aratag' which contains the
substring 'rat'.  The substitution will not be performed if it would make
the resulting string longer than 255 characters.


7.3.10. _UpCase

     _UpCase(str) converts the character string str to upper case.  For
example, _upcase('UpCase') gives 'UPCASE'.



7.4. Random numbers


     The random number functions in the Pascal Macro Compiler can be used
to produce sequences of pseudo-random numbers.	The Pascal Macro Compiler
provides a pseudo-random number generator that is much stronger, and has a
much longer period, than the pseudo-random number generators provided by
conventional compilers.  The generated numbers are statistically
indistinguishable from true random numbers.  The generator has a very long
cycle, approximately 296, or about 7.923x1028.

     Note that it is the magnitude of the pseudo-random numbers which is
most random.  The low-order bit repeats with a cycle of approximately 266,
or about 7.38x1019.	Therefore, if a sequence of random bits is desired,
the high-order bit of the random outputs should be used, not the low-order
bit.


7.4.1. _Random

     _Random(limit) returns a pseudo-random integer.  If limit is between 1
and 230, that is, 1 and 1,073,741,824 then the random number will be as
uniformly distributed as possible in the range 0 to limit-1.  If limit is
specified as 0, then the random number will be uniformly distributed in the
range 0 to 231-1, that is 0 to 2,147,483,647.

     If limit is not 0 and also not a power of 2, then the distribution
cannot be perfect.  On average, for every 231 random numbers generated some
numbers will appear N times, and some numbers will appear N+1 times, where
N*limit < 231 < (N+1)*limit.	The more-frequent numbers will be distributed
uniformly across the range 0 to limit-1, so there will be no discernible
bias towards smaller numbers.

     Each time the Pascal Macro Compiler is run, the same sequence of
pseudo-random numbers will be generated, unless either _Randomize or
_RandSet is called.


7.4.2. _Randomize

     The _Randomize procedure resets the pseudo-random number generator to
a different starting value.  That is, it skips to a different section of
the pseudo-random number stream.  The section of the number stream is
unpredictable, so that calling _Randomize several different times will
yield a different portion of the number stream each time.

     Calling _Randomize many times does not increase or improve the
randomness of the result.  The randomness of the generator comes from the
mathematical algorithm that is used.  Calling _Randomize before each call
to _Random would greatly decrease the randomness of the resulting output.


7.4.3. _RandSet

     The _RandSet(n1,n2,n3) procedure resets the pseudo-random number
generator to a different starting value.  That is, it skips to a different
section of the random number stream.  The section of the number stream is
determined by the three integer parameters, n1, n2 and n3.  The three
parameters may be specified as any integers whatsoever.  Calling _RandSet
again with the same arguments will cause the same sequence of pseudo-random
numbers to be generated.



7.5. Output functions


     The output functions are used to change the appearance of the
generated Pascal code.


7.5.1. _Col

     _Col(nn) skips to column nn in the generated Pascal code.  If the
current line (including blanks) already extends to or past column nn then a
line skip is taken and the generated code begins in column nn of the new
line.  For example,

     power := power _col(21)+ spike;
     voltage := voltage _col(21)+ spike;
     kilowatts := kilowatts _col(21)+ spike;

would generate

     power := power	 + spike;
     voltage := voltage  + spike;
     kilowatts := kilowatts
			 + spike;


7.5.2. _Line

     _Line skips to the next line in the generated Pascal code.  For
example,

     Dear John,_line	 I have met somebody new;

would generate

     Dear John,
	  I have met somebody new;



8. PROGRAMMING NOTES



     This chapter contains notes that may be helpful to the macro
programmer.  There is no narrative to this chapter.  The notes are simply
presented in alphabetical order.

     DEBUGGING A MACRO  Suppose that a macro you have written is producing
Pascal code that does not compile correctly.  How do you identify the cause
of the error?  If the error had occurred in a Pascal program, one standard
method is to put temporary writeln statements into the Pascal code to show
you the internal state of the program as it executes.  But the macro
compiler does not have a writeln statement, nor any other input or output
statement.

     One good debugging method is to put temporary Pascal statements into
the macro code to show you its internal state.	These statements can
produce lines in the generated Pascal code that show you such things as the
values of macro variables and the order in which the macro program is being
executed.  If you include some marker in this code, for example >>>, then
it is easy to spot the diagnostic output in the generated code, and also
easy to spot the diagnostics in the macro program to that they can be
removed, or changed into comments, once they are no longer needed.

     ERROR MESSAGES  Every care has been taken to make the Pascal Macro
Compiler error messages as specific and as clear as possible.  However,
because code expressions can contain any Pascal code whatsoever, including
unmatched parentheses, brackets and begin or end statements, this is often
not feasible.

     When an error message that does not seem to fit the situation appears,
the most common cause is that the compiler interpreted some macro code as
Pascal code.  The cause of this is almost always a missing % sign.  Start
backwards from the point where the error was flagged, and look for a macro
statement where the % has been omitted.  In particular, check for begin and
end statements that should have been %begin or %end.

     Another likely cause of odd error messages is unpaired comment braces.
This would cause the macro compiler to treat all of the code from the
unpaired left brace up to the end of the following comment as a single long
comment.  This puts the macro compiler out of sync, and the resulting error
message may refer to a point several lines past the actual cause of the
error.

     INDENTED FORMAT  Nearly all programmers follow the practice of
indenting programs to show their block structure.  For example, in a
Begin-End block, all of the statements within the block would be indented a
few spaces deeper than the Begin and End statements that bound the block.

     With the macro compiler, this presents a problem, because there are
two sets of code to be considered, the macro code and the Pascal code.	If
the macro program is indented normally, including all of the Pascal
statements, then the generated Pascal code will have some lines with
excessively deep indents.  On the other hand, if the Pascal statements are
placed so that the generated code has natural indents, then the macro
program becomes difficult to read.

     The problem can be seen in the GenSort macro procedure that is
distributed with the macro compiler.  The Pascal statements have been
positioned close to the left margin so that the generated Pascal code has a
natural block structure.  This makes the macro program very dense and hard
to read.  In this case, the GenSort procedure is expected to be used as
supplied, and not modified by the user.

     The user needs to make a judgement, based on how the generated code
will be used.  If the macro source is regarded as the source code for the
project, and all changes will be made via the macro code, then it does not
much matter how the generated code looks.  The macro source, including
Pascal statements, should be indented.	Conversely, if the macro program is
going to be used only once in order to generate the Pascal code, and all
further development will be done on the generated code, then it is more
important to make the generated code look natural, and less important to
structure the macro code.

     QUOTES  When a variable is assigned a value that includes a quoted
literal, such as 'sample', the macro compiler sometimes retains the quotes,
and sometimes does not.  This can be confusing.

     The reason for this is that all characters are significant in code
expressions, including any quote marks, but in string expressions the quote
marks are not part of the expression.  Therefore, when an assignment is
made to a code variable, the quote marks are retained, but when an
assignment is made to a string variable, the quote marks are removed.
Similarly, if a parameter to a procedure or function has been declared with
type code, the quote marks will be kept, but if the parameter was declared
with type string, the quote marks will be deleted.



Appendix A. DOS BASICS



     The Pascal Macro Compiler runs under DOS, not under Windows.  DOS was
the primary operating system for personal computers from about 1975 to
1995, and every computer user of that era knew it well.  Older versions of
Windows, prior to the introduction of Windows 95, ran as tasks under DOS.
However, newer computer users may not be familiar with DOS, so that a
little basic orientation may be needed.



A.1. Starting DOS


     On newer computers it may be difficult even to find DOS in order to
use it.  There are two methods for running DOS.  The first method is to
click on a DOS icon from your desktop, or from a taskbar at the top or
bottom edge of the desktop.  The icon may say DOS, or MSDOS, or possibly
CMD or COMMAND.  Clicking any one of these icons will start DOS.  However,
the DOS icon may not be there.	You have to find it.

     You start by clicking on "Start" in the corner of the screen.  This
will bring up a menu listing various programs and options.  If there is a
DOS icon there, you can use it directly, or you could drag it onto the
desktop for future use.  If it is not there, click on "Programs" or "All
Programs."  This will bring up a long list of various programs that are on
your computer.	If one of these is DOS, you can click it, or you can drag
it to the desktop.

     If you still don't see a DOS or CMD icon, put your mouse on each of
the icons that you see.  Don't click, just let the mouse cursor rest on the
icon.  This will often bring up another list of programs, and DOS may be
among them.

     If DOS still is not there, don't give up.  In the list of All Programs
there will be some folders with names such as "Applications" or "System
Utilities."  Click to open each of these folders.  In those folders you may
find DOS or CMD.  Or, you may find more folders.  Again, rest the mouse on
the names of programs, and click on folders to find even more well-hidden
programs and folders.

     Once you find the DOS icon, drag it to the desktop.  Put the mouse
cursor on the icon and hold down the left button.  Move the mouse to drag
the cursor onto the desktop, and then release it to drop the icon on the
desktop.  Click the desktop to close all of the other windows.	Then drag
the DOS icon to wherever you want it on the desktop.

     If all of this fails, it is time to try the second method.  Go back to
the desktop, and click on "Start" again.  In the list of options click on
"Run" or "Run Program."  This will open a small window with a box where you
can type the name of a program that you wish to run.  Type CMD in this box,
and then press Enter.  This will open a DOS window.



A.2. Sizing the DOS window


     The DOS window will often be a small window in the middle of the
screen, probably off-center.  It is easier to work with DOS in full-screen
mode, with no distracting windows or borders.  To do this, right click on
the border of the DOS window, and select "Properties" from the pop-up
window that appears.  Use the various options to select full-screen mode.
This may take several tries before it works, so don't get frustrated if the
next time you use DOS you get the same small window, and need to resize it
again.

     When you do get the full screen mode, the screen is likely to be set
to 50-line mode.  This make the characters small and crudely formed.  You
may be more comfortable using 25-line mode.  To switch, you can type the
command

     mode con lines=25

This will double the size of the characters and make them easier to read.



A.3. Directories


     In DOS your computer's hard disk is organized into directories.  All
of the files on your computer are in directories.  These correspond to the
folders in Windows.  Directories and folders are the same thing.  A
directory or a folder can contain files and more directories or folders, so
that the folders or directories are nested one inside the other in a
hierarchy.

     The top of the hierarchy is called the "root directory."  Typically
the root directory does not contain any files.	Rather, it contains all of
the principal directories on the computer, such as

     \Windows\
     \Program Files\
     \Documents and Settings\

and so forth.  The backslash \ in front of these directory names shows that
they are directories within the root directory.

     A directory within another directory is sometimes called a
subdirectory.  In the example above the directory Windows would be a
subdirectory of the root directory.



A.4. Current directory


     Files are identified in DOS by using a path, a filename and a
filetype.  For example,

     direc1\direc2\file1.doc

Here the path is direc1\direc2, the filename is file1 and the filetype is
doc.  The path consists of the sequence of nested directories which contain
the desired file.

     If the path starts with a \ backslash, then the sequence of
directories start from the root directory.  If the backslash is omitted,
then the path starts from the current directory.  For example, if the
current directory is Windows, then the file identifier
direc1\direc2\file1.doc would refer to the file
\Windows\direc1\direc2\file1.doc

     By setting the current directory you can shorten the names of programs
and files that you must type.  For example, if you want to use the program

    \direc1\direc2\prog1.exe

to process the data files

    \direc1\direc2\file1.dat
 and
    \direc1\direc2\file2.dat

you could type

    \direc1\direc2\prog1 \direc1\direc2\file1.dat \direc1\direc2\file2.dat

If you changed the current directory to \direc1\direc2 then this could be
shortened to

    prog1 file1.dat file2.dat

    The command to change the current directory is cd.  To change the
current directory to \direc1\direc2 you would type

     cd \direc1\direc2\

If you then wanted to change the current directory to \direc1\direc2\direc3
it is sufficient to type

     cd direc3

since you were already in the directory \direc1\direc2.



A.5. Working with directories


     You can make your own directories by using the Make Directory command.
For example, if the current directory is \direc1\direc2 and you wanted to
make a subdirectory called direc3, then you could type

     md direc3

Starting from the root directory, the new directory would be
\direc1\direc2\direc3.

     To remove a directory, you can use the Remove Directory command.  For
example, to remove the directory \direc1\direc2\direc3 you would type

     rd \direc1\direc2\direc3

As a safety precaution, you cannot remove a directory until you have erased
or deleted all of the files in the directory, and removed all of its
subdirectories.  This prevents you from accidentally deleting files that
you need to keep.

     To list the contents of a directory, you can use the Directory
command.  The basic format is

     dir mydirec /options

Here mydirec is the directory you want to list.	There are many possible
options.  Here are a few of the most useful:

     /s    List the contents of all subdirectories
     /on   Sort the files by name
     /os   Sort the files, smallest to largest
     /o-s  Sort the files, largest to smallest
     /od   Sort the files, oldest to newest
     /o-d  Sort the files, newest to oldest
     /p    Pause after every 20 lines

You can use several options in the same command.  For example,

     dir \direc1 /s /od /p

would list the files in \direc1 and all of its subdirectories sorted from
oldest to newest, and pausing after every 20 lines.

     You can also list specific files, files that have a given filename or
filetype, or files whose filenames and filetypes begin with specific
letters.  Here are some examples

     dir tax.ref   Lists the file tax.ref.
     dir tax.*	   Lists all files with the name tax.
     dir *.doc	   Lists all files of type doc.
     dir st*.c*    Lists all files whose filename starts with st
		   and whose filetype begins with c, such as
		   startup.cfg, study.com or state.core.

The * asterisks in these commands are called wildcards because they can be
replaced by any set of letters.  These commands can tell you whether these
files exist, their sizes, and the date they were last updated.



A.6. Identifying files


     All of the data in your computer resides in files.  Files contain the
operating system, all of the application programs, and all of the data that
they use and create.  Files are identified to DOS by four fields, namely
the drive, path, filename and extension.

     drive	is the device where your file is stored, usually
		C for your hard drive, A or B for a floppy drive,
		D or E for a CDROM drive.

     path	is the directory on your drive where the file is
		located.

     filename	is the name that you gave your file.  The name
		usually indicates the contents or purpose of the
		file.

     extension	is a suffix that indicates the kind of file, such
		as TXT for a text file, JPEG for a picture file,
		EXE for an executable file, etc.

A full file identifier might look like this,

     c:\mycompany\mydepartment\2005\sales.wp

     In this example, c: identifies that your file is on the C drive, which
is your hard drive.  \mycompany\mydepartment\2005\ is the path to your
data.  It shows that the data file is located in the 2005 folder, which is
inside the mydepartment folder, in the mycompany folder.	So the path
consists of nested folders, or a list of directories.  sales.wp is the file
with the data.	The filename is sales, and the extension is wp, which
indicates that it is a WordPerfect document.

     In a file identifier all of the fields except the filename are
optional.

     drive	can be omitted if the file is on the current
		drive, that is, the drive where you are now
		working.

     path	can be omitted if the file is on the current
		directory of the drive.

     extension	can be omitted if the file does not have an
		extension on its name.	For example, if the file
		is just named oldstuff then no extension is
		needed.

Here are some examples of valid file identifiers:

     a:budget
	  identifies the file budget in the current directory
	  of the A drive.

     \jones\commissions
	  identifies the file commissions in the jones directory
	  on the current drive.

     late\requests.txt
	  identifies the file requests.txt in the late
	  subdirectory of the current directory.



A.7. File operations


     Since the Pascal Macro Compiler runs under DOS, and operates on DOS
files, it can be useful to know some of the common DOS file operations.

     There is no DOS operation to create a file.  Files are created by
application programs such as word processors, picture editors,
spreadsheets, etc.  Once created, files can be copied, renamed and deleted.

     To copy a file to a new location, the command is

     copy oldfile newfile

The old file and new file identifiers can be fully qualified, that is, they
may have drive, path, filename and filetype.  So the copy command can be
used to copy files to other directories or to other drives.

     Wildcards can be used in the copy command to copy groups of files.
For example, the command

     copy \oldpath\*.doc \newpath\*.*

would copy all files of type doc from the \oldpath directory to the
\newpath directory.

     The rename command works similarly to the copy command.  The form is

     ren oldfile newname

Here oldfile can be fully qualified, with drive, path, filename and
filetype.  However, newname can have only a new filename and filetype.
There cannot be a new drive or new path because the file does not change
its location, only its name and/or type.  For example,

     ren target\x3*.jpg x4*.*

would rename all of the jpg files in the target directory that start with
x3 to start with x4.

     The command to delete files takes the form

     del file

Here, file can be a fully-qualified file identifier, with drive, path,
filename and filetype.	It can also have wildcards so that you can erase
several files with a single command.  For example,

     erase a:old*.*

would erase all files in the current directory of the a drive whose
filenames start with old.

     There are many other DOS commands and options.  This is just a small
sample of useful DOS commands.




© Copyright 2004, 2005 Frank Rubin
All rights reserved. No part of this manual may be reproduced in any form without the express permission of the author.