C--INFO.DOC >>> INFORMATION ON THE SPHINX C-- PROGRAMMING LANGUAGE Copyright Peter Cellik (C) 1993. All rights reserved. Last Updated: 30 Nov 1993 ============================================================================= See ALLPROCS.DOC for a complete list of all stack procedures, REG procedures and macros in the C-- library. See STAKPROC.DOC for a more detailed description of all stack procedures. See REGPROC.DOC for a more detailed description of all REG procedures and macros. See WBHELP.DOC for help on using the C-- Work Bench. ============================================================================= TABLE OF CONTENTS ^^^^^^^^^^^^^^^^^ 0 INTRODUCTION 0.1 C--, what can it do? 0.2 C--, what is it like? 1 THE C-- LANGUAGE 1.0 Section Introduction 1.1 Identifiers 1.1.1 Identifier Format 1.1.2 Reserved Identifiers 1.2 Constants 1.2.1 Numerical Constants 1.2.2 Character Constants 1.2.3 String Constants 1.2.4 Constant Expressions 1.3 Data Types 1.3.1 Types of Variables 1.3.2 Declaration of Global Variables 1.4 Expressions 1.4.1 Types of Expressions 1.4.2 EAX/AX/AL Expressions 1.4.3 Non-EAX/AX/AL Expressions 1.4.4 Conditional Expressions 1.5 Declaring Procedures, Functions and Macros 1.5.1 Types of Procedures, Functions and Macros 1.5.2 Stack Procedures 1.5.3 REG Procedures 1.5.4 Dynamic Procedures 1.6 Using Procedures, Functions and Macros 1.6.1 Stack Procedures 1.6.2 REG Procedures 1.6.3 Macros 1.6.6 Return Value Format 1.7 Selection Statements 1.8 Looping Statements 1.8.1 Types of Looping Statements 1.8.2 'do {} while' Loops 1.8.3 'loop' Loops 1.9 Array Indexing 1.9.1 Relative Addressing 1.9.2 Absolute Addressing 1.10 Jump Labels 1.11 Other Syntax 1.11.1 Swap Operator 1.11.2 Neg Operator 1.11.3 NOT Operator 1.11.4 Special Conditional Expressions 1.12 Compiler Directives 1.13 Inline Assembly 2 COM File Symbiosis 2.0 What is it? 2.1 Hows it done 2.2 How to do it 2.3 Uses 2.4 Abuses 3 CURRENT LIMITATIONS OF C-- A APPENDIX A.1 Registers That Must Be Preserved A.2 Table of C-- Symbols A.3 C-- Version Notes ============================================================================= 0 Introduction ^^^^^^^^^^^^^^^ 0.1 C--, what can it do? C-- was designed to build small and fast programs. It is most suitable for memory resident programs (TSRs), programs requiring interrupt handling or programs that have limited resources. C-- supports, among other things, inline assembly and recursion. Also the internal C-- library of functions and macros, contains code support for files, sound, graphics and access to extended memory by the use of the XMS standard 2.0. ----------------------------------------------------------------------------- 0.2 C--, what is it like? Nothing you have experienced before. :-) Seriously, its sort of like C and kinda like assembly. ============================================================================= 1 THE C-- LANGUAGE ^^^^^^^^^^^^^^^^^^^ 1.0 SECTION INTRODUCTION After pondering for quite some time over what the best method to explain C-- to a new user, I came to the conclusion of describing its syntax and usage as a contrast to C. This does limit the explanation's usefulness to only C programmers, but since anyone who is anyone knows C, I don't see it a problem. :-) ----------------------------------------------------------------------------- 1.1 IDENTIFIERS 1.1.1 Identifier Format C-- identifiers must start with either an underscore (_) or an upper or lower lower case letter. The then may be followed by any combination of underscores, upper or lower case letters or numerical digits (0 to 9). The total length of an identifier may not exceed 32 characters. Some examples of valid C-- indentifiers are: _DOG CoW loony12 HowYBoys_AND_Girls WOW___ x Some examples of invalid C-- indentifiers are: 12bogus /* cannot start an identifier with a numerical digit */ wowisthisalongidentifieryupitsureisnotOK /* identifier length exceeds 32 */ y_es sir /* spaces not allowed */ the-end /* hyphens not allowed */ 1.1.2 Reserved Identifiers The following is a list of C-- reserved identifiers which can not be used as general identifiers for they have already been defined for other language purposes: byte word char int if IF loop return do while EXTRACT else ELSE FROM interrupt void DSBYTE DSWORD DSCHAR DSINT ESBYTE ESWORD ESCHAR ESINT SSBYTE SSWORD SSCHAR SSINT CSBYTE CSWORD CSCHAR CSINT FSBYTE FSWORD FSCHAR FSINT GSBYTE GSWORD GSCHAR GSINT enum TRUE FALSE CARRYFLAG NOTCARRYFLAG OVERFLOW NOTOVERFLOW CODE_POINTER DATA_POINTER dword long inline DSLONG DSDWORD ESLONG ESDWORD SSLONG SSDWORD CSLONG CSDWORD FSLONG FSDWORD GSLONG GSDWORD AX CX DX BX SP BP SI DI AL CL DL BL AH CH DH BH ES CS SS DS FS GS HS IS EAX ECX EDX EBX ESP EBP ESI EDI DR0 DR1 DR2 DR3 DR4 DR5 DR6 DR7 CR0 CR1 CR2 CR3 CR4 CR5 CR6 CR7 TR0 TR1 TR2 TR3 TR4 TR5 TR6 TR7 __CODEPTR__ __DATAPTR__ __POSTPTR__ __COMPILER__ __DATESTR__ __YEAR__ __MONTH__ __DAY__ __HOUR__ __MINUTE__ __SECOND__ __WEEKDAY__ __VER1__ __VER2__ This list can be obtained from the C-- compiler at anytime by running it with the /KEYWORDS command line option. ----------------------------------------------------------------------------- 1.2 CONSTANTS 1.2.1 Numerical Constants Expressing numerical constants in decimal (base 10) or hexadecimal (base 16) are the same as in C. To express a numerical constant in binary (base 2) notation, the sequence of 1's and 0's are preceded by 0b, with no spaces in between. To express a numerical constant in octal (base 8) notation, the sequence of octal digits (0 to 7) are preceded by 0o with no spaces. Some examples: 0b11111111 // same as 255 0x00F // same as 15 0o10 // same as 8 1.2.2 Character Constants Single character constants are, like in C, enclosed in single quotes ('). Also as in C, special characters are expressed by a back slash (\) followed by the key letter or letters. Special characters supported are: '\a' /* same as in C */ '\b' /* beep */ '\f' /* form feed */ '\l' /* line feed */ '\n' /* carrage return */ '\r' /* carrage return */ '\t' /* tab */ '\x??' /* ASCII character formed from the ?? which would be two hexadecimal digits for the character value */ '\???' /* ASCII character formed from the ??? which would be three decimal digits for the character value */ Any other character following a back slash is just accepted. This allows the single quote to be included by '\'', for '' is the NULL character. C-- treats all character constants as a numeric value of the ASCII value of the character. 1.2.3 String Constants String constants, like in C, are inclosed in double quotes ("). Special characters are expressed within strings the same way as in character constants. All the special characters are the same as in character constants with the exception of \n which inserts both a carrage return and a line feed. 1.2.4 Constant Expressions A constant expression is single numerical constant or a list of numerical constants linked together by operators which are evaluated at compile time to a single constant value. Like all expressions in C--, constant expressions are always evaluated from left to right, regardless of operations! This is quite different that most other languages, and care must be used to remember that 2 + 3 * 2 = 10 and not 8. All numerical values in C-- are integer values. Some examples of constant expressions are: 45 & 1 + 3 // equals 4 14 - 1 / 2 // equals 6 (remember integer values) 1 * 2 * 3 / 2 + 4 // equals 7 ----------------------------------------------------------------------------- 1.3 DATA TYPES 1.3.1 Types of Variables There six memory variable types in C--, they are byte, word, dword, char, int and long. The following table shows the size and range of each of the variable types: NAME | SIZE(bytes) | VALUE RANGE (decimal) | VALUE RANGE (hex) ---------------------------------------------------------------------------- byte | 1 | 0 to 255 | 0x00 to 0xFF word | 2 | 0 to 65535 | 0x0000 to 0xFFFF dword | 4 | 0 to 4294967295 | 0x00000000 to 0xFFFFFFFF char | 1 | -128 to 127 | 0x80 to 0x7F int | 2 | -32768 to 32767 | 0x8000 to 0x7FFF long | 4 | -2147483648 to 2147483647 | 0x80000000 to 0x7FFFFFFF NOTE: 32 bit (4 byte) integer instructions are used to implement dword and long values, therefore support for dword and long is limited to 80386 and higher CPU's. 1.3.2 Declaration of Global Variables The syntax for declaring variables is as follows: variable-type identifier; Where variable-type is any one of char, byte, int, word, long or dword. Several identifers may be declared of the same type as follows: variable-type identifier1, identifier2, ... , identifierN; One dimensional arrays may be declared as follows: variable-type identifier[elements]; Where elements is a constant expression for the amount of entries of that variable type to be in the array. Some examples of global declarations: byte i,j; /* declare i and j to be of type byte */ word see[10] /* declare see to be an array of 10 word's */ int h,x[27] /* declare h to be of type int and declare x to be an array of 27 int's */ ----------------------------------------------------------------------------- 1.4 EXPRESSIONS 1.4.1 Types of Expressions There are three types of expressions in C--, not counting constant expressions. They are EAX/AX/AL expressions, non-EAX/AX/AL expressions and conditional expressions. All C-- expressions are evaluated left to right, regardless of the operations involved. 1.4.2 EAX/AX/AL Expressions EAX/AX/AL math is used for expressions which the result will be stored in a memory variable or the EAX, AX or AL register. If the expression is going to be stored in a char or byte variable, AL math will be used. If the expression is going to be stored in a int or word variable, AX math will be used. If the expression is going to be stored in a long or dword variable, EAX math will be used. If there are no procedure calls in an EAX/AX/AL expression, only the values of AX, CX and DX may be destroyed, all other register values will be preserved during and after the expression is evaluated. 1.4.3 Non-EAX/AX/AL Expressions Non-EAX/AX/AL math is used for expressions which the result will be stored in a register other than EAX, AX or AL. With non-EAX/AX/AL only the result register's value will change, all other register values will be preserved, the high byte of the byte registers may be destroyed, if a word value is used with an expression which will be stored in a byte register. This does however restrict the operations and operands available with non-EAX/AX/AL math. No MACRO, REG procedure or STACK procedure calls may be made within a non-AX/AL/EAX expression. 1.4.4 Conditional Expressions Conditional expressions are expressions which... ----------------------------------------------------------------------------- 1.5 DECLARING PROCEDURES, FUNCTIONS AND MACROS 1.5.1 Types of Procedures, Functions and Macros ... 1.5.2 Stack Procedures ... Stack procedures are defined by using an identifer that contains at least one lower case letter. ... 1.5.3 REG Procedures ... REG procedures are defined by using an identifer that does not contain any lower case letters. In order for a REG procedure to be used as a macro, it must be declared as a dynamic procedure. ... 1.5.4 Dynamic Procedures Dynamic procedures are procedures which are defined but only inserted into the program code if called. Only REG procedures defined as a dynamic procedure may be used as a macro. Dynamic procedures are specified by a preceding ':'. Since dynamic procedures can be relocated anywhere in the code, several restrictions are nessasary. These restrictions are: - Only macros may be used within the dynamic procedure. Calls to REG or stack procedures are illegal. - Constant strings cannot be defined within a dynamic procedure. To use a constant string within a dynamic procedure, define the contant string as a global variable. - Only local jump labels may be defined within a dynamic procedure. Global jump labels are illegal. - Jumps to addresses outside the dynamic procedure are illegal. No error message will be given, but the results, as you can imagine, are unpredictable. ----------------------------------------------------------------------------- 1.6 USING PROCEDURES, FUNCTIONS AND MACROS 1.6.1 Stack Procedures Stack procedures use the pascal calling style for parameters. Stack procedures must therefore be called with the same number of parameters as declared for the procedure. Stack procedure names must contain at least one lower case letter to signify that it is a stack procedure, not a REG procedure. The programmer must specify what the type is for each parameter. If the programmer does not specify a type, 'word' will be assumed. stack_procedure(x,y); is the same as: stack_procedure(word x,word y); C-- does not remember what the type is for each parameter of a procedure, care must be used by the programmer to ensure that the types are the same. For example, if a procedure has three parameters, and the first parameter is a 'long' and last two are 'int', the programmer must call it in the following format: stack_procedure(long x,int x,int x); If the programmer left out the 'long', only 6 bytes will be pushed onto the stack, not 8. Unexpected things would then start to happen, so watch out. 1.6.2 REG Procedures For REG procedures, the parameters are passed via registers. The 16 bit register used for each position is as follows: REG_PROCEDURE(AX,BX,CX,DX,DI,SI); If byte or char is used in a position, the 8 bit register that is used for the position is as follows (note that byte or char values cannot be used in the DI and SI positions): REG_PROCEDURE(byte AL,byte BL,byte CL,byte DL); If dword or long is used in a positions, the 32 bit register that will be used for the position is as follows: REG_PROCEDURE(long EAX,long EBX,long ECX,long EDX,long EDI,long ESI); 1.6.3 Macros Macros are simply REG procedures whose code is inserted rather than called. An '@' symbol is placed before the REG procedure name to specify the code to be inserted rather than called. In order for a REG procedure to be used as a macro, the REG procedure must be declared as a dynamic procedure or found in the internal library. All other characteristics of macros are identical to REG procedures. 1.6.6 C-- Return Value Format return type | register returned in --------------------------------------- byte | AL word | AX dword | EAX char | AL int | AX long | EAX ----------------------------------------------------------------------------- 1.7 CONDITIONAL STATEMENTS Selection statements, better known as 'if' statements, are similar to those in C. C-- has two selections statements. 'if' and 'IF'. 'if' does a near jump, and 'IF' does a short jump. 'IF' executes faster, and can save up to 3 bytes in code size but can only jump over 127 bytes of code. Selection statements, like in C can be followed by either a single command, or a block of many commands enclosed within '{' and '}'. C-- selection statements are restricted to C-- conditional expressions (as described in section 1.4 Expressions). If more than 127 bytes of code follow an 'IF' statement, the compiler will issue the following error message: IF jump distance too far, use if. This can be simply remeded by changing the offending 'IF' statement to 'if'. 'else' and 'ELSE' statements are used just like the 'else' command in C, except that 'ELSE' has the same 127 byte jump restriction as 'IF' of 127 bytes. 'else' generates 1 more byte of code than 'ELSE'. 'IF' and 'else', and 'if' and 'ELSE' may be mixed freely, such as the following example: if( x == 2 ) WRITESTR("Two"); ELSE{WRITESTR("not two."); printmorestuff(); } If more than 127 bytes of code follow an 'ELSE' statement, the compiler will issue the following error message: ELSE jump distance too far, use else. Simply change the 'ELSE' statement to 'else' to correct the error. ----------------------------------------------------------------------------- 1.8 LOOPING STATEMENTS 1.8.1 Types of Looping Statements C-- has two types of looping statements. They are 'do {} while' and 'loop'. 1.8.2 'do {} while' Loops 'do {} while' loops repeat a block of code while a certain conditional statement remains true. The block of code will be executed at least once. An example of a 'do {} while' loop that loops five times follows: count = 0; do { count++; WRITEWORD(count); WRITELN(); } while (count < 5); The conditional expression in the 'do {} while' statement must conform to the same rules as 'IF' and 'if' statements. 1.8.3 'loop' Loops 'loop' loops repeat a block of code while the specified variable or register is different than zero. At the end of executing the block of code, the given variable or register is decremented by one, then tested if equal to zero. If the variable is not equal to zero, the block of code will be executed again, and the process repeated. An example of a 'loop' loop using a variable count as the loop counter: count = 5; loop( count ) {WRITEWORD(count); WRITELN(); } Use of the register CX for small code block loops will yield the greatest code size efficiency for a 'loop', for the loop will be implemented by the use of the machine language 'LOOP' command. If the loop counter is zero before starting the 'loop' command, the loop will be executed the maximum number of times for the range of the variable. 256 times for a 8 bit (byte or char) counter, 65536 for a 16 bit (word or int) counter, and 4294967296 for a 32 bit (dword or long) loop counter. For example, the following loop will execute 256 times: BH = 0; loop( BH ) { } If no loop counter is given, the loop will loop forever. The following example will write *'s to the screen forever: loop() WRITE('*'); The programmer may, if he or she wishes to, use and/or change the value of the loop counter variable within the loop. For example the following loop will only execute 3 times: CX = 1000; loop( CX ) { IF( CX > 3 ) CX = 3; } ----------------------------------------------------------------------------- 1.9 ARRAY INDEXING 1.9.1 Relative Addressing Elements in an array are indexed in byte units, regardless of the data type. Indexes are restricted to the format of 8086 RM field, thus only the following index formats are available (where index is a 16 bit constant value): variable[index] variable[BX+SI+index] variable[BX+DI+index] variable[BP+SI+index] variable[BP+DI+index] variable[SI+index] variable[DI+index] variable[BP+index] variable[BX+index] Some examples: ... 1.9.2 Absolute Addressing Absolute addressing is also available. The same restrictions on the indexes apply. The calculated index will be absolute from the segment register specified. Any segment register can be used, DS, CS, SS and ES. On a 80386+ FS and GS can also be used. The syntax is exactly the same to relative addressing, except that a segment and type specifier is used. The specifiers available are: // addressing the Data Segment DSBYTE[offset] // address a byte in the DS segment DSWORD[offset] // address a word in the DS segment DSCHAR[offset] // address a char in the DS segment DSINT[offset] // address a int in the DS segment DSDWORD[offset] // address a dword in the DS segment DSLONG[offset] // address a long in the DS segment // addressing the Code Segment CSBYTE[offset] // address a byte in the CS segment CSWORD[offset] // address a word in the CS segment CSCHAR[offset] // address a char in the CS segment CSINT[offset] // address a int in the CS segment CSDWORD[offset] // address a dword in the CS segment CSLONG[offset] // address a long in the CS segment // addressing the Stack Segment SSBYTE[offset] // address a byte in the SS segment SSWORD[offset] // address a word in the SS segment SSCHAR[offset] // address a char in the SS segment SSINT[offset] // address a int in the SS segment SSDWORD[offset] // address a dword in the SS segment SSLONG[offset] // address a long in the SS segment // addressing the Extra Segment ESBYTE[offset] // address a byte in the ES segment ESWORD[offset] // address a word in the ES segment ESCHAR[offset] // address a char in the ES segment ESINT[offset] // address a int in the ES segment ESDWORD[offset] // address a dword in the ES segment ESLONG[offset] // address a long in the ES segment // addressing the Extra Segment 2 (80386+) FSBYTE[offset] // address a byte in the FS segment FSWORD[offset] // address a word in the FS segment FSCHAR[offset] // address a char in the FS segment FSINT[offset] // address a int in the FS segment FSDWORD[offset] // address a dword in the FS segment FSLONG[offset] // address a long in the FS segment // addressing the Extra Segment 3 (80386+) GSBYTE[offset] // address a byte in the GS segment GSWORD[offset] // address a word in the GS segment GSCHAR[offset] // address a char in the GS segment GSINT[offset] // address a int in the GS segment GSDWORD[offset] // address a dword in the GS segment GSLONG[offset] // address a long in the GS segment Some examples: ... ----------------------------------------------------------------------------- 1.10 JUMP LABELS Jump labels are used for labeling code locations for use with an inline assembly jump command. There are two types of jump labels, global and local. Global labels, as the name suggests, are labels which are 'visible' from anywhere in the program. Local labels are only 'visible' within their own procedure block and will be undefined outside the block. Labels are defined by a identifier followed by a colon. If the identifier used contains one or more lower case letters, it is a global jump label, otherwise it is a local jump label. Global jump labels must not be used within dynamic procedures, only local labels may be used. This is important to remember, for dynamic procedures are relocated at compile time, and for the case of a dynamic REG procedures which can actually be in more than one place in the code, by use of the macro command, thus would result in a label representing more than one address. ----------------------------------------------------------------------------- 1.11 OTHER SYNTAX 1.11.1 Swap Operator C--, I am proud to say, has an operator that I haven't yet found in any other language, the swap operator. The swap operator swaps two values. The symbol is '><'. The variables on either side of the swap operator must be of the same size, 8 bit and 8 bit, 16 bit and 16 bit, or 32 bit and 32 bit. Some examples follow: AX >< BX; // store the value of BX in AX and the value of AX in BX CH >< BL; // swap the values of CH and BL dog >< cat; /* swap the values of the variable dog and the variable cat */ counter >< CX; // swap the values of counter and CX If a swap is between two 8 bit memory variables, AL will be destroyed. If a swap is between two 16 bit memory variables, AX will be destroyed. If a swap is between 32 bit memory variables, EAX will be destroyed. In all other cases, such as a memory variable and a register, all register values will be preserved. 1.11.2 Neg Operator C-- supports a quick syntax of toggling the sign of a variable, the Neg operator. By placing a '-' infront of a memory variable or register followed by a ';', the sign of the memory variable or register will be toggled. Some examples follow: -AX; // same as 'AX = -AX;' but faster. -tree; // same as 'tree = -tree;' but faster. -BH; // toggle the sign of BH. 1.11.3 NOT Operator C-- supports a quick syntax of doing a logical NOT toggling on a variable, the NOT operator. By placing a '!' infront of a memory variable or register followed by a ';', the value of the memory variable or register will be changed to the logical NOT of its current value. Some examples follow: !AX; // same as 'AX ^= 0xFFFF;' but faster. !node; // change the value of 'node' to its logical NOT. !CL; // same as 'CL ^= 0xFF' but faster. 1.11.4 Special Conditional Expressions C-- supports six special conditional expressions: CARRYFLAG NOTCARRYFLAG OVERFLOW NOTOVERFLOW ZEROFLAG NOTZEROFLAG These can be used in place of any normal conditional expressions. If for example you wish to execute a block of code only if the carry flag is set, then you would use the following code sequence: IF( CARRYFLAG ) { // do some stuff here } If you wish to continuously execute a block of code until the overflow flag is set, you would use something like the following section of code: do { // do your thing in here } while( NOTOVERFLOW ); ----------------------------------------------------------------------------- 1.12 COMPILER DIRECTIVES C-- does not contain a preprocessor. It does however give the user several funtions that are very similar to the functions of the C preprocessor. These are given by compiler directives. All compiler directives begin with a '?'. Below is a list of supported compiler directives and their functions: ? align /* insert byte into program code if currently at an odd address. */ ? aligner (aligner value) /* set value of insert byte. */ ? alignword (TRUE or FALSE) /* enable or disable even address alignment of words and ints, default is TRUE. */ ? assumeDSSS (TRUE or FALSE) /* enable or disable assumption of DS == SS for local and parameter variable addressing, default is FALSE. */ ? beep /* cause the compiler to beep upon reaching this line */ ? codesize /* optimize for code size not speed. */ ? ctrl_c (TRUE or FALSE ) /* enable or disable ctrl-C ignoring */ ? define (identifier) (token) /* define an identifier. */ ? DOSrequired (number) /* set the minimum DOS version required: high byte majoe number, low byte minor number: 0x0101 for DOS version 1.1 0x0302 for DOS version 3.2 0x0315 for DOS version 3.21 0x0303 for DOS version 3.3 0x0600 for DOS version 6.0 etc. */ ? include ("filename") /* include another source file. */ ? jumptomain (NONE, SHORT, NEAR or FALSE) /* set inital jump type to main(), default is NEAR */ ? maxerrors (number) /* number of error to find before compiler aborts */ ? parsecommandline (TRUE or FALSE) /* include command line parsing code into program, default is FALSE */ ? print (number or string) /* displays a string or number to the screen */ ? printhex (number) /* displays a number in hexadecimal to the screen */ ? randombyte /* insert a random byte into program code */ ? resize (TRUE or FALSE) /* resize program memory block upon start up to the minimum amount required, default is TRUE */ ? resizemessage (string) /* message to display before aborting if the resizing of the program memory block failed. */ ? speed /* optimize for speed (default) not code size */ ? stack (number) /* specifies the size of the stack in bytes for the program */ ? startaddress (number) /* set initial code start address, default 0x100 */ ? use8086 /* restrict code generation to 8088/8086 (default) */ ? use8088 /* restrict code generation to 8088/8086 (default) */ ? use80186 /* enable 80186 code generation and optimizations */ ? use80286 /* enable 80286 code generation and optimizations */ ? use80386 /* enable 80386 code generation and optimizations */ ? use80486 /* enable 80486 code generation and optimizations */ ? use80586 /* enable 80586 code generation and optimizations */ ----------------------------------------------------------------------------- 1.13 INLINE ASSEMBLY C-- inline assembly supports all of the 8088/8086 assembly codes, plus most of the 80286 and 80386 enhanced instructions. All codes must start with the $ inline assembly specifier. Below is a list of all supported assembly op codes: $CS: /* Use Code Segment */ $DS: /* Use Data Segment */ $ES: /* Use Extra Segment */ $FS: /* Use Extra Segment 2 (386+) */ $GS: /* Use Extra Segment 3 (386+) */ $SS: /* Use Stack Segment */ $AAA /* ASCII Adjust After Addition */ $AAD /* ASCII Adjust After Division */ $AAM /* ASCII Adjust After Multiplication */ $AAS /* ASCII Adjust After Subtraction */ $ADC wordreg,value16 /* Add with carry value16 to wordreg */ $ADC bytereg,value8 /* Add with carry value8 to bytereg */ $ADC var16,imm16 /* Add with carry imm16 to 16 bit variable */ $ADC var16,wordreg /* Add with carry wordreg to 16 bit variable */ $ADC var8,imm8 /* Add with carry imm8 to 8 bit variable */ $ADC var8,bytereg /* Add with carry bytereg to 8 bit variable */ $ADD wordreg,value16 /* Add value16 to wordreg */ $ADD bytereg,value8 /* Add value8 to bytereg */ $ADD var8,imm8 /* Add imm8 to 8 bit variable */ $ADD var8,bytereg /* Add bytereg to 8 bit variable */ $ADD var16,imm16 /* Add imm16 to 16 bit variable */ $ADD var16,wordreg /* Add wordreg to 16 bit variable */ $ADRSIZ /* toggle address size (386+) */ $ADRSIZE /* toggle address size (386+) same as $ADRSIZ */ $AND wordreg,value16 /* And value16 to wordreg */ $AND bytereg,value8 /* And value8 to bytereg */ $AND var8,imm8 /* And imm8 to 8 bit variable */ $AND var8,bytereg /* And bytereg to 8 bit variable */ $AND var16,imm16 /* And imm16 to 16 bit variable */ $AND var16,wordreg /* And wordreg to 16 bit variable */ $BOUND reg16,var /* Check Bounds */ $CALL imm16 /* Near Call */ $CALL FAR imm16:imm16 /* Far Call */ $CALL wordreg /* CALL Near Address In Word Register */ $CALL var /* Indirect Near Call */ $CALL FAR var /* Indirect Far Call $CBD /* Convert Byte To Double Word (386+), AL to EAX */ $CBW /* Convert Byte To Word, AL to AX */ $CDQ /* Convert Double Word To Quad Word (386+), EAX to EDX:EAX */ $CLC /* Clear Carry Flag */ $CLD /* Clear Direction Flag */ $CLI /* Clear Interrupt Flag (disable interrupts) */ $CLTS /* Clear Task Switched Flag (286+) */ $CMC /* Complement Carry Flag */ $CWD /* Convert Word To Double Word, AX to DX:AX */ $CMP bytereg,value8 /* Compare value8 to bytereg */ $CMP wordreg,value16 /* Compare value16 to wordreg */ $CMP var8,imm8 /* Compare imm8 to 8 bit variable */ $CMP var8,bytereg /* Compare bytereg to 8 bit variable */ $CMP var16,imm16 /* Compare imm16 to 16 bit variable */ $CMP var16,wordreg /* Compare wordreg to 16 bit variable */ $CMPSB /* Compare String Byte */ $CMPSW /* Compare String Word */ $CMPSD /* Compare String Double Word (386+) */ $DAA /* Decimal Adjust After Addition */ $DAS /* Decimal Adjust After Subtraction */ $DB imm8 /* Data Byte (a method for putting a byte value in code) */ $DW imm16 /* Data Word (a method for putting a word value in code) */ $DEC varreg8 /* Decrement an 8 bit memory variable or register */ $DEC varreg16 /* Decrement a 16 bit memory variable or register */ $DEC varreg32 /* Decrement a 32 bit memory variable or register (386+) */ $DIV varreg8 /* Divide AX by an 8 bit memory var or register */ $DIV varreg16 /* Divide DX-AX by a 16 bit memory var or register */ $DIV varreg32 /* Divide EDX-EAX by a 32 bit memory var or register (386+) */ $ENTER imm16,imm8 /* Make Stack Frame (286+) */ $HLT /* Halt Processor */ $IDIV varreg8 /* Integer Divide AL by an 8 bit memory var or register */ $IDIV varreg16 /* Integer Divide AX by a 16 bit memory var or register */ $IDIV varreg32 /* Integer Divide EAX by a 32 bit memory var or reg (386+) */ $IMUL varreg8 /* Integer Multiply AL by an 8 bit memory var or register */ $IMUL varreg16 /* Integer Multiply AX by a 16 bit memory var or register */ $IMUL varreg32 /* Integer Multiply EAX by a 32 bit mem var or reg (386+) */ $IN AL,imm8 /* Read A Byte Into AL From A Constant Port Number */ $IN AX,imm8 /* Read A Word Into AX From A Constant Port Number */ $IN EAX,imm8 /* Read A Word Into EAX From A Constant Port Number (386+) */ $IN AL,DX /* Read A Byte Into AL From Port DX */ $IN AX,DX /* Read A Word Into AX From Port DX */ $IN EAX,DX /* Read A Word Into EAX From Port DX (80386+) */ $INC varreg8 /* Increment an 8 bit memory variable or register */ $INC varreg16 /* Increment a 16 bit memory variable or register */ $INSB /* Input String Byte (286+) */ $INSW /* Input String Word (286+) */ $INSD /* Input String Double Word (386+) */ $INT imm8 /* Call To Interrupt */ $INTO /* Interrupt 4 On Overflow */ $IRET /* Return From Interrupt */ $JMP SHORT imm8 /* Direct Short Jump */ $JMP imm16 /* Direct Near Jump */ $JMP FAR imm16:imm16 /* Direct Far Jump */ $JMP wordreg /* Jump To Near Address In Word Register */ $JMP var16 /* Indirect Near Jump */ $JMP FAR var /* Indirect Far Jump */ $JMP var32 /* Indirect Far Jump */ $JNO imm8 /* Jump Short On Not Overflow */ $JNO imm16 /* Jump Near On Not Overflow (386+) */ $JO imm8 /* Jump Short On Overflow */ $JO imm16 /* Jump Near On Overflow (386+) */ $JB imm8 /* Jump Short On Below */ $JB imm16 /* Jump Near On Below (386+) */ $JNAE imm8 /* Jump Short On Not Above Or Equal */ $JNAE imm16 /* Jump Near On Not Above Or Equal (386+) */ $JNB imm8 /* Jump Short On Not Below */ $JNB imm16 /* Jump Near On Not Below (386+) */ $JAE imm8 /* Jump Short On Above Or Equal */ $JAE imm16 /* Jump Near On Above Or Equal (386+) */ $JE imm8 /* Jump Short On Equal */ $JE imm16 /* Jump Near On Equal (386+) */ $JZ imm8 /* Jump Short On Zero */ $JZ imm16 /* Jump Near On Zero (386+) */ $JNE imm8 /* Jump Short On Not Equal */ $JNE imm16 /* Jump Near On Not Equal (386+) */ $JNZ imm8 /* Jump Short On Not Zero */ $JNZ imm16 /* Jump Near On Not Zero (386+) */ $JBE imm8 /* Jump Short On Below Or Equal */ $JBE imm16 /* Jump Near On Below Or Equal (386+) */ $JNA imm8 /* Jump Short On Not Above */ $JNA imm16 /* Jump Near On Not Above (386+) */ $JNBE imm8 /* Jump Short On Not Below Or Equal */ $JNBE imm16 /* Jump Near On Not Below Or Equal (386+) */ $JA imm8 /* Jump Short On Above */ $JA imm16 /* Jump Near On Above (386+) */ $JS imm8 /* Jump Short On Sign */ $JS imm16 /* Jump Near On Sign (386+) */ $JNS imm8 /* Jump Short On Not Sign */ $JNS imm16 /* Jump Near On Not Sign (386+) */ $JP imm8 /* Jump Short On Parity */ $JP imm16 /* Jump Near On Parity (386+) */ $JPE imm8 /* Jump Short On Parity Even */ $JPE imm16 /* Jump Near On Parity Even (386+) */ $JNP imm8 /* Jump Short On Not Parity */ $JNP imm16 /* Jump Near On Not Parity (386+) */ $JPO imm8 /* Jump Short On Parity Odd */ $JPO imm16 /* Jump Near On Parity Odd (386+) */ $JL imm8 /* Jump Short On Less */ $JL imm16 /* Jump Near On Less (386+) */ $JNGE imm8 /* Jump Short On Not Greater Or Equal */ $JNGE imm16 /* Jump Near On Not Greater Or Equal (386+) */ $JNL imm8 /* Jump Short On Not Less */ $JNL imm16 /* Jump Near On Not Less (386+) */ $JGE imm8 /* Jump Short On Greater Or Equal */ $JGE imm16 /* Jump Near On Greater Or Equal (386+) */ $JLE imm8 /* Jump Short On Less Or Equal */ $JLE imm16 /* Jump Near On Less Or Equal (386+) */ $JNG imm8 /* Jump Short On Not Greater */ $JNG imm16 /* Jump Near On Not Greater (386+) */ $JNLE imm8 /* Jump Short On Not Less Or Equal */ $JNLE imm16 /* Jump Near On Not Less Or Equal (386+) */ $JG imm8 /* Jump Short On Greater */ $JG imm16 /* Jump Near On Greater (386+) */ $JCXZ imm8 /* Jump Short On CX == 0 */ $JCXZ imm16 /* Jump Near On CX == 0 (386+) */ $LAHF /* Load Flags Into AH Register */ $LDS reg16,var /* Load DS pointer */ $LEA reg16,var /* Load Effective Address */ $LEAVE /* Release Stack Frame (286+) */ $LES reg16,var /* Load ES pointer */ $LFS reg16,var /* Load FS pointer (386+) */ $LGS reg16,var /* Load GS pointer (386+) */ $LODSB /* Load String Byte: AL = DSBYTE[DI]; DI++; */ $LODSW /* Load String Word: AX = DSWORD[DI]; DI+=2; */ $LODSD /* Load String Double Word (386+): EAX = DSDWORD[DI]; DI+=4; */ $LOCK /* Bus Lock */ $LOOP imm8 /* Loop CX Times */ $LOOPE imm8 /* Loop CX Times While Equal */ $LOOPNE imm8 /* Loop CX Times While Not Equal */ $LOOPNZ imm8 /* Loop CX Times While Not Zero */ $LOOPZ imm8 /* Loop CX Times While Zero */ $LSS reg16,var /* Load SS pointer (386+) */ $MOV wordreg,value16 /* move value16 into word register */ $MOV bytereg,value8 /* move value8 into byte register */ $MOV var16,wordreg /* move word register into 16 bit variable */ $MOV var8,bytereg /* move byte register into 8 bit variable */ $MOV var16,imm16 /* move constant value into 16 bit variable */ $MOV var8,imm8 /* move constant value into 8 bit variable */ $MOV var16,segreg /* move segment register into 16 bit variable */ $MOV wordreg,segreg /* move segment register into word register */ $MOV var16,seg386 /* move 386 seg reg into 16 bit var (386+) */ $MOV wordreg,seg386 /* move 386 seg reg into word reg (386+) */ $MOV wordreg,imm16 /* move constant value into word register */ $MOV bytereg,imm8 /* move constant value into byte register */ $MOV segreg,var16 /* move word variable into segment register */ $MOV segreg,wordreg /* move word reg into segment register */ $MOV seg386,var16 /* move word variable into 386 seg reg (386+) */ $MOV seg386,wordreg /* move word register into 386 seg reg (386+) */ $MOV reg32,reg32 /* move 32 bit reg into 32 bit reg (386+) */ $MOV reg32,debugreg /* move debug reg into 32 bit reg (386+) */ $MOV reg32,testreg /* move test reg into 32 bit reg (386+) */ $MOV reg32,controlreg /* move control reg into 32 bit reg (386+) */ $MOV debugreg,reg32 /* move 32 bit reg into debug reg (386+) */ $MOV testreg,reg32 /* move 32 bit reg into test reg (386+) */ $MOV controlreg,reg32 /* move 32 bit reg into control reg (386+) */ $MOVSB /* Move String Byte: ESBYTE[DI] = DSBYTE[SI]; DI++; SI++; */ $MOVSW /* Move String Word: ESWORD[DI] = DSWORD[SI]; DI+=2; SI+=2; */ $MOVSD /* Move String Double Word (80386+): ESDWORD[DI] = DSDWORD[SI]; DI+=4; SI+=4; */ $MUL varreg8 /* Multiply AL by an 8 bit memory variable or register, result stored in AX */ $MUL varreg16 /* Multiply AX by a 16 bit memory variable or register, high 16 bits of result stored in DX, low 16 bits of result stored in AX */ $MUL varreg32 /* Multiply EAX by a 32 bit memory variable or register, high 32 bits of result stored in EDX, low 32 bits of result stored in EAX (80386+) */ $NEG varreg8 /* Negate an 8 bit memory variable or register */ $NEG varreg16 /* Negate a 16 bit memory variable or register */ $NOP /* No Operation */ $NOT varreg8 /* Not an 8 bit memory variable or register */ $NOT varreg16 /* Not a 16 bit memory variable or register */ $OPSIZ /* toggle operand size (386+) */ $OPSIZE /* toggle operand size (386+) */ $OR wordreg,value16 /* Or value16 to wordreg */ $OR bytereg,value8 /* Or value8 to bytereg */ $OR var16,imm16 /* Or imm16 to 16 bit variable */ $OR var16,wordreg /* Or wordreg to 16 bit variable */ $OR var8,imm8 /* Or imm8 to 8 bit variable */ $OR var8,bytereg /* Or bytereg to 8 bit variable */ $OUT imm8,AL /* Write AL To A Constant Port Number */ $OUT imm8,AX /* Write AX To A Constant Port Number */ $OUT imm8,EAX /* Write EAX To A Constant Port Number (386+) */ $OUT DX,AL /* Write AL To Byte Port DX */ $OUT DX,AX /* Write AX To Word Port DX */ $OUT DX,EAX /* Write EAX To Word Port DX (386+) */ $OUTSB /* Output String Byte (286+) */ $OUTSW /* Output String Word (286+) */ $OUTSD /* Output String Double Word (386+) */ $POP wordreg /* POP Word Register Off Stack */ $POP var16 /* POP 16 bit Variable Off Stack */ $POP reg32 /* POP 32 bit Word Register Off Stack (386+) */ $POP segreg /* POP Segment Register Off Stack */ $POP seg386 /* POP 386 Segment Register (FS or GS) Off Stack (386+) */ $POPA /* POPs all wordreg registers off stack (286+) */ $POPAD /* POPs all reg32 registers off stack (386+) */ $POPF /* POP Flags Off Stack */ $POPFD /* POP 32 bit Flags Off Stack */ $PUSH wordreg /* PUSH Word Register Onto Stack */ $PUSH var16 /* PUSH 16 bit Variable Onto Stack */ $PUSH reg32 /* PUSH 32 bit Word Register Onto Stack (386+) */ $PUSH segreg /* PUSH Segment Register Onto Stack */ $PUSH seg386 /* PUSH 386 Segment Register (FS or GS) Onto Stack (386+) */ $POPA /* PUSHes all wordreg registers onto stack (286+) */ $POPAD /* PUSHes all reg32 registers onto stack (386+) */ $PUSHF /* PUSH Flags Onto Stack */ $PUSHFD /* PUSH 32 bit Flags Onto Stack (386+) */ $RCL varreg,1 /* Rotate Through Carry Left By One */ $RCL varreg,imm8 /* Rotate Through Carry Left By imm8 (286+) */ $RCL varreg,CL /* Rotate Through Carry Left By CL */ $RCR varreg,1 /* Rotate Through Carry Right By One */ $RCR varreg,imm8 /* Rotate Through Carry Right By imm8 (286+) */ $RCR varreg,CL /* Rotate Through Carry Right By CL */ $REPE /* Repeat While Equal */ $REPZ /* Repeat While Zero */ $REPNE /* Repeat While Not Equal */ $REPNZ /* Repeat While Not Zero */ $RET /* Near Return */ $RETF /* Far Return */ $ROL varreg,1 /* Rotate Left By One */ $ROL varreg,imm8 /* Rotate Left By imm8 (286+) */ $ROL varreg,CL /* Rotate Left By CL */ $ROR varreg,1 /* Rotate Right By One */ $ROR varreg,imm8 /* Rotate Right By imm8 (286+) */ $ROR varreg,CL /* Rotate Right By CL */ $SAHF /* Store AH Register Into Flags */ $SAL varreg,1 /* Shift Left Arithmatic By One */ $SAL varreg,imm8 /* Shift Left Arithmatic By imm8 (286+) */ $SAL varreg,CL /* Shift Left Arithmatic By CL */ $SAR varreg,1 /* Shift Right Arithmatic By One */ $SAR varreg,imm8 /* Shift Right Arithmatic By imm8 (286+) */ $SAR varreg,CL /* Shift Right Arithmatic By CL */ $SCASB /* Scan String Byte */ $SCASW /* Scan String Word */ $SCASD /* Scan String Double Word (386+) */ $SHL varreg,1 /* Shift Left Logical By One */ $SHL varreg,imm8 /* Shift Left Logical By imm8 (286+) */ $SHL varreg,CL /* Shift Left Logical By CL */ $SHR varreg,1 /* Shift Right Logical By One */ $SHR varreg,imm8 /* Shift Right Logical By imm8 (286+) */ $SHR varreg,CL /* Shift Right Logical By CL */ $STC /* Set Carry Flag */ $STD /* Set Direction Flag */ $STI /* Set Interrupt Flag */ $STOSB /* Store String Byte: ESBYTE[DI] = AL; DI++; */ $STOSW /* Store String Word: ESWORD[DI] = AX; DI+=2; */ $STOSD /* Store String Double Word (386+): ESDWORD[DI] = EAX; DI+=4; */ $SBB wordreg,value16 /* Subtract with borrow value16 to wordreg */ $SBB bytereg,value8 /* Subtract with borrow value8 to bytereg */ $SBB var16,imm16 /* Subtract with borrow imm16 to 16 bit variable */ $SBB var16,wordreg /* Subtract with borrow wordreg to 16 bit variable */ $SBB var8,imm8 /* Subtract with borrow imm8 to 8 bit variable */ $SBB var8,bytereg /* Subtract with borrow bytereg to 8 bit variable */ $SUB wordreg,value16 /* Subtract value16 to wordreg */ $SUB bytereg,value8 /* Subtract value8 to bytereg */ $SUB var16,imm16 /* Subtract imm16 to 16 bit variable */ $SUB var16,wordreg /* Subtract wordreg to 16 bit variable */ $SUB var8,imm8 /* Subtract imm8 to 8 bit variable */ $SUB var8,bytereg /* Subtract bytereg to 8 bit variable */ $TEST wordreg,value16 /* AND word register and value16 to flags */ $TEST bytereg,value8 /* AND byte register and value16 to flags */ $WAIT /* Wait For Co-Processor */ $XLAT /* Table LookUp Translation */ $XLATB /* Table LookUp Translation (same as XLAT) */ $XOR wordreg,value16 /* Xor value16 to wordreg */ $XOR bytereg,value8 /* Xor value8 to bytereg */ $XOR var16,imm16 /* Xor imm16 to 16 bit variable */ $XOR var16,wordreg /* Xor wordreg to 16 bit variable */ $XOR var8,imm8 /* Xor imm8 to 8 bit variable */ $XOR var8,bytereg /* Xor bytereg to 8 bit variable */ imm32 represents a 32 bit constant value. imm16 represents a 16 bit constant value. imm8 represents an 8 bit constant value. reg32 represents any one of EAX,EBX,ECX,EDX,ESP,EBP,EDI or ESI. wordreg represents any one of AX,BX,CX,DX,SP,BP,DI or SI. bytereg represents any one of AL,BL,CL,DL,AH,BH,CH or DH. segreg represents any one of DS,CS,ES or SS. seg386 represents one of the two extra 80386 segments registers, FS or GS. testreg represents any one of TR0,TR1,TR2,TR3,TR4,TR5,TR6 or TR7. debugreg represents any one of DR0,DR1,DR2,DR3,DR4,DR5,DR6 or DR7. controlreg represents any one of CR0,CR1,CR2,CR3,CR4,CR5,CR6 or CR7. var represents any memory variable. value32 represents any one of dword, long, imm32 or reg32. value16 represents any one of word, int, imm16 or wordreg. value8 represents any one of byte, char, imm8 or bytereg. varreg32 represents any one of dword, long or reg32. varreg16 represents any one of word, int or wordreg. varreg8 represents any one of byte, char or bytereg. varreg represents any one of varreg16 or varreg8. var32 represents a dword or long memory variable var16 represents a word or int memory variable var8 represents a byte or char memory variable (286+) 80286 or higher processor required. (386+) 80386 or higher processor required. ============================================================================= 2 COM FILE SYMBIOSIS ^^^^^^^^^^^^^^^^^^^^^ 2.0 WHAT IS IT? The C-- compiler has the option to append the program it is compiling to the end of an already created COM file. This I call "COM File Symbiosis". When the program is loaded, execution will start in the appended C-- code, and when execution passes the end of the main() procedure block, execution of the original program will begin. If a procedure like EXIT() or ABORT() is called within the C-- program, the program will quit, and the original code from the COM file will not be executed. This allows the program being appended on to the COM file to determine whether control will be passed onto the original code. 2.1 HOWS IT DONE I will tell you later, its not really that complicated. 2.2 HOW TO DO IT To do it, you need to use the /SYM command line option followed by the full name of the COM file to append to. The original COM file will not be changed, only copied into the beginning of the outputted run COM file. For example, to compile the program HELLO.C-- on to the end of a copy of C:\COMMAND.COM use the following command: C-- /SYM C:\COMMAND.COM HELLO.C-- An output file HELLO.COM will be created. 2.3 USES You can probably think of lots of ways of using this function. Such as: - Adding password protection to certain special COM files. - Reducing the memory available to the COM file at start up. - Initializing a video mode for the COM file. 2.4 ABUSES Anyone with an evil mind (most people do) can think of some not so nice ways of using this function. The most obvious of which would be the creation of trojan horses. I WOULD LIKE TO POINT OUT THAT THIS IS NOT A CONSTRUCTIVE USE OF C-- AND ANY DESTRUCTIVE USE OF COM FILE SYMBIOSIS IS PROHIBITED. In other words, don't be a jerk. ============================================================================= 3 CURRENT LIMITATIONS OF C-- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Lack of perfection in the aspect of documentation. I am sure you agree. Documentation takes time, just like coding. '...' in the docs, marks a spot where I have to add a paragraph or finish explaining something. I assure you that every week or so, the documentation for C-- becomes a little more robust, and hopefully more helpful. Be on the look out for new versions of C--. - 32 bit data types require 386 or above processor. I am not too bothered with this limitation. Most machines these days are 386+ and using the 386 instructions to do 32 bit operations is so much faster. Hey if you've got it, use it! - No floating point variables. If the demand for floating point types of variables is high, they may be included in future versions. They were omitted because of the large amount of support code required to handle the mathematical operations. One possibility maybe that floating point support will be restricted to 8087+, and that software emulation will not be done. A greater possibility would be the implementation of a 32 bit fixed point variable, giving 16 bits integer and 16 bits fractional parts. Fixed point is fast, and hey, who doesn't like speed. - Limited libraries. Dynamic procedures were introduced with version 0.170. This now allows all procedures to be defined within include files (*.h), thus making them available for the programmer to improve and change to his needs. Currently, a number of procedures are still containned within the interal library, in the future, most of these will moved to include files and converted back to C-- code. You may also notice that in VGA.H--, some procedures have been extracted from the interal library but not yet converted back from binary data to C-- code. I'll get around to it, but they should still be useful as they are. There is now support for the Gravis Ultra Sound by use of the YEA_GUS.EXE sound driver. It seems to work ok, and as it says, it's free for human use. If anyone has a newer version of YEA_GUS.EXE or a better way of programming the card, give me a yell. Support for other sound cards would also be nice. Send me any code or ideas for procedures that you wish to be added, and I will see what I can do. If you do send code, it will definitely make it easier on me, C, C-- or ASM doesn't matter. Also, if you find any errors or possible optimizations to any of the existing procedures, send it to me. - Code, Stack and declared Data limited to 64K total. Well that's the problem with COM files. With the use of GETMEM() and FREEMEM(), large data buffers can be allocated for use, which usually satisfies most program requirements. I might in the future add an EXE file output option, but I first need the format of the EXE file header. If I do add EXE output, it would be a small memory model (64K Code, 64K Data and Stack), to keep with the design philosophy of C--, which is to make small and fast programs. If anyone has some good detailed information on how to make EXE run files, please send them to me. On the same subject, anyone have the format for standard OBJ files? - The tilda '~' is currently not used for anything in C--. Can you think of and essencial use for it in C--? If so, tell me. - You tell me. What have you found limiting about C--, and what do you feel should be done about it. C-- is new, and must grow. I need your input. Be bold, express you view. I won't take offense, I just might not agree. ============================================================================ A APPENDIX ^^^^^^^^^^^ A.1 REGISTERS THAT MUST BE PRESERVED Registers that should be preserved are BP, DI, SI, DS, SS, SP, CS and IP. BP is used for pointing to local and parameter variables on the stack, and thus must be preserved. DI and SI need not be preserved if the programmer is aware of the consequences. DI and SI are often used for indexing arrays such as the statement: dog = firehydrant(1,red) + legs[DI];. If DI was not preserved in the procedure firehydrant, then the value moved into dog would probably not be the desired value, for the index for legs would have been changed. As a matter of consistency, all procedures should supply addequate comments if DI and/or SI are not preserved. DS points to the data segment and all global variable operations requires its value. SS holds the segment of the stack and must be preserved. SP points to the current position on the stack and must be preserved. CS holds the segment of the program code. All instructions are fetched using CS and IP, therefore their values must be preserved. IP, by the way is the Instruction Pointer, and CS and IP can not be directly modified on the 8086, 8088, 80286, 80386, 80486, 80586 and probably not the 80686 either. FS and GS are the new extra segment registers introduced with the 80386. Do what you want with these. ============================================================================ A.2 TABLE OF C-- SYMBOLS SYMBOL | FUNCTION | EXAMPLE ------------------------------------------------------------------------ /* | start comment block | /* comment */ */ | end comment block | /* comment */ | | // | comment to end of line | // comment | | = | assignment | AX = 12; + | addition | AX = BX + 12; - | subtraction | house = dog - church; * | multiplication | x = y * z; / | division | x1 = dog / legs; & | bitwise AND | polution = stupid & pointless; | | bitwise inclusive OR | yes = i | mabe; ^ | bitwise exclusive OR | snap = got ^ power; << | bit shift left | x = y << z; >> | bit shift right | x = y >> z; | | += | addition | fox += 12; // fox = fox +12; -= | subtraction | cow -= BX; // cow = cow - BX; &= | bitwise AND | p &= q; // p = p & q; |= | bitwise inclusive OR | p |= z; // p = p | z; ^= | bitwise exclusive OR | u ^= s; // u = u ^ s; <<= | bit shift left | x <<= z; // x = x << z >>= | bit shift right | x >>= z; // x = x >> z | | >< | swap | x >< y; /* exchange values of x and y */ | | == | equal to | IF(AX == 12) > | greater than | IF(junk > BOGUS) < | less than | if( x < y ) >= | greater or equal to | if(AX >= 12) <= | less than or equal to | IF(BL >= CH) != | not equal to | IF(girl != boy) <> | different than | IF(cat <> dog) /* same function as != */ | | @ | insert code | @ COLDBOOT(); /* insert COLDBOOT code */ : | dynamic procedure | : functionname () // declare functionname $ | assembly operation | $ PUSH AX /* push AX onto stack */ # | offset address of | loc = #cow; /* loc = address of cow */ | | ~ | | This symbol is currently unused. ============================================================================ A.3 C-- VERSION NOTES Version # Comments ^^^^^^^^^ ^^^^^^^^ up to 0.187 - Lots of stuff changed. 0.187a - VGAX.H-- modified. - VGA.H-- supplemented. - VGAFILL.H-- added. 0.188 - Fixed two lame compare statement bugs. - Spiffed up docs a bit more. - KEYCODES.H-- modified and supplemented. - VIDEO.H-- modified and supplemented. - WRITEHEX(word_value) added to WRITE.H--. - STARS.C-- added. - DPMI.H-- and DPMI.C-- added. - ZEROFLAG and NOTZEROFLAG conditional expressions added. 0.189 - Fixed local_var = seg_reg bug. - Everyone should upgrade at least to this version! ============================================================================ /* end of C--INFO.DOC */