HLACompileTimeLanguage.pdf

(222 KB) Pobierz
AoA.book
The HLA Compile-Time Language
The HLA
Compile-Time Language
Chapter Seven
7.1
Chapter Overview
No
w we come to the fun part. F
or the past nine chapters this te
xt has been molding and conforming you
to deal with the HLA language and assembly language programming in general. In this chapter you get to
turn the tables; you’
ll learn ho
w to force HLA to conform to your desires.
This chapter will teach you ho
w
to e
xtend the HLA language using HLA
s
compile-time langua
g
e
. By the time you are through with this
chapter
, you should ha
v
e a health
y appreciation for the po
wer of the HLA compile-time language.
ou will
be able to write short compile-time programs.
Y
ou will also be able to add ne
w statements, of your o
wn
choosing, to the HLA language.
7.2
Introduction to the Compile-Time Language (CTL)
HLA is actually tw
o languages rolled into a single program.
The
run-time langua
g
e
is the standard
80x86/HLA assembly language you’
v
e been reading about in all the past chapters.
This is called the
run-time language because the programs you write e
x
ecute when you run the e
x
ecutable fi
le. HLA contains
an interpreter for a second language, the HLA Compile-T
ime Language (or CTL) that e
x
ecutes programs
while HLA is compiling a program.
The source code for the
CTL program is embedded in an HLA assem
-
bly language source fi
le; that is, HLA source fi
les contain instructions for both the HLA CTL and the
run-time program. HLA e
x
ecutes the CTL program during compilation. Once HLA completes compilation,
the CTL program terminates; the CTL application is not a part of the run-time e
x
ecutable that HLA emits,
although the CTL application can
write
part of the run-time program for you and, in f
act, this is the major
purpose of the CTL.
Beta Draft - Do not distribute
© 2001, By Randall Hyde
Page
949
Y
286679386.002.png
Chapter Seven
Volume Four
HLA Compiler &
Compile-Time
Interpreter
Actions produced by the interpretation
of the compile-time language during
compilation.
Executable File
Compile Time
Run Time
Actions produced by the executing object code
produced by the compiler.
Figure 7.1
Compile-Time vs. Run-Time Execution
It may seem confusing to ha
v
e tw
o separate languages b
uilt into the same compiler
. Perhaps you’
re
e
v
en questioning wh
y an
yone w
ould need a compile time language.
T
o understand the benefi
ts of a compile
time language, consider the follo
wing statement that you should be v
ery comfortable with at this point:
stdout.put( "i32=", i32, " strVar=", strVar, " charVar=", charVar, nl );
This statement is neither a statement in the HLA language nor a call to some HLA Standard Library proce
-
dure. Instead,
stdout.put
is actually a statement in a CTL application provided by the HLA Standard Library.
"application" processes a list of objects (the parameter list) and makes calls to various other
Standard Library procedures; it chooses the procedure to call based on the type of the object it is currently
processing. For example, the
stdout.put
stdout.put
"application" above will emit the following statements to the
run-time executable:
stdout.puts( "i32=" );
stdout.puti32( i32 );
stdout.puts( " strVar=" );
stdout.puts( strVar );
stdout.puts( " charVar=" );
stdout.putc( charVar );
stdout.newln();
Clearly the
stdout.put
statement is much easier to read and write than the sequence of statements that
stdout.put
emits in response to its parameter list.
This is one of the more po
werful capabilities of the HLA
programming language: the ability to modify the language to simplify common programming tasks. Print
-
ing lots of dif
ferent data objects in a sequential f
ashion is a common task; the
stdout.put
"application"
greatly simplifi
es this process.
The HLA Standard Library is
loaded
with lots of HLA CTL e
xamples. In addition to standard library
usage, the HLA CTL is quite adept at handling "one-of
f" or "one-use" applications.
A classic e
xample is fi
ll
-
ing in the data for a lookup table.
An earlier chapter in this te
xt noted that it is possible to construct look-up
tables using the HLA CTL (see
T
ables
” on page
647
and
Generating
T
ables
” on page
651
). Not only is
this possible, b
ut it is often f
ar less w
ork to use the HLA CTL to construct these look-up tables.
This chapter
abounds with e
xamples of e
xactly this application of the CTL.
Page
950
© 2001, By Randall Hyde
Beta Draft - Do not distribute
The
286679386.003.png
The HLA Compile-Time Language
Although the CTL itself is relati
v
ely inef
cient and you w
ould not use it to write end-user applications,
it does maximize the use of that one precious commodity of which there is so little a
v
ailable: your time. By
learning ho
w to use the HLA CTL, and applying it properly
, you can de
v
elop assembly language applica
-
tions as rapidly as high le
v
el language applications (e
v
en f
aster since HLA
s CTL lets you create
very
high
level language constructs).
7.3 The #PRINT and #ERROR Statements
Chapter One of this textbook began with the typical first program most people write when learning a
new language; the "Hello World" program. It is only fitting for this chapter to present that same program
when discussing the second language of this text. So here it is, the basic "Hello World" program written in
the HLA compile time language:
program ctlHelloWorld;
begin ctlHelloWorld;
#print( "Hello, World of HLA/CTL" )
end ctlHelloWorld;
Program 7.1
The CTL "Hello World" Program
The only CTL statement in this program is the "#print" statement. The remaining lines are needed just
to keep the compiler happy (though we could have reduced the overhead to two lines by using a UNIT rather
than a PROGRAM declaration).
The #PRINT statement displays the textual representation of its argument list during the compilation of
an HLA program. Therefore, if you compile the program above with the command "hla ctlHW.hla" the
HLA compiler will immediately print, before returning control to the command line, the text:
Hello, World of HLA/CTL
Note that there is a big difference between the following two statements in an HLA source file:
#print( "Hello World" )
stdout.puts( "Hello World" nl );
The first statement prints "Hello World" (and a newline) during the compilation process. This first statement
does not have any effect on the executable program. The second line doesn’t affect the compilation process
(other than the emission of code to the executable file). However, when you run the executable file, the sec-
ond statement prints the string "Hello World" followed by a new line sequence.
The HLA/CTL #PRINT statement uses the following basic syntax:
#print( list_of_comma_separated_constants )
Note that a semicolon does not terminate this statement. Semicolons terminate run-time statements, they
generally do not terminate compile-time statements (there is one big exception, as you will see a little later).
The #PRINT statement must have at least one operand; if multiple operands appear in the parameter
list, you must separate each operand with a comma (just like stdout.put ). If a particular operand is not a
string constant, HLA will translate that constant to its corresponding string representation and print that
string. Example:
#print( "A string Constant ", 45, ’ ’, 54.9, ’ ’, true )
Beta Draft - Do not distribute
© 2001, By Randall Hyde
Page
951
286679386.004.png
Chapter Seven
Volume Four
You may specify named symbolic constants and constant expressions. However, all #PRINT operands
must be constants (either literal constants or constants you define in the CONST or VAL sections) and those
constants must be defined before you use them in the #PRINT statement. Example:
const
pi := 3.14159;
charConst := ’c’;
#print( "PI = ", pi, " CharVal=", CharConst )
The HLA #PRINT statement is particularly invaluable for debugging CTL programs (since there is no
debugger available for CTL code). This statement is also useful for displaying the progress of the compila-
tion and displaying assumptions and default actions that take place during compilation. Other than display-
ing the text associated with the #PRINT parameter list, the #PRINT statement does not have any affect on
the compilation of the program.
The #ERROR statement allows a single string constant operand. Like #PRINT this statement will dis-
play the string to the console during compilation. However, the #ERROR statement treats the string as a
error message and displays the string as part of an HLA error diagnostic. Further, the #ERROR statement
increments the error count and this will cause HLA to stop the compilation (without assembly or linking) at
the conclusion of the source file. You would normally use the #ERROR statement to display an error mes-
sage during compilation if your CTL code discovers something that prevents it from creating valid code.
Example:
#error( "Statement must have exactly one operand" )
Like the #PRINT statement, the #ERROR statement does not end with a semicolon. Although #ERROR
only allows a string operand, it’s very easy to print other values by using the string (constant) concatenation
operator and several of the HLA built-in compile-time functions (see “Compile-Time Constants and Vari-
ables” on page 952 and “Compile-Time Functions” on page 956) for more details).
7.4 Compile-Time Constants and Variables
Just as the run-time language supports constants and variables, so does the compile-time language.
You declare compile-time constants in the CONST section, the same as for the run-time language. You
declare compile-time variables in the VAL section. Objects you declare in the VAL section are constants as
far as the run-time language is concerned, but remember that you can change the value of an object you
declare in the VAL section throughout the source file. Hence the term "compile-time variable." See “HLA
Constant and Value Declarations” on page 397 for more details.
The CTL assignment statement ("?") computes the value of the constant expression to the right of the
assignment operator (":=") and stores the result into the VAL object name appearing immediately to the left
of the assignment operator 1 . The following example is a rework of the example above; this example, how-
ever, may appear anywhere in your HLA source file, not just in the VAL section of the program.
?ConstToPrint := 25;
#print( "ConstToPrint = ", ConstToPrint )
?ConstToPrint := ConstToPrint + 5;
#print( "Now ConstToPrint = ", ConstToPrint )
Note that HLA’s CTL ignores the distinction between the different sizes of numeric objects. HLA
always reserves storage for the largest possible object of a given type, so HLA merges the following types:
byte, word, dword -> dword
uns8, uns16, uns32 -> uns32
int8, int16, int32 -> int32
1. If the identifier to the left of the assignment operator is undefined, HLA will automatically declare this object at the current
scope level.
Page 952
© 2001, By Randall Hyde
Beta Draft - Do not distribute
286679386.005.png
The HLA Compile-Time Language
real32, real64, real80 -> real80
For most practical applications of the CTL, this shouldn’t make a difference in the operation of the program.
7.5 Compile-Time Expressions and Operators
As the previous section states, the HLA CTL supports constant expressions in the CTL assignment
statement. Unlike the run-time language (where you have to translate algebraic notation into a sequence of
machine instructions), the HLA CTL allows a full set of arithmetic operations using familiar expression syn-
tax. This gives the HLA CTL considerable power, especially when combined with the built-in compile-time
functions the next section discusses.
HLA’s CTL supports the following operators in compile-time expressions:
Table 1: Compile-Time Operators
Operator(s)
Operand Types a
Description
numeric
Negates the specific numeric value (int, uns, real).
- (unary)
cset
Returns the complement of the specified character
set.
integer
Inverts all the bits in the operand (bitwise not).
! (unary)
boolean
Boolean NOT of the operand.
numericL * numericR
Multiplies the two operands.
*
csetL * csetR
Computes the intersection of the two sets
div
integerL div integerR
Computes the integer quotient of the two integer
(int/uns/dword) operands.
mod
integerL mod integerR
Computes the remainder of the division of the two
integer (int/uns/dword) operands.
/
numericL / numericR
Computes the real quotient of the two numeric
operands. Returns a real result even if both oper-
ands are integers.
<<
integerL << integerR
Shifts integerL operand to the left the number of
bits specified by the integerR operand.
>>
integerL >> integerR
Shifts integerL operand to the right the number of
bits specified by the integerR operand.
numericL + numericR
Adds the two numeric operands.
+
csetL + csetR
Computes the union of the two sets.
strL + strR
Concatenates the two strings.
Beta Draft - Do not distribute
© 2001, By Randall Hyde
Page 953
286679386.001.png
Zgłoś jeśli naruszono regulamin