info-mac@uw-beaver.UUCP (11/02/84)
From: Mike Schuster <MIKES@CIT-20.ARPA> Consulair Corp's Mac C Compiler and Toolkit I received Consulair Corp's Compiler and Toolkit last week. Here are some my feelings about its good and bad points, along with a list of undocumented bugs and workarounds. * Overview Consulair Corp (415) 851-3849 Mac C compiler translates C programs into 68000 assembly language for Apple's Macintosh 68000 Development System. It runs on both 128k and 512k Macs with hard disk or external drive, or a Lisa running MacWorks. It requires the Editor, Assembler, Linker, and Exec portions of the Development System. The Mac C Toolkit is a collection of C and assembler routines that implement a variety of useful I/O, math, string, memory, and utility functions. The Compiler and Toolkit list for $425, add $25 for a copyable version. * Mac C Compiler Hilites -- Supports code segmentation via standard Toolbox segment loader. -- Supports standard Apple family of debuggers. -- Calls to stack based Toolbox routines and register based Operating System routines are emitted inline with no "glue routines". -- Source ".h" header files give system values and C structure definitions. (Header files based in part on Stanford's SUMEX project SUMACC Development System). -- Mac C was used to write the Assembler, Linker, Editor, and Exec portions of the Macintosh 68000 Development System. -- Supports a Lisp-like Signal/CatchSignal function escape mechanism. * Mac C Toolkit Hilites -- I/O package for synchronous or multiply buffered asynchronous I/O. -- Complete Standard C I/O and Memory Routines (printf, malloc, ...). -- TTY window emulation package. -- Source code included. Extract, modify and compile/assemble only those routines that seem most useful. * Mac C versus "Standard C" -- Floating point types Float, Double, Comp, and Extended are not implemented. -- Bit fields in structure are not implemented. -- Enumerated types are not implemented. -- Register variables are implemented as normal stack variables. -- Structures passed by value and functions returning structures are not implemented. -- All characters in an identifier are significant. -- All field names are local in scope to the structure in which they are declared. -- Type and field checking is carried out through all levels of indirection. -- Inline assembly code allowed between #asm and #endasm. -- Integer size may be either 16 or 32 bits. (Compile time option). -- Literal values can be cast to structures and structure pointers. -- Literals and identifiers may be cast on the left side of assignments. -- Scope of structure is always from definition point to end of file, even if structure is declared within a function. -- Local variables may not be redefined within a subordinate block. * Code Generation -- First seven arguments to C functions are passed in registers D0-D6. -- Rest of arguments (if any) are pushed on the stack. -- Arguments to Toolbox routines are passed on the stack or in registers as appropriate. Trap instruction emitted inline. -- Register D0 contains the result of the function call if the result is a value; A0 contains the result if it is a pointer. -- Functions must preserve ONLY registers A5, A6, and A7. -- Switch statements are implemented as a sequence of tests followed by conditional jumps. -- Common subexpressions are not identified, nor is register usage or condition code state tracked to eliminate redundant loads, stores, and tests. * Run Time -- External variables are stored relative to A5 or optionally in a Global Data Segment allocated at start up. Global Data Segment may be refered to via A0, ..., A4 (Compile time option). (Useful for desk accessories.) -- Constants (other than those used to initialize external variables) are stored as operands to instructions or as data after the final instruction in the segment. String constants are of the latter form. -- Startup code (580 bytes) consists of a few long integer math and string routines, the Signal/CatchSignal routines, and a routine that copies initialized external variable values from a resource in the compiled application program to either A5 relative or into the Global Data Segment. Source for Startup is included and may be easily modified. -- Taking the address of a function in a segment other than segment 1 produces the address of the jump table entry so that calls will invoke the segment loader properly. * Watch Out -- Since string constants are stored in code segments, avoid taking the address of a string constant and then unloading the segment containing the string. -- All identifiers are converted to uppercase ASM, so case sensitivity is NOT carried outside the source file. For example: extern char *PtoCStr(); char *p; p = PtoCstr("foo"); /* notice the lower case 's' */ Since PtoCstr (lower case s) is undeclared, Mac C assumes it returns an integer, and so emits code to move the expected result in D0 to p. Assembler and Linker, however, bind PtoCstr to the existing Toolkit routine PtoCStr (upper case s), which returns its result in A0. So, DON'T forget to declare external functions returning pointers. * A Few Undocumented Bugs and Workarounds (Mac C 1.05, 10/29/84) -- Indexed array address computation sign extends unsigned short indicies and hence fails for values greater than 32K. To fix, declare index variables long. -- Comma expressions can only be used in expressions immediately following FOR and WHILE. -- Brackets must not be placed around single initializers, use int x = 1; rather than int x = {1}; -- Bad code is sometimes generated when constants are used in conditional expressions, use #define debug #ifdef debug if (x) ... #endif rather than #define debug 1 if (x && debug) ... -- Global variable QD is improperly initialized at startup. Add 4 to QD to get the proper value. -- Startup code fails if A4 is used as the Global Data Segment index register. -- The first field of an external structure may not be properly word aligned. Mike Schuster @cit-20 ------- -------