
- •Acknowledgments
- •About the Author
- •1.1 Basic Computer Structure
- •1.3 A Few Instructions and Some Simple Programs
- •2 The Instruction Set
- •3.1 Op Code Byte Addressing Modes
- •4.2 Assembler Directives
- •4.3 Mechanics of a Two-Pass Assembler
- •4.6 Summary
- •5.1 Cross Assemblers and Downloaders
- •5 Problems
- •6.3 Passing Arguments by Value, Reference, and Name
- •7 Arithmetic Operations
- •7.2 Integer Conversion
- •8 Programming in C and C++
- •8.1 Compilers and Interpreters
- •9 Implementation of C Procedures
- •9.2 Expressions and Assignment Statements
- •9.4 Loop Statements, Arrays, and Structs
- •10 Elementary Data Structures
- •10.1 What a Data Structure Is
- •11.4 Synchronization Hardware
- •12.4 The 68300 Series
- •A2.1 Loading HiWare Software
- •A2.2 Opening the HiWare Toolbox
- •A2.3 Running Examples From the ManualProgramFolder
- •A2.6 POD-Mode BDM Interface
- •Index

8
Programming in C and C++
This chapter gives background material for Chapter 9, which shows how C or C++ statements are encoded in assembly language. Together, they illustrate what a programmer is doing when he or she writes high-level language programs. However, if you have already covered this material, it can be skipped.
The first section provides terminology and understanding of where to use high-level language compilers and interpreters. We then begin with a description of C, illustrating first operators and statements and then conditional and loop expressions. We give an example of a program that uses many of the features we need in the next chapter, and then discuss C++ and object-oriented programming.
8.1 Compilers and Interpreters
We first discuss the difference between an assembler and a compiler. A compiler is a program that converts a sequence of (ASCII) characters that are written in a high-level language into machine code or into assembly language that can be converted into machine code. A high-level language is different from an assembly language in two ways. First, a line of a high-level language statement will often generate five to a few tens of machine instructions, whereas an assembly-language statement will usually generate (at most) one machine instruction. Second, a high-level language is designed to be oriented to the specification of the problem that is to be solved by the program and to the human thought process, while a program in an assembly language is oriented to the computer instruction set and to the hardware used to execute the program. Consider the dot product subroutine used in the previous chapter, written in C below. Each line of the program generates many machine instructions or lines of assembly-language code. Each high-level language statement is designed to express an idea used in the statement of the problem and is oriented to the user rather than the machine. The compiler could generate the assembly-language program or the machine code produced by this program.
int dotprod(char |
v[], char w [ ] ) { int i, |
dprd = 0; |
|
for(i = 0; |
i |
< 2; i++) dprd += v[i] |
* w[i]; |
return dprd; |
|
|
}
221
















8.7 Object-oriented Programming in C++ |
237 |
A class's function members are written rather like C procedures with the return type and class name in front of two colons and the function member name.
void Cstack::push{int i){if(Ptr==Top){Error=l; return?} *(++Ptr)=i; }
int Cstack::pull{){if(Ptr==Bottom){ Error=l; return 0;} return *(Ptr—);}
char Cstack::error{){ char i; i = Error; Error = 0; return i; }
Any data member, such as Top, may be accessed inside any function member of class Cstack, such as push() . Inside a function member, when a name appears in an expression, the variable's name is first searched against local variables and function formal parameters. If the name matches, the variable is local or an argument. Then the variable is matched against the object data members and finally against the global variables. In a sense, object data members are global among the function members, because each of them can get to these same variables. However, it is possible that a data member and a local variable or argument have the same name such as Error. The data member can be identified as this->Error, using key word this to point to the object that called the function member, while the local variable or argument is just Error.
C++ uses constructors, allocators, destructors, and deallocators. An allocator allocates data member storage. A constructor initializes these variables; it has the same function name as the class name. Declaring or blessing an object automatically calls the allocator and constructor, as we will see shortly. A destructor terminates the use of an object. A destructor has the same function name as the class name but has a tilde (~) in front of the function member name. A deallocator recovers storage for data members for later allocation. We do not use a deallocator in our experiments; it is easier to reset the 6812 to deallocate storage. Here's Cstack's constructor:
Cstack::Cstack(int i){Top=(Ptr=Bottom=(char*)allocate(i))+i;Qlen= Error=0;}
Throughout this section, a conventional C procedure allocate provides buffer storage for an object's data members and for an object's additional storage such as its stacks. The contents of global variable free are initialized to the address just above the last global; storage between free and the stack pointer is subdivided into buffers for each object by the allocate routine. The stack used for return addresses and local variables builds from one end and the allocator builds from the other end of a common RAM buffer area, allocate's return type void * means a pointer toanything.
char *free=0xb80;
void *allocate(int i) { void *p=free; free += i; return p; }
A global object of a class is declared and then used as shown below:
Cstack S(10);
void main() { int i;
S.push(l); i = S.pull();
}











248 |
Chapter 8 Programming in C and C++ |
a. Write a C procedure encode ( ) |
to convert the ASCII string to Huffman code, as |
defined by the coding tree in Figure 8.5a, storing the code as a bit string, first bit as most significant bit of first element of int code [16];.
b. Write a C procedure decode ( ) that decodes such a code in int code [ 16], using the coding tree in Figure 8.5a, putting the ASCII string back as it was in char string[4Q].
9. Repeat Problem 8 for the Huffman coding tree in Figure 8.5b.
10. Write an initialization and four shortest C procedures void pstop( int) push to
top, int pltop() pull from top, psbot(int) push to bottom, int |
plbot( ) pull |
from bottom, of a ten-element 16-bit word deque. The deque's |
buffer is int |
deque [ 10]. Use global int pointers, top and bottom. Use global char varaibles for the size of the deque, size, and error flag errors which is to remain cleared if there are no errors and to be 1 if there are underflow or overflow errors. Note that C always initializes global variables to zero if not otherwise initialized. The procedures should manage the deque correctly as long as errors is zero. Procedures pstop() and psbot ( ) pass by value, andprocedures pltop() and plbot ( ) pass byresult.
11. Write a C procedure get (char *a, int |
i), whose body consists entirely of |
embedded assembly language, which moves i |
bytes following address a into a char |
global vector v, assuming v has a dimension larger than or equal to i. To achieve speed, use the MOVE and DBNE instructions. The call to this procedure, get (s, n ) , is implemented:
Idx s pshx
Idx n jsr get leas 4,sp
12. Write a shortest C procedure hexString(unsigned int n, char *s) that runs in a target machine to convert an unsigned integer n into printable characters in s that represent it in hexadecimal so that sfOJ is the ASCII code for the 1000's hex digit, s[l] is the code for the IQO's hex digit, and so on. Suppress leading Osby replacing them with blanks.
13. Write the shortest procedure int inhex() in C to input a four-digit hexadecimal number from the keyboard (the letters A through F may be upper or lower case; typing any character other than 0...9, a...f, A...F, or entering more than four hexadecimal digits terminates the input and starts the conversion) and convert it to a binary number, returning the converted binary number as an unsigned int. Although you do not have to use a compiler and target machine to answer this problem, you can use it without penalty, and it may help you get error-free results faster.



PROBLEMS |
|
251 |
invert an interval containing 0 or get the square root of an interval containing |
a negtive |
|
value. Finally, write a main() procedure that will initialize intervals |
a to <1,2>, b to |
|
<3,4>, and c to <5,6>, and then evaluate the result of the expression ( |
-b + |
sqrt ( b |
* b - 4 * a * c ) ) / (a + a). |
|
|
