Declarations


Declarations
7.0 - Interface
7.1 - Overview of Declarations
7.2 - Var, Endvar
7.2.1 - Calling Conventions and Assertions
7.2.2 - Syntax & Examples
7.3 - DclType
7.3.1 - Calling Conventions and Assertions
7.3.2 - Syntax & Examples
7.4 - Index
7.4.1 - Calling Conventions and Assertions
7.4.2 - Syntax & Examples
7.5 - InitList
7.5.1 - Calling Conventions and Assertions
7.5.2 - Syntax & Examples
7.6 - Enum
7.6.1 - Calling Conventions and Assertions
7.6.2 - Syntax & Examples
7.7 - Predefined Types


Declarations

The declarations package in the UCR Standard Library contains several macros that let you define variables using a high level language (HLL) syntax rather than standard assembly language syntax. These macros automatically convert such declarations into their MASM counterparts.

The declarations package provides HLL definitions for Integer, Unsigned, Long, ULong (unsigned long), Char, String, Hex, SHex (short hex), Boolean, Float, Double, and Extended (long double) data types. It is very easy to add new types to this list.

The declarations package also contains a macro that makes it easy to create enumerated data types. This spares you the trouble of generating a list of sequential constants manually.

The declarations package also contains some macros that provide some "syntactical sugar" and Stream I/O macros to support I/O via the Stream I/O operations.


7.0 Interface

To access the routines in the declarations package, your assembly language module must include the file "dcls.a" during assembly. You can accomplish this with either of the following include statements in your assembly code:




	include	dcls.a
or
	include	ucrlib.a

The dcls.a include file exports several symbols. The UCR Standard Library prefaces all "private" names with a dollar sign ("$"). You should not call any routine in this package that begins with this symbol unless otherwise advised. To avoid name conflicts, you should not define any symbols in your programs that begin with a dollar sign ("$"). Note that future versions of the stdlib (that remain compatible with this release) may change "private" names. To remain compatible with future releases, you must not refer to these "private" names within your programs.

Source code appearing in this chapter is current as of Version Two, Release 40. There may be minor changes between this source code and the current release.


7.1 Overview of Declarations

The declarations package contains five primary macros you would use to create new data types: var, endvar, enum, InitList, and DclType. In addition, this package contains a macro (INDEX) that computes the index into a two dimensional array. Finally, this package contains declarations for the stdlib "built-in" data types.


7.2 Var, Endvar

The Var and Endvar macros delimit a variable declarations section. Actually, the use of these macros is purely optional. All they do is emit the following statements:




Var:	dseg		segment		para public 'DATA'
Endvar:	dseg		ends

You can declare your variables in any appropriate segment. However, most programs that use the Standard Library place all global variables in a segment named "dseg". Therefore, the macros above are convenient since they automatically include any declarations between them in the "dseg" segment.

Note that all variables you declare between Var and Endvar are global and static, regardless of where you place VAR..ENDVAR in your program. If you insert VAR..ENDVAR in a procedure, the names are not local to that procedure, nor is the variable's lifetime limited to the execution time of that procedure. VAR..ENDVAR and static and global in every sense of the word.

Note that it is okay to insert variable declarations into the middle of code as long as you have the VAR..ENDVAR macros around such declarations. MASM will automatically move such declarations out of your code stream and into the data segment. The following example is perfectly legal:




MyProc	proc	near
var
    integer i,j,k
    float f,x
    char cArray[28]
endvar

	mov	i, 0
	mov	j, 1
	 .
	 .
	 .

Note, however, that if you leave the surrounding VAR..ENDVAR declarations out of the above example, MASM would emit the bytes for these variable declarations directly in the code stream. This would probably create havoc when you attempt to call MyProc.


7.2.1 Calling Conventions and Assertions

Var:

Inputs: None.

Outputs: None.

Errors: None.

Side Effects: Opens a DSEG declaration at point of invocation.

Assertions: None.

Endvar:

Inputs: None.

Outputs: None.

Errors: None.

Side Effects: Closes a DSEG declaration at point of invocation.

Assertions: None.


