Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1257 lines
40 KiB

  1. //----------------------------------------------------------------------------
  2. //
  3. // Copyright (C) Microsoft Corporation, 1991-2002.
  4. //
  5. //----------------------------------------------------------------------------
  6. #include "ntsdp.hpp"
  7. #include "i386_asm.h"
  8. UCHAR PeekAsmChar(void);
  9. ULONG PeekAsmToken(PULONG);
  10. void AcceptAsmToken(void);
  11. ULONG GetAsmToken(PULONG);
  12. ULONG NextAsmToken(PULONG);
  13. ULONG GetAsmReg(PUCHAR, PULONG);
  14. void GetAsmOperand(PASM_VALUE);
  15. void GetAsmExpr(PASM_VALUE, UCHAR);
  16. void GetAsmOrTerm(PASM_VALUE, UCHAR);
  17. void GetAsmAndTerm(PASM_VALUE, UCHAR);
  18. void GetAsmNotTerm(PASM_VALUE, UCHAR);
  19. void GetAsmRelTerm(PASM_VALUE, UCHAR);
  20. void GetAsmAddTerm(PASM_VALUE, UCHAR);
  21. void GetAsmMulTerm(PASM_VALUE, UCHAR);
  22. void GetAsmSignTerm(PASM_VALUE, UCHAR);
  23. void GetAsmByteTerm(PASM_VALUE, UCHAR);
  24. void GetAsmOffTerm(PASM_VALUE, UCHAR);
  25. void GetAsmColnTerm(PASM_VALUE, UCHAR);
  26. void GetAsmDotTerm(PASM_VALUE, UCHAR);
  27. void GetAsmIndxTerm(PASM_VALUE, UCHAR);
  28. void AddAsmValues(PASM_VALUE, PASM_VALUE);
  29. void SwapPavs(PASM_VALUE, PASM_VALUE);
  30. extern PUCHAR pchAsmLine;
  31. struct _AsmRes {
  32. PCHAR pchRes;
  33. ULONG valueRes;
  34. } AsmReserved[] = {
  35. { "mod", ASM_MULOP_MOD },
  36. { "shl", ASM_MULOP_SHL },
  37. { "shr", ASM_MULOP_SHR },
  38. { "and", ASM_ANDOP_CLASS },
  39. { "not", ASM_NOTOP_CLASS },
  40. { "or", ASM_OROP_OR },
  41. { "xor", ASM_OROP_XOR },
  42. { "eq", ASM_RELOP_EQ },
  43. { "ne", ASM_RELOP_NE },
  44. { "le", ASM_RELOP_LE },
  45. { "lt", ASM_RELOP_LT },
  46. { "ge", ASM_RELOP_GE },
  47. { "gt", ASM_RELOP_GT },
  48. { "by", ASM_UNOP_BY },
  49. { "wo", ASM_UNOP_WO },
  50. { "dw", ASM_UNOP_DW },
  51. { "poi", ASM_UNOP_POI },
  52. { "low", ASM_LOWOP_LOW },
  53. { "high", ASM_LOWOP_HIGH },
  54. { "offset", ASM_OFFOP_CLASS },
  55. { "ptr", ASM_PTROP_CLASS },
  56. { "byte", ASM_SIZE_BYTE },
  57. { "word", ASM_SIZE_WORD },
  58. { "dword", ASM_SIZE_DWORD },
  59. { "fword", ASM_SIZE_FWORD },
  60. { "qword", ASM_SIZE_QWORD },
  61. { "tbyte", ASM_SIZE_TBYTE }
  62. };
  63. #define RESERVESIZE (sizeof(AsmReserved) / sizeof(struct _AsmRes))
  64. UCHAR regSize[] = {
  65. sizeB, // byte
  66. sizeW, // word
  67. sizeD, // dword
  68. sizeW, // segment
  69. sizeD, // control
  70. sizeD, // debug
  71. sizeD, // trace
  72. sizeT, // float
  73. sizeT // float with index
  74. };
  75. UCHAR regType[] = {
  76. regG, // byte - general
  77. regG, // word - general
  78. regG, // dword - general
  79. regS, // segment
  80. regC, // control
  81. regD, // debug
  82. regT, // trace
  83. regF, // float (st)
  84. regI // float-index (st(n))
  85. };
  86. UCHAR tabWordReg[8] = { // rm value
  87. (UCHAR)-1, // AX - error
  88. (UCHAR)-1, // CX - error
  89. (UCHAR)-1, // DX - error
  90. 7, // BX - 111
  91. (UCHAR)-1, // SP - error
  92. 6, // BP - 110
  93. 4, // SI - 100
  94. 5, // DI - 101
  95. };
  96. UCHAR rm16Table[16] = { // new rm left rm right rm
  97. (UCHAR)-1, // error 100 = [SI] 100 = [SI]
  98. (UCHAR)-1, // error 100 = [SI] 101 = [DI]
  99. 2, // 010 = [BP+SI] 100 = [SI] 110 = [BP]
  100. 0, // 000 = [BX+SI] 100 = [SI] 111 = [BX]
  101. (UCHAR)-1, // error 101 = [DI] 100 = [SI]
  102. (UCHAR)-1, // error 101 = [DI] 101 = [DI]
  103. 3, // 011 = [BP+DI] 101 = [DI] 110 = [BP]
  104. 1, // 001 = [BX+DI] 101 = [DI] 111 = [BX]
  105. 2, // 010 = [BP+SI] 110 = [BP] 100 = [SI]
  106. 3, // 011 = [BP+DI] 110 = [BP] 101 = [DI]
  107. (UCHAR)-1, // error 110 = [BP] 110 = [BP]
  108. (UCHAR)-1, // error 110 = [BP] 111 = [BX]
  109. 0, // 000 = [BX+SI] 111 = [BX] 100 = [SI]
  110. 1, // 001 = [BX+DI] 111 = [BX] 101 = [DI]
  111. (UCHAR)-1, // error 111 = [BX] 110 = [BP]
  112. (UCHAR)-1 // error 111 = [BX] 111 = [BX]
  113. };
  114. PUCHAR savedpchAsmLine;
  115. ULONG savedAsmClass;
  116. ULONG savedAsmValue;
  117. /*** PeekAsmChar - peek the next non-white-space character
  118. *
  119. * Purpose:
  120. * Return the next non-white-space character and update
  121. * pchAsmLine to point to it.
  122. *
  123. * Input:
  124. * pchAsmLine - present command line position.
  125. *
  126. * Returns:
  127. * next non-white-space character
  128. *
  129. *************************************************************************/
  130. UCHAR PeekAsmChar (void)
  131. {
  132. UCHAR ch;
  133. do
  134. ch = *pchAsmLine++;
  135. while (ch == ' ' || ch == '\t');
  136. pchAsmLine--;
  137. return ch;
  138. }
  139. /*** PeekAsmToken - peek the next command line token
  140. *
  141. * Purpose:
  142. * Return the next command line token, but do not advance
  143. * the pchAsmLine pointer.
  144. *
  145. * Input:
  146. * pchAsmLine - present command line position.
  147. *
  148. * Output:
  149. * *pvalue - optional value of token
  150. * Returns:
  151. * class of token
  152. *
  153. * Notes:
  154. * savedAsmClass, savedAsmValue, and savedpchAsmLine saves the
  155. * token getting state for future peeks.
  156. * To get the next token, a GetAsmToken or AcceptAsmToken call
  157. * must first be made.
  158. *
  159. *************************************************************************/
  160. ULONG PeekAsmToken (PULONG pvalue)
  161. {
  162. UCHAR *pchTemp;
  163. // Get next class and value, but do not
  164. // move pchAsmLine, but save it in savedpchAsmLine.
  165. // Do not report any error condition.
  166. if (savedAsmClass == (ULONG)-1) {
  167. pchTemp = pchAsmLine;
  168. savedAsmClass = NextAsmToken(&savedAsmValue);
  169. savedpchAsmLine = pchAsmLine;
  170. pchAsmLine = pchTemp;
  171. }
  172. *pvalue = savedAsmValue;
  173. return savedAsmClass;
  174. }
  175. /*** AcceptAsmToken - accept any peeked token
  176. *
  177. * Purpose:
  178. * To reset the PeekAsmToken saved variables so the next PeekAsmToken
  179. * will get the next token in the command line.
  180. *
  181. * Input:
  182. * None.
  183. *
  184. * Output:
  185. * None.
  186. *
  187. *************************************************************************/
  188. void AcceptAsmToken (void)
  189. {
  190. savedAsmClass = (ULONG)-1;
  191. pchAsmLine = savedpchAsmLine;
  192. }
  193. /*** GetAsmToken - peek and accept the next token
  194. *
  195. * Purpose:
  196. * Combines the functionality of PeekAsmToken and AcceptAsmToken
  197. * to return the class and optional value of the next token
  198. * as well as updating the command pointer pchAsmLine.
  199. *
  200. * Input:
  201. * pchAsmLine - present command string pointer
  202. *
  203. * Output:
  204. * *pvalue - pointer to the token value optionally set.
  205. * Returns:
  206. * class of the token read.
  207. *
  208. * Notes:
  209. * An illegal token returns the value of ERROR_CLASS with *pvalue
  210. * being the error number, but produces no actual error.
  211. *
  212. *************************************************************************/
  213. ULONG GetAsmToken (PULONG pvalue)
  214. {
  215. ULONG opclass;
  216. if (savedAsmClass != (ULONG)-1) {
  217. opclass = savedAsmClass;
  218. savedAsmClass = (ULONG)-1;
  219. *pvalue = savedAsmValue;
  220. pchAsmLine = savedpchAsmLine;
  221. }
  222. else
  223. opclass = NextAsmToken(pvalue);
  224. if (opclass == ASM_ERROR_CLASS)
  225. error(*pvalue);
  226. return opclass;
  227. }
  228. /*** NextAsmToken - process the next token
  229. *
  230. * Purpose:
  231. * Parse the next token from the present command string.
  232. * After skipping any leading white space, first check for
  233. * any single character tokens or register variables. If
  234. * no match, then parse for a number or variable. If a
  235. * possible variable, check the reserved word list for operators.
  236. *
  237. * Input:
  238. * pchAsmLine - pointer to present command string
  239. *
  240. * Output:
  241. * *pvalue - optional value of token returned
  242. * pchAsmLine - updated to point past processed token
  243. * Returns:
  244. * class of token returned
  245. *
  246. * Notes:
  247. * An illegal token returns the value of ERROR_CLASS with *pvalue
  248. * being the error number, but produces no actual error.
  249. *
  250. *************************************************************************/
  251. ULONG NextAsmToken (PULONG pvalue)
  252. {
  253. ULONG base;
  254. UCHAR chSymbol[MAX_SYMBOL_LEN];
  255. UCHAR chPreSym[9];
  256. ULONG cbSymbol = 0;
  257. UCHAR fNumber = TRUE;
  258. UCHAR fNumberSigned;
  259. UCHAR fSymbol = TRUE;
  260. UCHAR fForceReg = FALSE;
  261. ULONG errNumber = 0;
  262. UCHAR ch;
  263. UCHAR chlow;
  264. UCHAR chtemp;
  265. UCHAR limit1 = '9';
  266. UCHAR limit2 = '9';
  267. UCHAR fDigit = FALSE;
  268. ULONG value = 0;
  269. ULONG tmpvalue;
  270. ULONG index;
  271. ImageInfo* pImage;
  272. ULONG64 value64;
  273. base = g_DefaultRadix;
  274. fNumberSigned = base == 10;
  275. // skip leading white space
  276. ch = PeekAsmChar();
  277. chlow = (UCHAR)tolower(ch);
  278. pchAsmLine++;
  279. // test for special character operators and register variable
  280. switch (chlow) {
  281. case '\0':
  282. pchAsmLine--;
  283. return ASM_EOL_CLASS;
  284. case ',':
  285. return ASM_COMMA_CLASS;
  286. case '+':
  287. *pvalue = ASM_ADDOP_PLUS;
  288. return ASM_ADDOP_CLASS;
  289. case '-':
  290. *pvalue = ASM_ADDOP_MINUS;
  291. return ASM_ADDOP_CLASS;
  292. case '*':
  293. *pvalue = ASM_MULOP_MULT;
  294. return ASM_MULOP_CLASS;
  295. case '/':
  296. *pvalue = ASM_MULOP_DIVIDE;
  297. return ASM_MULOP_CLASS;
  298. case ':':
  299. return ASM_COLNOP_CLASS;
  300. case '(':
  301. return ASM_LPAREN_CLASS;
  302. case ')':
  303. return ASM_RPAREN_CLASS;
  304. case '[':
  305. return ASM_LBRACK_CLASS;
  306. case ']':
  307. return ASM_RBRACK_CLASS;
  308. case '@':
  309. fForceReg = TRUE;
  310. chlow = (UCHAR)tolower(*pchAsmLine); pchAsmLine++;
  311. break;
  312. case '.':
  313. return ASM_DOTOP_CLASS;
  314. case '\'':
  315. for (index = 0; index < 5; index++) {
  316. ch = *pchAsmLine++;
  317. if (ch == '\'' || ch == '\0')
  318. break;
  319. value = (value << 8) + (ULONG)ch;
  320. }
  321. if (ch == '\0' || index == 0 || index == 5) {
  322. pchAsmLine--;
  323. *pvalue = SYNTAX;
  324. return ASM_ERROR_CLASS;
  325. }
  326. pchAsmLine++;
  327. *pvalue = value;
  328. return ASM_NUMBER_CLASS;
  329. }
  330. // if first character is a decimal digit, it cannot
  331. // be a symbol. leading '0' implies octal, except
  332. // a leading '0x' implies hexadecimal.
  333. if (chlow >= '0' && chlow <= '9') {
  334. if (fForceReg) {
  335. *pvalue = SYNTAX;
  336. return ASM_ERROR_CLASS;
  337. }
  338. fSymbol = FALSE;
  339. if (chlow == '0') {
  340. ch = *pchAsmLine++;
  341. chlow = (UCHAR)tolower(ch);
  342. if (chlow == 'x') {
  343. base = 16;
  344. ch = *pchAsmLine++;
  345. chlow = (UCHAR)tolower(ch);
  346. fNumberSigned = FALSE;
  347. }
  348. else if (chlow == 'n') {
  349. base = 10;
  350. ch = *pchAsmLine++;
  351. chlow = (UCHAR)tolower(ch);
  352. fNumberSigned = TRUE;
  353. }
  354. else {
  355. base = 8;
  356. fDigit = TRUE;
  357. fNumberSigned = FALSE;
  358. }
  359. }
  360. }
  361. // a number can start with a letter only if base is
  362. // hexadecimal and it is a hexadecimal digit 'a'-'f'.
  363. else if ((chlow < 'a' && chlow > 'f') || base != 16)
  364. fNumber = FALSE;
  365. // set limit characters for the appropriate base.
  366. if (base == 8)
  367. limit1 = '7';
  368. if (base == 16)
  369. limit2 = 'f';
  370. // perform processing while character is a letter,
  371. // digit, or underscore.
  372. while ((chlow >= 'a' && chlow <= 'z') ||
  373. (chlow >= '0' && chlow <= '9') || (chlow == '_')) {
  374. // if possible number, test if within proper range,
  375. // and if so, accumulate sum.
  376. if (fNumber) {
  377. if ((chlow >= '0' && chlow <= limit1) ||
  378. (chlow >= 'a' && chlow <= limit2)) {
  379. fDigit = TRUE;
  380. tmpvalue = value * base;
  381. if (tmpvalue < value)
  382. errNumber = OVERFLOW;
  383. chtemp = (UCHAR)(chlow - '0');
  384. if (chtemp > 9)
  385. chtemp -= 'a' - '0' - 10;
  386. value = tmpvalue + (ULONG)chtemp;
  387. if (value < tmpvalue)
  388. errNumber = OVERFLOW;
  389. }
  390. else {
  391. fNumber = FALSE;
  392. errNumber = SYNTAX;
  393. }
  394. }
  395. if (fSymbol) {
  396. if (cbSymbol < 9)
  397. chPreSym[cbSymbol] = chlow;
  398. if (cbSymbol < MAX_SYMBOL_LEN - 1)
  399. chSymbol[cbSymbol++] = ch;
  400. }
  401. ch = *pchAsmLine++;
  402. chlow = (UCHAR)tolower(ch);
  403. }
  404. // back up pointer to first character after token.
  405. pchAsmLine--;
  406. if (cbSymbol < 9)
  407. chPreSym[cbSymbol] = '\0';
  408. // if fForceReg, check for register name and return
  409. // success or failure
  410. if (fForceReg)
  411. if ((index = GetAsmReg(chPreSym, pvalue)) != 0) {
  412. if (index == ASM_REG_SEGMENT)
  413. if (PeekAsmChar() == ':') {
  414. pchAsmLine++;
  415. index = ASM_SEGOVR_CLASS;
  416. }
  417. return index; // class type returned by GetAsmReg
  418. }
  419. else {
  420. *pvalue = BADREG;
  421. return ASM_ERROR_CLASS;
  422. }
  423. // next test for reserved word and symbol string
  424. if (fSymbol) {
  425. // if possible symbol, check lowercase string in chPreSym
  426. // for text operator or register name.
  427. // otherwise, return symbol value from name in chSymbol.
  428. for (index = 0; index < RESERVESIZE; index++)
  429. if (!strcmp((PSTR)chPreSym, AsmReserved[index].pchRes)) {
  430. *pvalue = AsmReserved[index].valueRes;
  431. return AsmReserved[index].valueRes & ASM_CLASS_MASK;
  432. }
  433. // start processing string as symbol
  434. chSymbol[cbSymbol] = '\0';
  435. // test if symbol is a module name (with '!' after it)
  436. // if so, get next token and treat as symbol
  437. pImage = g_Process->FindImageByName((PSTR)chSymbol, cbSymbol,
  438. INAME_MODULE, FALSE);
  439. if (pImage && (ch = PeekAsmChar()) == '!')
  440. {
  441. pchAsmLine++;
  442. ch = PeekAsmChar();
  443. pchAsmLine++;
  444. cbSymbol = 0;
  445. while ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') ||
  446. (ch >= '0' && ch <= '9') || (ch == '_'))
  447. {
  448. chSymbol[cbSymbol++] = ch;
  449. ch = *pchAsmLine++;
  450. }
  451. chSymbol[cbSymbol] = '\0';
  452. pchAsmLine--;
  453. }
  454. if (GetOffsetFromSym(g_Process, (PSTR)chSymbol, &value64, NULL))
  455. {
  456. *pvalue = (ULONG)value64;
  457. return ASM_SYMBOL_CLASS;
  458. }
  459. // symbol is undefined.
  460. // if a possible hex number, do not set the error type
  461. if (!fNumber)
  462. errNumber = VARDEF;
  463. }
  464. // if possible number and no error, return the number
  465. if (fNumber && !errNumber) {
  466. if (fDigit) {
  467. // check for possible segment specification
  468. // "<16-bit number>:"
  469. if (PeekAsmChar() == ':') {
  470. pchAsmLine++;
  471. if (value > 0xffff)
  472. error(BADSEG);
  473. *pvalue = value;
  474. return ASM_SEGMENT_CLASS;
  475. }
  476. *pvalue = value;
  477. return fNumberSigned ? ASM_SIGNED_NUMBER_CLASS : ASM_NUMBER_CLASS;
  478. }
  479. else
  480. errNumber = SYNTAX;
  481. }
  482. // last chance, undefined symbol and illegal number,
  483. // so test for register, will handle old format
  484. if ((index = GetAsmReg(chPreSym, pvalue)) != 0) {
  485. if (index == ASM_REG_SEGMENT)
  486. if (PeekAsmChar() == ':') {
  487. pchAsmLine++;
  488. index = ASM_SEGOVR_CLASS;
  489. }
  490. return index; // class type returned by GetAsmReg
  491. }
  492. *pvalue = (ULONG) errNumber;
  493. return ASM_ERROR_CLASS;
  494. }
  495. ULONG GetAsmReg (PUCHAR pSymbol, PULONG pValue)
  496. {
  497. static UCHAR vRegList[] = "axcxdxbxspbpsidi";
  498. static UCHAR bRegList[] = "alcldlblahchdhbh";
  499. static UCHAR sRegList[] = "ecsdfg"; // second char is 's'
  500. // same order as seg enum
  501. ULONG index;
  502. UCHAR ch0 = *pSymbol;
  503. UCHAR ch1 = *(pSymbol + 1);
  504. UCHAR ch2 = *(pSymbol + 2);
  505. UCHAR ch3 = *(pSymbol + 3);
  506. // only test strings with two or three characters
  507. if (ch0 && ch1) {
  508. if (ch2 == '\0') {
  509. // symbol has two characters, first test for 16-bit register
  510. for (index = 0; index < 8; index++)
  511. if (*(PUSHORT)pSymbol == *((PUSHORT)vRegList + index)) {
  512. *pValue = index;
  513. return ASM_REG_WORD;
  514. }
  515. // next test for 8-bit register
  516. for (index = 0; index < 8; index++)
  517. if (*(PUSHORT)pSymbol == *((PUSHORT)bRegList + index)) {
  518. *pValue = index;
  519. return ASM_REG_BYTE;
  520. }
  521. // test for segment register
  522. if (ch1 == 's')
  523. for (index = 0; index < 6; index++)
  524. if (ch0 == *(sRegList + index)) {
  525. *pValue = index + 1; // list offset is 1
  526. return ASM_REG_SEGMENT;
  527. }
  528. // finally test for floating register "st" or "st(n)"
  529. // parse the arg here as '(', <octal value>, ')'
  530. // return value for "st" is REG_FLOAT,
  531. // for "st(n)" is REG_INDFLT with value 0-7
  532. if (ch0 == 's' && ch1 == 't') {
  533. if (PeekAsmChar() != '(')
  534. return ASM_REG_FLOAT;
  535. else {
  536. pchAsmLine++;
  537. index = (ULONG)(PeekAsmChar() - '0');
  538. if (index < 8) {
  539. pchAsmLine++;
  540. if (PeekAsmChar() == ')') {
  541. pchAsmLine++;
  542. *pValue = index;
  543. return ASM_REG_INDFLT;
  544. }
  545. }
  546. }
  547. }
  548. }
  549. else if (ch3 == '\0') {
  550. // if three-letter symbol, test for leading 'e' and
  551. // second and third character being in the 16-bit list
  552. if (ch0 == 'e') {
  553. for (index = 0; index < 8; index++)
  554. if (*(UNALIGNED USHORT *)(pSymbol + 1) ==
  555. *((PUSHORT)vRegList + index)) {
  556. *pValue = index;
  557. return ASM_REG_DWORD;
  558. }
  559. }
  560. // test for control, debug, and test registers
  561. else if (ch1 == 'r') {
  562. ch2 -= '0';
  563. *pValue = ch2;
  564. // legal control registers are CR0, CR2, CR3, CR4
  565. if (ch0 == 'c') {
  566. if (ch2 >= 0 && ch2 <= 4)
  567. return ASM_REG_CONTROL;
  568. }
  569. // legal debug registers are DR0 - DR3, DR6, DR7
  570. else if (ch0 == 'd') {
  571. if (ch2 <= 3 || ch2 == 6 || ch2 == 7)
  572. return ASM_REG_DEBUG;
  573. }
  574. // legal trace registers are TR3 - TR7
  575. else if (ch0 == 't') {
  576. if (ch2 >= 3 && ch2 <= 7)
  577. return ASM_REG_TRACE;
  578. }
  579. }
  580. }
  581. }
  582. return 0;
  583. }
  584. // Operand parser - recursive descent
  585. //
  586. // Grammar productions:
  587. //
  588. // <Operand> ::= <register> | <Expr>
  589. // <Expr> ::= <orTerm> [(XOR | OR) <orTerm>]*
  590. // <orTerm> ::= <andTerm> [AND <andTerm>]*
  591. // <andTerm> ::= [NOT]* <notTerm>
  592. // <notTerm> ::= <relTerm> [(EQ | NE | GE | GT | LE | LT) <relTerm>]*
  593. // <relTerm> ::= <addTerm> [(- | +) <addTerm>]*
  594. // <addTerm> ::= <mulTerm> [(* | / | MOD | SHL | SHR) <mulTerm>]*
  595. // <mulTerm> ::= [(- | +)]* <signTerm>
  596. // <signTerm> ::= [(HIGH | LOW)]* <byteTerm>
  597. // <byteTerm> ::= [(OFFSET | <type> PTR)]* <offTerm>
  598. // <offTerm> ::= [<segovr>] <colnTerm>
  599. // <colnTerm> ::= <dotTerm> [.<dotTerm>]*
  600. // <dotTerm> ::= <indxTerm> ['['<Expr>']']*
  601. // <indxTerm> ::= <index-reg> | <symbol> | <number> | '('<Expr>')'
  602. // | '['<Expr>']'
  603. // <Operand> ::= <register> | <Expr>
  604. void GetAsmOperand (PASM_VALUE pavExpr)
  605. {
  606. ULONG tokenvalue;
  607. ULONG classvalue;
  608. classvalue = PeekAsmToken(&tokenvalue);
  609. if ((classvalue & ASM_CLASS_MASK) == ASM_REG_CLASS) {
  610. AcceptAsmToken();
  611. classvalue &= ASM_TYPE_MASK;
  612. pavExpr->flags = fREG;
  613. pavExpr->base = (UCHAR)tokenvalue; // index within reg group
  614. pavExpr->index = regType[classvalue - 1];
  615. pavExpr->size = regSize[classvalue - 1];
  616. }
  617. else {
  618. GetAsmExpr(pavExpr, FALSE);
  619. if (pavExpr->reloc > 1) // only 0 and 1 are allowed
  620. error(OPERAND);
  621. }
  622. }
  623. // <Expr> ::= <orTerm> [(XOR | OR) <orTerm>]*
  624. void GetAsmExpr (PASM_VALUE pavValue, UCHAR fBracket)
  625. {
  626. ULONG tokenvalue;
  627. ASM_VALUE avTerm;
  628. dprintf("enter GetAsmExpr\n");
  629. GetAsmOrTerm(pavValue, fBracket);
  630. while (PeekAsmToken(&tokenvalue) == ASM_OROP_CLASS) {
  631. AcceptAsmToken();
  632. GetAsmOrTerm(&avTerm, fBracket);
  633. if (!(pavValue->flags & avTerm.flags & fIMM))
  634. error(OPERAND);
  635. if (tokenvalue == ASM_OROP_OR)
  636. pavValue->value |= avTerm.value;
  637. else
  638. pavValue->value ^= avTerm.value;
  639. }
  640. dprintf("exit GetAsmExpr with %lx\n", pavValue->value);
  641. }
  642. // <orTerm> ::= <andTerm> [AND <andTerm>]*
  643. void GetAsmOrTerm (PASM_VALUE pavValue, UCHAR fBracket)
  644. {
  645. ULONG tokenvalue;
  646. ASM_VALUE avTerm;
  647. dprintf("enter GetAsmOrTerm\n");
  648. GetAsmAndTerm(pavValue, fBracket);
  649. while (PeekAsmToken(&tokenvalue) == ASM_ANDOP_CLASS) {
  650. AcceptAsmToken();
  651. GetAsmAndTerm(&avTerm, fBracket);
  652. if (!(pavValue->flags & avTerm.flags & fIMM))
  653. error(OPERAND);
  654. pavValue->value &= avTerm.value;
  655. }
  656. dprintf("exit GetAsmOrTerm with %lx\n", pavValue->value);
  657. }
  658. // <andTerm> ::= [NOT]* <notTerm>
  659. void GetAsmAndTerm (PASM_VALUE pavValue, UCHAR fBracket)
  660. {
  661. ULONG tokenvalue;
  662. dprintf("enter GetAsmAndTerm\n");
  663. if (PeekAsmToken(&tokenvalue) == ASM_NOTOP_CLASS) {
  664. AcceptAsmToken();
  665. GetAsmAndTerm(pavValue, fBracket);
  666. if (!(pavValue->flags & fIMM))
  667. error(OPERAND);
  668. pavValue->value = ~pavValue->value;
  669. }
  670. else
  671. GetAsmNotTerm(pavValue, fBracket);
  672. dprintf("exit GetAsmAndTerm with %lx\n", pavValue->value);
  673. }
  674. // <notTerm> ::= <relTerm> [(EQ | NE | GE | GT | LE | LT) <relTerm>]*
  675. void GetAsmNotTerm (PASM_VALUE pavValue, UCHAR fBracket)
  676. {
  677. ULONG tokenvalue;
  678. ULONG fTest;
  679. ULONG fAddress;
  680. ASM_VALUE avTerm;
  681. dprintf("enter GetAsmNotTerm\n");
  682. GetAsmRelTerm(pavValue, fBracket);
  683. while (PeekAsmToken(&tokenvalue) == ASM_RELOP_CLASS) {
  684. AcceptAsmToken();
  685. GetAsmRelTerm(&avTerm, fBracket);
  686. if (!(pavValue->flags & avTerm.flags & fIMM) ||
  687. pavValue->reloc > 1 || avTerm.reloc > 1)
  688. error(OPERAND);
  689. fAddress = pavValue->reloc | avTerm.reloc;
  690. switch (tokenvalue) {
  691. case ASM_RELOP_EQ:
  692. fTest = pavValue->value == avTerm.value;
  693. break;
  694. case ASM_RELOP_NE:
  695. fTest = pavValue->value != avTerm.value;
  696. break;
  697. case ASM_RELOP_GE:
  698. if (fAddress)
  699. fTest = pavValue->value >= avTerm.value;
  700. else
  701. fTest = (LONG)pavValue->value >= (LONG)avTerm.value;
  702. break;
  703. case ASM_RELOP_GT:
  704. if (fAddress)
  705. fTest = pavValue->value > avTerm.value;
  706. else
  707. fTest = (LONG)pavValue->value > (LONG)avTerm.value;
  708. break;
  709. case ASM_RELOP_LE:
  710. if (fAddress)
  711. fTest = pavValue->value <= avTerm.value;
  712. else
  713. fTest = (LONG)pavValue->value <= (LONG)avTerm.value;
  714. break;
  715. case ASM_RELOP_LT:
  716. if (fAddress)
  717. fTest = pavValue->value < avTerm.value;
  718. else
  719. fTest = (LONG)pavValue->value < (LONG)avTerm.value;
  720. break;
  721. default:
  722. printf("bad RELOP type\n");
  723. }
  724. pavValue->value = (ULONG)(-((LONG)fTest)); // FALSE = 0; TRUE = -1
  725. pavValue->reloc = 0;
  726. pavValue->size = sizeB; // immediate value is byte
  727. }
  728. dprintf("exit GetAsmNotTerm with %lx\n", pavValue->value);
  729. }
  730. // <relTerm> ::= <addTerm> [(- | +) <addTerm>]*
  731. void GetAsmRelTerm (PASM_VALUE pavValue, UCHAR fBracket)
  732. {
  733. ULONG tokenvalue;
  734. ASM_VALUE avTerm;
  735. dprintf("enter GetAsmRelTerm\n");
  736. GetAsmAddTerm(pavValue, fBracket);
  737. while (PeekAsmToken(&tokenvalue) == ASM_ADDOP_CLASS) {
  738. AcceptAsmToken();
  739. GetAsmAddTerm(&avTerm, fBracket);
  740. if (tokenvalue == ASM_ADDOP_MINUS) {
  741. if (!(avTerm.flags & (fIMM | fPTR)))
  742. error(OPERAND);
  743. avTerm.value = (ULONG)(-((LONG)avTerm.value));
  744. avTerm.reloc = (UCHAR)(-avTerm.reloc);
  745. // Assume that negating an immediate means it's
  746. // fundamentally a signed immediate.
  747. if (avTerm.flags & fIMM)
  748. avTerm.flags |= fSIGNED;
  749. }
  750. AddAsmValues(pavValue, &avTerm);
  751. }
  752. dprintf("exit GetAsmRelTerm with %lx\n", pavValue->value);
  753. }
  754. // <addTerm> ::= <mulTerm> [(* | / | MOD | SHL | SHR) <mulTerm>]*
  755. void GetAsmAddTerm (PASM_VALUE pavValue, UCHAR fBracket)
  756. {
  757. ULONG tokenvalue;
  758. ASM_VALUE avTerm;
  759. dprintf("enter GetAsmAddTerm\n");
  760. GetAsmMulTerm(pavValue, fBracket);
  761. while (PeekAsmToken(&tokenvalue) == ASM_MULOP_CLASS) {
  762. AcceptAsmToken();
  763. GetAsmMulTerm(&avTerm, fBracket);
  764. if (tokenvalue == ASM_MULOP_MULT) {
  765. if (pavValue->flags & fIMM)
  766. SwapPavs(pavValue, &avTerm);
  767. if (!(avTerm.flags & fIMM))
  768. error(OPERAND);
  769. if (pavValue->flags & fIMM)
  770. pavValue->value *= avTerm.value;
  771. else if ((pavValue->flags & fPTR32)
  772. && pavValue->value == 0
  773. && pavValue->base != indSP
  774. && pavValue->index == 0xff) {
  775. pavValue->index = pavValue->base;
  776. pavValue->base = 0xff;
  777. pavValue->scale = 0xff;
  778. if (avTerm.value == 1)
  779. pavValue->scale = 0;
  780. if (avTerm.value == 2)
  781. pavValue->scale = 1;
  782. if (avTerm.value == 4)
  783. pavValue->scale = 2;
  784. if (avTerm.value == 8)
  785. pavValue->scale = 3;
  786. if (pavValue->scale == 0xff)
  787. error(OPERAND);
  788. }
  789. else
  790. error(OPERAND);
  791. }
  792. else if (!(pavValue->flags & avTerm.flags & fIMM))
  793. error(OPERAND);
  794. else if (tokenvalue == ASM_MULOP_DIVIDE
  795. || tokenvalue == ASM_MULOP_MOD) {
  796. if (avTerm.value == 0)
  797. error(DIVIDE);
  798. if (tokenvalue == ASM_MULOP_DIVIDE)
  799. pavValue->value /= avTerm.value;
  800. else
  801. pavValue->value %= avTerm.value;
  802. }
  803. else if (tokenvalue == ASM_MULOP_SHL)
  804. pavValue->value <<= avTerm.value;
  805. else
  806. pavValue->value >>= avTerm.value;
  807. }
  808. dprintf("exit GetAsmAddTerm with %lx\n", pavValue->value);
  809. }
  810. // <mulTerm> ::= [(- | +)]* <signTerm>
  811. void GetAsmMulTerm (PASM_VALUE pavValue, UCHAR fBracket)
  812. {
  813. ULONG tokenvalue;
  814. dprintf("enter GetAsmMulTerm\n");
  815. if (PeekAsmToken(&tokenvalue) == ASM_ADDOP_CLASS) { // BY WO DW POI UNDN
  816. AcceptAsmToken();
  817. GetAsmMulTerm(pavValue, fBracket);
  818. if (tokenvalue == ASM_ADDOP_MINUS) {
  819. if (!(pavValue->flags & (fIMM | fPTR)))
  820. error(OPERAND);
  821. pavValue->value = (ULONG)(-((LONG)pavValue->value));
  822. pavValue->reloc = (UCHAR)(-pavValue->reloc);
  823. // Assume that negating an immediate means it's
  824. // fundamentally a signed immediate.
  825. if (pavValue->flags & fIMM)
  826. pavValue->flags |= fSIGNED;
  827. }
  828. }
  829. else
  830. GetAsmSignTerm(pavValue, fBracket);
  831. dprintf("exit GetAsmMulTerm with %lx\n", pavValue->value);
  832. }
  833. // <signTerm> ::= [(HIGH | LOW)]* <byteTerm>
  834. void GetAsmSignTerm (PASM_VALUE pavValue, UCHAR fBracket)
  835. {
  836. ULONG tokenvalue;
  837. dprintf("enter GetAsmSignTerm\n");
  838. if (PeekAsmToken(&tokenvalue) == ASM_LOWOP_CLASS) {
  839. AcceptAsmToken();
  840. GetAsmSignTerm(pavValue, fBracket);
  841. if (!(pavValue->flags & (fIMM | fPTR)))
  842. error(OPERAND);
  843. if (tokenvalue == ASM_LOWOP_LOW)
  844. pavValue->value = pavValue->value & 0xff;
  845. else
  846. pavValue->value = (pavValue->value & ~0xff) >> 8;
  847. pavValue->flags = fIMM; // make an immediate value
  848. pavValue->reloc = 0;
  849. pavValue->segment = segX;
  850. pavValue->size = sizeB; // byte value
  851. }
  852. else
  853. GetAsmByteTerm(pavValue, fBracket);
  854. dprintf("exit GetAsmSignTerm with %lx\n", pavValue->value);
  855. }
  856. // <byteTerm> ::= [(OFFSET | <size> PTR)]* <offTerm>
  857. void GetAsmByteTerm (PASM_VALUE pavValue, UCHAR fBracket)
  858. {
  859. ULONG tokenvalue;
  860. ULONG classvalue;
  861. dprintf("enter GetAsmByteTerm\n");
  862. classvalue = PeekAsmToken(&tokenvalue);
  863. if (classvalue == ASM_OFFOP_CLASS) {
  864. AcceptAsmToken();
  865. GetAsmByteTerm(pavValue, fBracket);
  866. if (!(pavValue->flags & (fIMM | fPTR)) || pavValue->reloc > 1)
  867. error(OPERAND);
  868. pavValue->flags = fIMM; // make offset an immediate value
  869. pavValue->reloc = 0;
  870. pavValue->size = sizeX;
  871. pavValue->segment = segX;
  872. }
  873. else if (classvalue == ASM_SIZE_CLASS) {
  874. AcceptAsmToken();
  875. if (GetAsmToken(&classvalue) != ASM_PTROP_CLASS) // dummy token
  876. error(SYNTAX);
  877. GetAsmByteTerm(pavValue, fBracket);
  878. if (!(pavValue->flags & (fIMM | fPTR | fPTR16 | fPTR32))
  879. || pavValue->reloc > 1
  880. || pavValue->size != sizeX)
  881. error(OPERAND);
  882. pavValue->reloc = 1; // make ptr a relocatable value
  883. if (pavValue->flags & fIMM)
  884. pavValue->flags = fPTR;
  885. pavValue->size = (UCHAR)(tokenvalue & ASM_TYPE_MASK);
  886. // value has "size?"
  887. }
  888. else
  889. GetAsmOffTerm(pavValue, fBracket);
  890. dprintf("exit GetAsmByteTerm with %lx\n", pavValue->value);
  891. }
  892. // <offTerm> ::= [<segovr>] <colnTerm>
  893. void GetAsmOffTerm (PASM_VALUE pavValue, UCHAR fBracket)
  894. {
  895. ULONG classvalue;
  896. ULONG tokenvalue;
  897. dprintf("enter GetAsmOffTerm\n");
  898. classvalue = PeekAsmToken(&tokenvalue);
  899. if (classvalue == ASM_SEGOVR_CLASS || classvalue == ASM_SEGMENT_CLASS) {
  900. if (fBracket)
  901. error(SYNTAX);
  902. AcceptAsmToken();
  903. }
  904. GetAsmColnTerm(pavValue, fBracket);
  905. if (classvalue == ASM_SEGOVR_CLASS) {
  906. if (pavValue->reloc > 1 || pavValue->segovr != segX)
  907. error(OPERAND);
  908. pavValue->reloc = 1; // make ptr a relocatable value
  909. if (pavValue->flags & fIMM)
  910. pavValue->flags = fPTR;
  911. pavValue->segovr = (UCHAR)tokenvalue; // has segment override
  912. }
  913. else if (classvalue == ASM_SEGMENT_CLASS) {
  914. if (!(pavValue->flags & fIMM) || pavValue->reloc > 1)
  915. error(OPERAND);
  916. pavValue->segment = (USHORT)tokenvalue; // segment has segment value
  917. pavValue->flags = fFPTR; // set flag for far pointer
  918. }
  919. dprintf("exit GetAsmOffTerm with %lx\n", pavValue->value);
  920. }
  921. // <colnTerm> ::= <dotTerm> [.<dotTerm>]*
  922. void GetAsmColnTerm (PASM_VALUE pavValue, UCHAR fBracket)
  923. {
  924. ULONG tokenvalue;
  925. ASM_VALUE avTerm;
  926. dprintf("enter GetAsmColnTerm\n");
  927. GetAsmDotTerm(pavValue, fBracket);
  928. while (PeekAsmToken(&tokenvalue) == ASM_DOTOP_CLASS) {
  929. AcceptAsmToken();
  930. GetAsmDotTerm(&avTerm, fBracket);
  931. AddAsmValues(pavValue, &avTerm);
  932. }
  933. dprintf("exit GetAsmColnTerm with %lx\n", pavValue->value);
  934. }
  935. // <dotTerm> ::= <indxTerm> ['['<Expr>']']*
  936. void GetAsmDotTerm (PASM_VALUE pavValue, UCHAR fBracket)
  937. {
  938. ULONG tokenvalue;
  939. ASM_VALUE avExpr;
  940. dprintf("enter GetAsmDotTerm\n");
  941. GetAsmIndxTerm(pavValue, fBracket);
  942. if (pavValue->reloc > 1)
  943. error(OPERAND);
  944. while (PeekAsmToken(&tokenvalue) == ASM_LBRACK_CLASS) {
  945. AcceptAsmToken();
  946. if (fBracket)
  947. error(SYNTAX);
  948. GetAsmExpr(&avExpr, TRUE);
  949. AddAsmValues(pavValue, &avExpr);
  950. if (GetAsmToken(&tokenvalue) != ASM_RBRACK_CLASS)
  951. error(SYNTAX);
  952. if (pavValue->flags & fIMM)
  953. pavValue->flags = fPTR;
  954. }
  955. dprintf("exit GetAsmDotTerm with %lx\n", pavValue->value);
  956. }
  957. // <indxTerm> ::= <index-reg> | <symbol> | <number> | '('<Expr>')'
  958. // | '['<Expr>']'
  959. void GetAsmIndxTerm (PASM_VALUE pavValue, UCHAR fBracket)
  960. {
  961. ULONG tokenvalue;
  962. ULONG classvalue;
  963. dprintf("enter GetAsmIndxTerm\n");
  964. classvalue = GetAsmToken(&tokenvalue);
  965. pavValue->segovr = segX;
  966. pavValue->size = sizeX;
  967. pavValue->reloc = 0;
  968. pavValue->value = 0;
  969. if (classvalue == ASM_LPAREN_CLASS) {
  970. GetAsmExpr(pavValue, fBracket);
  971. if (GetAsmToken(&tokenvalue) != ASM_RPAREN_CLASS)
  972. error(SYNTAX);
  973. }
  974. else if (classvalue == ASM_LBRACK_CLASS) {
  975. if (fBracket)
  976. error(SYNTAX);
  977. GetAsmExpr(pavValue, TRUE);
  978. if (GetAsmToken(&tokenvalue) != ASM_RBRACK_CLASS)
  979. error(SYNTAX);
  980. if (pavValue->flags == fIMM)
  981. pavValue->flags = fPTR;
  982. }
  983. else if (classvalue == ASM_SYMBOL_CLASS) {
  984. pavValue->value = tokenvalue;
  985. pavValue->flags = fIMM;
  986. pavValue->reloc = 1;
  987. }
  988. else if (classvalue == ASM_NUMBER_CLASS ||
  989. classvalue == ASM_SIGNED_NUMBER_CLASS) {
  990. pavValue->value = tokenvalue;
  991. pavValue->flags = fIMM |
  992. (classvalue == ASM_SIGNED_NUMBER_CLASS ? fSIGNED : 0);
  993. }
  994. else if (classvalue == ASM_REG_WORD) {
  995. if (!fBracket)
  996. error(SYNTAX);
  997. pavValue->flags = fPTR16;
  998. pavValue->base = tabWordReg[tokenvalue];
  999. if (pavValue->base == 0xff)
  1000. error(OPERAND);
  1001. }
  1002. else if (classvalue == ASM_REG_DWORD) {
  1003. if (!fBracket)
  1004. error(SYNTAX);
  1005. pavValue->flags = fPTR32;
  1006. pavValue->base = (UCHAR)tokenvalue;
  1007. pavValue->index = 0xff;
  1008. }
  1009. else
  1010. error(SYNTAX);
  1011. dprintf("exit GetAsmIndxTerm with %lx\n", pavValue->value);
  1012. }
  1013. void AddAsmValues (PASM_VALUE pavLeft, PASM_VALUE pavRight)
  1014. {
  1015. // swap values if left one is a pointer
  1016. if (pavLeft->flags & fPTR)
  1017. SwapPavs(pavLeft, pavRight);
  1018. // swap values if left one is an immediate
  1019. if (pavLeft->flags & fIMM)
  1020. SwapPavs(pavLeft, pavRight);
  1021. // the above swaps reduce the cases to test.
  1022. // pairs with an immediate will have it on the right
  1023. // pairs with a pointer will have it on the right,
  1024. // except for a pointer-immediate pair
  1025. // if both values are 16-bit pointers, combine them
  1026. if (pavLeft->flags & pavRight->flags & fPTR16) {
  1027. // if either side has both registers (rm < 4), error
  1028. if (!(pavLeft->base & pavRight->base & 4))
  1029. error(OPERAND);
  1030. // use lookup table to compute new rm value
  1031. pavLeft->base = rm16Table[((pavLeft->base & 3) << 2) +
  1032. (pavRight->base & 3)];
  1033. if (pavLeft->base == 0xff)
  1034. error(OPERAND);
  1035. pavRight->flags = fPTR;
  1036. }
  1037. // if both values are 32-bit pointers, combine them
  1038. if (pavLeft->flags & pavRight->flags & fPTR32) {
  1039. // error if either side has both base and index,
  1040. // or if both have index
  1041. if (((pavLeft->base | pavLeft->index) != 0xff)
  1042. || ((pavRight->base | pavRight->index) != 0xff)
  1043. || ((pavLeft->index | pavRight->index) != 0xff))
  1044. error(OPERAND);
  1045. // if left side has base, swap sides
  1046. if (pavLeft->base != 0xff)
  1047. SwapPavs(pavLeft, pavRight);
  1048. // two cases remaining, index-base and base-base
  1049. if (pavLeft->base != 0xff) {
  1050. // left side has base, promote to index but swap if left
  1051. // base is ESP since it cannot be an index register
  1052. if (pavLeft->base == indSP)
  1053. SwapPavs(pavLeft, pavRight);
  1054. if (pavLeft->base == indSP)
  1055. error(OPERAND);
  1056. pavLeft->index = pavLeft->base;
  1057. pavLeft->scale = 0;
  1058. }
  1059. // finish by setting left side base to right side value
  1060. pavLeft->base = pavRight->base;
  1061. pavRight->flags = fPTR;
  1062. }
  1063. // if left side is any pointer and right is nonindex pointer,
  1064. // combine them. (above cases set right side to use this code)
  1065. if ((pavLeft->flags & (fPTR | fPTR16 | fPTR32))
  1066. && (pavRight->flags & fPTR)) {
  1067. if (pavLeft->segovr + pavRight->segovr != segX
  1068. && pavLeft->segovr != pavRight->segovr)
  1069. error(OPERAND);
  1070. if (pavLeft->size + pavRight->size != sizeX
  1071. && pavLeft->size != pavRight->size)
  1072. error(OPERAND);
  1073. pavRight->flags = fIMM;
  1074. }
  1075. // if right side is immediate, add values and relocs
  1076. // (above case sets right side to use this code)
  1077. // illegal value types do not have right side set to fIMM
  1078. if (pavRight->flags & fIMM) {
  1079. pavLeft->value += pavRight->value;
  1080. pavLeft->reloc += pavRight->reloc;
  1081. }
  1082. else
  1083. error(OPERAND);
  1084. }
  1085. void SwapPavs (PASM_VALUE pavFirst, PASM_VALUE pavSecond)
  1086. {
  1087. ASM_VALUE temp;
  1088. memmove(&temp, pavFirst, sizeof(ASM_VALUE));
  1089. memmove(pavFirst, pavSecond, sizeof(ASM_VALUE));
  1090. memmove(pavSecond, &temp, sizeof(ASM_VALUE));
  1091. }