Source code of Windows XP (NT5)

1239 lines
38 KiB

  1. //----------------------------------------------------------------------------
  2. //
  3. // Copyright (C) Microsoft Corporation, 1991-2001.
  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 fSymbol = TRUE;
  259. UCHAR fForceReg = FALSE;
  260. ULONG errNumber = 0;
  261. UCHAR ch;
  262. UCHAR chlow;
  263. UCHAR chtemp;
  264. UCHAR limit1 = '9';
  265. UCHAR limit2 = '9';
  266. UCHAR fDigit = FALSE;
  267. ULONG value = 0;
  268. ULONG tmpvalue;
  269. ULONG index;
  270. PDEBUG_IMAGE_INFO pImage;
  271. ULONG64 value64;
  272. base = g_DefaultRadix;
  273. // skip leading white space
  274. ch = PeekAsmChar();
  275. chlow = (UCHAR)tolower(ch);
  276. pchAsmLine++;
  277. // test for special character operators and register variable
  278. switch (chlow) {
  279. case '\0':
  280. pchAsmLine--;
  281. return ASM_EOL_CLASS;
  282. case ',':
  283. return ASM_COMMA_CLASS;
  284. case '+':
  285. *pvalue = ASM_ADDOP_PLUS;
  286. return ASM_ADDOP_CLASS;
  287. case '-':
  288. *pvalue = ASM_ADDOP_MINUS;
  289. return ASM_ADDOP_CLASS;
  290. case '*':
  291. *pvalue = ASM_MULOP_MULT;
  292. return ASM_MULOP_CLASS;
  293. case '/':
  294. *pvalue = ASM_MULOP_DIVIDE;
  295. return ASM_MULOP_CLASS;
  296. case ':':
  297. return ASM_COLNOP_CLASS;
  298. case '(':
  299. return ASM_LPAREN_CLASS;
  300. case ')':
  301. return ASM_RPAREN_CLASS;
  302. case '[':
  303. return ASM_LBRACK_CLASS;
  304. case ']':
  305. return ASM_RBRACK_CLASS;
  306. case '@':
  307. fForceReg = TRUE;
  308. chlow = (UCHAR)tolower(*pchAsmLine); pchAsmLine++;
  309. break;
  310. case '.':
  311. return ASM_DOTOP_CLASS;
  312. case '\'':
  313. for (index = 0; index < 5; index++) {
  314. ch = *pchAsmLine++;
  315. if (ch == '\'' || ch == '\0')
  316. break;
  317. value = (value << 8) + (ULONG)ch;
  318. }
  319. if (ch == '\0' || index == 0 || index == 5) {
  320. pchAsmLine--;
  321. *pvalue = SYNTAX;
  322. return ASM_ERROR_CLASS;
  323. }
  324. pchAsmLine++;
  325. *pvalue = value;
  326. return ASM_NUMBER_CLASS;
  327. }
  328. // if first character is a decimal digit, it cannot
  329. // be a symbol. leading '0' implies octal, except
  330. // a leading '0x' implies hexadecimal.
  331. if (chlow >= '0' && chlow <= '9') {
  332. if (fForceReg) {
  333. *pvalue = SYNTAX;
  334. return ASM_ERROR_CLASS;
  335. }
  336. fSymbol = FALSE;
  337. if (chlow == '0') {
  338. ch = *pchAsmLine++;
  339. chlow = (UCHAR)tolower(ch);
  340. if (chlow == 'x') {
  341. base = 16;
  342. ch = *pchAsmLine++;
  343. chlow = (UCHAR)tolower(ch);
  344. }
  345. else if (chlow == 'n') {
  346. base = 10;
  347. ch = *pchAsmLine++;
  348. chlow = (UCHAR)tolower(ch);
  349. }
  350. else {
  351. base = 8;
  352. fDigit = TRUE;
  353. }
  354. }
  355. }
  356. // a number can start with a letter only if base is
  357. // hexadecimal and it is a hexadecimal digit 'a'-'f'.
  358. else if ((chlow < 'a' && chlow > 'f') || base != 16)
  359. fNumber = FALSE;
  360. // set limit characters for the appropriate base.
  361. if (base == 8)
  362. limit1 = '7';
  363. if (base == 16)
  364. limit2 = 'f';
  365. // perform processing while character is a letter,
  366. // digit, or underscore.
  367. while ((chlow >= 'a' && chlow <= 'z') ||
  368. (chlow >= '0' && chlow <= '9') || (chlow == '_')) {
  369. // if possible number, test if within proper range,
  370. // and if so, accumulate sum.
  371. if (fNumber) {
  372. if ((chlow >= '0' && chlow <= limit1) ||
  373. (chlow >= 'a' && chlow <= limit2)) {
  374. fDigit = TRUE;
  375. tmpvalue = value * base;
  376. if (tmpvalue < value)
  377. errNumber = OVERFLOW;
  378. chtemp = (UCHAR)(chlow - '0');
  379. if (chtemp > 9)
  380. chtemp -= 'a' - '0' - 10;
  381. value = tmpvalue + (ULONG)chtemp;
  382. if (value < tmpvalue)
  383. errNumber = OVERFLOW;
  384. }
  385. else {
  386. fNumber = FALSE;
  387. errNumber = SYNTAX;
  388. }
  389. }
  390. if (fSymbol) {
  391. if (cbSymbol < 9)
  392. chPreSym[cbSymbol] = chlow;
  393. if (cbSymbol < MAX_SYMBOL_LEN - 1)
  394. chSymbol[cbSymbol++] = ch;
  395. }
  396. ch = *pchAsmLine++;
  397. chlow = (UCHAR)tolower(ch);
  398. }
  399. // back up pointer to first character after token.
  400. pchAsmLine--;
  401. if (cbSymbol < 9)
  402. chPreSym[cbSymbol] = '\0';
  403. // if fForceReg, check for register name and return
  404. // success or failure
  405. if (fForceReg)
  406. if ((index = GetAsmReg(chPreSym, pvalue)) != 0) {
  407. if (index == ASM_REG_SEGMENT)
  408. if (PeekAsmChar() == ':') {
  409. pchAsmLine++;
  410. index = ASM_SEGOVR_CLASS;
  411. }
  412. return index; // class type returned by GetAsmReg
  413. }
  414. else {
  415. *pvalue = BADREG;
  416. return ASM_ERROR_CLASS;
  417. }
  418. // next test for reserved word and symbol string
  419. if (fSymbol) {
  420. // if possible symbol, check lowercase string in chPreSym
  421. // for text operator or register name.
  422. // otherwise, return symbol value from name in chSymbol.
  423. for (index = 0; index < RESERVESIZE; index++)
  424. if (!strcmp((PSTR)chPreSym, AsmReserved[index].pchRes)) {
  425. *pvalue = AsmReserved[index].valueRes;
  426. return AsmReserved[index].valueRes & ASM_CLASS_MASK;
  427. }
  428. // start processing string as symbol
  429. chSymbol[cbSymbol] = '\0';
  430. // test if symbol is a module name (with '!' after it)
  431. // if so, get next token and treat as symbol
  432. pImage = GetImageByName(g_CurrentProcess, (PSTR)chSymbol,
  433. INAME_MODULE);
  434. if (pImage && (ch = PeekAsmChar()) == '!') {
  435. pchAsmLine++;
  436. ch = PeekAsmChar();
  437. pchAsmLine++;
  438. cbSymbol = 0;
  439. while ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') ||
  440. (ch >= '0' && ch <= '9') || (ch == '_')) {
  441. chSymbol[cbSymbol++] = ch;
  442. ch = *pchAsmLine++;
  443. }
  444. chSymbol[cbSymbol] = '\0';
  445. pchAsmLine--;
  446. }
  447. if (GetOffsetFromSym((PSTR)chSymbol, &value64, NULL)) {
  448. *pvalue = (ULONG)value64;
  449. return ASM_SYMBOL_CLASS;
  450. }
  451. // symbol is undefined.
  452. // if a possible hex number, do not set the error type
  453. if (!fNumber)
  454. errNumber = VARDEF;
  455. }
  456. // if possible number and no error, return the number
  457. if (fNumber && !errNumber) {
  458. if (fDigit) {
  459. // check for possible segment specification
  460. // "<16-bit number>:"
  461. if (PeekAsmChar() == ':') {
  462. pchAsmLine++;
  463. if (value > 0xffff)
  464. error(BADSEG);
  465. *pvalue = value;
  466. return ASM_SEGMENT_CLASS;
  467. }
  468. *pvalue = value;
  469. return ASM_NUMBER_CLASS;
  470. }
  471. else
  472. errNumber = SYNTAX;
  473. }
  474. // last chance, undefined symbol and illegal number,
  475. // so test for register, will handle old format
  476. if ((index = GetAsmReg(chPreSym, pvalue)) != 0) {
  477. if (index == ASM_REG_SEGMENT)
  478. if (PeekAsmChar() == ':') {
  479. pchAsmLine++;
  480. index = ASM_SEGOVR_CLASS;
  481. }
  482. return index; // class type returned by GetAsmReg
  483. }
  484. *pvalue = (ULONG) errNumber;
  485. return ASM_ERROR_CLASS;
  486. }
  487. ULONG GetAsmReg (PUCHAR pSymbol, PULONG pValue)
  488. {
  489. static UCHAR vRegList[] = "axcxdxbxspbpsidi";
  490. static UCHAR bRegList[] = "alcldlblahchdhbh";
  491. static UCHAR sRegList[] = "ecsdfg"; // second char is 's'
  492. // same order as seg enum
  493. ULONG index;
  494. UCHAR ch0 = *pSymbol;
  495. UCHAR ch1 = *(pSymbol + 1);
  496. UCHAR ch2 = *(pSymbol + 2);
  497. UCHAR ch3 = *(pSymbol + 3);
  498. // only test strings with two or three characters
  499. if (ch0 && ch1) {
  500. if (ch2 == '\0') {
  501. // symbol has two characters, first test for 16-bit register
  502. for (index = 0; index < 8; index++)
  503. if (*(PUSHORT)pSymbol == *((PUSHORT)vRegList + index)) {
  504. *pValue = index;
  505. return ASM_REG_WORD;
  506. }
  507. // next test for 8-bit register
  508. for (index = 0; index < 8; index++)
  509. if (*(PUSHORT)pSymbol == *((PUSHORT)bRegList + index)) {
  510. *pValue = index;
  511. return ASM_REG_BYTE;
  512. }
  513. // test for segment register
  514. if (ch1 == 's')
  515. for (index = 0; index < 6; index++)
  516. if (ch0 == *(sRegList + index)) {
  517. *pValue = index + 1; // list offset is 1
  518. return ASM_REG_SEGMENT;
  519. }
  520. // finally test for floating register "st" or "st(n)"
  521. // parse the arg here as '(', <octal value>, ')'
  522. // return value for "st" is REG_FLOAT,
  523. // for "st(n)" is REG_INDFLT with value 0-7
  524. if (ch0 == 's' && ch1 == 't') {
  525. if (PeekAsmChar() != '(')
  526. return ASM_REG_FLOAT;
  527. else {
  528. pchAsmLine++;
  529. index = (ULONG)(PeekAsmChar() - '0');
  530. if (index < 8) {
  531. pchAsmLine++;
  532. if (PeekAsmChar() == ')') {
  533. pchAsmLine++;
  534. *pValue = index;
  535. return ASM_REG_INDFLT;
  536. }
  537. }
  538. }
  539. }
  540. }
  541. else if (ch3 == '\0') {
  542. // if three-letter symbol, test for leading 'e' and
  543. // second and third character being in the 16-bit list
  544. if (ch0 == 'e') {
  545. for (index = 0; index < 8; index++)
  546. if (*(UNALIGNED USHORT *)(pSymbol + 1) ==
  547. *((PUSHORT)vRegList + index)) {
  548. *pValue = index;
  549. return ASM_REG_DWORD;
  550. }
  551. }
  552. // test for control, debug, and test registers
  553. else if (ch1 == 'r') {
  554. ch2 -= '0';
  555. *pValue = ch2;
  556. // legal control registers are CR0, CR2, CR3, CR4
  557. if (ch0 == 'c') {
  558. if (ch2 >= 0 && ch2 <= 4)
  559. return ASM_REG_CONTROL;
  560. }
  561. // legal debug registers are DR0 - DR3, DR6, DR7
  562. else if (ch0 == 'd') {
  563. if (ch2 <= 3 || ch2 == 6 || ch2 == 7)
  564. return ASM_REG_DEBUG;
  565. }
  566. // legal trace registers are TR3 - TR7
  567. else if (ch0 == 't') {
  568. if (ch2 >= 3 && ch2 <= 7)
  569. return ASM_REG_TRACE;
  570. }
  571. }
  572. }
  573. }
  574. return 0;
  575. }
  576. // Operand parser - recursive descent
  577. //
  578. // Grammar productions:
  579. //
  580. // <Operand> ::= <register> | <Expr>
  581. // <Expr> ::= <orTerm> [(XOR | OR) <orTerm>]*
  582. // <orTerm> ::= <andTerm> [AND <andTerm>]*
  583. // <andTerm> ::= [NOT]* <notTerm>
  584. // <notTerm> ::= <relTerm> [(EQ | NE | GE | GT | LE | LT) <relTerm>]*
  585. // <relTerm> ::= <addTerm> [(- | +) <addTerm>]*
  586. // <addTerm> ::= <mulTerm> [(* | / | MOD | SHL | SHR) <mulTerm>]*
  587. // <mulTerm> ::= [(- | +)]* <signTerm>
  588. // <signTerm> ::= [(HIGH | LOW)]* <byteTerm>
  589. // <byteTerm> ::= [(OFFSET | <type> PTR)]* <offTerm>
  590. // <offTerm> ::= [<segovr>] <colnTerm>
  591. // <colnTerm> ::= <dotTerm> [.<dotTerm>]*
  592. // <dotTerm> ::= <indxTerm> ['['<Expr>']']*
  593. // <indxTerm> ::= <index-reg> | <symbol> | <number> | '('<Expr>')'
  594. // | '['<Expr>']'
  595. // <Operand> ::= <register> | <Expr>
  596. void GetAsmOperand (PASM_VALUE pavExpr)
  597. {
  598. ULONG tokenvalue;
  599. ULONG classvalue;
  600. classvalue = PeekAsmToken(&tokenvalue);
  601. if ((classvalue & ASM_CLASS_MASK) == ASM_REG_CLASS) {
  602. AcceptAsmToken();
  603. classvalue &= ASM_TYPE_MASK;
  604. pavExpr->flags = fREG;
  605. pavExpr->base = (UCHAR)tokenvalue; // index within reg group
  606. pavExpr->index = regType[classvalue - 1];
  607. pavExpr->size = regSize[classvalue - 1];
  608. }
  609. else {
  610. GetAsmExpr(pavExpr, FALSE);
  611. if (pavExpr->reloc > 1) // only 0 and 1 are allowed
  612. error(OPERAND);
  613. }
  614. }
  615. // <Expr> ::= <orTerm> [(XOR | OR) <orTerm>]*
  616. void GetAsmExpr (PASM_VALUE pavValue, UCHAR fBracket)
  617. {
  618. ULONG tokenvalue;
  619. ASM_VALUE avTerm;
  620. dprintf("enter GetAsmExpr\n");
  621. GetAsmOrTerm(pavValue, fBracket);
  622. while (PeekAsmToken(&tokenvalue) == ASM_OROP_CLASS) {
  623. AcceptAsmToken();
  624. GetAsmOrTerm(&avTerm, fBracket);
  625. if (!(pavValue->flags & avTerm.flags & fIMM))
  626. error(OPERAND);
  627. if (tokenvalue == ASM_OROP_OR)
  628. pavValue->value |= avTerm.value;
  629. else
  630. pavValue->value ^= avTerm.value;
  631. }
  632. dprintf("exit GetAsmExpr with %lx\n", pavValue->value);
  633. }
  634. // <orTerm> ::= <andTerm> [AND <andTerm>]*
  635. void GetAsmOrTerm (PASM_VALUE pavValue, UCHAR fBracket)
  636. {
  637. ULONG tokenvalue;
  638. ASM_VALUE avTerm;
  639. dprintf("enter GetAsmOrTerm\n");
  640. GetAsmAndTerm(pavValue, fBracket);
  641. while (PeekAsmToken(&tokenvalue) == ASM_ANDOP_CLASS) {
  642. AcceptAsmToken();
  643. GetAsmAndTerm(&avTerm, fBracket);
  644. if (!(pavValue->flags & avTerm.flags & fIMM))
  645. error(OPERAND);
  646. pavValue->value &= avTerm.value;
  647. }
  648. dprintf("exit GetAsmOrTerm with %lx\n", pavValue->value);
  649. }
  650. // <andTerm> ::= [NOT]* <notTerm>
  651. void GetAsmAndTerm (PASM_VALUE pavValue, UCHAR fBracket)
  652. {
  653. ULONG tokenvalue;
  654. dprintf("enter GetAsmAndTerm\n");
  655. if (PeekAsmToken(&tokenvalue) == ASM_NOTOP_CLASS) {
  656. AcceptAsmToken();
  657. GetAsmAndTerm(pavValue, fBracket);
  658. if (!(pavValue->flags & fIMM))
  659. error(OPERAND);
  660. pavValue->value = ~pavValue->value;
  661. }
  662. else
  663. GetAsmNotTerm(pavValue, fBracket);
  664. dprintf("exit GetAsmAndTerm with %lx\n", pavValue->value);
  665. }
  666. // <notTerm> ::= <relTerm> [(EQ | NE | GE | GT | LE | LT) <relTerm>]*
  667. void GetAsmNotTerm (PASM_VALUE pavValue, UCHAR fBracket)
  668. {
  669. ULONG tokenvalue;
  670. ULONG fTest;
  671. ULONG fAddress;
  672. ASM_VALUE avTerm;
  673. dprintf("enter GetAsmNotTerm\n");
  674. GetAsmRelTerm(pavValue, fBracket);
  675. while (PeekAsmToken(&tokenvalue) == ASM_RELOP_CLASS) {
  676. AcceptAsmToken();
  677. GetAsmRelTerm(&avTerm, fBracket);
  678. if (!(pavValue->flags & avTerm.flags & fIMM) ||
  679. pavValue->reloc > 1 || avTerm.reloc > 1)
  680. error(OPERAND);
  681. fAddress = pavValue->reloc | avTerm.reloc;
  682. switch (tokenvalue) {
  683. case ASM_RELOP_EQ:
  684. fTest = pavValue->value == avTerm.value;
  685. break;
  686. case ASM_RELOP_NE:
  687. fTest = pavValue->value != avTerm.value;
  688. break;
  689. case ASM_RELOP_GE:
  690. if (fAddress)
  691. fTest = pavValue->value >= avTerm.value;
  692. else
  693. fTest = (LONG)pavValue->value >= (LONG)avTerm.value;
  694. break;
  695. case ASM_RELOP_GT:
  696. if (fAddress)
  697. fTest = pavValue->value > avTerm.value;
  698. else
  699. fTest = (LONG)pavValue->value > (LONG)avTerm.value;
  700. break;
  701. case ASM_RELOP_LE:
  702. if (fAddress)
  703. fTest = pavValue->value <= avTerm.value;
  704. else
  705. fTest = (LONG)pavValue->value <= (LONG)avTerm.value;
  706. break;
  707. case ASM_RELOP_LT:
  708. if (fAddress)
  709. fTest = pavValue->value < avTerm.value;
  710. else
  711. fTest = (LONG)pavValue->value < (LONG)avTerm.value;
  712. break;
  713. default:
  714. printf("bad RELOP type\n");
  715. }
  716. pavValue->value = (ULONG)(-((LONG)fTest)); // FALSE = 0; TRUE = -1
  717. pavValue->reloc = 0;
  718. pavValue->size = sizeB; // immediate value is byte
  719. }
  720. dprintf("exit GetAsmNotTerm with %lx\n", pavValue->value);
  721. }
  722. // <relTerm> ::= <addTerm> [(- | +) <addTerm>]*
  723. void GetAsmRelTerm (PASM_VALUE pavValue, UCHAR fBracket)
  724. {
  725. ULONG tokenvalue;
  726. ASM_VALUE avTerm;
  727. dprintf("enter GetAsmRelTerm\n");
  728. GetAsmAddTerm(pavValue, fBracket);
  729. while (PeekAsmToken(&tokenvalue) == ASM_ADDOP_CLASS) {
  730. AcceptAsmToken();
  731. GetAsmAddTerm(&avTerm, fBracket);
  732. if (tokenvalue == ASM_ADDOP_MINUS) {
  733. if (!(avTerm.flags & (fIMM | fPTR)))
  734. error(OPERAND);
  735. avTerm.value = (ULONG)(-((LONG)avTerm.value));
  736. avTerm.reloc = (UCHAR)(-avTerm.reloc);
  737. }
  738. AddAsmValues(pavValue, &avTerm);
  739. }
  740. dprintf("exit GetAsmRelTerm with %lx\n", pavValue->value);
  741. }
  742. // <addTerm> ::= <mulTerm> [(* | / | MOD | SHL | SHR) <mulTerm>]*
  743. void GetAsmAddTerm (PASM_VALUE pavValue, UCHAR fBracket)
  744. {
  745. ULONG tokenvalue;
  746. ASM_VALUE avTerm;
  747. dprintf("enter GetAsmAddTerm\n");
  748. GetAsmMulTerm(pavValue, fBracket);
  749. while (PeekAsmToken(&tokenvalue) == ASM_MULOP_CLASS) {
  750. AcceptAsmToken();
  751. GetAsmMulTerm(&avTerm, fBracket);
  752. if (tokenvalue == ASM_MULOP_MULT) {
  753. if (pavValue->flags & fIMM)
  754. SwapPavs(pavValue, &avTerm);
  755. if (!(avTerm.flags & fIMM))
  756. error(OPERAND);
  757. if (pavValue->flags & fIMM)
  758. pavValue->value *= avTerm.value;
  759. else if ((pavValue->flags & fPTR32)
  760. && pavValue->value == 0
  761. && pavValue->base != indSP
  762. && pavValue->index == 0xff) {
  763. pavValue->index = pavValue->base;
  764. pavValue->base = 0xff;
  765. pavValue->scale = 0xff;
  766. if (avTerm.value == 1)
  767. pavValue->scale = 0;
  768. if (avTerm.value == 2)
  769. pavValue->scale = 1;
  770. if (avTerm.value == 4)
  771. pavValue->scale = 2;
  772. if (avTerm.value == 8)
  773. pavValue->scale = 3;
  774. if (pavValue->scale == 0xff)
  775. error(OPERAND);
  776. }
  777. else
  778. error(OPERAND);
  779. }
  780. else if (!(pavValue->flags & avTerm.flags & fIMM))
  781. error(OPERAND);
  782. else if (tokenvalue == ASM_MULOP_DIVIDE
  783. || tokenvalue == ASM_MULOP_MOD) {
  784. if (avTerm.value == 0)
  785. error(DIVIDE);
  786. if (tokenvalue == ASM_MULOP_DIVIDE)
  787. pavValue->value /= avTerm.value;
  788. else
  789. pavValue->value %= avTerm.value;
  790. }
  791. else if (tokenvalue == ASM_MULOP_SHL)
  792. pavValue->value <<= avTerm.value;
  793. else
  794. pavValue->value >>= avTerm.value;
  795. }
  796. dprintf("exit GetAsmAddTerm with %lx\n", pavValue->value);
  797. }
  798. // <mulTerm> ::= [(- | +)]* <signTerm>
  799. void GetAsmMulTerm (PASM_VALUE pavValue, UCHAR fBracket)
  800. {
  801. ULONG tokenvalue;
  802. dprintf("enter GetAsmMulTerm\n");
  803. if (PeekAsmToken(&tokenvalue) == ASM_ADDOP_CLASS) { // BY WO DW POI UNDN
  804. AcceptAsmToken();
  805. GetAsmMulTerm(pavValue, fBracket);
  806. if (tokenvalue == ASM_ADDOP_MINUS) {
  807. if (!(pavValue->flags & (fIMM | fPTR)))
  808. error(OPERAND);
  809. pavValue->value = (ULONG)(-((LONG)pavValue->value));
  810. pavValue->reloc = (UCHAR)(-pavValue->reloc);
  811. }
  812. }
  813. else
  814. GetAsmSignTerm(pavValue, fBracket);
  815. dprintf("exit GetAsmMulTerm with %lx\n", pavValue->value);
  816. }
  817. // <signTerm> ::= [(HIGH | LOW)]* <byteTerm>
  818. void GetAsmSignTerm (PASM_VALUE pavValue, UCHAR fBracket)
  819. {
  820. ULONG tokenvalue;
  821. dprintf("enter GetAsmSignTerm\n");
  822. if (PeekAsmToken(&tokenvalue) == ASM_LOWOP_CLASS) {
  823. AcceptAsmToken();
  824. GetAsmSignTerm(pavValue, fBracket);
  825. if (!(pavValue->flags & (fIMM | fPTR)))
  826. error(OPERAND);
  827. if (tokenvalue == ASM_LOWOP_LOW)
  828. pavValue->value = pavValue->value & 0xff;
  829. else
  830. pavValue->value = (pavValue->value & ~0xff) >> 8;
  831. pavValue->flags = fIMM; // make an immediate value
  832. pavValue->reloc = 0;
  833. pavValue->segment = segX;
  834. pavValue->size = sizeB; // byte value
  835. }
  836. else
  837. GetAsmByteTerm(pavValue, fBracket);
  838. dprintf("exit GetAsmSignTerm with %lx\n", pavValue->value);
  839. }
  840. // <byteTerm> ::= [(OFFSET | <size> PTR)]* <offTerm>
  841. void GetAsmByteTerm (PASM_VALUE pavValue, UCHAR fBracket)
  842. {
  843. ULONG tokenvalue;
  844. ULONG classvalue;
  845. dprintf("enter GetAsmByteTerm\n");
  846. classvalue = PeekAsmToken(&tokenvalue);
  847. if (classvalue == ASM_OFFOP_CLASS) {
  848. AcceptAsmToken();
  849. GetAsmByteTerm(pavValue, fBracket);
  850. if (!(pavValue->flags & (fIMM | fPTR)) || pavValue->reloc > 1)
  851. error(OPERAND);
  852. pavValue->flags = fIMM; // make offset an immediate value
  853. pavValue->reloc = 0;
  854. pavValue->size = sizeX;
  855. pavValue->segment = segX;
  856. }
  857. else if (classvalue == ASM_SIZE_CLASS) {
  858. AcceptAsmToken();
  859. if (GetAsmToken(&classvalue) != ASM_PTROP_CLASS) // dummy token
  860. error(SYNTAX);
  861. GetAsmByteTerm(pavValue, fBracket);
  862. if (!(pavValue->flags & (fIMM | fPTR | fPTR16 | fPTR32))
  863. || pavValue->reloc > 1
  864. || pavValue->size != sizeX)
  865. error(OPERAND);
  866. pavValue->reloc = 1; // make ptr a relocatable value
  867. if (pavValue->flags & fIMM)
  868. pavValue->flags = fPTR;
  869. pavValue->size = (UCHAR)(tokenvalue & ASM_TYPE_MASK);
  870. // value has "size?"
  871. }
  872. else
  873. GetAsmOffTerm(pavValue, fBracket);
  874. dprintf("exit GetAsmByteTerm with %lx\n", pavValue->value);
  875. }
  876. // <offTerm> ::= [<segovr>] <colnTerm>
  877. void GetAsmOffTerm (PASM_VALUE pavValue, UCHAR fBracket)
  878. {
  879. ULONG classvalue;
  880. ULONG tokenvalue;
  881. dprintf("enter GetAsmOffTerm\n");
  882. classvalue = PeekAsmToken(&tokenvalue);
  883. if (classvalue == ASM_SEGOVR_CLASS || classvalue == ASM_SEGMENT_CLASS) {
  884. if (fBracket)
  885. error(SYNTAX);
  886. AcceptAsmToken();
  887. }
  888. GetAsmColnTerm(pavValue, fBracket);
  889. if (classvalue == ASM_SEGOVR_CLASS) {
  890. if (pavValue->reloc > 1 || pavValue->segovr != segX)
  891. error(OPERAND);
  892. pavValue->reloc = 1; // make ptr a relocatable value
  893. if (pavValue->flags & fIMM)
  894. pavValue->flags = fPTR;
  895. pavValue->segovr = (UCHAR)tokenvalue; // has segment override
  896. }
  897. else if (classvalue == ASM_SEGMENT_CLASS) {
  898. if (!(pavValue->flags & fIMM) || pavValue->reloc > 1)
  899. error(OPERAND);
  900. pavValue->segment = (USHORT)tokenvalue; // segment has segment value
  901. pavValue->flags = fFPTR; // set flag for far pointer
  902. }
  903. dprintf("exit GetAsmOffTerm with %lx\n", pavValue->value);
  904. }
  905. // <colnTerm> ::= <dotTerm> [.<dotTerm>]*
  906. void GetAsmColnTerm (PASM_VALUE pavValue, UCHAR fBracket)
  907. {
  908. ULONG tokenvalue;
  909. ASM_VALUE avTerm;
  910. dprintf("enter GetAsmColnTerm\n");
  911. GetAsmDotTerm(pavValue, fBracket);
  912. while (PeekAsmToken(&tokenvalue) == ASM_DOTOP_CLASS) {
  913. AcceptAsmToken();
  914. GetAsmDotTerm(&avTerm, fBracket);
  915. AddAsmValues(pavValue, &avTerm);
  916. }
  917. dprintf("exit GetAsmColnTerm with %lx\n", pavValue->value);
  918. }
  919. // <dotTerm> ::= <indxTerm> ['['<Expr>']']*
  920. void GetAsmDotTerm (PASM_VALUE pavValue, UCHAR fBracket)
  921. {
  922. ULONG tokenvalue;
  923. ASM_VALUE avExpr;
  924. dprintf("enter GetAsmDotTerm\n");
  925. GetAsmIndxTerm(pavValue, fBracket);
  926. if (pavValue->reloc > 1)
  927. error(OPERAND);
  928. while (PeekAsmToken(&tokenvalue) == ASM_LBRACK_CLASS) {
  929. AcceptAsmToken();
  930. if (fBracket)
  931. error(SYNTAX);
  932. GetAsmExpr(&avExpr, TRUE);
  933. AddAsmValues(pavValue, &avExpr);
  934. if (GetAsmToken(&tokenvalue) != ASM_RBRACK_CLASS)
  935. error(SYNTAX);
  936. if (pavValue->flags & fIMM)
  937. pavValue->flags = fPTR;
  938. }
  939. dprintf("exit GetAsmDotTerm with %lx\n", pavValue->value);
  940. }
  941. // <indxTerm> ::= <index-reg> | <symbol> | <number> | '('<Expr>')'
  942. // | '['<Expr>']'
  943. void GetAsmIndxTerm (PASM_VALUE pavValue, UCHAR fBracket)
  944. {
  945. ULONG tokenvalue;
  946. ULONG classvalue;
  947. dprintf("enter GetAsmIndxTerm\n");
  948. classvalue = GetAsmToken(&tokenvalue);
  949. pavValue->segovr = segX;
  950. pavValue->size = sizeX;
  951. pavValue->reloc = 0;
  952. pavValue->value = 0;
  953. if (classvalue == ASM_LPAREN_CLASS) {
  954. GetAsmExpr(pavValue, fBracket);
  955. if (GetAsmToken(&tokenvalue) != ASM_RPAREN_CLASS)
  956. error(SYNTAX);
  957. }
  958. else if (classvalue == ASM_LBRACK_CLASS) {
  959. if (fBracket)
  960. error(SYNTAX);
  961. GetAsmExpr(pavValue, TRUE);
  962. if (GetAsmToken(&tokenvalue) != ASM_RBRACK_CLASS)
  963. error(SYNTAX);
  964. if (pavValue->flags == fIMM)
  965. pavValue->flags = fPTR;
  966. }
  967. else if (classvalue == ASM_SYMBOL_CLASS) {
  968. pavValue->value = tokenvalue;
  969. pavValue->flags = fIMM;
  970. pavValue->reloc = 1;
  971. }
  972. else if (classvalue == ASM_NUMBER_CLASS) {
  973. pavValue->value = tokenvalue;
  974. pavValue->flags = fIMM;
  975. }
  976. else if (classvalue == ASM_REG_WORD) {
  977. if (!fBracket)
  978. error(SYNTAX);
  979. pavValue->flags = fPTR16;
  980. pavValue->base = tabWordReg[tokenvalue];
  981. if (pavValue->base == 0xff)
  982. error(OPERAND);
  983. }
  984. else if (classvalue == ASM_REG_DWORD) {
  985. if (!fBracket)
  986. error(SYNTAX);
  987. pavValue->flags = fPTR32;
  988. pavValue->base = (UCHAR)tokenvalue;
  989. pavValue->index = 0xff;
  990. }
  991. else
  992. error(SYNTAX);
  993. dprintf("exit GetAsmIndxTerm with %lx\n", pavValue->value);
  994. }
  995. void AddAsmValues (PASM_VALUE pavLeft, PASM_VALUE pavRight)
  996. {
  997. // swap values if left one is a pointer
  998. if (pavLeft->flags & fPTR)
  999. SwapPavs(pavLeft, pavRight);
  1000. // swap values if left one is an immediate
  1001. if (pavLeft->flags & fIMM)
  1002. SwapPavs(pavLeft, pavRight);
  1003. // the above swaps reduce the cases to test.
  1004. // pairs with an immediate will have it on the right
  1005. // pairs with a pointer will have it on the right,
  1006. // except for a pointer-immediate pair
  1007. // if both values are 16-bit pointers, combine them
  1008. if (pavLeft->flags & pavRight->flags & fPTR16) {
  1009. // if either side has both registers (rm < 4), error
  1010. if (!(pavLeft->base & pavRight->base & 4))
  1011. error(OPERAND);
  1012. // use lookup table to compute new rm value
  1013. pavLeft->base = rm16Table[((pavLeft->base & 3) << 2) +
  1014. (pavRight->base & 3)];
  1015. if (pavLeft->base == 0xff)
  1016. error(OPERAND);
  1017. pavRight->flags = fPTR;
  1018. }
  1019. // if both values are 32-bit pointers, combine them
  1020. if (pavLeft->flags & pavRight->flags & fPTR32) {
  1021. // error if either side has both base and index,
  1022. // or if both have index
  1023. if (((pavLeft->base | pavLeft->index) != 0xff)
  1024. || ((pavRight->base | pavRight->index) != 0xff)
  1025. || ((pavLeft->index | pavRight->index) != 0xff))
  1026. error(OPERAND);
  1027. // if left side has base, swap sides
  1028. if (pavLeft->base != 0xff)
  1029. SwapPavs(pavLeft, pavRight);
  1030. // two cases remaining, index-base and base-base
  1031. if (pavLeft->base != 0xff) {
  1032. // left side has base, promote to index but swap if left
  1033. // base is ESP since it cannot be an index register
  1034. if (pavLeft->base == indSP)
  1035. SwapPavs(pavLeft, pavRight);
  1036. if (pavLeft->base == indSP)
  1037. error(OPERAND);
  1038. pavLeft->index = pavLeft->base;
  1039. pavLeft->scale = 0;
  1040. }
  1041. // finish by setting left side base to right side value
  1042. pavLeft->base = pavRight->base;
  1043. pavRight->flags = fPTR;
  1044. }
  1045. // if left side is any pointer and right is nonindex pointer,
  1046. // combine them. (above cases set right side to use this code)
  1047. if ((pavLeft->flags & (fPTR | fPTR16 | fPTR32))
  1048. && (pavRight->flags & fPTR)) {
  1049. if (pavLeft->segovr + pavRight->segovr != segX
  1050. && pavLeft->segovr != pavRight->segovr)
  1051. error(OPERAND);
  1052. if (pavLeft->size + pavRight->size != sizeX
  1053. && pavLeft->size != pavRight->size)
  1054. error(OPERAND);
  1055. pavRight->flags = fIMM;
  1056. }
  1057. // if right side is immediate, add values and relocs
  1058. // (above case sets right side to use this code)
  1059. // illegal value types do not have right side set to fIMM
  1060. if (pavRight->flags & fIMM) {
  1061. pavLeft->value += pavRight->value;
  1062. pavLeft->reloc += pavRight->reloc;
  1063. }
  1064. else
  1065. error(OPERAND);
  1066. }
  1067. void SwapPavs (PASM_VALUE pavFirst, PASM_VALUE pavSecond)
  1068. {
  1069. ASM_VALUE temp;
  1070. memmove(&temp, pavFirst, sizeof(ASM_VALUE));
  1071. memmove(pavFirst, pavSecond, sizeof(ASM_VALUE));
  1072. memmove(pavSecond, &temp, sizeof(ASM_VALUE));
  1073. }