home *** CD-ROM | disk | FTP | other *** search
/ Shareware Overload / ShartewareOverload.cdr / progm / a86d86-1.zip / A08.DOC < prev    next >
Text File  |  1989-03-10  |  27KB  |  720 lines

  1. CHAPTER 8   NUMBERS AND EXPRESSIONS
  2.  
  3.  
  4. Numbers and Bases
  5.  
  6. A86 supports a variety of formats for numbers.  In non-computer
  7. life, we write numbers in a decimal format.  There are ten
  8. digits, 0 through 9, that we use to describe numbers; and each
  9. digit position is ten times as significant as the position to its
  10. right.   The number ten is called the "base" of the decimal
  11. format.  Computer programmers often find it convenient to use
  12. other bases to specify numbers used in their programs.  The most
  13. commonly-used bases are two (binary format), sixteen (hexadecimal
  14. format), and eight (octal format).
  15.  
  16. The hexadecimal format requires sixteen digits.  The extra six
  17. digits beyond 0 through 9 are denoted by the first six letters of
  18. the alphabet: A for ten, B for eleven, C for twelve, D for
  19. thirteen, E for fourteen, and F for fifteen.
  20.  
  21. In A86, a number must always begin with a digit from 0 through 9,
  22. even if the base is hexadecimal.  This is so that A86 can
  23. distinguish between a number and a symbol that happens to have
  24. digits in its name.  If a hexadecimal number would begin with a
  25. letter, you precede the letter with a zero.  For example, hex A0,
  26. which is the same as decimal 160, would be written 0A0.
  27.  
  28. Because it is necessary for you to append leading zeroes to many
  29. hex numbers, and because you never have to do so for decimal
  30. numbers, I decided to make hexadecimal the default base for
  31. numbers with leading zeroes.  Decimal is still the default base
  32. for numbers beginning with 1 through 9.
  33.  
  34. Large numbers can be given as the operands to DD, DQ, or DT
  35. directives.  For readability, you may freely intersperse
  36. underscore characters anywhere with your numbers.
  37.  
  38. The default base can be overridden, with a letter or letters at
  39. the end of the number: B or xB for binary, O or Q for octal, H
  40. for hexadecimal, and D or xD for decimal.  Examples:
  41.  
  42.  077Q       octal, value is 8*7 + 7 = 63 in decimal notation
  43.  123O       octal if the "O" is a letter: 64 + 2*8 + 3 = 83 decimal
  44.  1230       decimal 1230: shows why you should use "Q" for octal!!
  45.  01234567H  large constant
  46.  0001_0000_0000_0000_0003R real number specified in hexadecimal
  47.  100D       superfluous D indicates decimal base
  48.  0100D      hex number 100D, which is 4096 + 13 = 5009 in decimal
  49.  0100xD     decimal 100, since xD overrides the default hex format
  50.  0110B      hex 110B, which is 4096 + 256 + 11 = 4363 in decimal
  51.  0110xB     binary 4+2 = 6 in decimal notation
  52.  110B       also binary 4+2 = 6, since "B" is not a decimal digit
  53.                                                               8-2
  54.  
  55. The last five examples above illustrate why an "x" is sometimes
  56. necessary before the base-override letter "B" or "D".  If that
  57. letter can be interpreted as a hex digit, it is; the "x" forces
  58. an override interpretation for the "B" or "D".  By the way, the
  59. usage of lower case for x and upper case for the following
  60. override letter is simply a recommendation; A86 treats upper-and
  61. lower-case letters equivalently.
  62.  
  63.  
  64. The RADIX Directive
  65.  
  66. The above-mentioned set of defaults (hex if leading zero, decimal
  67. otherwise) can be overridden with the RADIX directive.  The RADIX
  68. directive consists of the word RADIX followed by a number from 2
  69. to 16.  The default base for the number is ALWAYS decimal,
  70. regardless of any (or no) previous RADIX commands.  The number
  71. gives the default base for ALL subsequent numbers, up to (but not
  72. including) the next RADIX command.  If there is no number
  73. following RADIX, then A86 returns to its initial mixed default of
  74. hex for leading zeroes, decimal for other leading digits.
  75.  
  76. For compatibility with IBM's assembler, RADIX can appear with a
  77. leading period; although I curse the pinhead designer who put
  78. that period into IBM's language.
  79.  
  80. As an alternative to the RADIX directive, I provide the D switch,
  81. which causes A86 to start with decimal defaults.  You can put +D
  82. into the A86 command invocation, or into the A86 environment
  83. variable.  The first RADIX command in the program will override
  84. the D switch setting.
  85.  
  86. Following are examples of radix usage.  The numbers in the
  87. comments are all in decimal notation.
  88.  
  89.   DB 10,010     ; produces 10,16 if RADIX was not seen yet
  90.                 ;   and +D switch was not specified
  91. RADIX 10
  92.   DB 10,010     ; produces 10,10
  93. RADIX 16
  94.   DB 10,010     ; produces 16,16
  95. RADIX 2
  96.   DB 10,01010   ; produces 2,10
  97. RADIX 3         ; for Martian programmers in Heinlein novels
  98.   DB 10,100     ; produces 3,9
  99. RADIX
  100.   DB 10,010     ; produces 10,16
  101.                                                               8-3
  102.  
  103. Floating Point Initializations
  104.  
  105. A86 allows floating point numbers as the operands to DD, DQ, and
  106. DT directives.  The numbers are encoded according to the IEEE
  107. standard, followed by the 8087 and 287 coprocessors.  The format
  108. for floating point constants is as follows: First, there is a
  109. decimal number containing a decimal point.  There must be a
  110. decimal point, or else the number is interpreted as an integer.
  111. There must also be at least one decimal digit, either to the left
  112. or right of the decimal point, or else the decimal point is
  113. interpreted as an addition (structure element) operator.
  114. Optionally, there may follow immediately after the decimal number
  115. the letter E followed by a decimal number.  The E stands for
  116. "exponent", and means "times 10 raised to the power of".  You may
  117. provide a + or - between the E and its number.  Examples:
  118.  
  119.   0.1             constant one-tenth
  120.   .1              the same
  121.   300.            floating point three hundred
  122.   30.E1           30 * 10**1; i.e., three hundred
  123.   30.E+1          the same
  124.   30.E-1          30 * 10**-1; i.e., three
  125.   30E1            not floating point: hex integer 030E1
  126.   1.234E20        scientific notation: 1.234 times 10 to the 20th
  127.   1.234E-20       a tiny number: 1.234 divided by 10 to the 20th
  128.  
  129.  
  130.  
  131. Overview of Expressions
  132.  
  133. Most of the operands that you code into your instructions and
  134. data initializations will be simple register names, variable
  135. names, or constants.  However, you will regularly wish to code
  136. operands that are the results of arithmetic calculations,
  137. performed either by the machine when the program is running (for
  138. indexing), or by the assembler (to determine the value to
  139. assemble into the program).  A86 has a full set of operators that
  140. you can use to create expressions to cover these cases:
  141.  
  142. * Arithmetic Operators
  143.              byte isolation and combination (HIGH, LOW, BY)
  144.              addition and subtraction (+,-)
  145.              multiplication and division (* , /, MOD)
  146.              shifting operators (SHR, SHL, BIT)
  147.  
  148. * Logical Operators
  149.              (AND, OR, XOR, NOT)
  150.  
  151. * Boolean Negation Operator
  152.              (!)
  153.  
  154. * Relational Operators
  155.              (EQ, LE, LT, GE, GT, NE)
  156.  
  157. * String Comparison Operators
  158.              (EQ, NE, =)
  159.                                                               8-4
  160.  
  161. * Attribute Operators/Specifiers
  162.              size specifiers (B=BYTE,W=WORD,F=FAR,SHORT,LONG)
  163.              attribute specifiers (OFFSET,NEAR,brackets)
  164.              segment addressing specifier (:)
  165.              compatibility operators (PTR,ST)
  166.              built-in value specifiers (TYPE,THIS,$)
  167.  
  168. * Special Data Duplication Operator
  169.              (DUP)  --see Chapter 9 for a description
  170.  
  171.  
  172. Types of Expression Operands
  173.  
  174. Numbers and Label Addresses
  175.  
  176. A number or constant (16-bit number) can be used in most
  177. expressions.   A label (defined with a colon) is also treated as
  178. a constant and so can be used in expressions, except when it is a
  179. forward reference.
  180.  
  181. Variables
  182.  
  183. A variable stands for a byte- or word-memory location.   You may
  184. add or subtract constants from variables; when you do so, the
  185. constant is added to the address of the variable.  You typically
  186. do this when the variable is the name of a memory array.
  187.  
  188. Index Expressions
  189.  
  190. An index expression consists of a combination of a base register
  191. [BX] or [BP], and/or an index register [SI] or [DI], with an
  192. optional constant added or subtracted.   You will usually want to
  193. precede the bracketed expression with B, W, or F; to specify the
  194. kind of memory unit (byte, word, or far pointer) you are
  195. referring to.  The expression stands for the memory unit whose
  196. address is the run-time value(s) of the base and/or index
  197. registers added to the constant.  See the Effective Address
  198. section and the beginning of this chapter for more details on
  199. indexed memory.
  200.  
  201.  
  202. Arithmetic Operators
  203.  
  204.  
  205. HIGH/LOW
  206.  
  207. Syntax:  HIGH operand
  208.          LOW operand
  209.  
  210. These operators are called the "byte isolation" operators.  The
  211. operand  must evaluate to a 16-bit number.   HIGH returns the
  212. high order byte of the number; LOW the low order byte.
  213.  
  214. For example,
  215.  
  216.   MOV AL,HIGH(01234)     ; AL = 012
  217.   TENHEX EQU LOW(0FF10)  ; TENHEX = 010
  218.                                                               8-5
  219.  
  220. These operators can be applied to each other.   The following
  221. identities apply:
  222.  
  223. LOW LOW Q = LOW Q
  224. LOW HIGH Q = HIGH Q
  225. HIGH LOW Q = 0
  226. HIGH HIGH Q = 0
  227.  
  228.  
  229. BY
  230.  
  231. Syntax:  operand BY operand
  232.  
  233. This operator is a "byte combination" operator.  It returns the
  234. word whose high byte is the left operand, and whose low byte is
  235. the right operand.  For example, the expression 3 BY 5 is the
  236. same as hexadecimal 0305.  The BY operator is exclusive to A86. I
  237. added it to cover the following situation: Suppose you are
  238. initializing your registers to immediate values.  Suppose you
  239. want to initialize AH to the ASCII value 'A', and AL to decimal
  240. 10.  You could code this as two instructions MOV AH,'A' and MOV
  241. AL,10; but you realize that a single load into the AX register
  242. would save both program space and execution time.  Without the BY
  243. operator, you would have to code MOV AX,0410A, which disguises
  244. the types of the individual byte operands you were thinking
  245. about.  With BY, you can code it properly: MOV AX,'A' BY 10.
  246.  
  247.  
  248. Addition (combination)
  249.  
  250. Syntax:  operand + operand
  251.          operand.operand
  252.          operand PTR operand
  253.          operand operand
  254.  
  255. As shown in the above syntax, addition can be accomplished in
  256. four ways: with a plus sign, with a dot operator, with a PTR
  257. operator, and simply by juxtaposing two operands next to each
  258. other.  The dot and PTR operators are provided for compatibility
  259. with Intel/IBM assemblers.  The dot is used in structure field
  260. notation; PTR is used in expressions such as BYTE PTR 0.  (See
  261. Chapter 12 for recommendations concerning PTR.)
  262.  
  263. If either operand is a constant, the answer is an expression with
  264. the typing of the other operand, with the offsets added.  For
  265. example, if BVAR is a byte variable, then BVAR + 100 is the byte
  266. variable 100 bytes beyond BVAR.
  267.  
  268. Other examples:
  269.  
  270.    DB 100+17         ; simple addition
  271.    CTRL EQU -040
  272.    MOV AL,CTRL'D'    ; a nice notation for control-D!
  273.    MOV DX,[BP].SMEM  ; --where SMEM was in an unindexed structure
  274.    DQ  10.0 + 7.0    ; floating point addition
  275.                                                               8-6
  276.  
  277. Subtraction
  278.  
  279. Syntax:  operand - operand
  280.  
  281. The subtraction operator may have operands that are:
  282.  
  283.   a. both absolute numbers
  284.  
  285.   b. variable names that have the same type
  286.  
  287. The result is an absolute number; the difference between the two
  288. operands.
  289.  
  290. Subtraction is also allowed between floating point numbers; the
  291. answer is the floating point difference.
  292.  
  293.  
  294. Multiplication and Division
  295.  
  296. Syntax:   operand * operand     (multiplication)
  297.           operand / operand     (division)
  298.           operand MOD operand   (modulo)
  299.  
  300. You may only use these operators with absolute or floating point
  301. numbers, and the result is always the same type.  Either operand
  302. may be a numeric expression, as long as the expression evaluates
  303. to an absolute or floating point number.  Examples:
  304.  
  305. CMP AL,2 * 4    ; compare AL to 8
  306. MOV BX,0123/16  ; BX = 012
  307. DT  1.0 / 7.0
  308.  
  309.  
  310.  
  311. Shifting Operators
  312.  
  313. Syntax:  operand SHR count   (shift right)
  314.          operand SHL count   (shift left)
  315.          BIT count           (bit number)
  316.  
  317. The shift operators will perform a "bit-wise" shift of the
  318. operand.  The operand will be shifted "count" bits either to the
  319. right or the left.  Bits shifted into the operand will be set to
  320. 0.
  321.  
  322. The expression "BIT count" is equivalent to "1 SHL count"; i.e.,
  323. BIT returns the mask of the single bit whose number is "count".
  324. The operands must be numeric expressions that evaluate to
  325. absolute numbers.  Examples:
  326.  
  327. MOV BX, 0FACBH SHR 4   ; BX = 0FACH
  328. OR AL,BIT 6            ; AL = AL OR 040; 040 is the mask for bit 6
  329.                                                               8-7
  330.  
  331. Logical Operators
  332.  
  333. Syntax:  operand OR operand
  334.          operand XOR operand
  335.          operand AND operand
  336.          NOT operand
  337.  
  338. The logical operators may only be used with absolute numbers.
  339. They always return an absolute number.
  340.  
  341. Logical operators operate on individual bits.   Each bit of the
  342. answer depends only on the corresponding bit in the operand(s).
  343.  
  344. The functions performed are as follows:
  345.  
  346. 1.  OR: An answer bit is 1 if either or both of the operand bits
  347.     is 1.   An answer bit is 0 only if both operand bits are 0.
  348.  
  349. Example:
  350.  
  351. 11110000xB OR 00110011xB = 11110011xB
  352.  
  353.  
  354. 2.  XOR: This is "exclusive OR."  An answer bit is 1 if the
  355.     operand bits are different; an answer bit is 0 if the operand
  356.     bits are the same.   Example:
  357.  
  358. 11110000xB XOR 00110011xB = 11000011xB
  359.  
  360.  
  361. 3.  AND: An answer bit is 1 only if both operand bits are 1.   An
  362.     answer bit is 0 if either or both operand bits are 0.
  363.     Example:
  364.  
  365. 11110000xB AND 00110011xB = 00110000xB
  366.  
  367. 4.  NOT: An answer bit is the opposite of the operand bit.   It
  368.     is 1 if the operand bit is 0; 0 if the operand bit is 1.
  369.     Example:
  370.  
  371. NOT 00110011xB = 11001100xB
  372.  
  373.  
  374. Boolean Negation Operator
  375.  
  376. Syntax:  ! operand
  377.  
  378. The exclamation-point operator, rather than reversing each
  379. individual bit of the operand, considers the entire operand as a
  380. boolean variable to be negated.  If the operand is non-zero (any
  381. of the bits are 1), the answer is 0.  If the operand is zero, the
  382. answer is 0FFFF.
  383.                                                               8-8
  384.  
  385. Because ! is intended to be used in conditional assembly
  386. expressions (described in Chapter 11), there is also a special
  387. action when ! is applied to an undefined name: the answer is the
  388. defined value 0FFFF, meaning it is TRUE that the symbol is
  389. undefined.  Similarly, when ! is applied to some defined quantity
  390. other than an absolute constant, the answer is 0, meaning it is
  391. FALSE that the operand is undefined.
  392.  
  393.  
  394. Relational Operators
  395.  
  396. Syntax:    operand EQ operand    (equal)
  397.            operand NE operand    (not equal)
  398.            operand LT operand    (less than)
  399.            operand LE operand    (less or equal)
  400.            operand GT operand    (greater than)
  401.            operand GE operand    (greater or equal)
  402.  
  403. The relational operators may have operands that are:
  404.  
  405.   a.  both absolute numbers
  406.  
  407.   b.  variable names that have the same type
  408.  
  409. The result of a relational operation is always an absolute
  410. number.  They return an 8-or 16-bit result of all 1's for TRUE
  411. and all 0's for FALSE.  Examples:
  412.  
  413. MOV AL, 3 EQ 0     ; AL = 0 (false)
  414. MOV AX, 2 LE 15    ; AX = 0FFFFH (true)
  415.  
  416.  
  417. String Comparison Operators
  418.  
  419. Syntax:    string EQ string    (equal)
  420.            string NE string    (not equal)
  421.            string = string     (equal ignoring case)
  422.  
  423. In order to subsume the string comparison facilities offered by
  424. That Other Assembler's special conditional-assembly directives
  425. IFIDN and IFDIF, A86 allows the relational operators EQ and NE to
  426. accept string arguments.  For this syntax to be accepted by A86,
  427. both strings must be bounded using the same delimiter (either
  428. single quotes for both strings, or double quotes for both
  429. strings).  For a match (EQ returns TRUE or NE returns FALSE), the
  430. strings must be the same length, and every character must match
  431. exactly.
  432.                                                               8-9
  433.  
  434. An additional A86-exclusive feature is the = operator, which
  435. returns TRUE if the characters of the strings differ only in the
  436. bit masked by the value 020.  Thus you may use = to compare a
  437. macro parameter to a string containing nothing but letters.  The
  438. comparison will be TRUE whether the macro parameter is upper-case
  439. or lower-case.  No checking is made to detect non-letters, so if
  440. you use = on strings containing non-letters, you may get some
  441. false TRUE results.  Also, = is accepted when it is applied to
  442. non-strings as well-- the corresponding values are interpreted as
  443. two-byte strings, with the 020 bits masked away before
  444. comparison.
  445.  
  446.  
  447.  
  448. Attribute Operators/Specifiers
  449.  
  450.  
  451. B,W,D,Q,T memory variable specifiers
  452.  
  453. Syntax:  B operand          Q operand
  454.          operand B          operand Q
  455.          W operand          T operand
  456.          operand W          operand T
  457.          D operand
  458.          operand D
  459.  
  460. B, W, D, F, Q, and T convert the operand into a byte, word,
  461. doubleword, far, quadword, and ten-byte variable, respectively.
  462. The operand can be a constant, or a variable of the other type.
  463. Examples:
  464.  
  465. ARRAY_PTR:
  466.   DB 100 DUP (?)
  467. WVAR  DW ?
  468.   MOV AL,ARRAY_PTR B  ; load first byte of ARRAY_PTR array into AL
  469.   MOV AL,WVAR B       ; load the low byte of WVAR into AL
  470.   MOV AX,W[01000]     ; load AX with the memory word at loc. 01000
  471.   LDS BX,D[01000]     ; load DS:BX with the doubleword at loc. 01000
  472.   JMP F[01000]        ; jump far to the 4-byte location at 01000
  473.   FLD T[BX]           ; load ten-byte number at [BX] to 87 stack
  474.  
  475.  
  476. For compatibility with Intel/IBM assemblers, A86 accepts the more
  477. verbose synonyms BYTE, WORD, DWORD, FAR, QWORD, and TBYTE for
  478. B,W,D,F,Q,T, respectively.
  479.  
  480.  
  481. SHORT and LONG Operators
  482.  
  483. Syntax:    SHORT label
  484.            LONG label
  485.                                                              8-10
  486.  
  487. The SHORT operator is used to specify that the label referenced
  488. by a JMP instruction is within 127 bytes of the end of the
  489. instruction.  The LONG operator specifies the opposite: that the
  490. label is not within 127 bytes.  The appropriate operator can (and
  491. sometimes must) be used if the label is forward referenced in the
  492. instruction.
  493.  
  494. When a non-local label is forward referenced, the assembler
  495. assumes that it will require two bytes to represent the relative
  496. offset of the label (so the instruction including the opcode byte
  497. will be three bytes).  By correctly using the SHORT operator, you
  498. can save a byte of code when you use a forward reference. If the
  499. label is not within the specified range, an error will occur. The
  500. following example illustrates the use of the SHORT operator.
  501.  
  502. JMP FWDLAB        ; three byte instruction
  503. JMP SHORT FWDLAB  ; two byte instruction
  504. JMP >L1           ; two byte instruction assumed for a local label
  505.  
  506. Because the assembler assumes that a forward reference local
  507. label is SHORT, you may sometimes be forced to override this
  508. assumption if the label is in fact not within 127 bytes of the
  509. JMP.  This is why LONG is provided:
  510.  
  511. JMP LONG >L9      ; three byte instruction
  512.  
  513. If you are bothered by this possibility, you can specify the +L
  514. switch, which causes A86 to pessimistically generate the three
  515. byte JMP for all forward references, unless specifically told not
  516. to with SHORT.
  517.  
  518. NOTE that LONG will have effect only on the operand to an
  519. unconditional JMP instruction; not to conditional jumps.  This is
  520. because the conditional jumps don't have 3-byte forms; the only
  521. conditional jumps are short ones.  If you run into this problem,
  522. then chances are your code is getting out of control--time to
  523. rearrange, or to break off some of the intervening code into
  524. separate procedures.  If you insist upon leaving the code intact,
  525. you can replace the conditional jump with an "IF cond JMP".
  526.  
  527.  
  528. OFFSET Operator
  529.  
  530. Syntax:  OFFSET var-name
  531.  
  532. OFFSET is used to convert a variable into the constant pointer to
  533. the variable.  For example, if you have declared  XX DW ?, and
  534. you want to load SI with the pointer to the variable XX, you can
  535. code: MOV SI,OFFSET XX.  The simpler instruction MOV SI,XX moves
  536. the variable contents of XX into SI, not the constant pointer to
  537. XX.
  538.                                                              8-11
  539.  
  540. NEAR Operator
  541.  
  542. Syntax:  NEAR operand
  543.  
  544. NEAR converts the operand to have the type of a code label, as if
  545. it were defined by appearing at the beginning of a program line
  546. with a colon after it.  NEAR is provided mainly for compatibility
  547. with Intel/IBM assemblers.
  548.  
  549.  
  550. Square Brackets Operator
  551.  
  552. Syntax:  [operand]
  553.  
  554. Square brackets around an operand give the operand a memory
  555. variable type.  Square brackets are generally used to enclose the
  556. names of base and index registers: BX, BP, SI, and DI.  When the
  557. size of the memory variable can be deduced from the context of
  558. the expression, square brackets are also used to turn numeric
  559. constants into memory variables.  Examples:
  560.  
  561.   MOV B[BX+50],047  ; move imm value 047 into mem byte at BX+50
  562.   MOV AL,[050]      ; move byte at memory location 050 into AL
  563.   MOV AL,050        ; move immediate value 050 into AL
  564.  
  565.  
  566. Colon Operator
  567.  
  568. Syntax:   constant:operand
  569.           segreg:operand
  570.           seg_or_group_name:operand
  571.  
  572. The colon operator is used to attach a segment register value to
  573. an operand.  The segment register value appears to the left of
  574. the colon; the rest of the operand appears to the right of the
  575. colon.
  576.  
  577. There are three forms to the colon operator.  The first form has
  578. a constant as the segment register value.  This form is used to
  579. create an operand to a long (inter-segment) JMP or CALL
  580. instruction.  An example of this is the instruction JMP 0FFFF:0,
  581. which jumps to the cold-boot reset location of the 86 processor.
  582.  
  583. The only context other than JMP or CALL in which this first form
  584. is legal, is as the operand to a DD directive or an EQU
  585. directive.  The EQU case has a further restriction: the offset
  586. (the part to the right of the colon) must have a value less than
  587. 256.  This is because there simply isn't room in a symbol table
  588. entry for a segment register value AND a 2-byte offset.  I don't
  589. think you will be hurt by this restriction, since references to
  590. other segments are usually to jump tables at the beginning of
  591. those segments.
  592.                                                              8-12
  593.  
  594. The second form has a segment register name to the left of the
  595. colon.  This is the segment override form, provided for
  596. compatibility with Intel/IBM assemblers.  A86 will generate a
  597. segment override byte when it sees this form, unless the operand
  598. to the right of the colon already has a default segment register
  599. that is the same as the given override.
  600.  
  601. I prefer the more explicit method of overrides, exclusive to A86:
  602. simply place the segment register name before the instruction
  603. mnemonic.  For example, I prefer ES MOV AL,[BX] to MOV
  604. AL,ES:[BX].
  605.  
  606. The third form has a segment or group name before the colon. This
  607. form is ignored by A86; it is provided for compatibility with
  608. Turbo C, which likes to include spurious DGROUP: overrides, to
  609. satisfy MASM's ASSUME-checking.
  610.  
  611.  
  612. ST Operator
  613.  
  614. ST is ignored whenever it occurs in an expression.  It is
  615. provided for compatibility with Intel and IBM assemblers. For
  616. example, you can code FLD ST(0),ST(1), which will be taken by A86
  617. as FLD 0,1.
  618.  
  619.  
  620. TYPE Operator
  621.  
  622. Syntax:  TYPE operand
  623.  
  624. The TYPE operator returns 1 if the operand is a byte variable; 2
  625. if the operand is a word variable; 4 if the operand is a
  626. doubleword variable; 8 if the operand is a quadword variable; 10
  627. if the operand is a ten-byte variable; and the number of bytes
  628. allocated by the structure if the operand is a structure name
  629. (see STRUC in the next chapter).
  630.  
  631. A common usage of the TYPE operator is to represent the number of
  632. bytes of a named structure.  For example, if you have declared a
  633. structure named LINE (as described in the next chapter) that
  634. defines 82 bytes of storage, then two ways you might refer to the
  635. value symbolically are as follows:
  636.  
  637.   MOV CX,TYPE LINE     ; loads the size of LINE into CX
  638.   DB TYPE LINE DUP ?   ; allocates an area of memory for a LINE
  639.  
  640.  
  641.  
  642. THIS and $ Specifiers
  643.  
  644. THIS returns the value of the current location counter.  It is
  645. provided for compatibility with Intel/IBM assemblers.  The dollar
  646. sign $ is the more standard and familiar specifier for this
  647. purpose; it is equivalent to THIS NEAR.  THIS is typically used
  648. with the BYTE and WORD specifiers to create alternate-typed
  649. symbols at the same memory location:
  650.                                                              8-13
  651.  
  652.      BVAR EQU THIS BYTE
  653.      WVAR  DW ?
  654.  
  655. I don't recommend the use of THIS.  If you wish to retain Intel
  656. compatibility, you can use the less verbose LABEL directive:
  657.  
  658.       BVAR LABEL BYTE
  659.       WVAR  DW ?
  660.  
  661. If you are not concerned with compatibility to lesser assemblers,
  662. A86 offers a variety of less verbose forms.  The most concise is
  663. DB without an operand:
  664.  
  665.       BVAR DB
  666.       WVAR DW ?
  667.  
  668. If this is too cryptic for you, there is always BVAR EQU B[$].
  669.  
  670.  
  671. Operator Precedence
  672.  
  673. Consider the expression 1 + 2 * 3.  When A86 sees this
  674. expression, it could perform the multiplication first, giving an
  675. answer of 1+6 = 7; or it could do the addition first, giving an
  676. answer of 3*3 = 9.  In fact, A86 does the multiplication first,
  677. because A86 assigns a higher precedence to multiplication than it
  678. does addition.
  679.  
  680. The following list specifies the order of precedence A86 assigns
  681. to expression operators. All expressions are evaluated from left
  682. to right following the precedence rules.  You may override this
  683. order of evaluation and precedence through the use of parentheses
  684. ( ).  In the example above, you could override the precedence by
  685. parenthesizing the addition: (1+2) * 3.
  686.  
  687. Some symbols that we have referred to as operators, are treated
  688. by the assembler as operands having built-in values.  These
  689. include B, W, F, $, and ST.  In a similar vein, a segment
  690. override term (a segment register name followed by a colon) is
  691. recorded when it is scanned, but not acted upon until the entire
  692. containing expression is scanned and evaluated.
  693.  
  694. If two operators are adjacent, the rightmost operator must have
  695. precedence; otherwise, parentheses must be used.  For example,
  696. the expression BIT ! 1 is illegal because the leftmost operator
  697. BIT has the higher precedence of the two adjacent operators BIT
  698. and "!".  You can code BIT (! 1).
  699.  
  700. --Highest Precedence--
  701.                                                              8-14
  702.  
  703. 1.  Parenthesized expressions
  704. 2.  Period
  705. 3.  OFFSET, SEG, TYPE, and PTR
  706. 4.  HIGH, LOW, and BIT
  707. 5.  Multiplication and division: *, /, MOD, SHR, SHL
  708. 6.  Addition and subtraction: +,-
  709.        a. unary
  710.        b. binary
  711. 7.  Relational: EQ, NE, LT, LE, GT, GE =
  712. 8.  Logical NOT and !
  713. 9.  Logical AND
  714. 10. Logical OR and XOR
  715. 11. Colon for long pointer, SHORT, LONG, and BY
  716. 12. DUP
  717.  
  718. --Lowest Precedence--
  719.  
  720.