shithub: scc

ref: 6d3664ac10f50ea4ac3618404fa3522a226fbc81
dir: /README/

View raw version
Introduction
============
This is the kcc compiler, a one very stupid non retargetable compiler
for z80. This compiler is intended to be very simple and suitable for
running in small machines (like MSX for example), and let almost part
of optimizations to the programmer.

After a lot of years seeing compilers for z80 I notice that it is very
hard for a C compiler generates a good code for a 8 bit processor like
z80, with an expensive indirect addressing mode, so the best solution
is to not try that compiler optimize the code and use C as a macro
macro assembler.

In order to get this target, we need a compiler that does exactly the
things programmer want to do. For example is a variable is register it MUST be
register and fails in other case. If a variable is automatic try to
realize operations directly with the stack (for example use ADD
A,(IX+4), instead of allocate the variable into register add and store
again in memory). So if you declare an automatic variable you are a
big bullshit or you need it for recursion (static variables are your
friends). 

This is the reason why I began to develop this compiler, and I hope
it will be useful for you.

Changes from standard C
=======================
This compiler is near of being full compatible with C99 standard, but
it has some differences:

- Type qualifiers are accepted but ignored.
  -----------------------------------------

Type qualifers make the type system ugly, and the useless of them
add innecessary complexity to the compiler (with a bigger compilation
time):
	- const: The definition of const is not clear in the standard.
	  If a const value is modified then the behaviour is implementation
	  defined. It seems that it was defined more in order to can
	  allocate variables in ROM than for the error detection. This
	  implememtation will not warn about these modifications and
	  the code will use them as normal variables (standard specifies
	  that a diagnosis message must be printed).

	- volatile: The definition of volatile is not concrete, because
	  it is defined as 'remove all the optimizations about the
	  variable', which of course depend of the king of optimizations
	  applied to the variable. This qualifier was added to the standard
	  to can deal with longjmp (local variables that are not volatile
	  have undefined state), and for memory mapped registers or variables
	  whose value is modified asynchronous but this can achieved with
	  special pragma values.
	  In the first case, this is a a non portable code by definition
	  (depend of the register mapped), so it is better to deal with
	  it using another solution (compiler extensions or directly
	  assembler), and in the second case it generated a lot of
	  problems with moderm processors out of order and multiprocesor,
	  where not hold the value in a register is good enough (it is
	  needed a explicit memory barrier).

	- restrict: This qualifer can be only applied to pointers, to
	  mark that the pointed object has no other alias. This qualifer
	  was introduced to can fix some performance problems in numerical
	  algorithm, where FORTRAN can achieve a better performance (and
	  in fact even with this specifier FORTRAN has a better performance
	  in this field). Ignores it doesn't make the code non standard
	  and in almost of the applications the performance will be the same.

- Function type names
  -------------------

C99 allows to define type names of function types and write something like:

int f(int (int));

Accepting function types in typenames (or abstract declarators) makes the
grammar ambiguous because it is impossible difference between:

        (int (f))  -> function returning int with one parameter of type f
        (int (f))  -> integer variable f

Function type names are stupid, because they are used as an alias
of the function pointer types, but it makes stupid that something
like sizeof(int (int)) is not allowed (because here should be
understood as the size of a function), but it is allowed f(int (int))
because it is understood as a parameter with function pointer type.

This complexity is not needed at all, because function pointers fix
all these problems without this complexity (and they are the more usual
way of writing such codes).