home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / INFO / C / SMALL_C.ZIP / SMALLC.DOC < prev    next >
Encoding:
Text File  |  1987-01-19  |  38.8 KB  |  953 lines

  1.        I.  INTRODUCTION
  2.  
  3.            Welcome to Small-c:PC.  Small-c:PC is a compiler that runs
  4.        under PC-DOS on the IBM Personal Computer (PC).  The source input
  5.        to the compiler is written in small-c, a subset of the C
  6.        programming language.  The compiler outputs symbolic assembly
  7.        language code that can be assembled on the PC using the ASM or
  8.        MASM assembler programs available from IBM.
  9.  
  10.            The reference manual for C is THE C PROGRAMMING LANGUAGE book
  11.        published by Prentice-Hall and authored by Brian W.  Kernighan
  12.        and Dennis M.  Ritchie.  The original compiler for Small-c was
  13.        written by Ron Cain as a personal project (see Dr.  Dobb's
  14.        Journal, #45, Volume V, Number 5 for a description of small-c).
  15.        A CP/M version of the compiler for the Intel 8080 is being
  16.        distributed by The Code Works, 5266 Hollister, Suite 224, Santa
  17.        Barbara, California 93111 (805) 683-1585.
  18.  
  19.            After using the CP/M version of the compiler, we decided to
  20.        port it over to the IBM PC (so we could take some of our small-c
  21.        programs over with us).  The conversion effort was guided by a
  22.        desire to not alter the personality of the original small-c
  23.        compiler.  The objective was to minimize the effort required to
  24.        convert existing small-c programs to the Small-c:PC environment.
  25.        We think we have been successful since our small-c programs have
  26.        been converted to the PC with few problems using Small-c:PC.
  27.  
  28.            The compiler was converted by first deciding what the output
  29.        should look like and then modifying it to generate code for the
  30.        Intel 8088 instead of the 8080.  In parallel, the run time
  31.        library was rewritten in 8088 assembly language to operate under
  32.        PC-DOS.  If you have The Code Works run time library for CP/M and
  33.        are interested in the differences between CP/M and PC-DOS, you
  34.        might take the time to compare our library with theirs.
  35.  
  36.            Most of the compiler conversion problems centered around
  37.        ASM's need for memory.  The goal was to produce a tool that could
  38.        be used on a 64KB PC with two 160KB drives.  Since ASM cannot
  39.        deal with large programs in a 64 KB configuration, the small-c
  40.        compiler was modified to produce code that could be assembled
  41.        separately and then put together using LINK.  The original
  42.        small-c compiler produces one large output file.  Small-c:PC can
  43.        produce multiple output files (one for each input file).  These
  44.        files can be assembled separately using ASM and then LINKed
  45.        together.  This can significantly reduce program development
  46.        time, however, since only the modified file need be recompiled in
  47.        the event of source code changes.  It can then be assembled and
  48.        linked with existing object files.
  49.  
  50.            If you have more than 64KB, ASM can assemble larger files.
  51.        With sufficient memory, you can work with larger small-c program
  52.  
  53.                                   - 2 -
  54.  
  55.        files.  The memory requirement for using Small-c:PC, however, is
  56.        imposed by ASM, not by the Small-c:PC compiler.  Small-c:PC will
  57.        compile large programs quite nicely in 64KB.
  58.  
  59.            If you examine your distribution copy of the compiler, named
  60.        CPCN.C, you will notice that the source code is marked so that it
  61.        can be broken into many smaller files.  The makers are small-c
  62.        comment statements written as:
  63.  
  64.                               /* ### cpcn-xx */
  65.  
  66.            Each of these comment statements marks the start of a
  67.        separate file.  We marked it this way so that users with only
  68.        64KB can modify the compiler if they choose to do so.  It will be
  69.        necessary, however, to insert the proper external declarations
  70.        into each file.  For those of you with more memory, it is a
  71.        simple matter to generate a new version of the compiler after
  72.        making any source editing changes.
  73.  
  74.            We have also distributed the source code for FORMAT, a text
  75.        processor described in the book SOFTWARE TOOLS by Brian W.
  76.        Kernighan and P.J.  Plauger and published by Addison-Wesley.
  77.        This program is written in small-c.  This manual was produced
  78.        using it.  The file FORMAT.DOC contains a brief description of
  79.        the FORMAT program and how to use it.
  80.  
  81.            As a final note before we get into the operational details of
  82.        the compiler you should be aware of the fact that it may contain
  83.        bugs.  We have tested it quite a bit, but you know how those
  84.        little rascals can hide.  So beware, one may sneak up and bite
  85.        you (usually in the wee hours at the worst time).  If you find
  86.        any of these critters, please write us and describe the problem.
  87.        We have priced Small-c:PC to recover our development cost only.
  88.        Please don't call us to discuss problems over the phone.
  89.  
  90.  
  91.  
  92.  
  93.  
  94.  
  95.  
  96.  
  97.                                   - 3 -
  98.  
  99.        II.  OPERATING Small-c:PC
  100.  
  101.            The compiler is initiated by entering CPC in response to the
  102.        PC-DOS command prompt A>.  The compiler clears the screen, greets
  103.        you and asks two questions.  The possible answers are contained
  104.        in parenthesis following each question.  The capitalized response
  105.        in the default taken if you press the ENTER key.  The first
  106.        question asked is:
  107.  
  108.                         Should I pause after an error (y,N)?
  109.  
  110.            Answering Y to this question causes the compiler to pause
  111.        after displaying an error.  This will give you an opportunity to
  112.        continue the compilation or not.  Moreover, in the event of a lot
  113.        of screen activity during a compilation this insures that you
  114.        won't miss an error message.  The N response causes the compiler
  115.        to continue automatically after displaying an error.
  116.  
  117.        The second question asked is:
  118.  
  119.                Do you want the Small-c:PC-text to appear (y,N)?
  120.  
  121.            Answering Y to this question causes the compiler to write the
  122.        input source code into the output file(s) as comment statements.
  123.        each small-c statement appears with a semicolon as the first
  124.        character (to make it a comment to ASM) followed by the assembly
  125.        language code generated by the compiler for that statement.  This
  126.        interleaving of source code and generated code is very useful in
  127.        learning how the compiler implements various small-c statements.
  128.        Choosing this option causes the output files to be larger,
  129.        however.  Answering N will cause the compiler to not write the
  130.        small-c source to the output file.
  131.  
  132.            The two previous questions are followed by requests for input
  133.        and output filenames.  There are no default extensions supplied
  134.        by the compiler.  Each input file generates a separate output
  135.        file.
  136.  
  137.            You can break a large small-c program into separate smaller
  138.        files and feed these to the compiler.  Hopefully ASM will be able
  139.        to swallow the resultant output files without running out of
  140.        memory.  Again, if you have more than 64KB, ASM should be able to
  141.        process a large output file.  In this case you will not be forced
  142.        to divide a large small-c program into multiple files.
  143.  
  144.        The next request by the compiler is?
  145.  
  146.                                     Input filename?
  147.  
  148.            The small-c source code is contained in the file you name in
  149.        response to this question.  There is no default extension supplied
  150.  
  151.                                   - 4 -
  152.  
  153.        by the compiler.
  154.  
  155.            A single function definition cannot be spread out across
  156.        multiple input files.  This is because the compiler assumes the
  157.        output file corresponding to each input file will be separately
  158.        assembled.  It writes extra assembly language statements into
  159.        each output file to support this.  A function spread across two
  160.        input files may not assemble correctly.  Also, due to the way the
  161.        compiler handles externals, it is possible that a function name
  162.        could be multiply defined and the compiler not detect it.  This
  163.        can happen if the separate definitions occur in different input
  164.        files.  In this circumstance, the error will be detected by LINK.
  165.  
  166.            The runtime library (CPCLIB.ASM) is not input to the compiler
  167.        as in other incarnations of small-c.  Instead, it is input to
  168.        LINK as just another object file.  LINK will bind all of the
  169.        object inputs together to produce an execute (.EXE) file.
  170.  
  171.            If your response to the input filename request is the ENTER
  172.        key or a space (as the first character), the compiler terminates
  173.        and returns control to PC-DOS.  This is the way the compiler is
  174.        normally ended.
  175.  
  176.        Following the input filename request is the question:
  177.  
  178.                                Output filename?
  179.  
  180.            The assembly language generated by the compiler for the
  181.        previous input file is written into the named file.  Normally
  182.        this file will have the extension .ASM (not supplied
  183.        automatically by the compiler) since it will be input to the
  184.        assembler.  If you press ENTER instead of providing a file name,
  185.        the compiler will direct its output to the display.  You might
  186.        try this initially to get a feel for the code the compiler
  187.        generates.
  188.  
  189.            Let's consider the interactions to compile a sample program.
  190.        Suppose the program is broken into two files names "SAMPLE-1.C"
  191.        and "SAMPLE-2.C".  You should first format a PC-DOS data disk and
  192.        copy over to it the following files.
  193.  
  194.        CPC.EXE         [from the Small-c:PC distribution disk]
  195.        CPCLIB.OBJ                        "
  196.        SAMPLE-1.C                        "
  197.        SAMPLE-2.C                        "
  198.  
  199.        We assume the following files are on your system disk which is in
  200.        drive A.
  201.  
  202.        ASM.EXE         [from your IBM supplied macro assembler disk]
  203.        LINK.EXE        [from your IBM supplied PC-DOS disk]
  204.  
  205.                                   - 5 -
  206.  
  207.        Note:  You could use MASM instead of ASM.
  208.  
  209.        Get started by entering the following (the disk you made is in
  210.        drive B) and drive B is the logged in disk.
  211.  
  212.        B>CPC                                     [invoke the compiler]
  213.  
  214.        * * *  Small-C:PC  V1.1  * * *   [first line of a clear screen]
  215.  
  216.        By Ron Cain, Modified by CAPROCK SYSTEMS for the IBM PC
  217.  
  218.  
  219.        Distributed by:  CAPROCK SYSTEMS, INC>
  220.                         P.O. Box 13814
  221.                         Arlington, Texas 76013
  222.  
  223.        PC-DOS Version N:  June, 1982
  224.  
  225.  
  226.        Should I pause after an error (y,N)>?  Y          [You don't want
  227.                                                          to miss any]
  228.  
  229.        Do you want the Small-c:PC-text to appear (y,N)?  N      [no]
  230.  
  231.        Input filename?  SAMPLE-1.C
  232.  
  233.        Output filename?  SAMPLE-1.ASM
  234.        ====== main ()                  [you know when it starts on a new
  235.        ====== plc()                    function]
  236.  
  237.        There were 0 errors in compilation.
  238.  
  239.        Input filename?  SAMPLE-2.C     [the program is stored in two
  240.                                        separate files]
  241.  
  242.        Output filename?  SAMPLE-2.ASM
  243.        ====== getname()
  244.  
  245.        There were 0 errors in compilation.
  246.  
  247.        Input filename?  [press ENTER]
  248.  
  249.  
  250.  
  251.            Notice that the two input files could have been processed in
  252.        separate executions of the compiler.  SAMPLE-2.C contains the
  253.        necessary external data declarations to inform the compiler about
  254.        referenced data allocated elsewhere.
  255.  
  256.             The output files are assembled next.
  257.  
  258.  
  259.                                   - 6 -
  260.  
  261.        B>A:ASM SAMPLE-1,,NUL:,NUL:
  262.        B>A:ASM SAMPLE-2,,NUL:,NUL:
  263.  
  264.            Next, we want to produce an execute file.  You do this by
  265.        executing LINK.  Our example assumes LINK inputs as required by
  266.        PC-DOS Version 1.1.  If you have Version 2.0 your LINK inputs
  267.        will be slightly different, but the results should be the same.
  268.        The order of the object file names supplied to LINK is
  269.        immaterial.
  270.  
  271.        B>A:LINK SAMPLE-1+SAMPLE-2+CPCLIB,SAMPLE,NUL:,NUL:
  272.  
  273.        They you are ready to execute the small-c program.  This is
  274.        accomplished by typing the .EXE file name.
  275.  
  276.        B>SAMPLE SAMPLE-1.ASM
  277.  
  278.        The SAMPLE program provided on the distribution disk types a text
  279.        file onto the display.  It obtains the file name to operate on
  280.        from the command line.
  281.  
  282.  
  283.        ERROR REPORTING
  284.  
  285.  
  286.        When the compiler detects an error in the small-c program, it
  287.        displays a message on the screen.  An example would be:
  288.  
  289.        Line 20, main + 0: missing open paren
  290.        main)
  291.             ^
  292.  
  293.  
  294.            The error occurred on the 20-th line in the input file.  The
  295.        function being compiled was "main".  The error occurred 0 lines
  296.        into the function.  the error detected was a "missing open
  297.        paren".  The hat character (^) shows where the compiler was at
  298.        character-wise when it detected the error.  The compiler
  299.        continues automatically if you answered N to the first question
  300.        asked by the compiler (see example above).  If you answered Y to
  301.        this questions, you will see the following message displayed.
  302.  
  303.                            Continue (Y,n,g)  ?
  304.  
  305.        Pressing Y (or just ENTER) causes the compiler to continue
  306.        processing the source input.  If you type N, the compiler
  307.        displays the message
  308.  
  309.                           Compilation aborted.
  310.  
  311.        and returns to PC-DOS.  If you answer G, the compiler continues
  312.  
  313.                                   - 7 -
  314.  
  315.        processing the source input, but will no longer pause after an
  316.        error.
  317.  
  318.            Pressing CTRL+BREAK at any time will abort the compiler and
  319.        return you to PC-DOS.  If the compiler is terminated by
  320.        CTRL+BREAK, no input or output files are closed.
  321.  
  322.  
  323.  
  324.  
  325.  
  326.  
  327.  
  328.  
  329.  
  330.  
  331.  
  332.                                   - 8 -
  333.  
  334.        III.  USING THE LIBRARY FUNCTIONS
  335.  
  336.            All of the modules whose entry point names began with CC are
  337.        used to support the compiler generated code.  As a user, you will
  338.        probably never use these routines directly.  The functions that
  339.        start with QZ are user callable.  They can be divided into PC-DOS
  340.        interface routines and system interfact routines.  The PC-DOS
  341.        interfact routines generally provide I/O through the operating
  342.        system.  The disk I/O functions buffer only one 512 byte sector
  343.        at a time (each open file has its own sector buffer space,
  344.        however).  This combined with the fact that the transfer width
  345.        between a small-c program and the disk routines is only one byte
  346.        causes file I/O to be somewhat slow.  Also, the library routines
  347.        support only ASCII files.  Certain characters are given special
  348.        meanings.  AS a result, you can not manipulate binary files with
  349.        small-c programs.  These file types include .OBJ, .EXE and .COM
  350.        files.
  351.  
  352.  
  353.  
  354.  
  355.  
  356.  
  357.  
  358.  
  359.  
  360.  
  361.                                   - 9 -
  362.  
  363.        THE PC-DOS INTERFACE LIBRARY ROUTINES
  364.  
  365.  
  366.            The following presents examples to illustrate the PC-DOS
  367.        interface routines.  The small-c declarations are simply
  368.        illustrations of what can be done.  There are myriad ways to
  369.        accomplish the same coding example.  The PC-DOS function numbers
  370.        mentioned in the descriptions are given in decimal.
  371.  
  372.                           int c;
  373.                           char buffer[81];
  374.                           char *name,*mode;
  375.                           int *ptr;
  376.                           int ax,ah,dx;
  377.                           char *string;
  378.  
  379.  
  380.        1.  Read a character from the keyboard.
  381.  
  382.                                   c = getchar();
  383.  
  384.            Reads a character from the keyboard using PC-DOS function 1.
  385.        The character read is echoed back to the display.  Extended ASCII
  386.        codes will require two calls to this function.  A second call is
  387.        indicated if the returned character is null.  If the character
  388.        input is a carriage return, a line feed is also echoed back to
  389.        the display.  If the character is CTRL-Z, a -1 is returned
  390.        instead.
  391.  
  392.        2.  Write a character to the display.
  393.  
  394.                                   c = putchar(c);
  395.  
  396.            The character in the low order byte of c is written to the
  397.        display using PC-DOS function 2.  Refer to appendix G of the
  398.        BASIC manual to determine the effect of each possible character
  399.        code.  If the character passed is a carriage return, a line feed
  400.        is also sent to the display.  This function returns the character
  401.        passed to it.
  402.  
  403.        3.  Read a line from the keyboard.
  404.  
  405.                                    gets(buffer);
  406.  
  407.            Reads one line of characters into the character array buffer
  408.        using PC-DOS function 10 for buffered keyboard input.  Editing of
  409.        the buffer during character entry is supported by PC-DOS (see
  410.        chapter 1 of the DOS manual).  A null character is placed at the
  411.        end of the line (replaces the usual carriage return at the end of
  412.        the line).  Note:  the buffer is assumed to be at least 80 bytes
  413.        in length.
  414.  
  415.                                   - 10 -
  416.  
  417.        4.  Print a line on the display.
  418.  
  419.                                    puts(buffer);
  420.  
  421.            Each character of the buffer is written to the display using
  422.        PC-DOS function 2 (display character).  Refer to appendix G of
  423.        the BASIC manual to see how the character codes are interpreted.
  424.        Characters are sent to the display until a null character is
  425.        encountered.  The null character is not sent to the display.  No
  426.        carriage return or line feed is automatically sent to the
  427.        display.
  428.  
  429.        5.  Open a disk file for processing.
  430.  
  431.                                    ptr = fopen(name,mode);
  432.  
  433.            The named file is opened for processing using DOS function
  434.        15.  The name is parsed using DOS function 41 before the open
  435.        call.  The mode determines how the file is opened.  An "r" or "R"
  436.        opens it for input and "w" or "W" opens it for output.  Notice
  437.        that mode is a pointer to a string.  The string contains the
  438.        character indicating the desired mode.  No error checks are made.
  439.        The pointer returned is an offset into the library data segment
  440.        of an I/O structure.  The structure consists of the FCB followed
  441.        by the sector buffer (see CPCLIB data segment).  This pointer
  442.        must be passed to functions getc, putc and fclose described
  443.        below.  If the open fails, a zero is returned to ptr.  The open
  444.        can fail for a variety of reasons.  No more than four files may
  445.        be open at one time.  So lack of an available I/O structure can
  446.        cause failure.  The filename supplied could be in error or not
  447.        exist.  It could be that the mode indicated is not one of the
  448.        four possible characters indicated above.  Programming note:  to
  449.        test if a file exists before opening it for output, first open it
  450.        for input.  If this open is successful the file exists.
  451.  
  452.        6.  Close a disk file.
  453.  
  454.                                    fclose(ptr);
  455.  
  456.            The file described by the I/O structure indicated by ptr is
  457.        closed to further processing.  Any unwritten characters in the
  458.        sector buffer are written to disk first.  No error check is made
  459.        on the value in ptr.  The function returns a zero if the close
  460.        fails.  It returns a non-zero value if the close is successful.
  461.        Note that files are not automatically closed when the program
  462.        exits.
  463.  
  464.        7.  Read the next character from an opened disk file.
  465.  
  466.                                    c = getc(ptr);
  467.  
  468.  
  469.                                   - 11 -
  470.  
  471.            The next unread character is returned.  The ptr is the I/O
  472.        structure offset returned by fopen.  The file is assumed to be a
  473.        text file.  When a carriage return is read, the character that
  474.        immediately follows the carriage return is presumed to be a line
  475.        feed and is discarded automatically.  (No check is made to verify
  476.        that it was a line feed).  When a CTRL-Z or a physical
  477.        end-of-file is detected, a -1 is returned.  A read error also
  478.        returns a -1.
  479.  
  480.        8.  Write a character to an opened disk file.
  481.  
  482.                                    c = putc(c,ptr);
  483.  
  484.            The character is buffered into the sector buffer indicated by
  485.        the ptr (see fopen).  If the character is a carriage return, a
  486.        line feed is automatically buffered.  A physical disk write
  487.        occurs when the sector buffer is filled.  This function returns
  488.        the argument character if no error occurs.  A -1 is returned if
  489.        an error occurs.
  490.  
  491.        9.  Call to PC-DOS.
  492.  
  493.                                    ax = pcdos(ah,dx);
  494.  
  495.            This function calls PC-DOS.  The low order byte of the first
  496.        argument is placed into the AH register.  The second argument is
  497.        placed into the DX register.  PC-DOS returns a value in the AX
  498.        register.  This value is stored into the variable ax as
  499.        indicated.
  500.  
  501.            This function is useful for supporting I/O to the printer or
  502.        communications device.  The following function sends the passed
  503.        character to the printer.
  504.  
  505.                          listchar(c)
  506.                           char c;
  507.                          {
  508.                           pcdos(5,c);
  509.                           return (c);
  510.                          }
  511.  
  512.  
  513.  
  514.  
  515.  
  516.  
  517.  
  518.                                   - 12 -
  519.  
  520.        THE SYSTEM INTERFACE LIBRARY ROUTINES
  521.  
  522.  
  523.            Like those used above, the following additional declarations
  524.        are made to illustrate usage of the system interface library
  525.        routines.  These routines generally provide access to the
  526.        hardware on the PC or to special software elements of the system.
  527.  
  528.                           int port,ah,al,bh,bl,ch,cl,dh,dl;
  529.                           char string[256];
  530.                           int val;
  531.  
  532.            Some of the declared names refer to 808x registers.  When the
  533.        name of an 8-bit register appears as an argument in the examples
  534.        below, the low order byte of the value passed is copied into the
  535.        808x register with the same name to execute the function
  536.        indicated.  If a 16-bit register is designated, the full 16-bit
  537.        argument is loaded into the 808x register with the same name.
  538.  
  539.        1.  Send a byte to a physical output port.
  540.  
  541.                                    out808x(port,al);
  542.  
  543.            The low order byte of the second argument is sent to the
  544.        hardware port address indicated by the first argument.  No value
  545.        is returned.  Refer to the PC Technical Reference Manual for a
  546.        description of the physical I/O ports on the PC.
  547.  
  548.        2.  Input a byte from a physical input port.
  549.  
  550.                                    val = in808x(port);
  551.  
  552.            An IN instruction is executed using the hardware port address
  553.        provided by the argument.  The byte read is sign extended and
  554.        returned as a 16-bit value.  Refer to the PC Technical Reference
  555.        Manual for a description of the physical I/O ports on the PC.
  556.  
  557.        3.  Display control through the PC rom BIOS.
  558.  
  559.                             int10(ah,al,bh,bl,ch,cl,dh,dl);
  560.  
  561.            PC-DOS does not support complete display capabilities as
  562.        provided on the PC.  This function allows the small-c programmer
  563.        control over the display as supported by the rom BIOS routines.
  564.        The PC Technical Reference Manual contains a description in the
  565.        rom listings of the required parameter values.  Certain functions
  566.        may not require all of the argument registers.  A dummy argument
  567.        must be provided, however, since the library routine expects all
  568.        of the indicated arguments (it is not function sensitive).
  569.  
  570.        4.  Control and I/O through the asynchronous port.
  571.  
  572.                                   - 13 -
  573.  
  574.                                ax = int14(ah,al,dx);
  575.  
  576.            Support of the async adapter through PC-DOS is not complete
  577.        (especially on status information).  This function allows the
  578.        small-c programmer greater control over the comm port.  Again,
  579.        the ROM listings in the PC Technical Reference Manual contain a
  580.        complete description of the parameters for this function.
  581.  
  582.        5.  Sound the bell.
  583.  
  584.                                     bell();
  585.  
  586.            This function simply calls PC-DOS to display the bell
  587.        character code.
  588.  
  589.        6.  Clear the display buffer (and hence the display screen).
  590.  
  591.                                    clrscreen();
  592.  
  593.            This is essentially a clear screen function as provided on
  594.        many dumb terminals.  This function illustrates how the PC
  595.        programmer may manipulate the display memory directly to manage
  596.        the display.
  597.  
  598.        7.  Copy code segment prefix into a small-c data array.
  599.  
  600.                                  copyprefix(string);
  601.  
  602.            The program prefix as described in the DOS manual contains
  603.        information that may be useful to the small-c programmer.  For an
  604.        example, study the sample program provided on the distribution
  605.        disk.  This function copies all 256 bytes of the prefix into
  606.        string.  Using appropriate offsets (or subscripts), the contents
  607.        of the prefix area can be examined.
  608.  
  609.        8.  Exit to PC-DOS.
  610.  
  611.                                      exit();
  612.  
  613.            This is the function to use in exiting a small-c program at a
  614.        point other than a normal return from the main() function.  The
  615.        exit function assumes that the DS and SS registers are unchanged
  616.        from their contents at program entry.
  617.  
  618.  
  619.  
  620.  
  621.                                   - 14 -
  622.  
  623.        IV.  ASSEMBLY LANGUAGE INTERFACE
  624.  
  625.            Some remaining portions of this manual are reproduced from
  626.        the user manual for the small-c compiler distributed by The Code
  627.        Works.  Interfacing to assembly language is accomplished in two
  628.        ways.  As the library routines demonstrate, you can simply code a
  629.        module in the code segment CSEG, assemble it and LINK will
  630.        resolve the call if the function name is made PUBLIC.  You can
  631.        build your own assembly language library to LINK with small-c
  632.        programs that you write.
  633.  
  634.            The compiler also supports a language construct that permits
  635.        in-line assembly language code to be directly inserted into the
  636.        generated output file.  This language construct is the
  637.        #asm...#endasm statements.  Like all preprocessor commands, #asm
  638.        and #endasm must be entered in lower case.  Since it is
  639.        considered by the compiler to be a single statement, it may
  640.        appear any where a statement is needed.  For example,
  641.  
  642.                          while(...) #asm...#endasm
  643.  
  644.                          or
  645.  
  646.                          if(...) #asm...#endasm else ...
  647.  
  648.            Due to the workings of the preprocessor (which must be
  649.        suppressed by this construct), the pseudo-op #asm must be the
  650.        last item before the carriage return on the end of the line
  651.        (since the text between #asm and the carriage return is thrown
  652.        away).  The parser is free-format (outside of these exceptions).
  653.        So the expected format is as follows:
  654.  
  655.                        if (...) #asm            [nothing following #asm]
  656.                                ...
  657.                                ...
  658.                                #endasm
  659.                        else statement;
  660.  
  661.        A semicolon is not required after the #endasm.
  662.  
  663.            Assembly language code within the #asm...#endasm context can
  664.        access all global variables and functions by name.  It is up to
  665.        the programmer to know the data type of a variable (i.e.  whether
  666.        to access a byte or a word).  Global variables should be accessed
  667.        relative to the stack segment as opposed to the data segment.  To
  668.        store the AX register into the variable named intvar, code
  669.  
  670.                                    MOV SS:QZINTVAR,AX
  671.  
  672.            All global variables and function names have a 'QZ' prefix
  673.        added by the compiler.  This is illustrated above.  As another
  674.  
  675.                                   - 15 -
  676.  
  677.        illustration, to call putchar() in an assembler routine, code
  678.        CALL QZPUTCHAR.  Since the library is not assembled with the
  679.        generated code, it is necessary to tell the assembler that a
  680.        library name is external.  Insert the statement
  681.  
  682.                                EXTRN     QZPUTCHAR:NEAR
  683.  
  684.        in your assembly language code.  If putchar() is called by the
  685.        small-c code containing your assembler code, then you do not need
  686.        to insert the EXTRN statement.  The compiler will generate one
  687.        for the reference in the small-c code.  A similar situation
  688.        exists for global data items.  For instance, if intvar is not
  689.        defined (or referenced) by containing small-c code, it will be
  690.        necessary to code
  691.  
  692.                                EXTRN QZINTVAR:NEAR
  693.  
  694.        For other illustrations of this, refer to the generated code for
  695.        the sample program on the distribution disk to see how the
  696.        compiler handles similar references.
  697.  
  698.            External assembly language routines invoked by function calls
  699.        from the small-c code have access to all registers.  However, the
  700.        DS and SS (and naturally CS) must be preserved across the
  701.        assembly language code.  All other registers can be altered
  702.        without restoration.  The calling program removes arguments from
  703.        the stack upon return.  The function should not prune the stack
  704.        itself.
  705.  
  706.  
  707.  
  708.  
  709.  
  710.  
  711.  
  712.  
  713.  
  714.                                   - 16 -
  715.  
  716.        RUN TIME CODE STRUCTURE AND SEGMENT USAGE
  717.  
  718.  
  719.            The compiler generates three segments as a result of
  720.        processing the user's small-c program.  Executable code is placed
  721.        in segment CSEG with a class 'code'.  Data items are stored in
  722.        the segment STACK with the class 'stack'.  No information is
  723.        stored in generated segment DUMMY.  It is produced to avoid a
  724.        LINK error message.  The run time library makes use of a data
  725.        segment DATASEG also in the class 'code'.  The LINK program
  726.        combines all output files with specified libraries to produce the
  727.        executable module.  This module, when loaded into memory, has the
  728.        segments in class 'code' first followed by the stack segment
  729.        whose class is 'stack'.  The entry point is CCGO in the run time
  730.        library.  Routine CCGO loads the stack segment register and sets
  731.        the stack pointer SP to the highest possible value.  It pushes
  732.        information necessary to return to DOS onto the stack, then calls
  733.        the user's main() function.  The exit() routine is entered either
  734.        by a call from the user program or upon a return from main().
  735.        The function exit() cleans the stack off up to the information
  736.        placed there by CCGO.  It then does a long return to DOS.
  737.  
  738.            During execution, the stack is used extensively.  Function
  739.        arguments are placed onto the stack in their textual order (left
  740.        to right).  This is illustrated below by the code generated for
  741.        the following statement.
  742.  
  743.                          function(x,y,z,());
  744.  
  745.                          MOV     BX,SS:QZX
  746.                          PUSH    BX
  747.                          MOV     BX,SS:QZY
  748.                          PUSH    BX
  749.                          CALL    QZZ
  750.                          PUSH    BX
  751.                          CALL    QZFUNCTION
  752.                          POP     CX
  753.                          POP     CX
  754.                          POP     CX
  755.  
  756.        Notice that the compiler generated code to clean up the stack.
  757.  
  758.        Local variables are allocated onto the stack.  The current value
  759.        of SP thus becomes their address.  For example, inside a
  760.        function, the statement:
  761.  
  762.                                     int k;
  763.  
  764.        generates the code PUSH CX to occupy two bytes on the stack.
  765.        References to the value k use the current value of SP.  If
  766.        another value is defined, such as:
  767.  
  768.                                   - 17 -
  769.  
  770.                                  char array[3];
  771.  
  772.        the compiler would generate
  773.  
  774.                        DEC     SP
  775.                        PUSH    CX
  776.  
  777.        to reserve three bytes on the stack.  The offset of array is the
  778.        current value of SP.  So array[0] is at SP+0, array[1] at SP+1,
  779.        array[2] at SP+2, and k would now be at SP+3.  Thus, assembly
  780.        language code in the statement #asm...#endasm cannot access local
  781.        variables by name.  They can be accessed by knowing how many
  782.        intervening bytes have been allocated between the declaration of
  783.        the variable and its use.  It is worth noting that local
  784.        declarations use only as much stack space as required, including
  785.        an odd number of bytes.  However, function arguments always
  786.        consist of two bytes apiece.  If a function argument is of type
  787.        char (one byte), the it is sign extended to obtain a 2 byte value
  788.        to push onto the stack.
  789.  
  790.  
  791.  
  792.  
  793.  
  794.  
  795.  
  796.  
  797.                                   - 18 -
  798.  
  799.        Appendix A:  Small-c:PC COMPILER SPECIFICATION
  800.  
  801.        The compiler supports the following.
  802.  
  803.        1.  Data type declarations can be:
  804.  
  805.                         char                    8-bits
  806.                         int                     16-bits
  807.                         extern char             external 8-bits
  808.                         extern int              external 16-bits
  809.                         extern                  external 16-bits
  810.  
  811.        A pointer to either of these types is declared by placing an
  812.        asterisk "*" before the pointer name.  A pointer is a 16-bit
  813.        stack offset.
  814.  
  815.        2.  Arrays must be single dimension (vector) structures of type
  816.        char or int.
  817.  
  818.        3.  Expressions:
  819.                 unary operators:
  820.                         "-"     minus
  821.                         "*"     indirection
  822.                         "&"     address of scalar
  823.                         "++"    increment, either prefix or postfix
  824.                         "--"    decrement, either prefix or postfix
  825.  
  826.                 binary operators:
  827.                         "+"     addition
  828.                         "-"     subtraction
  829.                         "*"     multiplication
  830.                         "/"     division
  831.                         "%"     mod, i.e. remainder from division
  832.                         "|"     inclusive or
  833.                         "^"     exclusive or
  834.                         "&"     logical and
  835.                         "=="    test for equality
  836.                         "!="    test for inequality
  837.                         "<"     test for less than
  838.                         "<="    test for less or equal
  839.                         ">"     test for greater than
  840.                         ">="    test for greater or equal
  841.                         "<<"    arithmetic shift left
  842.                         ">>"    arithmetic shift right
  843.                         "="     assignment
  844.  
  845.                  primaries:
  846.                         array[expression]
  847.                         function(arg1,...,argn)
  848.                         constants:
  849.                                 decimal number
  850.  
  851.                                   - 19 -
  852.  
  853.                                 quoted string ("sample")
  854.                                 primed string ('a' or '10')
  855.                         local variable (or pointer)
  856.                         global (static) variable (or pointer)
  857.  
  858.        4.  Program control:
  859.  
  860.                         if(expression) statement;
  861.                         if(expression) statement;
  862.                                 else statement;
  863.                         while (expression) statement;
  864.                         break;
  865.                         continue;
  866.                         return;
  867.                         return expression;
  868.                         ; (null statement)
  869.                         compound statement:
  870.                         {statement1; statement2;...;statementn;}
  871.  
  872.        5.  Pointers
  873.  
  874.                         local and static pointers can contain the
  875.        address of "char" or "int" data items.
  876.  
  877.        6.  Compiler commands:
  878.  
  879.                 #define name string
  880.                         (preprocessor will replace name by string
  881.        throughout the program text)
  882.                 #include filename
  883.                          (Input is suspended from the input filename and
  884.        text is read from the file named in the include statement.  When
  885.        end-of-file is detected, input is resumed from the input
  886.        filename.  A separate output file is not created for the #include
  887.        file.  Its output is directed to the currently open output file.)
  888.                 #asm
  889.                          (see section IV for description)
  890.  
  891.        7.  Miscellaneous notes:
  892.  
  893.        Expression evaluation maintains the same hierarchy as standard C.
  894.  
  895.        Function calls are defined as any primary followed by an open
  896.        parenthesis.  Legal forms include:
  897.  
  898.                          variable();
  899.                          array[expression]();
  900.                          constant();
  901.                          function() ();
  902.  
  903.        NOTE:  the various function call forms are not supported in
  904.  
  905.                                   - 20 -
  906.  
  907.        standard C.
  908.  
  909.        Pointer arithmetic takes into account the data type the pointer
  910.        was declared for (e.g. ptr++ will increment by 2 if declared
  911.        "int *ptr;").
  912.  
  913.        Pointers are compared as unsigned 16-bit values.
  914.  
  915.        The generated code is pure.  Data is separated from executable
  916.        code.
  917.  
  918.        The generated code is reentrant.  Since local variables are
  919.        allocated on the stack, each new invocation of a function
  920.        generates a new copy of local variables.
  921.  
  922.  
  923.  
  924.  
  925.  
  926.  
  927.  
  928.  
  929.                                   - 21 -
  930.  
  931.        Appendix B:  COMPILER RESTRICTIONS AND LIMITATIONS
  932.  
  933.        The compiler does not support:
  934.  
  935.        1.  Structures and unions
  936.  
  937.        2.  Multi-dimensional arrays
  938.  
  939.        3.  Floating point data
  940.  
  941.        4.  Long integers
  942.  
  943.        5.  Functions that return anything but "int" values
  944.  
  945.        6.  Unary operators "!", "~", "sizeof", casts
  946.  
  947.        7.  The operators "&&", "||", "?:", and ","
  948.  
  949.        8.  Assignment operators:
  950.  
  951.                 +=, -=, *=, /=, %=, >>=, <<=, &=, ^=,
  952.  
  953.