Page 245 - Introduction to Microcontrollers Architecture, Programming, and Interfacing of The Motorola 68HC12
P. 245
222 Chapter 8 Programming in C and C++
Compilers are used for different purposes than are assemblers. Studies have shown
that a typical programmer can generate about ten lines of documented, debugged code per
day, regardless of whether the program is written in a high-level language or an assembly
language. Because a high-level language generates about an order of magnitude more
machine instructions per line, a high-level language program should be an order of
magnitude shorter (in the number of lines) and an order of magnitude cheaper to write
than an assembly language program that does the same job.
However, a high-level language compiler usually produces inefficient code. For
example, an instruction STAA LOCI might be immediately followed by the instruction
LDAA LOCI in the compiler output. As the compiler generates code from each line of
the program, line by line, the last operation of one line can generate the STAA
instruction, and the first machine code generated by the next line might be the LDAA
instruction, for the same variable. The compiler is usually unable to detect such an
occurrence and to simplify the code produced by it. Such inefficient code is quite
acceptable in a large computer where the slow execution and large memory space needed
to store the program are traded against the cost of writing the program. Hardware is cheap
and programmers are expensive, so this is a good thing. In a very small computer, which
might be put in a refrigerator to control the cooling cycle or keep the time, memory
space is limited because the whole computer is on just one chip. Inefficient code is
unacceptable here because there is not much room for code and the cost of writing the
program is comparatively small. The company that uses high-level languages for small
microcomputers will not be able to offer all the features that are crammed into a
competitor's product that is programmed in efficient assembly language; or, if it offers
the same features, its product will cost more because more memory is needed.
Some compilers are called optimizing. They use rules to detect and eliminate the
unnecessary operations such as the STAA and LDAA pair described above. They can be
used to generate more efficient code than that generated by nonoptimizing compilers. But
even these optimizing compilers produce some inefficient code. You should examine the
output of an optimizing compiler to see just how inefficient it is, and you should ignore
the claims as to how optimal the code is. Compilers are more powerful, and using them
is like driving a car with an automatic transmission, whereas using assemblers is like
driving a car with a standard transmission. An automatic transmission is easy to drive
and appeals to a wider market. A standard transmission is more controlled and enables
you to get the full capabilities out of the machine.
We now consider the differences between the compiler and the interpreter. An
interpreter is rather like a compiler, being written to convert a high-level language into
machine code. However, it converts a line of code one line at a time and executes the
resulting code right after it converts it from the high-level language program. A pure
interpreter stores the high-level language program in memory, rather than the machine
code for the program, and reads a line at a time, interprets it, and executes it. A popular
high-level language for interpreters is JAVA, and a JAVA program appears below, doing
the same job as the previous programs in C. By design, it has the same syntax as C,
An interpreter reads and executes the source code expression dprd += v[i] *
w[ i 3 twice. A compiler interprets each source code expression just once, reading it and
generating its machine code. Later the machine executes the machine code twice.
Interpreters are slow. However, it is easy to change the program in memory and execute