📄 chapter 7 code generation for control statements.htm
字号:
<P>
<MENU><B>Service 00: Console Output</B><BR>This set of services deals with
some very basic output to the stream, <I>stdout</I>.
<P>
<MENU><B>Function 00: Write String</B><BR>
<MENU>This function writes a null-terminated string to the console. The
address to the string is a 32-bit pointer that is taken from the EES.
<P><PRE> EES
--------
| char* | <-- 32-bit pointer to a string
|--------|
| . . |
</PRE></MENU><B>Function 01: Write Character</B><BR>
<MENU>This function writes a single character to the console. The
character (8-bit) is taken from the EES.
<P><PRE> EES
--------
| char | <-- A byte
|--------|
| . . |
</PRE></MENU><B>Function 02: Write Integer</B><BR>
<MENU>This function writes integers of various sizes to the console, and
formats them, as well. The first byte taken from the EES is one of the VM
type specifiers (i.e., _u8, _u16, ..., _f32, _f64). The next four bytes is
a pointer to a string that contains formatting data. This pointer may be
null. The final data to be taken from the EES is the integer, itself. It
may be either signed or unsigned, and can be any size from 8, 16, 32, to
64 bits.
<P><PRE> EES
--------
| int | <-- 1, 2, 4, or 8 bytes
|--------|
| Format | <-- 4 bytes
|--------|
| Type | <-- A byte
|--------|
| . . |
</PRE></MENU><B>Function 03: Write Real</B><BR>
<MENU>This function writes floating point numbers of various types to the
console. The number is taken from the EES.
<P><PRE> EES
--------
| real | <-- 4 or 8 bytes
|--------|
| . . |
</PRE></MENU><B>Function 04: Write Boolean</B><BR>
<MENU>This function writes a character representing a bool to the console.
The bool (8-bit) is taken from the EES. If it is a 1, a 'T' is written, if
it is 0 then a 'F' is written. Otherwise a '?' is written.
<P><PRE> EES
--------
| bool | <-- A byte
|--------|
| . . |
</PRE></MENU></MENU><B>Service 01: Keyboard Input</B><BR>This set of services
deals with some very basic input from the stream, <I>stdin</I>.
<P>
<MENU><B>Function 00: Read String</B><BR>
<MENU>This function reads characters from the keyboard. It takes two
parameters from the EES. The first one is a word containing the maximum
number of characters in the buffer. The second parameter is an address to
the buffer. The function will read up to the maximum number minus one, or
until the user hits the enter key. The string will be null-terminated.
<P><PRE> EES
--------
| char* | <-- 4 bytes
|--------|
| buffsz | <-- 2 bytes
|--------|
| . . |
</PRE></MENU><B>Function 01: Read Character</B><BR>
<MENU>This function reads a single character from the keyboard and leaves
it on the EES.
<P><PRE> EES
After
--------
| char | <-- 1 byte
|--------|
| . . |
</PRE></MENU><B>Function 02: Read Integer</B><BR>
<MENU>This function reads text from the keyboard, interpretes it as an
integer, and stores the result (based on a specified size) onto the EES.
It takes a single-byte parameter, which is a type specifier--either a _sX
or a _uX. It outputs an integer of the sign and size specified onto the
EES after the user has hit return.
<P><PRE> EES EES
Before After
-------- --------
| Type | <-- 1 byte | int | <-- 1, 2, 4, or 8 bytes
|--------| |--------|
| . . | | . . |
</PRE></MENU><B>Function 03: Read Real</B><BR>
<MENU>This function reads text from the keyboard, interpretes it as a real
number, and stores the result (based on a specified size) onto the EES. It
takes a single-byte parameter, which is a type specifier--an _f32 or an
_f64. It outputs a real number of the size specified onto the EES after
the user has hit return.
<P><PRE> EES EES
Before After
-------- --------
| Type | <-- 1 byte | real | <-- 4 or 8 bytes
|--------| |--------|
| . . | | . . |
</PRE></MENU></MENU><B>Service 04: Memory and String Manipulation</B><BR>This
set of services mirrors several of the functions in <TT>string.h</TT> and
<TT>memory.h</TT>. The only two real functions that are necessary for our
compiler are functions 00 and 80, string and memory copy, respectively.
<P>
<MENU><B>Function 00: memcpy()</B><BR>
<MENU>This function does a <TT>memcpy()</TT>. parameter read from the EES
is a word containing the count of bytes to move. The second parameter read
is a 32-bit pointer to the destination. The last parameter is another
32-bit pointer to the source. This function is used for doing array/record
copys.
<P><PRE> EES
--------
| dest * | <-- 4 bytes
|--------|
| src * | <-- 4 bytes
|--------|
| size | <-- 2 bytes
|--------|
| . . |
</PRE></MENU></MENU>
<MENU><B>Function 80: strncpy()</B><BR>
<MENU>The following is a quote from MSDN:
<BLOCKQUOTE><TT>char *strncpy( char *strDest, const char *strSource,
size_t count );</TT>
<P>The strncpy function copies the initial count characters of strSource
to strDest and returns strDest. If count is less than or equal to the
length of strSource, a null character is not appended automatically to
the copied string. If count is greater than the length of strSource, the
destination string is padded with null characters up to length count.
The behavior of strncpy is undefined if the source and destination
strings overlap. </P></BLOCKQUOTE>This function calls <TT>strncpy()</TT>.
It is a lot safer than calling <TT>strcpy()</TT>, since <TT>strncpy()</TT>
is bounded, whereas <TT>strcpy()</TT> is not. This function is useful for
copying a string constant in SAL into an array, If the constant is longer
than the buffer, only the count of characters up to the length of the
buffer will be copied, protecting memory from corruption. <PRE> EES
--------
| dest * | <-- 4 bytes
|--------|
| src * | <-- 4 bytes
|--------|
| size | <-- 2 bytes
|--------|
| . . |
</PRE></MENU></MENU><B>Service 70: Network Input/Output</B><BR>This set of
services deals with network communication. It is basically a mirror of the
Berkley socket stream library. It will not be documented here since it is
beyond the scope of this chapter.
<P>
<H3>7.5.1 Implementing <TT>read</TT> and <TT>write</TT></H3>The read and write
statements are a way of making the language do a series of outputs and inputs
on different data types without having to put each item that is read/written
on a separate line. The code to generate a series of items to be written or
read is taken one item at a time. Each of these rules loop continuously until
they encounter a semicolon, and each item is processed separately.
<P>
<MENU><IMG
src="Chapter 7 Code Generation for Control Statements.files/RULE47.gif">
<P><FONT face=arial size=-1><B>Figure {RULE47}.</B> Code generation for rule
ReadStatement.</FONT>
<P>
<P><IMG
src="Chapter 7 Code Generation for Control Statements.files/REAMEM.gif">
<P>
<P>
<P></P></MENU>The code to emit the proper sys calls for each item to be read
is thus: <PRE> if VType.type >= chartyp && VType.type <= realtyp then
select VType.type from
case chartyp: // chars
Emit (SYS, 01, 01);
case inttyp, cardtyp: // ints
Emit (LIB, vtype.subtype);
Emit (SYS, 01, 02);
case realtyp: // reals
Emit (LIB, vtype.subtype);
Emit (SYS, 01, 03);
end select;
select VType.subtype from // Store the results
case _s8, _u8:
Emit (SSB, 0);
case _s16, _u16:
Emit (SSW, 0);
case _s32, _u32, _f32:
Emit (SSD, 0);
case _s64s, _u64s, _f64s:
Emit (xSSQ, 0);
end select;
elseif VType.type=arraytyp and VType.block->ToAtab()->eltyp()=chartyp then
with VType.block->ToAtab()^ do
Emit1 (LIW); // Emit count of chars
Emit2 (hi().i - lo().i + 1);
Emit (SYS, 01, 00);
end with;
else
Error ("Can not read this type");
end if;
</PRE>There is no way to directly read a boolean, since it makes more sense to
have the programmer tell the user to do something like "Do you wish to
continue [Y/n]?". Users hate having to type something esoteric like 'T'.
<P>Character arrays are used in SAL to store strings. If we are going to store
the value of some text typed at the keyboard, then we have to be prepared for
the user to type literally anything. That is why the system call to read a
string takes an upper limit of characters.
<P>
<MENU><IMG
src="Chapter 7 Code Generation for Control Statements.files/RULE48.gif">
<P><FONT face=arial size=-1><B>Figure {RULE48}.</B> Code generation for rule
WriteStatement.</FONT>
<P>
<P><IMG
src="Chapter 7 Code Generation for Control Statements.files/WRIMEM.gif">
<P></P></MENU>The code to emit the proper sys calls for each item to be
written is thus: <PRE> if RType.IsSimpleType()then
select RType.type from
case booltyp: // bool
Emit (JPZ, 7);
Emit (LIB, 'T');
Emit (JMP, 2);
Emit (LIB, 'F');
Emit (SYS, 00, 01);
case chartyp: // char
Emit (SYS, 00, 01);
case inttyp, cardtyp: // int/card
Emit (LID, 0);
Emit (LIB, rtype.subtype);
Emit (SYS, 00, 02);
case realtyp: // real
Emit (LIB, rtype.subtype);
Emit (SYS, 00, 03);
end select;
else if RType.type = arraytyp then s// String or array of char
if RType.block = null or RType.block->ToAtab()->eltyp() = chartyp then
Emit (SYS, 00, 00);
else
Error (ER_INCOMPAT);
end if;
end if;
</PRE>Here is a simple program that does some reads and writes: <PRE> program RWSample;
var
i: int;
begin
write "Enter a number: ";
read i;
write "\nThe number you entered was ", i, nl;
end program.
*** DISASSEMBLY *************************************
ENTR 00000000
LGA 00000004
TS
SJPZ begin
RTN
begin:
LSTA 00000000 <B>write "Enter a number: ";</B>
SYS 00 00
LGA 00000009 <B>read i;</B>
LIB _s32
SYS 01 02
SSD 00000000
<B>write</B>
LSTA 00000011 <B>"\nThe number you entered was ",</B>
SYS 00 00
LGD 00000009 <B>i,</B>
LID 00000000
LIB 14
SYS 00 02
LIB 0A <B>nl</B>
SYS 00 01
RTN
</PRE></MENU></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -