home *** CD-ROM | disk | FTP | other *** search
/ The Fred Fish Collection 1.5 / ffcollection-1-5-1992-11.iso / ff_disks / 300-399 / ff339.lzh / PCQ / Pascal.DOC < prev    next >
Text File  |  1990-03-19  |  66KB  |  1,562 lines

  1.  
  2.                         PCQ version 1.1
  3.             A very simple Pascal compiler for the Amiga
  4.                        by Patrick Quaid
  5.  
  6.  
  7.     PCQ (which stands for Pascal Compiler, um, Q ...  look, I
  8. couldn't come up with a name so I used my initials, OK?) is a modest
  9. Pascal sub-set compiler that produces assembly code.  It is not in
  10. the Public Domain (I retain the copyright to the source code, the
  11. compiler, the run time library source code, the run time library, and
  12. this documentation), but it can be freely distributed as long as all
  13. the files in the archive are included (with the possible exception of
  14. the assembler and linker) and unchanged.  The compiler is slow, and
  15. it can't handle a couple of things, but all in all it's worth the
  16. price.  To summarize:
  17.  
  18. The bad:
  19.  
  20.     The compiler is awfully slow.
  21.     It doesn't support sets.
  22.     The code is not optimized at all.  It is, therefore, slow,
  23.        fat and generally silly looking.
  24.     The compiler gets knocked for a loop by most errors.
  25.  
  26. The good:
  27.  
  28.     It works, for the most part.
  29.     The compiler supports include files.
  30.     It allows for external references, although you have to
  31.        do the checking (this isn't Modula-2, after all).
  32.     It supports records, enumerated types, pointers, arrays,
  33.        and strings.
  34.     Type conversion as found in Modula-2 is supported.  In
  35.        other words, something like "integer('d')" is legal.
  36.     Several features from Turbo and Quick Pascal, such as Exit
  37.        procedures, operators such as Shl and Shr, and typed
  38.        constants, have been added.
  39.     You can have as many const, var, type, procedure and
  40.        function blocks as you want, in any order.
  41.     It's free.
  42.  
  43.  
  44.  
  45.  
  46.  
  47.          Table of Contents
  48.  
  49.  
  50.     This manual is intended to be read with a file reader or
  51. text editor, so this table of contents is based on line numbers
  52. rather than page numbers.
  53.  
  54.  
  55. Section                                Line number
  56.  
  57. How To Use PCQ  ........................   88
  58. An Examination of Its Ills  ............  191
  59. Predefined Stuff  ......................  226
  60.     Constants  .........................  253
  61.     Types  .............................  299
  62.     Variables  .........................  350
  63.     Functions  .........................  379
  64.     Procedures  ........................  460
  65.     Extra Statements  ..................  516
  66. Reserved Words  ........................  556
  67. Expressions  ...........................  579
  68. Floating Point Math  ...................  606
  69. The Limits of PCQ  .....................  628
  70. Typed Constants  .......................  643
  71. Strings  ...............................  717
  72. Exit Procedures  .......................  779
  73. Compiler Directives  ...................  817
  74. Type Conversions  ......................  897
  75. External References  ...................  938
  76. Input/Output  .......................... 1013
  77. Standard IO  ........................... 1191
  78. Errors  ................................ 1252
  79. Run Time Errors  ....................... 1283
  80. Sources  ............................... 1312
  81. Notes to Assembly Programmers  ......... 1366
  82. Improvements On The Burner  ............ 1385
  83. Update History  ........................ 1399
  84. Other Notes, Copyright & My Address  ... 1508
  85.  
  86.  
  87.  
  88.                         How To Use PCQ
  89.  
  90.  
  91.     There are several files in this archive you will need to copy
  92. over to your work disk.  The compiler (Pascal) is one, of course, as
  93. well as the run time library (called PCQ.lib- there's a readme file
  94. in the archive that explains all the file names, by the way).  If you
  95. do not have the assembler (A68k) and linker (Blink), you'll have to
  96. copy them as well (they might not have been included in this archive,
  97. but should be available on a local bulletin board or on Fred Fish
  98. disks).  These files are necessary for even the simplest
  99. compilations.
  100.  
  101.     The files with the suffix .p are example Pascal programs, which
  102. you can copy over if you want.  I spent a lot more time working on
  103. the compiler than on these examples, but a couple of them are
  104. interesting if you haven't seen programs like them before.  They
  105. demonstrate just about every aspect of the compiler that I could
  106. think of, so you should probably take a look at them and then get rid
  107. of them.  If you got the source code with the compiler, there will be
  108. a bunch of those files lying around with the suffix ".p" also.
  109.  
  110.     The files that end with .i are include files for a few of system
  111. libraries.  They define the records, types, constants, procedures,
  112. functions and variables needed to access the system.  These you
  113. probably should keep around.  There are also a few include files for
  114. routines I've supplied in PCQ.lib.  Take a look through these files
  115. to see what's available- it changes frequently.  The code related to
  116. all these routines is in the run time library.
  117.  
  118.     In order to compile a program, first write one.  Or use one of
  119. the example programs.  Then type:
  120.  
  121.              1> Pascal prog.p prog.asm {-q}
  122.  
  123.     'Pascal' is, of course, the name of the compiler.  You can change
  124. it if you want.  'Prog.p' is the pascal source file, which can also
  125. be called whatever you want.  The second parameter is the name of the
  126. assembly file produced.  If you include the "-q" directive (which can
  127. be anywhere in the command line), the compiler will suppress all
  128. output except error reports.  Furthermore, the error reports will be
  129. shortened to a more regular form.  At the moment these are the only
  130. command line arguments allowed.
  131.     If you try to compile the example programs, you might run into
  132. some problems with the organization of the disk.  The examples all
  133. refer to the include files they require as ":Include/Something.i".
  134. Therefore the Include directory is expected to be on the root of the
  135. current disk.  If this conflicts with your setup, just edit the
  136. include statements at the start of the file.  Assuming the compiler
  137. finishes without any errors, you then type:
  138.  
  139.              1> A68k prog.asm prog.o
  140.  
  141.     This invokes the assembler to produce object code.  If the
  142. archive included A68k it probably also included the documentation for
  143. it, so read that for information about the assembler.  If the
  144. assembler was not included, get and use A68k by Charlie Gibbs,
  145. version 2.6 if possible.  A68k does lots of small scale optimization
  146. that the code from PCQ might very well depend upon, so I don't claim
  147. that the compiler works with any other assembler.  Finally, you want
  148. to link the program, so you type:
  149.  
  150.         1> Blink prog.o to prog library PCQ.lib
  151.  
  152.     This will produce a finished executable program called 'prog'.
  153. All of the Pascal run time routines, Amiga system routines, and my
  154. tiny little string library are contained in PCQ.lib.  If any of the
  155. routine names clash with ones you are working with, just be sure to
  156. put your library or object file in front of PCQ.lib on the Blink
  157. command line.  If Blink was included in the archive it's
  158. documentation probably was as well, so read that to answer any
  159. questions you may have about the link process.
  160.     I use Blink version 6.7, and again I assume that PCQ won't work
  161. with any other linker or version.  Note that in previous versions
  162. you had to include Small.lib on the Blink line.  I switched
  163. versions of Small.lib, however, so I was able to just include it
  164. with PCQ.lib.
  165.     Instead of all this business you could just use the 'make' script
  166. that's included in the archive.  You may have to change it around a
  167. bit so that it looks in the proper directories and whatnot, then
  168. through the magic of AmigaDOS 1.3 you should make it a script file.
  169. Then you can invoke it like:
  170.  
  171.         1> make prog
  172.  
  173.     It will take the file 'prog.p' and produce the finished file
  174. 'prog'.  If your program has separately compiled units, you'll need
  175. to modify the batch file or write another.  I recommend writing a
  176. script file for any program you'll need to compile a few times.  If
  177. none of this makes any sense, write or call me and I'll try to give
  178. you more coherent instructions.
  179.  
  180.     If you have the full distribution disk, there is a simple way
  181. to give the compiler a workout.  Just cd to the "Examples"
  182. directory, then type "MakeExample Moire".  Note that there's no
  183. ".p" on the program name.  This script looks for the compiler,
  184. assembler, linker and runtime library on the root of the disk, uses
  185. the T: directory extensively, and leaves the completed program in a
  186. file called "Moire" (or whatever you chose) in the Examples
  187. directory.
  188.  
  189.  
  190.  
  191.                  An Examination of Its Ills
  192.  
  193.    I might as well get this over with right away.  As was mentioned
  194. earlier, sets do not work at all.  Another thing that's not accepted
  195. is syntax like:
  196.  
  197.     type
  198.         WindowPtr = ^Window;
  199.         Window = record
  200.             NextWindow : WindowPtr;
  201.             ...
  202.  
  203.     It will fail on the first line with an 'Unknown ID' error. 
  204. Instead, use something like:
  205.  
  206.    type
  207.        Window = record
  208.            NextWindow : ^Window;
  209.            ....
  210.        end;
  211.        WindowPtr = ^Window;
  212.  
  213.     This is something I should get around to fixing, but it isn't
  214. strictly necessary, so there you go....
  215.  
  216.     The compiler still will not allow variant records.  I suppose
  217. I'll get around to fixing this eventually.  The familiar syntax for
  218. specifying a single quote character, which looks like: '''', is not
  219. accepted.  Instead, PCQ Pascal using the C escape convention.  Thus
  220. the single quote character would look like: '\''.  See the section
  221. called Strings for more information.
  222.  
  223.  
  224.  
  225.  
  226.                    Predefined Stuff
  227.  
  228.     I've arranged the predefined identifiers as they are supposed
  229. to appear in Pascal.  In PCQ, however, you can have these blocks
  230. in any order, and you can have more than one of each.  In other words,
  231. your program could look like:
  232.  
  233.    Program name;
  234.    var
  235.        variable declarations
  236.    type
  237.        types
  238.    var
  239.        more variables
  240.    procedure
  241.        a procedure
  242.    var
  243.        still more variables....
  244.  
  245.    And so on.  An identifier must still be declared before it
  246. is used, of course.  I allowed this because it is a real pain to
  247. arrange a bunch of different include files (each of the system
  248. include files would have had to be split into four sections : the
  249. constants, the types, the variables, and the procedures and
  250. functions).
  251.  
  252.  
  253. CONST
  254.  
  255.    True and False are defined as -1 and 0, respectively.
  256.    Nil is defined as a pointer with the constant value zero,
  257. but is not a reserved word as it is in standard Pascal.
  258.  
  259.    Most places the compiler requires a constant, it will take a
  260. constant expression (one that can be evaluated during the compile).
  261. For example, the following will work:
  262.  
  263.    const
  264.        first = 234;
  265.        second = first * 2;
  266.  
  267.    type
  268.        thetype = array [first .. first + 7] of char;
  269.  
  270.    Unfortunately you cannot yet use standard functions, type
  271. conversions, floating point numbers, or other nifty things that you
  272. can do with expressions in the program body.  Just the five basic
  273. math functions (+, -, *, div, mod), for now.  Also note that 'first +
  274. 7' up there would be evaluated during the compile, but the same text
  275. in the body of the program would be evaluated during run time.  In
  276. other words, there is no such thing as constant folding yet.
  277.    When you are using integer constants, you can separate the
  278. digits with an underscore, similar to Ada.  In other words you
  279. could have:
  280.  
  281.    const
  282.        thousand = 1_000;
  283.        tenthousand = 1_0_0_0_0;
  284.  
  285.    MaxInt is defined as $7FFFFFFF, which comes out to something
  286. over two billion.  MaxShort is 32767, or $7FFF in hex.
  287.  
  288.     Another form of constant is the 'Typed Constant'.  In this case
  289. the syntax looks like:
  290.  
  291.         CONST
  292.             Identifier : Type Description = Constant Expression;
  293.  
  294.     Typed constants are initialized at the beginning of the program
  295. to the Constant Expression, and thereafter can be used in exactly the
  296. same way as variables.  These values are explained in depth in the
  297. section called Typed Constants.
  298.  
  299. TYPE
  300.  
  301.    There are several predefined types.  They include:
  302.  
  303. Integer      4 bytes, so the range is plus or minus MaxInt.
  304. Short        2 bytes.  Literals within the program text are
  305.              assumed to be short values unless they are greater
  306.              than 32767 or less than -32767.
  307. Byte         1 byte.  These three types are all numeric types, so
  308.              you can use them in normal expressions without
  309.              worrying about type conversions.  The compiler
  310.              automatically 'promotes' the small values to
  311.              whatever size is required.  Remember that there is
  312.              currently no overflow checking.  As of version 1.1,
  313.              the Byte type has the range 0..255 rather than
  314.              -128..127, its range in previous versions.
  315. Real         4 bytes.  This is in FFP format.
  316. Char         1 byte.
  317. Boolean      1 byte.  False is 0 and true is -1.
  318. String       4 bytes.  Really just defined as '^char'.  I will
  319.              explain further in the section 'Strings'.
  320. Address      4 bytes.  This is a pointer to no particular type.
  321.              It is type compatible with any other pointer- in fact
  322.              the constant Nil is of type Address.
  323. Text         32 bytes.  This is not the same as a 'file of char'.
  324.              Input and Output are Text files.    You can read
  325.              and write integers, characters, arrays of characters,
  326.              and strings to Text files.  You can also write Boolean
  327.              values.
  328. Enumerated   1 or 2 bytes, depending on the number of enumerations.
  329.  
  330.    As was mentioned above, you can have arrays, pointers, records,
  331. and files based on the above types.  You can also have synonym types,
  332. like 'type int = integer;'.
  333.    Also note that almost anywhere you need a type, you can use a full
  334. type description.  Some compilers have a problem with this, and I'm
  335. not sure what Standard Pascal says about it, but then again I really
  336. don't care much.
  337.    In version 1.0, you were forced to write out a multi-dimensional
  338. fully.  In other words you couldn't just write:
  339.  
  340.     Array [0..5, 0..11] of Integer;
  341.  
  342.   Instead you needed to expand it to:
  343.  
  344.    Array [0..5] of Array [0..11] of Integer;
  345.  
  346.   ....for the definition, and ArrayName[x][y] for the actual use in a
  347. program.  Most Pascal compilers allow the comma-delimited shorthand,
  348. however, so now I do too.
  349.  
  350. VAR
  351.  
  352.    Version 1.1 of PCQ Pascal has several new variables.  They are:
  353.  
  354.    CommandLine   : String;
  355.  
  356.    In version 1.1 this was an Array of Char, and also a copy.  It is
  357. neither now:  it is a pointer to the actual stack space on which the
  358. command line is stored.  You can use routines such as GetParam to get
  359. copies of the individual parameters.
  360.  
  361.    ExitProc      : String;
  362.  
  363.    This variable points to the first in a chain of procedures to be
  364. executed when the program is shutting down.  See the section called
  365. Exit Procedures for more information.
  366.  
  367.    ExitCode      : Integer;
  368.  
  369.    If the program exited normally, this will be 0.  If the program
  370. called the Exit() procedure, this will be the argument of that call.
  371. Otherwise this is a run-time error code.  Again, see Exit Procedures
  372. for more information.
  373.  
  374.    ExitAddr      : Address;
  375.  
  376.    If the program died due to a run-time error, this value will hold
  377. the address of the statement after the error.
  378.  
  379. FUNCTION
  380.  
  381.    With the exception of a few exponential functions, most of the
  382. standard functions are provided.  They include:
  383.  
  384.    function ord(x : any ordinal type): integer;
  385.       returns the ordinal position of the argument.
  386.  
  387.    function chr(x : numeric type) : char;
  388.       returns the indicated character.
  389.  
  390.    function abs(x : real, integer, short, or byte) : the same type;
  391.       returns the absolute value.
  392.  
  393.    function succ(x : ordinal type) : the same type;
  394.       returns x + 1, of the same type
  395.  
  396.    function pred(x : ordinal type) : the same type;
  397.       returns x - 1, in that type
  398.  
  399.    function odd(x : numeric type) : boolean;
  400.       returns true if the number is odd
  401.  
  402.    function trunc(x : real) : integer;
  403.       returns the integer part of a real number.
  404.  
  405.    function float(x : integer, short or byte) : real;
  406.       converts these types to FFP format.
  407.  
  408.    function floor(x : real): real;
  409.       returns the greatest 'integer' value less than x.
  410.  
  411.    function ceil(x : real) : real;
  412.       returns the least 'integer' value greater than x.
  413.  
  414.    function sqr(x : real) : real;
  415.       returns x * x, but is slightly faster and smaller.
  416.  
  417.    function sqrt(x : real) : real;
  418.       returns the approximate square root of x.
  419.  
  420.    function sin(x : real radians) : real;
  421.       returns the approximate sine
  422.  
  423.    function cos(x : real radians) : real;
  424.       returns an approximation of the cosine
  425.  
  426.    function tan(x : real radians) : real;
  427.       returns the approximate tangent of x.  If x is a multiple
  428.       of Pi/2, this will blow up.
  429.  
  430.    function arctan(x : real) : real;
  431.       returns the approximate arctangent (in radians) of x.
  432.  
  433.    function eof(x : any file): boolean;
  434.       returns true if you are at the end of an input file.
  435.  
  436.    function adr(var x : any variable): Address;
  437.       returns the address of the variable in question.
  438.  
  439.    function SizeOf(t : name of a type) : Integer;
  440.       returns the size of the specified type, which must be a single
  441.       identifier.
  442.  
  443.    function Bit(t : Integer) : Integer;
  444.       returns the number corresponding to the bit position specified.
  445.       In other words it returns an integer with just the one bit set.
  446.  
  447.    Function IOResult : Integer;
  448.       Returns the result of the last IO statement.  If it is
  449.       non-zero, it's probably an AmigaDOS error code.  This call
  450.       clears IOResult.  If IO checking is off and there is an IO
  451.       error, IOResult will become non-zero and no subsequent IO
  452.       statements will have effect.
  453.  
  454.    There are two other standard functions (open and reopen), but
  455. since they are IO functions I'll describe them in the Input/Output
  456. section.  There is also a syntax like 'typename(expression)'
  457. supported by the language.  It looks like a function, but isn't,
  458. and will be explained in a later section called Type Conversions.
  459.  
  460. PROCEDURE
  461.  
  462.     The standard procedures are Write, Writeln, Read, Readln, Get,
  463. Put, New, Dispose, Exit, and Trap, Inc and Dec.  The first six will
  464. be covered in the IO section.  The other six are:
  465.  
  466.     Procedure New(var x : any pointer variable);
  467.  
  468.     This allocates public memory the size of whatever type is pointed
  469. to, then puts the address into x.  PCQ allocates memory using
  470. Intuition's AllocRemember() routine, so that at the end of execution
  471. all the memory allocated through new() is returned to the system.
  472. This means that you don't absolutely have to call dispose() for every
  473. new(), although you should.
  474.     If the allocation fails, the program aborts with a run-time error.
  475.  
  476.    Procedure Dispose(var x : pointer variable);
  477.  
  478.    This returns the allocated memory to the system.  If something got
  479. confused, and you try to dispose of memory you never allocated, this
  480. will just return.  Unfortunately that means you may never diagnose a
  481. problem in your program, but at least it won't be calling the Guru
  482. all the time.
  483.  
  484.    Procedure Exit(error : integer);
  485.  
  486.    Exit() aborts a program early.  It is the acceptable method of
  487. escaping a program.  It does the same stuff that the program normally
  488. does when it quits, then returns the error number you give it to
  489. AmigaDOS.  Any exit procedures you have installed can recognize a
  490. program that terminated due to the Exit() procedure because ExitAddr
  491. will always be Nil.  According to convention, the error number should be
  492. zero if the program terminated correctly, 5 for a warning, 10 for an
  493. error, and 20 for a catastrophic error.
  494.  
  495.    Procedure Trap(num : integer);
  496.  
  497.    The argument for this procedure must be a constant expression,
  498. although the type doesn't matter.  All it does is insert a 68000 trap
  499. instruction into the code at the point of the statement.  This is
  500. useful for the debugger I use, and for nothing else I can imagine.
  501. It effectively inserts a break point in the program.
  502.  
  503.    Procedure Inc(x : Any ordinal or Pointer type);
  504.  
  505.    If x is an ordinal type, Inc() just adds one to it.  If it is a
  506. pointer type, Inc() adds the size of whatever x points to.  If x is a
  507. string, for example, Inc() just adds one.  If x is an Address type,
  508. it adds four (No particular reason for that, by the way).
  509.  
  510.    Procedure Dec(x : any ordinal or pointer type);
  511.  
  512.    Dec() is exactly analogous to Inc(), in that it subtracts either
  513. one or the size of whatever the pointer points to.
  514.  
  515.  
  516. Extra Statements
  517.  
  518.    First of all, PCQ supports if, while, repeat, for, case, goto and
  519. with statements.
  520.    The if, while, repeat, goto and with statements work just like the
  521. Standard Pascal report says they should.  The case statement is now
  522. much more like normal Pascal than it was in version 1.0.  Each case
  523. can have any number of constants or constant ranges.  At the end of
  524. the case construct, as the final case, you can have an ELSE
  525. statement.  This will execute, not surprisingly, if none of the cases
  526. is true.  Thus a couple of example case statements are:
  527.  
  528.     case Letter of                   case Number * 5 of
  529.         'a'      : statement1;          -MaxInt..0 : statement1;
  530.         'b'..'g' : statement2;          1..MaxInt  : statement2;
  531.         'j',                         end;
  532.         'm'..'o',
  533.         'h'      : statement3;
  534.     else
  535.         statement4;
  536.     end;
  537.  
  538.    The for statement supports 'downto', which changes the increment
  539. from 1 to -1.  It also supports 'by', which allows you to set the
  540. increment.  The argument for the 'by' part can be any regular
  541. expression, but for any negative increment you must use 'downto'
  542. rather than 'to', or the loop will only run once.  For that matter
  543. all 'for' loops run at least one time.  Anyway the syntax looks
  544. something like:
  545.  
  546.       for <variable> := <expression> to|downto <expression>
  547.                         [by <expression>] do <statement>;
  548.  
  549.    The other statement included is 'return', which simply aborts a
  550. PROCEDURE early.  You can abort a FUNCTION early by assigning the
  551. function name to some value, so 'return' works only in procedures.
  552.  
  553.  
  554.  
  555.  
  556.                       Reserved Words
  557.  
  558.    The reserved words of PCQ are as follows:
  559.                             
  560.             and         for         procedure
  561.             array       forward     program
  562.             begin       function    record
  563.             by          goto        repeat
  564.             case        if          return
  565.             const       in          set
  566.             div         label       then
  567.             do          mod         to
  568.             downto      not         type
  569.             else        of          until
  570.             end         or          var
  571.             external    packed      while
  572.             file        private     with
  573.  
  574.    As you can see, even the unimplemented stuff is reserved.
  575.  
  576.  
  577.  
  578.  
  579.                         Expressions
  580.  
  581.    The compiler will accept the normal expression syntax, like most
  582. programming languages.  It will also accept several new operators
  583. similar to ones in Turbo Pascal and C.  These are:
  584.  
  585.      Xor        This operator returns the exclusive-or result of the
  586.                 two operands.  For example, 3 xor 5 returns 7.  This
  587.                 is the same as the Turbo XOR operator, or the ^
  588.                 operator in C.  This operator has the same precedence
  589.                 as the +, -, and OR operators.
  590.  
  591.      Shl        This operator shifts left the value on the left the
  592.                 number of bit positions specified on the right.  Thus
  593.                 1 shl 5 = 32.  This again is the same as the Turbo
  594.                 operator and the C << operator.  It has the same
  595.                 precedence as the *, /, div, and AND operator.
  596.  
  597.      Shr        This is the same as Shl, but shifts the value to the
  598.                 right.  It uses logical rather than arithmetic shifts,
  599.                 so negative values will provide positive results.
  600.  
  601.     Hexadecimal representation can be used anywhere an integer is
  602. expected.
  603.  
  604.  
  605.  
  606.                      Floating Point Math
  607.  
  608.    As of version 1.0c, real numbers are integrated into the language.
  609. In the program text they can be specified using the normal syntax of
  610. a series of digits, followed by a period, followed by any number of
  611. digits.  The syntax that looks like 1.0876E-4 is NOT supported.
  612.    The only math operators supported are +, -, /,  and *.  The rest
  613. of the MathFFP.library is also accessible.  The standard functions
  614. pertaining to real math are Abs(), floor(), ceil(), trunc() and
  615. float().  I have included some reasonable sin() and cos() functions,
  616. which are accurate to about four digits, and reasonably fast.
  617.    I also added a sqrt (square root) function based on Newton's
  618. method.  It is accurate enough that sqr(sqrt(x)) is less than
  619. x/10000 off.
  620.    Functions like exp() and ln() are not handled by the
  621. MathFFP.library.  They are located in MathTrans.library, which is
  622. disk based.  Thus whenever you write a program that needs these
  623. functions, the system disk will have to be inserted in order to get
  624. to LIBS:.  Read MathTrans.i for further information about all this.
  625.  
  626.  
  627.  
  628.                      The Limits of PCQ
  629.  
  630.    The compiler can accept lines of any length, although it will
  631. display at most the previous 128 characters read in if an error
  632. occurs.  As far as the size of the file is concerned, it can be any
  633. length (the only part of the file that is in memory at any time is
  634. the current character), with, of course, a few caveats.
  635.    The main limit is that, since the compiler produces lots of
  636. assembly code output, there must be room on the disk for the whole
  637. file.  The assembly output is, as a rule of thumb, as much as five
  638. times as large as the Pascal source.
  639.  
  640.  
  641.  
  642.  
  643.                        Typed Constants
  644.  
  645.     Turbo and Quick Pascal in the MS-DOS world have introduced typed
  646. constants to the Pascal world.  These objects serve the same purpose
  647. as initialized variables in C, and why they are not defined as
  648. variables I don't know.  In the interest of molding the syntax of PCQ
  649. Pascal after that of Turbo (the working standard), I maintain their
  650. odd Constant idea.
  651.  
  652.     As I mentioned above, the syntax of typed constants looks like:
  653.  
  654.     CONST
  655.         Identifier : TypeDefinition = Constant Expression;
  656.  
  657.     The identifier is a normal Pascal identifier, followed by a
  658. colon, followed by any full type expression, an equal sign, and a
  659. modified constant expression.  These expressions are the normal
  660. constant expressions (just like normal expressions without standard
  661. functions), augmented by a syntax for referring to arrays and records.
  662.  
  663.     Specifying types like Integer, Real, Char, Byte, Boolean, etc. is
  664. done in the same way as you would expect.  Specifying arrays is done
  665. by starting off with a left parenthesis, followed by a number of
  666. elements separated by commas, and ended by a right parenthesis.  The
  667. elements themselves would normally be integers or characters, but
  668. could also be arrays or records themselves.  In an array definition
  669. there is always the same number of of elements as there are elements
  670. in the array- any difference is an error.  The exception to the
  671. normal array format is in arrays of characters.  These are
  672. specified in the same way as most character arrays - an apostrophe
  673. followed by characters and ended with another apostrophe.
  674.  
  675.     Records are defined in the same way.  A left parenthesis,
  676. followed by the definition of each of the elements, followed by a
  677. right parenthesis.
  678.  
  679.     Pointers have a special syntax.  They will mostly be defined as
  680. Nil, but can also take the value of the address of previously defined
  681. global variables and typed constants.  This is done by using the '@'
  682. operator, also borrowed from Turbo Pascal.  The '@' operator returns
  683. the address of the following identifier, and is only used in this
  684. context.
  685.  
  686.     Some typed constants can even be used in subsequent constant
  687. expressions.  In this case the initial value of the constant is
  688. always used.  This value is only meaningful for simple types like
  689. integers, reals, characters, and strings.  For arrays and records you
  690. will get a nonsense result.
  691.  
  692.     Typed constants declared in procedures and functions can't be
  693. referenced outside of the function, of course, but they do have the
  694. interesting property that they retain their value across calls the
  695. the routine.  This will screw up recursive routines, so be careful.
  696.  
  697.     Examples of the typed constant definitions include:
  698.  
  699.     TYPE
  700.         Array1 : Array [-4..-2] of String;
  701.         Array2 : ^Array1;
  702.         Array3 : record
  703.                      Name : String;
  704.                      Letter : char;
  705.                      Value : Real;
  706.                  end;
  707.  
  708.     CONST
  709.         Pi : Real = 3.1415;
  710.         Val1    : Array1 = ("Message 1", "Second Message", Nil, "Last");
  711.         Val2    : Array2 = Nil;
  712.         Val3    : Array2 = @Val1;
  713.         Val4    : Array3 = ("Ziasus Pomouk", '\n', Pi);
  714.  
  715.  
  716.  
  717.                            Strings
  718.  
  719.    As was mentioned above, strings should be thought of like
  720. '^char'.  They are defined that way, but also are given special
  721. properties.  They can be dynamically created, sized, and disposed
  722. of.  A string is supposed to be terminated by a zero byte, so if
  723. you write any string handling routines be sure you follow that
  724. convention.  Otherwise you'll confuse all the other string
  725. routines.  In the text of a program, you delineate strings with
  726. double quotes, instead of the single quotes found around normal
  727. arrays of char.  Thus:
  728.  
  729.    "A string"   is indeed a string, while
  730.    'not one '   is considered an array [1..8] of char.
  731.  
  732.    The other interesting thing about strings is that they can
  733. have C-like escape sequences.  What happens is that you type a
  734. backslash (looks like this: \), and the very next character is
  735. specially handled.  C has a bunch of these things, and I've
  736. included most of them, including:
  737.  
  738.    \n   Line Feed, chr(10)
  739.    \t   Tab, chr(9)
  740.    \0   Null, chr(0)
  741.    \b   Backspace, chr(8)
  742.    \e   ESC, chr(27)
  743.    \c   CSI (Control Sequence Introducer), chr($9B)
  744.    \a   Attention, chr(7)
  745.    \f   Form Feed, chr(12)
  746.    \r   Carraige Return, chr(13)
  747.    \v   Vertical Tab, chr(11)
  748.  
  749.    Everything else passes through unchanged, so that you can
  750. also use this mechanism to include double quotes in your strings. 
  751. And you have to use it to include backslashes.  What this all
  752. boils down to is that the string "A\tboy\nand\\his \"dog.\""
  753. prints out like:
  754.  
  755.       |A       boy
  756.       |and\his "dog"
  757.  
  758.    There is something called StringLib.i in this archive that
  759. declares a few string handling routines - the ones I needed for the
  760. compiler, mostly.  Read that file for more information.  And if you
  761. get confused about strings, just remember that they're pretty much
  762. like C strings, and can be used in most of the same situations.
  763. Remember that if you declare a string you don't get any space for
  764. the characters.  All you get is space to hold the address of where
  765. the characters are, so you have to call AllocString() in StringLib
  766. or something like it to get some room to work.  If you are a BASIC
  767. programmer you might run into some difficulty on this subject, and
  768. I would suggest reading up on C strings in hopes that whatever you
  769. read can explain the situation better than I.
  770.    By the way, note that 'stringvar^' is valid, and is of type
  771. 'char'.  The other way to examine characters in a string is with the
  772. index notation.  For example 's[3]' returns the fourth character in
  773. the string 's', since all strings indexes begin at zero.
  774.  
  775.  
  776.  
  777.  
  778.  
  779.                         Exit Procedures
  780.  
  781.     Yet another feature imported from Turbo Pascal.  When your
  782. program ends, the exit routine will look at the value of ExitProc, a
  783. standard global variable.  If it is not Nil, the exit routine calls
  784. the routine pointed to by ExitProc.  Just before doing so, it puts
  785. the value Nil in ExitProc.  When that routine returns, the exit
  786. procedure again looks at ExitProc, and until it becomes Nil it keeps
  787. calling the routines.
  788.  
  789.     If you want to install an exit procedure, you first save the
  790. address of the previous exit procedure, then set ExitProc to the
  791. address of yours.  Part of your procedure should be to set ExitProc
  792. to its previous value.  In this way, exit procedures form a nested
  793. chain, and each procedure is called in the reverse order that it is
  794. installed.
  795.  
  796.    From within your exit procedure, you can examine the variables
  797. ExitAddr and ExitCode.  ExitAddr holds the location that a run-time
  798. error occured, so if you want to return to the program it is,
  799. theoretically, possible.  More frequently you'll use this value to
  800. determine the general area the error occured.  If you have entered
  801. the exit procedure by way of the standard Exit() function (not the
  802. DOS function), this value will be Nil.
  803.  
  804.     The ExitCode just holds the return value the program will return
  805. to DOS.  If you called the exit() procedure, ExitCode just holds the
  806. value you passed to that routine.  Otherwise it's a runtime error
  807. code, or zero if there was no error.
  808.  
  809.     By default, ExitProc holds the address of a routine that closes
  810. all open PCQ Pascal files and frees all memory acquired by New().  If
  811. you get rid of this routine in the chain, you might consider
  812. replacing the parts you want.
  813.  
  814.  
  815.  
  816.  
  817.                    Compiler Directives
  818.  
  819.    Eventually there will be billions of compiler directives, but for
  820. now there are just a few.  Compiler directives work like this:  if
  821. the first character in a comment is the dollar sign ($), the compiler
  822. looks to the next character for a command.  No spaces are allowed
  823. between the bracket, dollar sign, and command character.  Some
  824. directive can be followed by others:  if a comma is the first
  825. character after a directive, the next character is considered the
  826. beginning of another directive.  Thus the following is legal:
  827.  
  828.         {$O-,R+}
  829.  
  830. The I and A directives can't be followed by other directives,
  831. although they can be preceded by them.  The compiler directives are:
  832.  
  833. {$I "fname"}   This will insert the file "fname" into the
  834.                stream at this point.  When it has finished,
  835.                it will end the comment (no more directives
  836.                allowed in this comment) and continue on. 
  837.                There can be any amount of white space in
  838.                front of the filename and anything you want,
  839.                such as the rest of a comment, after it. The
  840.                filename is a string, so it must be in
  841.                quotes.  Several of the example programs should
  842.                demonstrate the include syntax.
  843.                    As of version 1.0c include files have two
  844.                new properties.  The first is that they can now
  845.                be nested.  That is, an include file can include
  846.                another file.  The second feature is that PCQ
  847.                now keeps a list of included files, and will not
  848.                include a particular file name twice.  It only
  849.                considers the actual file name for this, not the
  850.                directories or drives.
  851.  
  852. {$A            This directive inserts assembly instructions
  853. Instructions   into the assembly file produced by the compiler.
  854. }              Look at the assembly language produced by the
  855.                compiler to figure out how to reference variables
  856.                and subroutines.  This directive simply passes
  857.                everything from after the A until, but not including,
  858.                the closing bracket.  You should therefore include
  859.                comments in assembly fashion.
  860.  
  861. {$R+} or       The '+' directive instructs the compiler to produce
  862. {$R-}          range-checking code for arrays.  From this point
  863.                until the compiler reaches a {$R-} directive, each
  864.                array access will check that the index value is
  865.                within the bounds of the array.  This expands and
  866.                slows the code, so I recommend only doing this
  867.                during testing.  If the index is out of bounds, the
  868.                program will abort with an error code (look at the
  869.                section "Run Time Errors" for more information).  The
  870.                default for this directive is {$R-}.
  871.  
  872. {$O+} or       This directive controls IO checking.  A test is
  873. {$O-}          inserted after every IO operation (writeln, readln,
  874.                etc.), and if there was an error, the program aborts
  875.                with an AmigaDOS error code.  If this feature is
  876.                turned off, you will have to call IOResult after every
  877.                questionable IO operation.  This defaults to {$O+},
  878.                just like Turbo Pascal.
  879.  
  880. {$SN} or       This directive controls object declarations and
  881. {$SX} or       storage.  SN (which stands for Normal Storage)
  882. {$SP}          allocates space for all the global variables and typed
  883.                constants it runs across, and makes the identifiers
  884.                available to other units to import.  SX (External
  885.                Storage) assumes that all subsequent variables and
  886.                typed constants were defined and exported by some
  887.                other unit, so the current unit just imports the name.
  888.                SP (Private Storage) allocates space for all variables
  889.                and typed constants it runs across, but does not
  890.                export their names.  It does not export the names of
  891.                procedures or functions, either.  The default for
  892.                normal files is SN, and the default for External units
  893.                is SX.
  894.  
  895.  
  896.  
  897.                       Type Conversions
  898.  
  899.    If you have used Modula-2, you can skip this section.  In
  900. writing the compiler I found the need to cheat a bit on type
  901. checking, so I decided to use Modula-2's syntax for changing the
  902. type of an expression.  What you do is use the name of the type
  903. as if it were a function.  The expression in the parentheses is
  904. evaluated, and the result is considered to be of the type named. 
  905. It goes like this:
  906.  
  907.    IntegerVariable := integer(any ordinal expression);
  908.    CharVar := char(456 - 450);
  909.    if boolean('r') then ....
  910.  
  911.    This works not only for the included standard types, but
  912. also for any type you create.  Thus this is also legal:
  913.  
  914.    type
  915.        charptr = ^char;
  916.    var
  917.        charvar : charptr;
  918.    ....
  919.        charvar := charptr(0);
  920.        charvar := charptr(integer(charvar) + 1);
  921.  
  922.    Note that the type must be named in order for this to work. 
  923. Something like...
  924.  
  925.    variable := array [1..4] of char(expression())
  926.  
  927.    ...will not work.
  928.    Note further that not all type conversions are valid.  Converting
  929. a type to one of a different size is often a bad idea, as is
  930. converting a structured type (array or record) to a simple type.
  931.    I should probably warn you against the indiscriminate use of
  932. these, but what the heck.  Have a ball.
  933.  
  934.  
  935.  
  936.  
  937.  
  938.                     External References
  939.  
  940.    In version 1.0 of the compiler, procedure and function references
  941. were made external by a failure to define a forward-declared
  942. procedure or function.  Version 1.1 changes this arragement to be
  943. more consistent with other Pascal compilers.  Now in order to declare
  944. an external procedure or function, you simply use the External key
  945. word.  Therefore:
  946.  
  947.         Procedure DefinedElsewhere;
  948.             External;
  949.  
  950.    ....would simply generate an external reference.
  951.  
  952.    Now for something somewhat less kosher.  I needed some
  953. syntax to allow the external routines to access the same global
  954. variables as the main file.  What I came up with is a different
  955. file format.  Where the normal Pascal file looks like:
  956.  
  957.       program Name;
  958.       declarations
  959.       procedures and functions
  960.       begin
  961.           main program
  962.       end.
  963.  
  964.    The external file looks like this:
  965.  
  966.       external;
  967.       declarations (like normal)
  968.       procedure and functions (like normal)
  969.  
  970.    There are three things to note.  The first is that there is no
  971. main program, the second that there is no special ending syntax.  It
  972. is just a bunch of procedures and functions in a row until the end of
  973. the file.  The other thing is that any variables declared at the
  974. global, or outermost, level are considered, by default, external
  975. references.  In the source for the compiler there is a file that has
  976. just the global variable declarations.  This file is included by all
  977. ten of the source files, but only the main file produces storage
  978. space for them.  The other nine just produce external references.
  979. This can be changed by using the $S compiler directive explained
  980. above.
  981.  
  982.    I guess this is a good time to discuss a couple of issues related
  983. to using an assembler with the separate compilation deal.  First,
  984. note that all procedure, function and variable names are offered as
  985. external references by the module in which they are defined, unless
  986. the storage mode has been set to Private by the $SP directive.  If an
  987. outside routine wants to use any of these values, it should be
  988. looking for something starting with an underscore and spelled the
  989. same as the first time the word is encountered in the program.
  990. Pascal is case insensitive, of course, but I can't help the assembler
  991. and linker.  Also remember that there is no type checking across
  992. files (again, get Modula-2 if you want that sort of stuff).  This
  993. means that a procedure that expects a string might be sent a Boolean
  994. value, which would probably conjure the Guru.
  995.    The other thing to note is that this compiler pushes procedure
  996. and function arguments on the stack from left to right.  Most C
  997. compilers (including Lattice and PDC) do it the opposite way, so
  998. they can have variable numbers of parameters.  Draco also does it
  999. left to right.  This doesn't mean that you can't use code and
  1000. libraries from them - it simply means that you should reverse the
  1001. order of the arguments.
  1002.    Just two more notes on this subject:  first, the compiler
  1003. considers registers d0, d1, d2, a0, and a1 fair game, and will
  1004. destroy them at will.  d2 might be a problem, but the others
  1005. shouldn't.  For further information, just look at the assembly code
  1006. produced.  The second note is just a reminder to anyone who might
  1007. want to link Pascal programs to other languages:  remember what 'var'
  1008. does before a variable, and be sure to use it correctly.
  1009.  
  1010.  
  1011.  
  1012.  
  1013.                       Input/Output
  1014.  
  1015.  
  1016.    There are several routines for handling IO in PCQ.  Before I
  1017. get to them, however, let me discuss what happens when you open a
  1018. file.  The actual file variable you declare in the program, as in:
  1019.  
  1020.       var
  1021.           filevar : file of integer;
  1022.  
  1023.    is actually something like a record, which would look like
  1024. this:
  1025.  
  1026.    file = record
  1027.         HANDLE  : A DOS file handle
  1028.         NEXT    : A pointer to the next file in the system list
  1029.         BUFFER  : The address of the file's buffer
  1030.         CURRENT : The current position within the buffer
  1031.         LAST    : The Last position of a read.
  1032.         MAX     : One byte past the last byte of the buffer
  1033.         RECSIZE : The size of the file elements.
  1034.         INTERACTIVE : A boolean value
  1035.         EOF     : Another boolean value
  1036.         ACCESS  : Either ModeNewFile or ModeOldFile.
  1037.    end;
  1038.  
  1039.    Now you can't actually access these fields, but nonetheless 32
  1040. bytes of memory is reserved.  When you open a file, all of the fields
  1041. are initialized as necessary, and if the file is an input file and
  1042. it's not interactive, the buffer is filled.  The buffer can be accessed
  1043. by the filevar^ syntax, which in version 1.1 is considered an IO
  1044. statement (Therefore it might be followed by a IO check).
  1045.    If at the end of execution there remain some open files, the
  1046. shut-down code will close them for you.  This is only true for
  1047. files opened through Pascal, using one of the open() routines
  1048. explained below.  Anything you open directly through AmigaDOS is
  1049. your own responsibility.
  1050.  
  1051.    The routines that handle file IO are these:
  1052.  
  1053.    Function Open(filename : string;
  1054.                  filevar : file of something, or Text
  1055.                  {; BufferSize : Integer}) : Boolean;
  1056.  
  1057.        This opens a file for writing.  If the file was there
  1058.     before, this routine will erase it.  If everything worked
  1059.     OK, it will return true.  If not, of course, it's false.  The
  1060.     last option, the Buffer Size, is optional.  If you specify a
  1061.     value, the Open routine will attempt to allocate a buffer of
  1062.     approximately that size.  If you don't specify a value, 128 will
  1063.     be used.  Also note that the actual buffer size allocated will
  1064.     be:  (RequestedSize div RecSize) * RecSize.  If that value is
  1065.     zero, RecSize is used.
  1066.  
  1067.    Function ReOpen(filename : string;
  1068.                    filevar : file of something, or Text
  1069.                    {; BufferSize : Integer} ) : boolean;
  1070.  
  1071.        This is analogous to open() except it opens an existing
  1072.    file for reading.  You can also specify a value for the buffer
  1073.    size.  If the file turns out to be interactive (connected to a
  1074.    console), the actual buffer size allocated will be RecSize.
  1075.  
  1076.    The rest of the routines are the same as most Pascals.  Just
  1077. for the sake of completeness, however, they are:
  1078.  
  1079.    write()      Write the stuff to a file or to standard out.
  1080.                 This mimics the sequence:
  1081.                     FileVar^ := x;
  1082.                     Put(FileVar);
  1083.  
  1084.    writeln()    Do the same as write, then output a line
  1085.                 feed.  This only makes sense for Text files.
  1086.  
  1087.    read()       Read some stuff from a file or standard in.
  1088.                 read(filevar, x) mimics...
  1089.                     x := filevar^;
  1090.                     get(filevar);
  1091.  
  1092.    readln()     Do read then keep reading until you hit a
  1093.                 line feed.  This too only makes sense for
  1094.                 Text files.
  1095.  
  1096.    get()        Reads the next file element from the file
  1097.                 into the buffer.
  1098.  
  1099.    put()        Advances the file pointer past the current file
  1100.                 element, flushing the buffer to disk if necessary.
  1101.  
  1102.     If the first argument of a read or write is a file variable, the
  1103. input or output is from a file rather than to Input or Output, as the
  1104. case may be.  That, of course, is normal Pascal, and looks like:
  1105.  
  1106.     writeln(outfile, 'The result is ', 56 div 4);
  1107.  
  1108.     Field widths are supported, and can be any normal expression.
  1109. What this means is that something like...
  1110.  
  1111.     writeln((67 * 32) + 5:10);
  1112.  
  1113.     ...  will print the result right justified in a field of ten
  1114. characters, with spaces padding out the area to the left.  If you
  1115. specify a field width lower than the width of the number, the number
  1116. is printed in as few characters as possible.  Valid values for the
  1117. field width are greater than or equal to one and less than MaxShort.
  1118. You can specify a field width for any type in a write statement,
  1119. although only when writing to a text file.
  1120.     Real numbers take two field widths.  The first is used just like
  1121. the one for integers.  The second one is not required, and specifies
  1122. the number of places after the decimal point to print.  If it is
  1123. zero, no numbers and no period are printed.  The maximum for this is
  1124. about 30 digits, which is well beyond the accuracy limits of FFP
  1125. anyway.  The defaults for this are 1:2.
  1126.     Just for the sake of precision, I'll go over the delimeters
  1127. for IO on Text files with various types:
  1128.  
  1129.     Write Char
  1130.         Writes one character.
  1131.     Write Boolean
  1132.         Writes TRUE or FALSE, with no extra spaces.
  1133.     Write Integer
  1134.         Writes the number with no extra spaces, but
  1135.         possibly a negative sign
  1136.     Write Real
  1137.         Writes the integer part of the number just like an
  1138.         integer, then if the second field width is > 0 or
  1139.         absent it prints a period followed by the number of
  1140.         characters in the second field width.
  1141.     Write Array of Char
  1142.         writes the entire array, from first element to last.
  1143.     Write String
  1144.         Writes from the first character up to but not
  1145.         including the zero byte.
  1146.     Writeln
  1147.         Writes a single EOLN (chr(10)) to the file.
  1148.  
  1149.     Read Char
  1150.         Reads the next char.
  1151.     Read Boolean
  1152.         Can't do it.
  1153.     Read Integer
  1154.         This eats spaces and tabs until it meets up with
  1155.         something else, then eats digits until it comes
  1156.         upon a non-digit.  It does not eat that last non
  1157.         digit.  If the routine runs across an EOLN before
  1158.         it gets to the first digit, it returns zero.  If
  1159.         it finds letters before it finds digits, it returns
  1160.         zero also.
  1161.     Read Real
  1162.         Reads an integer just like the above.  If the next
  1163.         character is a period, it reads it then reads digits
  1164.         until something other than a digit is found.
  1165.     Read Array of Char
  1166.         Reads characters into the array until either the
  1167.         array is full or the routine finds an EOLN.  If it
  1168.         finds an EOLN it will not eat it, so you'll have to
  1169.         do that with a readln if you want.  If it returns
  1170.         because of an EOLN it will also pad the rest of the
  1171.         array with spaces.
  1172.     Read String
  1173.         Reads characters until it gets an EOLN.  The EOLN
  1174.         is left in the input stream, and a zero is put in
  1175.         its place in the string.  Note that this routine
  1176.         does not check for length, so you must be sure that
  1177.         your string can handle the longest line it might
  1178.         encounter.
  1179.     Readln
  1180.         Reads characters up to and including the next EOLN.
  1181.  
  1182.    Also remember EOF(filevar) and IOResult, from the functions.  For
  1183. examples of all of these, look at the example programs.  Also note
  1184. that the filevar^ sort of syntax is present.  Look at a Pascal text
  1185. to understand it (Turbo Pascal doesn't use it, so it might be Greek
  1186. to a lot of Pascal programmers).
  1187.  
  1188.  
  1189.  
  1190.  
  1191.                         Standard IO
  1192.  
  1193.     One of the tricky parts about programming on the Amiga is that
  1194. there are two distinct environments.  The CLI invokes a program in
  1195. much the same way as traditional computers, whereas the Workbench
  1196. sets the program up with, basically, nothing.  In particular, the
  1197. Workbench does not set up standard IO channels, which are always
  1198. provided by the CLI.  Version 1.0 of PCQ Pascal handled this by
  1199. automatically opening a console window if a) the program was invoked
  1200. by the Workbench and b) it tried to do a Read or Write to the
  1201. standard IO channels, which are now named files (Input and Output)
  1202. but were not then.  That has changed somewhat in version 1.1.
  1203.  
  1204. If your program is invoked by the Workbench, the startup code looks
  1205. for a string variable called StdInName.  If you don't declare a
  1206. string by this name, the program will use a default value included
  1207. in PCQ.lib.  If this string is Nil, the program will not open a
  1208. standard IO channel, and will go on to try to open an output
  1209. channel.  If StdInName is not Nil, the startup tries to open a file
  1210. by the name specified.  If it can't open it, the program dies with
  1211. a runtime error.  If it opens OK, and it's an interactive file
  1212. (attached to a window), and if StdInName and StdOutName point to
  1213. the same string, the same file is used as Output.  Otherwise the
  1214. code goes through much the same process for StdOutName.
  1215.  
  1216. Somewhere deep inside PCQ.lib is the equivalent of the following
  1217. fragment:
  1218.  
  1219.     CONST
  1220.         StdInName : String = "CON:0/0/640/200/";
  1221.         StdOutName: String = StdInName;
  1222.  
  1223.     Thus if you run a program from the Workbench, the startup code
  1224. will by default open a full screen, unnamed window.  If you don't
  1225. want the window, include the following fragment in your code:
  1226.  
  1227.     CONST
  1228.         StdInName : String = Nil;
  1229.         StdOutName: String = Nil;
  1230.  
  1231.     In this case, you'd better not use Write or Read without
  1232. specifying a file, or you could cause a Guru.  The reason I changed
  1233. this, by the way, is because the new IO system uses buffered IO, so
  1234. the program doesn't know the IO channels aren't open until after it's
  1235. already tried to write to it.
  1236.  
  1237.     One last thing about the standard IO files.  You can access them
  1238. by name, as Input and Output.  If the program was run from the CLI,
  1239. you can't close the files- the CLI opened them for you, and will
  1240. close them.  If the program was run from the Workbench, then you are
  1241. allowed at least to close Input.  If Input and Output refer to
  1242. different files (according to the rules above), then you can close
  1243. them both.  In fact if you get rid of the final exit procedure (the
  1244. one that closes all open files and frees all the memory), you will
  1245. have to close the files opened by the startup code.  The point of all
  1246. this is that if the startup code opens standard IO files, they can be
  1247. considered normal PCQ Pascal files.  At least one of them.
  1248.  
  1249.  
  1250.  
  1251.  
  1252.                        Errors
  1253.  
  1254.    As I mentioned somewhere above, most errors will completely
  1255. confuse the poor compiler, which will then start spewing out errors
  1256. that don't really exist.  It can get by a couple of errors- for
  1257. example if you leave out a semicolon somewhere, you should get an
  1258. error message but the assembly file should be valid.  Very few other
  1259. errors will work that well.  I hope to make the compiler a bit
  1260. friendlier, but in the meantime the it will abort the compile if it
  1261. gets 5 errors.  I put this in because the compiler will sometimes get
  1262. one error, then start producing errors on every symbol, and even get
  1263. hung up on a symbol.  Really ugly.
  1264.  
  1265.    If an error occurs, the compiler will write out at most the two
  1266. lines leading up to the error, and highlight the part that it's
  1267. currently working on.  The error probably occured either at the
  1268. highlighted symbol or just before it.  Also note that the highlighted
  1269. symbol is always the last symbol written (when the symbol is just
  1270. some punctuation, it can be difficult to see that it is highlighted).
  1271. On the next line is the line number of the error and the explanation
  1272. of the error.  Currently I'm using text descriptions of the errors,
  1273. so there are no error numbers.
  1274.  
  1275.    If you specified the "-q" command line directive, the error
  1276. reports will print something like "Line ### : Error Msg".  This is
  1277. so that automatic routines, in particular AREXX, will have an easier
  1278. time parsing the error reports.
  1279.  
  1280.  
  1281.  
  1282.  
  1283.                     Run Time Errors
  1284.  
  1285.    Several things can cause run time errors.  The few that are
  1286. handled at the moment are:
  1287.  
  1288.       Error   Explanation
  1289.  
  1290.         50    No memory for IO buffer
  1291.         51    Read past EOF
  1292.         52    Input file not open
  1293.         53    Could not open StdInName
  1294.         54    New() failed
  1295.         55    Integer divide by zero
  1296.         56    Output file not open
  1297.         57    Could not open StdOutName
  1298.         58    Found EOF before first digit in reading an integer
  1299.         59    No digits found in reading an integer
  1300.         60    Range error
  1301.  
  1302.    The error number is returned (through the exit() function) to
  1303. AmigaDOS.  If any of these errors occur, ExitCode will be set to the
  1304. appropriate number, and ExitAddr will have the address where it
  1305. occurred (actually the instruction after the error).  You might be
  1306. able to install exit procedures to gracefully handle these errors:
  1307. see the section called Exit Procedures for more information.
  1308.  
  1309.  
  1310.  
  1311.  
  1312.                        Sources
  1313.  
  1314.    Like I said, I wrote this for the learning experience.  Some
  1315. of the places I went for information are:
  1316.  
  1317. 1.   PDC, a freely distributable C compiler supported by Jeff
  1318.      Lydiatt.  This is a very good program, and one of the best
  1319.      freely available compilers for the Amiga (the other really
  1320.      good one is Draco by Chris Gray).  I learned (and used) a
  1321.      lot about activation frames from the listings produced by
  1322.      this compiler.  Looking at the assembly code produced by
  1323.      this compiler was also my inspiration for starting to
  1324.      write a compiler.
  1325.  
  1326. 2.   Pascal-S, the Pascal compiler produced out of ETH Zurich.
  1327.      I got some ideas about the structure of a compiler from
  1328.      this, but not too many.
  1329.  
  1330. 3.   Small-C, another freely distributable C compiler.  This one
  1331.      is not nearly as powerful as PDC, but its simplicity helped
  1332.      me understand a thing or two.  Probably the best compiler
  1333.      source code that I found to learn from.  This and PDC were
  1334.      the compilers I used before this compiler was able to
  1335.      compile itself.  Many aspects of the design of PCQ come
  1336.      from Small-C.
  1337.  
  1338. 4.   Brinch Hansen on Pascal Compilers, by Per Brinch Hansen. 
  1339.      This book was of some use, which is more than I can say
  1340.      about the other half dozen I read while writing this.  From
  1341.      this book I mainly learned about all the things I was doing
  1342.      wrong.  Great.
  1343.  
  1344. 5.   Sozobon-C.  This is a freeware C compiler for the Atari ST that
  1345.      was recently partially ported to the Amiga.  I got my 32 bit
  1346.      math routines from this project already, and I might lift some
  1347.      floating point math as well.
  1348.  
  1349. 6.   The Toy Compiler series in Amiga Transactor, written by Chris
  1350.      Gray.  This series is very informative, and is written by the
  1351.      author of Draco.  Gray also writes compilers for a living.
  1352.  
  1353.    If you like the idea of freely distributable compilers, please be
  1354. sure to check out Draco from Chris Gray (a new version is on Fred
  1355. Fish disk 201, I think), PDC from Jeff Lydiatt (an old version is on
  1356. Fred Fish 110) and Sozobon-C.  All three are much better products
  1357. than PCQ and even rival the commercial compilers.  I'm not sure what
  1358. a good source for the newer version of PDC would be - perhaps you
  1359. could write to Jeff (it's certainly worth it.  PDC has a full
  1360. preprocessor, a 'cc' front end, very fast optimized code ...  the
  1361. works).  The syntax of Draco, by the way, is fairly similar to
  1362. Pascal.
  1363.  
  1364.  
  1365.  
  1366.                  Notes to Assembly Programmers
  1367.  
  1368.    During the course of a program PCQ uses registers d0, d1,
  1369. a0 and a1 as scratch.  It also uses d2 and d3 during IO calls
  1370. and d2 when comparing or assigning large data structures.
  1371. D2, D3, and A2 are all blown away by the 32 bit math
  1372. routines.  a7 is, of course, the stack pointer, and I use a5
  1373. as the frame pointer.  a6 is used to hold the library base
  1374. during any call to the system, and a4 is used to access local
  1375. variables of a parent procedure.  The other registers are
  1376. free, and in fact the scratch registers should be free for
  1377. you to use between statements.  After all, the compiler does
  1378. no optimizing.  If you make a call to a 'glue' routine, you
  1379. should expect all registers used in passing parameters to be
  1380. scratch.
  1381.  
  1382.  
  1383.  
  1384.  
  1385.                  Improvements On The Burner
  1386.  
  1387.    Version 1.1 has all the features I predicted it would have in the
  1388. documentation for version 1.0, and many more.  In general future
  1389. enhancements will incorporate more and more of the features of Turbo
  1390. and Quick Pascal.  The feature that will motivate version 1.2 will be
  1391. better code generation, through the simple device of creating
  1392. expression trees before generating the code for them.  That will
  1393. provide dramatically smarter, and smaller, code.  Otherwise, it's
  1394. fixing bugs.
  1395.  
  1396.  
  1397.  
  1398.  
  1399.                       Update History
  1400.  
  1401. Version 1.1c, March 3, 1990:
  1402.  
  1403.     The only changes to the compiler are the new standard
  1404. functions.  The more significant changes were in the runtime
  1405. library.  First, I replaced the sin() and cos() functions based on
  1406. suggestions by Martin Combs - the result is that the results are
  1407. accurate to about 3 digits, and only slightly slower.  Martin was
  1408. kind enough to send along a very useful set of routines, which also
  1409. included the tan() and arctan() functions.  I also fixed the
  1410. routine that writes real numbers, so values between -1.0 and 0.0
  1411. now include the minus sign.
  1412.  
  1413. Version 1.1b, February 6, 1990:
  1414.  
  1415.     This program is over a year old.
  1416.     Added the Sqr() function.  Sqr(n) is the same as n * n, but
  1417. marginally faster and smaller.  Also, the compiler used to
  1418. generate lots of errors when an include file was missing.  Now
  1419. it skips the rest of the comment, like it should.
  1420.     Apparently floating point constants didn't used to work.
  1421. Why am I always the last to know?  I also added the Sin() and
  1422. Cos() functions, based on an aside during a lecture on an
  1423. entirely different topic.
  1424.     Later I added the sqrt() function, using Newton's method.
  1425.  
  1426. Version 1.1a, January 20, 1990:
  1427.  
  1428.     Fixed a bug in the WriteArb routine that manifested itself
  1429. whenever you wrote to a 'File of Something'.
  1430.     Fixed a bug left in the floating point math library.  It
  1431. seems that it had not been updated for the all the 1.1
  1432. changes, so during linking it required objects that aren't
  1433. around anymore.  Since floating point math is now handled by
  1434. the compiler, I hadn't noticed it before.
  1435.  
  1436. Version 1.1, December 1, 1989:
  1437.  
  1438.     This version is completely re-written, and has far too many
  1439. changes to list them individually here.  The main changes are the
  1440. with statement, the new IO system, a completely redesigned symbol
  1441. table, nested procedures, and several new arithmetic operators.  In
  1442. order to help port programs from Turbo Pascal and C, I added typed
  1443. constants, the Goto statement, and the normal syntax for multi-
  1444. dimensional arrays.
  1445.  
  1446. Version 1.0c, May 21, 1989:
  1447.  
  1448.     I changed the input routines around a bit, using DOS files rather
  1449. than PCQ files.  I buffered the input, and made the structure more
  1450. flexible so I could nest includes.  Rather than make up some IfNDef
  1451. directive, I decided to keep track of the file names included and
  1452. skip the ones already done.  Buffering the input cut compile times in
  1453. half.  I would not have guessed buffering would be that significant,
  1454. and I suppose I should rethink PCQ input/output in light of this.
  1455.     I added code to check for the CTRL-C, so you can break out early
  1456. but cleanly.  The Ports.i include file had a couple of errors, which
  1457. I fixed, and I also fixed the routine that opens a console for
  1458. programs programs that need one.  It used to have problems when there
  1459. were several arguments in the first write().
  1460.     I added the SizeOf() function, floating point math, and the
  1461. standard functions related to floating point math.
  1462.     There were several minor problems in the include files which I
  1463. found when I got the 1.3 includes, the first official set I've had
  1464. since 1.0.
  1465.     I relaxed the AND, OR and NOT syntax to allow any ordinal type.
  1466. This allows you to get bitwise operations on integers and whatever.
  1467. I also added a standard function called Bit(), described above.
  1468. These are all temporary until I can get sets into the language.
  1469.     I finally added string indexing.  In doing so I found a bug in
  1470. the addressing routine selector(), so I rewrote it to be more
  1471. sensible.  I think it also produces larger code, but I'm not too
  1472. worried because I'm going to add expression trees soon anyway.
  1473.  
  1474. Version 1.0b, April 17, 1989:
  1475.  
  1476.     I fixed a bug in the way complex structures were compared.  It
  1477. seems that one too many bytes were considered, so quite often the
  1478. comparison would fail.
  1479.  
  1480. Version 1.0a, April 8, 1989:
  1481.  
  1482.     This version added 32 bit math, and fixed the case statement.
  1483. The math part was just a matter of getting the proper assembly
  1484. source, but I changed the case statement completely.  Version 1.0
  1485. of the compiler produced a table that was searched sequentially for
  1486. the appropriate value, which if found was matched up with an
  1487. address.  I thought all compilers did this, but when debugging a
  1488. Turbo Pascal program at work I found that it just did a bunch of
  1489. comparisons before each statement, as if it were doing a series of
  1490. optimized if statements.  I had thought of this and rejected it as
  1491. being too simplistic, but if it's good enough for Turbo it's good
  1492. enough for me.
  1493.     The next thing I changed in this release was the startup code.
  1494. You can now run PCQ Pascal programs from the Workbench.  This was
  1495. just a matter of taking care of the Workbench message, but I also
  1496. fooled around with standard input and output.  If you try to read
  1497. or write to standard in or out from a program launched from the
  1498. Workbench, the run time code will open a window for you.
  1499.     I also fixed one bug that I found: an array index that was not
  1500. a numeric type had its type confused.  Nevermore.
  1501.  
  1502. Version 1.0, February 1, 1989
  1503.  
  1504.     Original release.
  1505.  
  1506.  
  1507.  
  1508.             Other Notes, Copyright & My Address
  1509.  
  1510.    As I mentioned above, this documentation, the source code
  1511. for the compiler, the compiler itself, the source code for the run
  1512. time library, and the run time library itself, are all (ahem):
  1513.  
  1514.    Copyright (c) 1989 Patrick Quaid.
  1515.  
  1516.    I will allow the package to be freely distributed, as long as all
  1517. the files in the archive, with the possible exception of the
  1518. assembler and linker (please include them if at all possible), are
  1519. included and unchanged.  Of course no one can make any real money for
  1520. distributing this program.  It may only be distributed on disk
  1521. collections where a reasonable fee is charged for the disk itself.  A
  1522. reasonable fee is defined here as the greater of $10 per disk, or
  1523. whatever Fred Fish is currently charging (about six dollars as I
  1524. write this).  Only one distributor is specifically prohibited from
  1525. distributing this package:  Stefan Ossowski, who evidently lives in
  1526. Essen, West Germany.  He charges far too much for my disk, and action
  1527. has been taken by German Amiga programmers against him.
  1528.     Feel free to mess around with the compiler source code.  If you
  1529. make any substantial improvements, I would appreciate a copy of them
  1530. so that they can be incorporated into the next version if
  1531. appropriate.  If you make improvements that are not along the lines
  1532. of standard Pascal or the path indicated above, please don't
  1533. distribute your program under the name PCQ.  That would only confuse
  1534. things.
  1535.     This is not a shareware package.  Feel no guilt about using it
  1536. without paying for it.  The one payment I would really appreciate is
  1537. if you could let me know about bugs you discover (not unimplemented
  1538. features- I know about them.  I'm not trying to write the end-all
  1539. greatest compiler, but I do want it to be correct).  If you have an
  1540. overwhelming urge to give money away, please send a donation to
  1541. Charlie Gibbs, who wrote the assembler, and the Software Distillery,
  1542. who wrote the linker.
  1543.     If you would like me to send you the latest version of the
  1544. compiler, keep the following in mind.  Disk mailers cost me about 50
  1545. cents, postage costs me 75 sents, and disks cost about a buck.
  1546. Therefore I would consider anything over $2.25 to be adequate to
  1547. cover my costs, and I don't want anything more.
  1548.  
  1549.     Any questions, comments, or whatever can be addressed to:
  1550.  
  1551.       Pat Quaid
  1552.       8320 E. Redwing
  1553.       Scottsdale, AZ 85250
  1554.  
  1555.       (602) 967-3356
  1556.  
  1557.     They changed our ZIP code (the one listed is the new one), but
  1558. the old one should work for quite a while.  You are much more
  1559. likely to be able to contact me by mail than by phone, but I
  1560. certainly don't mind if you try.  Enjoy the compiler.  If you have
  1561. any complaints, remember what you paid for it.
  1562.