7.2.2 Syntax & Examples




var
    integer i,j,k
    float f[20]
endvar


7.3 DclType

The DclType macro lets you declare your own "stdlib-aware" data types. The main purpose of this macro is to create data types for use in the VAR..ENDVAR section.

The DclType macro requires two parameters: a new type name and an existing (MASM) type name. A typical call takes the following form:




	DclType	integer, sword

The first difference between a DclType and a typedef typename is the syntax of the declaration. Consider the integer declaration above. To declare variables of type integer, you would use a statement like the following:




	integer	i

	integer	i,k,j

	integer	*pi, i, j, *pj

You can also declare one, two, three, and higher dimensional arrays, again using C/C++ style syntax:




	integer	iarray[20], array2d[10][10], array3d[2][4][6]

Finally, also similar to C/C++, you place initializers after an identifier in the declaration list:




	integer	i=10, j=20

	integer	*pi=i

	integer	iarray[10]=1			;Inits "iarray" with 10 ones.

Suppose you have the following DclType declaration:




	DclType	integer, sword

i	sword	?

If MASM encounters a statement of the form "integer *pi" it emits the following statement:




pi	dword	?

If you declare an array using a statement like "integer iarray[10]", then the integer macro will emit the following code:




iarray	sword	10 dup (?)

If you declare two (or higher) dimensional arrays, like "integer array2d[10][8]" then the integer macro generates the following code:




array2d	sword	10 dup (8 dup (?))

array3d	sword	2 dup (4 dup (6 dup (?)))

If you place an asterisk ("*") in front of an array declaration, the integer macro (and any macro generated by DclType) will emit a declaration for an array of pointers. For example, "integer *ia[10]" emits the following code:




ia	dword	10 dup (?)

If you add an initializer value in the declaration, the integer macro will replace the "?" in the operand field by that value. For example, "integer i=10, *pi=i, ia[10]=2" emits the following code:




i	sword	10
pi	dword	i
ia	sword	10 dup (2)

In addition to changing the syntax of a variable declaration, the macros DclType generates do one other thing that a typedef defined type does not - they create some special symbols you can use to test the type of a variable in your assembly code. Whenever you declare a variable with a DclType generated macro (e.g., integer), the macro emits two statements. The first, of course, is the variable declaration as described above. The second is a textequ statement that takes the following form:




$?varname	textequ	<typename>

i	sword	?
$?i	textequ	<integer>
j	sword	?
$?j	textequ	<integer>
k	sword	?
$?k	textequ	<integer>

If you declare a pointer type, e.g., "integer *pi" then the typename in the operand field of the textequ statement has an asterisk prefixed to the type name. For example, given "integer *pi" the corresponding assembly code will be:




pi	dword	?
$?pi	textequ	<*integer>

By default, DclType macros emit the "?" symbol to denote an unitialized value. This works great for most scalar and array data types. However, structure data types require that you use "{}" rather than a "?" to denote unitialized structures. The DclType macro allows for an optional third operand that lets you tell DclType that you are creating a structure type and you need to use "{" and "}" in the operand field rather than "?". If there is a third operand present, the the macro the DclType generates will surround the initial operand with braces ("{" and "}"). It will place an empty set of braces in the operand field if there is no initial value. See the example for details.


7.3.1 Calling Conventions and Assertions

DclType:

Inputs: Operand1: a new type name. Operand2: the corresponding MASM type to associate with this type name.

Outputs: A macro that will let you declare variables of this new type.

Errors: None.

Side Effects: None.

Assertions: None.


7.3.2 Syntax & Examples




stype	struct
Name	dword	?	;Pointer to name
Age	word	?
SSN	char	11	;Social Security Number
stype	ends
	 .
	 .
	 .
; Note the third operand is present in DclType below because we are
; creating a structure type.

	DclType	Student, stype, <{}>
	 .
	 .
	 .
	Student	Class

7.4 Index

The Index macro automatically generates the necessary code to access an element of a two dimensional array. You supply it the name of a two dimensional array, a row value, a column value, and an optional register. The Index macro computes




	(row*(size of a row) + column) * SizeOfElement

