home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-10-31 | 47.0 KB | 1,633 lines |
- Concepts
-
-
- This chapter describes the technical details of
- the MaxonBASIC language, together with some of
- its more advanced features. It is intended for
- users who already have a good understanding of
- the BASIC language and want to get to grips
- with MaxonBASIC quickly.
- If you are new to BASIC please read the
- Tutorials chapter first.
-
-
- Character Set
-
-
- MaxonBASIC uses plain ASCII characters in its
- input files. The following characters have
- special meanings:
- a-z, The letters, which are used in
- A-Z reserved words and the user´s
- variable names, labels and sub-
- program names. Lower and upper
- case are treated as the same in
- variable and reserved word
- definitions so that THEN, then and
- Then are all the same reserved
- word.
- E, e, These are also used for exponents
- D, d in numbers.
- 0-9 The digits, which are used in
- numbers and can also be used in
- names as long as they are not the
- first character.
- . The full stop or period, which is
- used as the decimal point in
- numbers and can also be used in
- names as long as it is not the
- first character.
- % The percentage sign, which is used
- to indicate that a variable is a
- 16 bit integer i.e. whose values
- must be in the range -32768 to
- 32767.
- & The ampersand, which is used to
- indicate that variables are long
- integers i.e. whose values must be
- in the range -2^31 to 2^31-1. Also
- used to introduce hexadecimal,
- octal and binary constants.
- ! The exclamation mark, which is
- used to indicate that a variable
- is a single-precision floating
- point number.
- # The hash or number sign, which is
- used to indicate that a variable
- is a double precision floating
- point number and also used to
- indicate that certain input/output
- operations are to be directed to
- channels rather than the screen
- (e.g. PRINT #).
- $ Used to indicate string variables.
- _ The underline character, which can
- be used in variables after the
- first character assuming the
- Underlines in Names (UNDERLINES)
- option has not been turned off. If
- it appears at the start of a
- symbol or the underlines has been
- disabled (NOUNDERLINES) then it
- indicates the rest of the line is
- to be ignored and that the
- following line is to be considered
- part of the current one.
- " The quotation mark or double quote
- which is used to delimit string
- literals.
- ´ The apostrophe or single quote
- which is used to indicate that the
- rest of this line is to be
- regarded as a comment.
- ( ) The parentheses or round brackets,
- which are used to enclose function
- arguments, over-ride the priority
- of operators and indicate arrays.
- + - * The basic arithmetic operators.
- /
- = The assignment operator and
- equality operator.
- < > Less than and greater than
- comparison operators - also used
- as parts of the shift operators.
- ^ Exponentiation operator.
- \ The back-slash character, which is
- used as the integer division
- operator.
- , Comma.
- ; Semi-colon.
- ? Used as an abbreviation for PRINT.
-
- Other characters with ASCII values lower than
- 32 are treated as white space, and ignored so
- you may, for example, include form-feed
- (chr$(12)) characters to give a new page on
- your printer when listed.
- Other characters may be used in strings, but
- otherwise will generate a warning and will be
- ignored.
-
-
- Program lines and labels
-
- Program lines consist of an optional line
- number or label, one or more statements
- separated by colons and an optional comment,
- which starts with an apostrophe or single
- quote.
-
- Line numbers may be any number between 1 and
- 65529 inclusive. (65529 may seem a strange
- number, it is the maximum allowed by Microsoft
- BASIC).
-
- Line labels consist of any valid variable name
- that is not used as a variable or a sub-program
- and labels are followed by a colon. There is no
- limit to the number of characters in a line
- label but lower- and upper-case letters are
- treated as the same and the characters must not
- be a reserved word. Thus the following line
- labels are allowed:
-
- Label9999:
-
- A.very.long.label.that.causes.problems.to.other
- .BASICs:
-
- Hello:
- The following line labels are the same:
-
- Start:
- START:
- start:
- Line numbers and labels may be preceded by
- white space. White space is not required after
- the last digit or colon. Line numbers may not
- contain spaces.
- Note: For compatibility with other BASICs we
- recommend that you do not use full stops (.) or
- underlines ( _ ) in labels and keep them to
- less than 40 characters.
- Line number 0 is not allowed because it would
- be confused when using ON ERROR GOTO 0 which
- does not mean go to line 0 if an error occurs.
- In general we do not recommend the use of line
- numbers since line labels are much more
- readable. The exception to this is when using
- ERL when the use of line numbers is useful
- since otherwise you must change the line
- numbers in your program each time you insert or
- delete lines in your program.
- Most of the time you do not need to use line
- numbers or line labels because MaxonBASIC has
- such a rich set of structured statements (much
- better than Pascal and even more flexible than
- C and Modula 2).
- You may have many statements per line provided
- each is separated by a colon.
- MaxonBASIC has an extension to call sub-
- programs without the CALL keyword. However you
- cannot do this if the sub-program has no
- parameters and is the first statement of a
- multi-statement line. For example, if you have:
-
- SUB john STATIC
- PRINT "John";
- END SUB
- then
-
- john
- PRINT " Smith"
- will print
-
- John Smith
- as will
-
- call john: print " Smith"
- However
-
- john: print " Smith"
- is wrong because the john: could be a label
- definition; normally the compiler will warn you
- on the parsing phase if you make this error.
- This problem does not apply if the sub-program
- has a parameter, for example:
-
- SUB john(para$) static
- PRINT "John ";para$;
- END SUB
-
- john "David": print " Smith"
- is fine because it cannot be mistaken for a
- label.
- If an apostrophe or single quote (´) appears on
- a line then the rest of the line is treated as
- comment and ignored. The only exception to this
- is DATA statements which treat the apostrophe
- as part of the data. If you want a comment on
- such a line precede it with a colon; this will
- terminate the DATA statement.
- Program lines may be any length theoretically,
- but it is generally a good idea to keep them
- less than 80 characters so that the whole line
- is displayed at once. If you need a line that
- is significantly longer than this then the
- chances are that the line is more complicated
- than it should be as far as ease of
- understanding is concerned. There are two
- exceptions to this. The FIELD statement where,
- for large records, you need many more than 80
- characters and the TAGLIST statement where you
- need to set up many tags when calling the
- operating system.
- To get around this the underline character ( _
- ) may be used to cause lines to be continued on
- the next physical line. Anything after the
- underline is ignored.
- For example:
-
- FIELD #3,20 AS name$, _ ´ surname only
- 5 AS initials$ ,_
- 50 AS street$, _ ´ include name or number
- here
- 20 AS town$, _
- 20 AS county$ ,_ ´ or state if applicable
- 20 AS country$
- which would be much more readable than the one-
- line equivalent where you would also have to
- leave out the comments.
- Normally MaxonBASIC allows underlines in
- variable names, unlike traditional BASICs.
- Underlines are treated as continuation
- characters if they are not part of a variable
- name. If you are porting programs that have
- continuation characters immediately after
- identifiers or reserved words then use the
- NOUNDERLINES option or de-select the
- appropriate box in the Compiler Options
- requester.
- For example:
-
- IF x THEN_
- PRINT "hello"
- will be accepted in some BASICs as a one-line
- IF statement (no need for an END IF). Without
- the NOUNDERLINES option MaxonBASIC will give an
- error because it thinks you are using a
- variable called THEN_. To solve this use
- UNDERLINES or insert a space in front of the _
- character.
- If you use NOUNDERLINES and inadvertently use
- an identifier containing an underline you may
- get a very strange error message because the
- compiler has ignored the rest of the line.
-
-
- Data Types
-
- There are five types of data in MaxonBASIC:
-
-
- .ib.Strings;
-
- A string is a sequence of characters that may
- be up to 16 megabytes long assuming you have
- enough memory. Strings may contain any
- character with a value of 0 to 255 inclusive.
-
-
- .ib.Integers;
-
- Integers are numeric and consist of the whole
- numbers from -32768 to 32767.
-
-
- .ib.Long Integers;
-
- Long integers are numeric and consist of the
- whole numbers between -2147483648 and
- 2147483647.
-
-
- .ib.Single precision numbers;
-
- Single-precision numbers have approximately
- seven digits of precision and a range of 5.4E-
- 20 to 9.2E-18 for positive values and -2.7E-20
- to -9.2E18 for negative values.
-
-
- .ib.Double precision numbers;
-
- Double precision numbers have approximately 16
- digits of precision and a range of 4.9E-324 to
- 1.8E308 for positive numbers and -4.9E-324 to -
- 1.8E308 for negative numbers. There is loss of
- precision with numbers of magnitude less than
- 2.2E-308.
-
-
- Constants
-
- Constants are values which do not change during
- program execution. Constants may be of all 5
- types.
- A string constant is a sequence of ASCII
- characters enclosed in double quotes ("). These
- can be any character between ASCII values 32
- (space) and 255. To obtain a double-quote in a
- string repeat it, so that, for example, the
- string consisting of one double quote character
- is """". The first is the start of the string,
- the second and third form the character itself
- and the last is the closing quote.
- Numeric constants are formed in one of the
- following ways:
-
-
- .ib.Decimal numbers;
-
- A sequence of decimal digits followed
- optionally by a decimal point (.) and more
- digits and/or an exponent. An exponent consists
- of the letter d, D, e or E followed by a
- decimal integer. E indicates single precision
- and D indicates double precision. The number
- may be preceded by a minus sign as may the
- numeric part of the exponent.
- The number before the decimal point may be
- omitted. The number may be followed by a type
- specifier (%,!,& or #).
-
-
- .ib.Hexadecimal Constants;
-
- Hexadecimal constants start with &H or &h and
- are followed by hexadecimal digits(0-9, a-f, A-
- F). The number may be followed by a type
- specifier (%,!,& or #).
- Hexadecimal integer constants between &h8000
- and &hFFFF are taken as signed 16 bit integers.
- Hexadecimal long integer constants between
- &h80000000 and &hFFFFFFFF are treated as signed
- 32 bit constants so that for example:
- &h7FFF = 32767 integer
- &h8000 = -32768 integer
- &h8001 = -32767 integer
- &hFFFF = -1 integer
- &h10000 = 65536 long integer
- &h7FFFFFFF = 2147483647long integer
- &h80000000 = -2147483648long integer
- &hFFFFFFFF = -1 long integer
- &h100000000= 4294967296 double
- If you want &h8000 to be treated as +32768 then
- follow the number with & and it will be treated
- as a long and thus positive e.g.
- &h8000& = 32768 long integer
-
-
- .ib.Octal Constants;
-
- Octal constants start with &O or &o or just
- simply &. and are followed by octal digits (0-
- 7). The number may be followed by a type
- specifier (%, !, & or #). The type of an un-
- terminated octal constant is determined by the
- same rules as for hexadecimal constants (see
- above).
-
-
- .ib.Binary Constants;
-
- Binary constants start with &B or &b and are
- followed by the digits 0 or 1. The number may
- be followed by a type specifier (%,!,& or #).
- The type of an un-terminated binary constant is
- determined by the same rules as for hexadecimal
- constants described previously.
-
-
- .ib.Character constants;
-
- These start like strings of only one character
- and are followed by the % character and have a
- value equivalent to the ASC() of the character.
- However they are generally easier to read and
- more efficient than the ASC() equivalent.
-
-
- Types of Constants
-
- The rules regarding what type a constant is are
- rather complicated but in general you should
- find that normally the compiler does what you
- expect. The most common problem is that some
- hexadecimal constants are treated as negative.
- If this is a problem please see the Hexadecimal
- Constants section above. The following are in
- decreasing order of importance:
- 1. A terminating character is used. If the
- number is terminated by:
- % it is taken as an integer
- & it is taken as a long integer
- ! as a single precision floating point
- number
- # as a double precision floating point
- number.
- 2. If the number is hexadecimal or octal and
- lies in the following range:
- 0 to &hFFFF it is taken as an integer
- &h10000 to &hFFFFFFFF it is taken as a long
- integer
- &h100000000 upwards it is taken as a
- double.
- For the rules concerning whether a constant is
- treated as negative see above.
- 3. If the number is decimal and it is not a
- whole number and has more than 6 digits in the
- whole number and decimal parts, then it is a
- double.
- 4. If it has an exponent of the form D or d
- then it is a double.
- 5. If it has an exponent of the form E or e
- then it is an integer.
- 6. If it has a decimal point then it is a
- single precision number.
- 7. If it is a whole number less than or equal
- to 32767 it is an integer.
- 8. If it is a whole number less than or equal
- to 2147483647 it is a long integer.
- Examples:
- 1 integer
- 1.0 single precision (.)
- 1.0E0 single precision(.
- and E)
- 1.00000 single precision
- 1.000000 double precision (7
- digits)
- 1.000000E0 single precision(E
- overrides 7 digits)
- 1D0 double precision (D)
- 1D0% integer (% over-rides
- D)
- 1.0& long integer (&
- overrides .)
- 1D0! single precision (!
- overrides D)
- 1# double precision.
-
-
- Variables and Reserved Words
-
-
-
- Variable names start with a letter and
- subsequent characters may be letters, digits,
- or full stops (.). In addition underlines (_)
- may be included if you haven´t switched this
- off using the NOUNDERLINES option. For maximum
- compatibility with other BASICs don´t use
- underlines or full stops.
- Lower and upper case are treated as the same in
- variable names and reserved words so that
- PRINT, Print and Print are all the same
- reserved word.
- Variables may be terminated with a type
- specifier % (integer), & (long integer), !
- (single precision floating point) or # (double
- precision floating point). If there is no type
- specifier then the type is determined by the
- current DEFtype statement for the first letter
- of the variable. If there have been no DEFtype
- statements then single precision (!) is used.
- Compiler error messages specifying variable
- names always include the type specifier that
- has been assumed.
- For example, the following gives the types of
- the respective variables:
-
- DEFINT i-k
- DEFSTR s
- DEFDBL q-r
- i% integer
- i integer i% (same as
- above)
- I (also the same as above)
- i& long integer (different)
- str1 string (same as str1$)
- real_value1 double (same as
- real_value1#)
- You can not use reserved words as the names of
- variables or sub-programs. The reserved words
- are listed in full in Appendix C. Reserved
- words and variables may be entered in upper or
- lower case or a mixture of both.
- In general using reserved words with type
- specifiers should be avoided for compatibility
- reasons.
- GO is not a reserved word. However if GO is
- followed by TO or SUB then it is made into GOTO
- or GOSUB respectively; so you can have white
- space between GO and TO and it will still be
- treated as GOTO. Thus you can use GO as a
- variable name if you like but some strange
- things can happen, such as
-
- FOR i=go TO from STEP 2
- is misunderstood because the compiler considers
- this to be
-
- FOR I = GOTO from STEP 2
-
- Variables must not start with FN because they
- would be treated as function names. The same
- rules for determining the type of a variable
- are used to determine the types of functions.
- The following are FN function names:
- FNtest
- FNsine&
- FNget.one.character
- Sub-program names must not have a type
- specifier because they do not have a type. You
- may use the same name for a variable and a sub-
- program although the type specifier of the
- variable must be used explicitly. However, this
- can be very confusing. For example
-
- SUB john
- john%=42
- END SUB
-
- john%=52 : john
-
-
- .ib.Arrays
-
-
-
- ;
-
- Array names follow the same rules as for
- variables and their types are determined in the
- same way. You may use the same name for an
- array and an ordinary variable. Normally an
- array name is followed by an open parenthesis,
- except in the ERASE statement and the UBOUND
- and LBOUND functions when this is assumed
- automatically.
- Arrays are tables of values each of the same
- type. Normally the number of elements in an
- array and the number of dimensions is specified
- with a DIM statement. There are no restrictions
- on the size of arrays other than available
- memory and subscripts may be long integer
- values if applicable. The maximum number of
- dimensions for an array is 31 (which would take
- up a minimum of 4 gigabytes of memory if each
- index had more than one element).
- If the DIM statement is not used, the maximum
- subscript is assumed to be 10. If you have
- switched off array checks using compiler option
- NOARRAY then you must use the DIM statement. To
- check whether you have inadvertently auto-
- dimensioned an array then you should use the
- Array Checks Warnings option - this will give a
- run-time error when an array is used before it
- has been DIMensioned.
- The minimum value of subscripts is 0 unless an
- OPTION BASE statement is used. When referenced,
- the element of the array to be accessed is
- specified by one or more expressions inside
- parentheses and separated by commas. The
- expressions may be of any numeric type although
- single and double precision real values will be
- converted to long integers.
- For example, given:
-
- DIM A(30), B$(table_entries,4), table&(100000)
- DIM t%(fred*fred),c(n,n,n)
- then the following are valid array references:
-
- A(i)
- B$(j*3,2)
- table&(i&)
- t%(k-l)
- c(i,j,k)
- By default MaxonBASIC arrays are static i.e.
- you cannot re-dimension them; this can be
- changed through the use of the REM $dynamic
- compiler option - for more information on this
- and other features of arrays see the Advanced
- Arrays section later in this chapter.
-
-
- .ib.Operators;
-
- Expressions are made up of constants,
- variables, array variables, function calls and
- operators. The order of priority is listed
- below with the highest priority first:
- 1. Exponentiation ( to the power of ) (^)
- 2. Unary Minus (-)
- 3. Multiplication (*) and Floating Point
- Division (/)
- 4. Integer Division (\)
- 5. Modulus ( MOD)
- 6. Addition (+) and Subtraction (-)
- 7. Shift left (<<) and Shift right (>>)
- 8. Comparisons (=,<>,>,<,>=,<=, ==)
- 9. NOT
- 10. AND
- 11. OR and XOR (exclusive or)
- 12. EQV
- 13. IMP
- The only exception to this is that x^-y is
- evaluated as x^(-y).
- To change the order of evaluation use
- parentheses (round brackets).
- The guiding principle for the precision used
- when evaluating expressions is that the minimum
- precision is used that will ensure that
- accuracy is not lost.
- The exponentiation operator (^) always has its
- operands converted to either single or double
- precision floating point and returns a result
- of the same type. Single precision is used if
- the operands are either integer or single
- precision. If either operand is a long integer
- or is double precision then it is evaluated in
- double precision for accuracy. See 6-2 below.
- This operator uses logarithms to give its
- result and as such is slow and inaccurate if
- the second operand is a small integer.
- The multiplication, addition, subtraction and
- unary minus operators may have operands of any
- numeric type with the following table giving
- the result of the expressions:
- integer long single double
- integer integer long
- single double
- long long long double double
- single single double single double
- double double double double double
- 6-1 Type conversion for most operators
- Addition may be also used for strings when it
- means concatenation so that, for example:
-
- "ABC" +"DEF" ="ABCDEF"
- Floating point division operands are always
- converted to single or double precision
- floating point numbers, the following table
- gives the result of the expression:
- integer long single double
- integer single double
- single double
- long double double double
- double
- single single double single
- double
- double double double double
- double
- 6-2 Type conversion for division operators
- The integer division operator \ uses long
- integer (32-bit) arithmetic unless both
- operands are integers in which case integer (16-
- bit) arithmetic is used.
- The comparison operators always return an
- integer value of -1 for true and 0 for false.
- The comparison is evaluated using the type
- given in 6-1 above for numeric types. Strings
- may also be compared.
- The comparison operators are
- = equality
- <> inequality
- > greater than
- < less than
- >= greater or equals
- <= less than or equals
- == almost equals (two equals signs)
- The ´almost-equals´ operator is a MaxonBASIC
- extension for single or double precision
- floating point comparisons and it is defined as
- follows:
-
- x==y
- calculates
-
- ABS(x-y) <= ABS(y * 1E-6)
- Thus == can be used to check for near equality
- even if a small number of rounding errors have
- been introduced. For integers and long integers
- the comparison is the same as equals and for
- strings the comparison is the same as equals
- except that lower case letters are treated as
- equal to their uppercase counterparts. For
- example:
- 2.0==2.0 is true
- 2.0==1.999999 is true
- 2.0==1.99999 is false
- A string is considered less than another if its
- first character that differs is lower in the
- ASCII set than the corresponding character in
- the first string. If the strings are the same
- until one string is exhausted then the shorter
- string is less. All the following examples are
- true:
- Fred"<"Hello" because "F"<"H"
- "Frederick"<"Hello because "F"<"H"
- "
- "fred">"Hello" because "f">"H". The
- lower case letters
- come after the upper.
- "Frederick">"Fred" because "Frederick"
- is longer
- The logical shift operators, <<,>> shift their
- first operand left or right respectively by the
- number of bits given as their second operand.
- The shift operations are unsigned and the first
- operand should be of either integer type - if
- you use a single or double this will be
- converted to a long integer. The resulting type
- is the same as the first operand after any
- conversion.
- Note that i<<1 is the same as i*2 except when
- would occur and that i>>1 is the same as i\2
- except when i is negative.
- For example:
- 1<<8 &h100 256
- (-1)<<8 &hFF00 -256
- 1<<15 &h8000 -32768
- &h1234<<4 &h2340 9024
- &h12345678<<4 &h23456780 591751940
- &h12345678>>4 &h1234567 305419896
- Note that the shift operators are not supported
- by Microsoft BASIC on the Macintosh or PC.
- All the logical operators NOT, AND, OR, XOR,
- EQV and IMP use long integer arithmetic (32-
- bit) unless both operands are integers in which
- case integer arithmetic is used. These
- operators work bitwise, with each bit affected
- as shown below.
-
- X Y NOT AND OR XOR IMP EQV
- 0 0 1 0 0 0 1 1
- 0 1 1 0 1 1 1 0
- 1 0 0 0 1 1 0 0
- 1 1 0 1 1 0 1 1
-
- Although these operations work on the
- individual bits they have the same affect as
- the corresponding logical operators if you use
- -1 for TRUE and 0 for FALSE.
- Examples:
- -1 OR -1 =-1
- 4 OR 3= 7 (100 and 011 in binary)
- -1 XOR 0 =-1
- 8 AND 4 = 0 (1000 and 100 in
- binary)
- These logical operators can be particularly
- useful when writing routines that interface
- directly to the operating system as many of the
- flag parameters are based on bits.
-
-
- Sub-programs and User Defined Functions
-
- .ib.Sub-programs;
- .ib.Functions;
- Sub-programs and user defined functions are one
- of the most powerful features of many modern
- BASICs and MaxonBASIC takes these ideas even
- further.
- The idea of using a sub-program is to isolate
- part of the code of your program in a way that
- makes it easy to call and easy to ensure that
- it is not interfering with variables that are,
- logically, not to do with the sub-program´s
- code.
- The simplest definition of a sub-program is
- something like
-
- SUB hello
- PRINT "hello"
- END SUB
- The SUB statement defines the name of the sub-
- program that we are defining and the END SUB
- indicates that we have finished.
- Sub-program definitions may not contain other
- sub-program definitions.
- The hello sub-program can be called using
-
- call hello
- or even just
-
- hello
- and will print the word hello. You can call sub-
- programs before or after their declarations.
- So far this doesn´t give us anything that you
- can´t do with old-style BASIC GOSUBÉRETURN
- statements. However by passing parameters to
- sub-programs we can make the sub-program work
- on different variables or values.
-
-
- Variable Parameters
-
-
-
- Sub-programs may take two different sorts of
- parameters, value and variable parameters. By
- default parameters are variable parameters and
- are passed by reference. This means that if the
- sub-program changes the value of the variable
- parameter, its value will be modified globally.
- For example:
-
- SUB TimesTwo(v)
- v=v*2
- END SUB
- If we call this using
-
- INPUT " Enter a number";i
- CALL TimesTwo(i)
- PRINT i
- and enter the number 42, i will be modified and
- then twice this, 84, will be printed.
- The shortened form of the CALL statement above
- is:
-
- TimesTwo i
- Note that the brackets are not used when
- omitting the CALL keyword.
- When using variable parameters, if you pass an
- expression rather than a variable of the
- required type then any modifications to the
- parameter are lost. In order for a variable
- parameter to be modified globally by the sub-
- program to which it is passed, the type of the
- passed variable must be the same as the type of
- the parameter and it must be a simple variable.
- If we changed the calling code to be:
-
- INPUT i#
- TimesTwo i#
- PRINT i#
- then the variable i# would not be modified.
- You can pass array elements as variable
- parameters; this causes the subscripting
- expression to be calculated before the sub-
- program is called e.g.
-
- TimesTwo a(3)
- would double the value of a(3). However this
- should be avoided if you are using ERASE and
- REDIM APPEND/PRESERVE inside sub-programs; see
- the Advanced Arrays section in this chapter for
- more information.
- If you want to call a sub-program that normally
- would modify the variable, but on this occasion
- you don´t want this to happen, then enclose the
- variable name in parentheses e.g.
-
- TimesTwo (i)
- This forces the parameter to be passed by
- value. If you use a CALL statement instead you
- use the same method e.g.
-
- CALL TimesTwo ((i)) ´passes i by value
- If you have more than one parameter for a sub-
- program they should be separated by commas in
- both the call and the definition.
- For example:
-
- SUB Multiply(i,j,k)
- k=i*j
-
- END SUB
-
- Multiply 2,3,i
- PRINT i
- This will print 6. Note that the i that is a
- parameter and used in the sub-program is an
- entirely different entity to the i in the main
- program.
-
-
- Value Parameters
-
-
- Parameters may also be called by value, which
- means that the parameter will not be modified
- by the sub-program or function.
- To indicate that a parameter is passed by value
- precede it in the definition with the keyword
- BYVAL. So the above example could be coded as:
-
- SUB Multiply(BYVAL i, BYVAL j,k)
- k=i*j
- END SUB
-
- Multiply 2,3,i
- PRINT i
- Value parameters are more efficient than
- variable parameters and are a MaxonBASIC
- extension. In most other BASICs with sub-
- programs you must use variable parameters and
- enclose them in parentheses. This works fine
- unless you forget the brackets, when you can
- modify your main program variables by mistake.
- In general make a parameter a BYVAL parameter
- unless you want to return a value.
- By default, parameters to sub-programs are
- passed by reference, as variable parameters.
- For compatibility with earlier versions of
- MaxonBASIC you can use VAL instead of BYVAL; we
- do not recommend this for new programs as BYVAL
- is used by the latest Microsoft BASICs for the
- PC.
-
-
- STATIC variables
-
-
- i. Variables :STATIC;
- In the examples so far we have only used
- parameters inside sub-programs. However sub-
- programs may have their own variables. For
- example
-
- SUB Sum(BYVAL n, k)
- STATIC count,total
- total=0
- FOR count=1 TO n
- total=total+count
- NEXT count
- k=count
- END SUB
-
- Sum 4,result
- PRINT result
- will print
-
- 10
- which is 1+2+3+4. The word STATIC is used to
- introduce ordinary local variables. You can use
- commas to separate them. In fact if you omit
- the STATIC statement, the above will still work
- because STATIC is assumed by the compiler.
- However we recommend strongly that you use this
- statement together with the variable checks
- flag (V+). This will warn you if you misspell
- variables in sub-programs.
- For example if we had typed
-
- k=k+cont
- in the example above, the compiler would
- complain that the variable cont was not
- declared.
- STATIC variables are zeroed when the program
- starts running but are not modified between
- different calls to the procedure. In the
- example above if we called the Sum sub-program
- again Total would have a value of 10 so we must
- zero it each time.
-
-
- SHARED variables
-
-
-
-
- You can also use variables from your main
- program inside sub-programs by using the SHARED
- statement. For example we could code the
- example above as:
-
- SUB Sum(BYVAL n)
- STATIC count,total
- SHARED k
- total=0
- FOR count=1 TO n
- total=total+count
- NEXT count
- k=count
- END SUB
-
- Sum 4
- PRINT k
- This is however less flexible than the original
- example because it modifies only one particular
- variable.
- Using SHARED variables with variable parameters
- which should be value parameters can lead to
- the following difficult-to-spot bug shown
- below:
-
- SUB process(t)
- SHARED token
- IF t=3 OR t=4 THEN
- .
- .
- token=5
- .
- .
- IF t=4 THEN ´ problem
- .
- .
- END IF
- END IF
- One would naturally expect t to be 3 or 4 at
- the point marked problem since t was 3 or 4 in
- the previous IF statement. However if the sub-
- program process was called as
-
- process token
- then this would not be the case because the
- modification of token will also change t. This
- can be solved by enclosing t in parentheses or,
- even better, by making the parameter a value
- parameter. This problem can also occur if the
- variable token was modified by a sub-program
- that is called inside process, which is even
- more difficult to spot.
- If you have some variables that are imported
- into many sub-programs and you wish to avoid
- having SHARED statements each time, you can use
- the DIM SHARED statement which causes the
- variable to be SHARED with every sub-program.
- For example, if you have
-
- DIM SHARED debug_flag
- then you can use debug_flag anywhere in your
- program.
-
-
- Recursion and Local variables
-
-
- and
-
- Sub-programs may be called recursively i.e.
- they may call themselves.
-
- SUB Fibonacci(BYVAL n, r)
- LOCAL temp1,temp2
-
- SELECT CASE n
- CASE 0: r=0
- CASE 1: r=1
- CASE REMAINDER:
- Fibonacci n-1, temp1
- Fibonacci n-2, temp2
- r=temp1*temp2
- END SELECT
-
- END SUB
-
- FOR i=0 TO 15
- Fibonacci i,res
- PRINT res;
- NEXT i
- This prints the first few numbers in the
- Fibonacci sequence, in which the nth term is
- the sum of the two previous terms with the
- sequence starting with 0, 1, ÉÉ. This is, in
- fact not the most efficient way to code this
- algorithm in MaxonBASIC; the algorithm can also
- be improved very easily.
- The above example also introduces LOCAL
- variables. These are like STATIC variables in
- that they cannot be accessed outside the sub-
- program. However a new variable is created for
- each invocation of the sub-program. This
- becomes important when you have recursive
- calls. In the example above if there was only
- one variable temp1 then it would be corrupted
- during the second recursive call. Try it and
- see.
- The memory for use of local scalar numeric
- variables is allocated on the machine stack. If
- you make heavy use of recursive calls with
- large numbers of local variables it is possible
- to run out of stack. Use the MINSTACK option,
- see Chapter 4 for details.
- Strings may also be used as parameters and
- local variables in exactly the same way as
- numbers. The only difference is that the actual
- data in the strings is allocated on the heap
- and not on the machine stack.
-
-
- User-Defined Functions
-
- .ib.User-Defined Functions;
- .ib.Functions: User-Defined ;
- As well as sub-programs you can also have user-
- defined functions. In MaxonBASIC there are two
- methods of defining user-defined functions, DEF
- FN and FUNCTION. The latter is the preferred
- modern form so we will discuss this first.
-
-
- Using FUNCTION
-
- The FUNCTION syntax makes user-defined
- functions use the same syntax as for sub-
- programs. User defined functions return results
- by assigning to a pseudo-variable with the name
- of the function.
- For example, here´s another coding of the
- Fibonacci example:
-
- FUNCTION Fibonacci(BYVAL n)
- SELECT CASE n
- CASE 0: Fibonacci=0
- CASE 1: Fibonacci=1
- CASE REMAINDER:
- Fibonacci= Fibonacci(n-1)+Fibonacci(n-
- 2)
- END SELECT
- END FUNCTION
-
- FOR i=0 TO 15
- PRINT Fibonacci (i);
- NEXT i
- This gives probably the neatest solution to
- this classic problem.
- There is no restriction on the name of the
- function and the rules for parameters and local
- variables are the same as for sub-programs.
- FUNCTIONs must be declared before they are
- used. The normal way to this is to ensure that
- the FUNCTION END FUNCTION statements are before
- any calls of the function. If you wish to use a
- function before you define it then you can use
- the .ib.DECLARE ;statement. This specifies the
- parameters of a function in the same way as a
- FUNCTION statement but does not actually
- contain any code.
- For example,
-
- DECLARE FUNCTION Fibonacci(BYVAL n)
-
- FOR i=0 TO 15
- PRINT Fibonacci (i);
- NEXT i
-
- FUNCTION Fibonacci(BYVAL n)
- SELECT CASE n
- CASE 0: Fibonacci=0
- CASE 1: Fibonacci=1
- CASE REMAINDER:
- Fibonacci= Fibonacci(n-1)+Fibonacci(n-
- 2)
- END SELECT
- END FUNCTION
-
- FOR i=0 TO 15
- PRINT Fibonacci (i);
- NEXT i
- This is our final Fibonacci example
- (honestly!). A couple of points to note:
-
- · The form of the DECLARE statement is exactly
- the same as the FUNCTION statement with the
- word DECLARE at the front.
-
- · DECLARE statements are needed for two reasons.
- Firstly, they enable the compiler to check that
- the correct number and type of parameters have
- been used. Secondly if DECLARE was not used,
- the compiler might think that Fibonacci(i) in
- the example above was referring to an array
- Fibonacci(). In fact probably the only
- advantage of the FN syntax is that you can
- instantly see the difference between a function
- call and an array access. Of course, you could
- easily decide to use the similar conventions
- with FUNCTION definitions.
-
- DECLARE statements can also be used for sub-
- programs. They are not required by MaxonBASIC
- but can be useful for compatibility with other
- modern BASICs such as QuickBASIC. You can also
- use them as a documentation aid by having
- DECLARE statements at the front of your program
- for all the sub-programs and functions.
- If you call a function which performs
- input/output inside another statement that
- performs input/output strange things may
- happen. There is no good reason for doing this
- and it should be avoided.
-
-
- Using the FN notation
-
- In the past you could only define a function by
- using FN as a prefix to the function name; old-
- style BASICs restricted you even further in
- that the function could only be one line long.
- For example,
-
- DEF FNrad(x)=x*3.141592653589793/180
- which converts an angle in radians to degrees
- and could be used as follows
-
- PRINT SIN(FNrad(45))
- to give the sine of 45 degrees. The names of
- such user-defined functions must start with FN.
- However, in MaxonBASIC, DEF FN functions may
- have all the facilities of sub-programs with
- the following differences:
- User defined functions return results by
- assigning to a pseudo-variable with the name of
- the function. For example
-
- DEF FNfactorial(n)
- IF n<=1 THEN
- FNfactorial=1
- ELSE
- FNfactorial=n*FNfactorial(n-1)
- END IF
- END DEF
- which calculates the famous factorial function.
- Note that the definition finishes with END DEF
- and that on the right hand side of the
- assignment FNfactorial causes the function to
- be called again recursively.
- The big difference between user-defined FN
- functions and sub-programs is that, in
- functions, parameters are call-by-value by
- default and to specify call-by-variable you
- should precede them with VARPTR. If you do not
- use variable checks, variables are assumed to
- be SHARED rather than STATIC. Naturally this
- difference can be confusing and so we recommend
- using the FUNCTION syntax instead.
- Here is yet another coding of the Fibonacci
- example:
-
- DEF FNfibonacci( n)
- SELECT CASE n
- CASE 0: FNfibonacci=0
- CASE 1: FNfibonacci=1
- CASE REMAINDER:
- FNfibonacci= FNfibonacci(n-
- 1)+FNfibonacci(n-2)
- END SELECT
- END DEF
-
- FOR i=0 TO 15
-
- PRINT FNfibonacci (i);
- NEXT i
- Incidentally you can insert a space between the
- FN and the function name.
-
-
- Arrays and Sub-programs
-
-
-
- Arrays may be used as parameters to sub-
- programs and user-defined functions. They are
- specified both in call statements and
- definitions with open and close parentheses
- after their names. The definition should
- contain the number of dimensions of the array.
- Arrays are always passed by reference.
-
- DIM b(3,6)
- MatSum b(),res
-
- PRINT res
-
- SUB MatSum(a(2),x)
- STATIC i,j,x
- x=0
- F OR i=LBOUND(a,1) TO UBOUND(a,1)
- FOR j=LBOUND(a,2) TO UBOUND(a,2)
- x=x+a(i,j)
- NEXT j
- NEXT i
-
- END SUB
- This sums all the elements of the two
- dimensional array.
- The corresponding function definition would be:
-
- DIM b(3,6)
- PRINT fnMatSum( b())
-
- DEF fnMatSum(a(2))
- STATIC i,j,x
- x=0
- FOR i=LBOUND(a,1) TO UBOUND(a,1)
- FOR j=LBOUND(a,2) TO UBOUND(a,2)
- x=x+a(i,j)
- NEXT j
- NEXT i
- fnMatSum=x
- END SUB
- Sub-programs may share arrays with the main
- program. The SHARED and DIM SHARED statements
- may be used as for scalar variables. The DIM
- SHARED statement when used with arrays also
- dimensions them. The SHARED variablesstatement
- should specify the number of dimensions of the
- array although this is not enforced.
- For example,
-
- DIM SHARED table(100)
- ´table() can now be access anywhere in the
- program.
- or alternatively
-
- DIM table(10)
- table(10)=42 : Silly
-
- SUB Silly
- SHARED table(1)
- PRINT table(10)
- END SUB
- This will print 42.
-
-
- Local Arrays
-
-
-
- Arrays may also be local to a sub-program and
- both STATIC and LOCAL varieties are supported.
- When using STATIC you need to make sure that
- the array is not dimensioned more than once. In
- the STATIC statement the number of dimensions
- may be included in parentheses.
- For example,
-
- ´constants for Table Handler operations
- CONST init=0, insert=1, find =2, replace=3
-
- TableHandler init,0,0 ´initialise the table
- SUB TableHandler(operation, index, value)
- STATIC table(1), first_free
-
- SELECT CASE operation
- CASE init
- DIM table(100)
- first_free=0
-
- CASE insert
- .
- .
- In this example the array will only be
- dimensioned once, as long as the TableHandler
- sub-program is not called with a parameter of
- init more than once.
- Using the LOCAL statement arrays may be created
- for the duration of this call to the sub-
- program. They are erased automatically at the
- end of the call. The actual dimensions are
- given in the LOCAL statement. For example:
-
- SUB Recursive
- ´a temporary array with elements up to
- temp(40).
- LOCAL temp(40)
- .
- .
- END SUB
-
-
- Advanced Arrays
-
-
- As well as the DIM, SHARED, STATIC and LOCAL
- statements described above there are a number
- of other array facilities that are not
- available in primitive BASICs.
- The UBOUND and LBOUND functions return the size
- of arrays. See the example MatSum previously.
- The lower-bound of arrays created by the DIM
- statement can be changed from the default value
- of 0 to 1 by the OPTION BASE statement, for
- example:
-
- OPTION BASE 1 ´arrays now start at one.
- OPTION BASE is an executable statement, and so
- its effect depends on the order of execution in
- the program, not the order of the program text.
- It is thus possible for an array to have
- different dimensions if it is ERASEd and then
- REDIMmed. Using OPTION BASE normally only saves
- a considerable amount of memory if you are
- using 3 or more dimensions in an array.
- When array checks are switched off OPTION BASE
- statements are ignored.
-
-
- Dynamic and static arrays
-
-
-
- Normally arrays that are DIMensioned using a
- constant value, for example DIM A(100) are
- treated as static arrays. Static arrays have a
- constant size specified by the DIM statement
- and may not be re-dimensioned or erased which
- means the compiler can generate code that will
- access them very quickly. If you have an array
- that you will subsequently want to re-dimension
- or erase then you´ll need to use REM $dynamic
- which causes the compiler to make all DIMension
- statements declare dynamic arrays from this
- point in your program.
- For example:
-
- REM $dynamic
- CONST arrsize=200
- DIM arr(arrsize)
-
- REDIM arrsize(300)
-
- You can revert to the normal behaviour by using
- REM $static.
- Dynamic arrays can grow and shrink in size and
- therefore MaxonBASIC has to generate more code
- to handle this possible behaviour - if you want
- arrays to be accessed as quickly as possible
- using the minimum amount of code, use static
- arrays, which is the default. Static arrays are
- stored in the program´s global space rather
- than on the heap.
- Note that you must have used REM $DYNAMIC
- before you DIM the array for the first time;
- you cannot change the type of an array after it
- is declared.
-
-
- Other array features
-
- ERASE works in two different ways, depending on
- the type of the array (dynamic or static). For
- static arrays, ERASE simply clears all the
- elements to 0 or to the null string. For
- dynamic arrays, ERASE may be used to free the
- space used by the array when it is no longer
- required. This is particularly useful if you
- have temporary results stored in an array. Once
- a dynamic array has been ERASEd you can DIM it
- again. For example,
-
- REM $dynamic
- DIM temp(10000) ´ 10000 temporary results
- .
- .
- ERASE temp
-
- ´ note that temp is not followed by parentheses.
- This
- ´ anomaly is present for compatibility with
- other BASICs
- The REDIM statement for dynamic arrays gives
- the equivalent of an ERASE followed by a DIM in
- one statement. Thus
-
- REDIM temp(100)
- is equivalent to
-
- ERASE temp: DIM temp(100)
- REDIM cannot be used for static arrays.
- MaxonBASIC has a powerful extension to let you
- change the size of dynamic arrays whilst
- retaining their data called REDIM PRESERVE.
- For example:
-
- REM $dynamic
-
- SUB AddElement(value)
-
- SHARED table(1), maxentries, nextentry
-
- IF nextentry> maxentries THEN
- ´ no room for this entry
- maxentries=maxentries+100
- REDIM PRESERVE table(maxentries)
- ´ the above makes the array 100 elements
- larger
- END IF
-
- table(nextentry)=value ´enter the value
- nextentry=nextentry+1 ´ready to store the next
- one
-
- END SUB
- This example shows how you can avoid fixed
- limits on the sizes of dynamic arrays. If you
- run out of room just make it bigger. REDIM
- PRESERVE requires enough memory to make a copy
- of the array. You can also use REDIM PRESERVE
- to make dynamic arrays smaller; again a copy of
- the array is made.
- Normally the ERASE, REDIM and REDIM PRESERVE
- statements cause dynamic arrays to be moved in
- memory. As a result, if there are any pending
- array elements that have been used in variable
- parameters, then these will be become invalid.
- The best way to avoid this is by not passing
- array elements by reference. For example the
- following may not work as intended:
-
- REM $dynamic
- DIM x(50), a(30)
- .
- .
- Subprog a(3) ´ note variable parameter.
- .
- SUB Subprog(b) ´ note variable parameter
-
- ERASE x
- ´ a() will now become corrupt, it has
- ´ been moved because it was declared
- ´ after x() which has been erased
-
- .
- .
- END SUB
- Unlike many BASIC compilers, MaxonBASIC will
- let you change the number of dimensions of
- dynamic arrays with a REDIM statement. This may
- prove useful when porting certain programs that
- were developed with interpreters, however we
- recommend strongly that you avoid this as it
- can make programs almost un-maintainable.
- For compatibility with earlier versions of
- MaxonBASIC, you can use REDIM APPEND instead of
- REDIM PRESERVE. However we recommend the use of
- the latter as it is the form used by Microsoft
- BASIC 7.1 on the PC.
-
-
- Limitations Imposed by the Compiler
-
-
- We have tried to avoid placing limits on the
- programs you can write. For example, most
- compilers have a limit on the number of
- characters that are significant in an
- identifier; MaxonBASIC does not impose any
- limit on this so that
- A_very_long_identifier_indeed_which_goes_on_and
- _on
- is different from
- A_very_long_identifier_indeed_which_goes_on_and
- _on_and_is_different
- This sort of limitation may not seem important
- to you, but such possible restrictions have the
- annoying habit of appearing when you think you
- have nearly finished a large program.
- This section intends to list the remaining
- limitations other than the total workspace of
- the compiler. If you find these restrictive
- please tell us.
- A program may not have more than 16383 lines.
- If you hit this limit you can probably get
- round it by having more than one statement per
- line. We have a 5000 line program which is
- about 135K bytes of source. If you exceed this
- you will be given a Too many lines in program
- compiler error.
- The total number of active labels in the code
- generation phase of the compiler, as specified
- by the Label Table option (LABEL) may not
- exceed 5641. A label is generated for each line
- number or label that is referenced (not for
- those that are un-used) together with 2-3 or
- each sub-program, 2 for each CASE in SELECT
- statements plus 2 for the SELECT itself and 2
- for most structure statements. For example our
- 5000 line program requires about 1100 such
- labels.
- There is a limit of approximately 8000 on the
- number of sub-programs, shared and local
- variables and parameters in the entire program;
- if you exceed this you will be given a
- Structure Table Full error message.
- The total number of different names in your
- program may not exceed 14000.
- The total code of a SELECT statement may not
- exceed 32k bytes. To avoid this make some of
- the alternatives into sub-programs.
- The total size of some FORÉNEXT loops may not
- exceed 32k bytes. To avoid this make some or
- all of the loop into a sub-program.
- Sub-programs and user defined functions may not
- have more than 128 parameters.
- The total space for global and STATIC local
- variables and the descriptor table may not
- exceed approximately 29K bytes. The amount of
- storage, in bytes, in this area required for
- the different types is:
- 2 integers
- 4 long integers, single precision numbers
- 8 strings, double-precision numbers, all
- arrays
- The data in strings and arrays is not stored in
- this area. Static arrays are stored at the end
- of this static array but they are not subject
- to this 29K restriction.
- Local variable stack space may not be more than
- 32k bytes per invocation. The different types
- require the number of bytes given in the table
- above.
- There are limits of 255 channels, 14 user
- libraries, 4 screens opened via the SCREEN
- statement and 12 windows opened via the WINDOW
- statement.
- ON GOTO and ON GOSUB statements may not have
- more than 8190 line numbers each (!)
-
-
-