The row and column values must be 16-bit values. They can be constants, registers, or memory locations (using any reasonable memory addressing mode).


7.4.1 Calling Conventions and Assertions

Index:

Inputs: Operand1: an array name. Operand2: the row number. Operand3: the column number. Operand4 (optional): a 16-bit register to use (BX, SI, or DI are the best choices).

Outputs: 80x86 code that computes the row-major ordering function for a two-dimensional array.

Errors: None.

Side Effects: Generated code modifies the BX register if you do not specify the register to use.

Assertions: None.


7.4.2 Syntax & Examples

The following code (using the ForLp macro from the control.a include file) fills a two-dimensonal array with incrementing values:




var
    integer i,j, counter
    integer a[20][30]
endvar

	mov	counter, 0
	ForLp	I, 0, 19
	ForLp	J, 0, 29

	index	a, I, J
	mov	a[bx], counter
	inc	counter

	next	J
	next	I


7.5 InitList

The type definition macros that DclType generates suffer from one major drawback- it is difficult to initialize an array (or other object) with more than a single value. Using standard MASM directives, it is easy to generate a table of objects using a statement like:




table	word	1,2,3,4,5,6,7,8


7.5.1 Calling Conventions and Assertions

InitList:

Inputs: A list of initial values (surrounded by parentheses).

Outputs: A textual data object that a DclType generated macro can use to initialize a list of values.

Errors: None.

Side Effects: None.

Assertions: None.


7.5.2 Syntax & Examples




integer table=InitList(1,2,3,4,5,6,7,8)

integer vals[8]=InitList(0,1,2,3)

Vals	sword	8 dup (1,2,3,4)


7.6 Enum

The Enum statement lets you easily create an enumerated data type. An enumerated data type is a list of named constants, each given a unique name. In the past, assembly language programmers would have created an enumerated list using code like this:




item1	=	0
item2	=	1
item3	=	2
 .	.	.
 .	.	.
 .	.	.

ItemVar	byte	?

enum	Items, <item1, item2, item3, ...>

Items	ItemVar

Note that Enum associates the value zero with the first item in the list. It assigns consecutive values to the following items in the constant list.


7.6.1 Calling Conventions and Assertions

enum:

Inputs: The name of the new data type (Operand1) and a list of named values for that type.

Outputs: A new DclType macro (using the name you've supplied) and a list of constant declarations for the type.

Errors: None.

Side Effects: None.

Assertions: None.


7.6.2 Syntax & Examples




enum	color,<red, orange, yellow, green, blue, purple>

var
    color	c1, c2=red, RGB=InitList(red, green blue)
endvar

	mov	cl, red
	cmp	c2, red
	je	IsRead
	 .
	 .
	 .

7.7 Predefined Types

The stdlib DCL.A include file provides definitions for 12 common types. This includes six common integer types, three floating point types, two character/string types, and a boolean data type.

The integer types include the following:

integer: 16-bit signed integer values. Defined as sword.

unsigned: 16-bit unsigned integer values. Defined as word.

long: 32-bit signed integer values. Defined as sdword.

ulong: 32-bit unsigned integer values. Defined as dword.

shex: 8-bit hexadecimal values. Defined as byte.

hex: 16-bit hexadecimal values. Defined as word.

The floating point types include the following:

float: 32-bit single precision floating point values. Defined as real4.

double: 64-bit double precision floating point values. Defined as real8.

extended: 80-bit extended precision floating point values. Defined as real10.

The character types include the following:




char:	one-byte character variables.  Defined as byte.
string:	Also one-byte character variables.  Defined as byte.

Boolean data type:




boolean:	enumerated data type.  Defined as byte.
	Predefined constants: false=0, true=1.

The primary difference between the char and string data types is with respect to the support provided for these types in the Stream I/O package. When reading or writing a character variable, the Stream I/O package always reads or writes a single character. When reading or writing strings, the Stream I/O package processes entire zero terminated strings.

The DCLS.A package also includes the necessary interface macros for the Stream I/O system. See the documentation for the Stream I/O package for more details.