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.

679 lines
21 KiB

  1. /*****************************************************************************
  2. *
  3. * eval.c
  4. *
  5. * Arithmetical evaluation.
  6. *
  7. *****************************************************************************/
  8. #include "m4.h"
  9. /*****************************************************************************
  10. *
  11. * First, a warm-up: Increment and decrement.
  12. *
  13. *****************************************************************************/
  14. /*****************************************************************************
  15. *
  16. * opIncr
  17. * opDecr
  18. *
  19. * Returns the value of its argument, augmented or diminished by unity.
  20. * The extra ptokNil covers us in the case where $# is zero.
  21. *
  22. *****************************************************************************/
  23. void STDCALL
  24. opAddItokDat(ARGV argv, DAT dat)
  25. {
  26. AT at = atTraditionalPtok(ptokArgv(1));
  27. #ifdef STRICT_M4
  28. if (ctokArgv != 1) {
  29. Warn("wrong number of arguments to %P", ptokArgv(0));
  30. }
  31. #endif
  32. PushAt(at+dat);
  33. }
  34. DeclareOp(opIncr)
  35. {
  36. opAddItokDat(argv, 1);
  37. }
  38. DeclareOp(opDecr)
  39. {
  40. opAddItokDat(argv, -1);
  41. }
  42. /*****************************************************************************
  43. *
  44. * Now the gross part: Eval.
  45. *
  46. * Expression evaluation is performed by a parser which is a mix of
  47. * shift-reduce and recursive-descent. (Worst of both worlds.)
  48. *
  49. * The precedence table for our expression language reads
  50. *
  51. * (...) grouping > primary
  52. * + - unary
  53. * ** exponentiation
  54. * * / % multiplicative
  55. * + - additive
  56. * << >> shift
  57. * == != > >= < <= relational
  58. * ! logical-negate
  59. * ~ bit-negate
  60. * & bit-and
  61. * ^ bit-xor
  62. * | bit-or
  63. * && logical-and
  64. * || logical-or
  65. *
  66. *
  67. * COMPAT -- AT&T style uses ^ for exponentiation; we use it for xor
  68. *
  69. * NOTE: "the rest is bogus" went the original comment. I forget what
  70. * I meant by that.
  71. *
  72. * The precedence table for the C-style expression language reads
  73. *
  74. * (...) grouping \ primary
  75. * + - ~ ! unary /
  76. * * / % multiplative \
  77. * + - additive \
  78. * << >> shift |
  79. * < > <= >= relational |
  80. * == != equality \ secondary
  81. * & bit-and /
  82. * ^ bit-xor |
  83. * | bit-or |
  84. * && logical-and /
  85. * || logical-or /
  86. * ? : ternary > tertiary
  87. *
  88. * Recursive descent is performed on the primary/secondary/tertiary
  89. * scale, but shift-reduce is performed within the secondary phase.
  90. *
  91. * The reason is that the operators in the secondary phase are
  92. * (1) binary, and (2) non-recursive. These two properties
  93. * make shift-reduce easy to implement.
  94. *
  95. * Primaries are recursive, so they are easier to implement in
  96. * recursive-descent. Tertiaries would clog up the shift-reduce
  97. * grammar, so they've been moved to recursive-descent as well.
  98. *
  99. *****************************************************************************/
  100. /*****************************************************************************
  101. *
  102. * EachEop
  103. *
  104. * Before calling this macro, define the following macros, each of
  105. * which will be called with three arguments,
  106. *
  107. * nm = operator name as a C identifier (e.g., "Add")
  108. * op = operator name as a bare token (e.g., "+")
  109. * cb = length of operator name
  110. *
  111. * The macros should be
  112. *
  113. * x1 -- for native C unary operators
  114. * x1a -- for native C unary operators which have binary aliases
  115. * x2 -- for native C binary operators
  116. * x2a -- for native C binary operators which have unary aliases
  117. * x2n -- for non-native C binary operators
  118. * xp -- for phantom operators,
  119. * in which case op and cb are useless
  120. *
  121. * The order in which operators appear is important for the purpose
  122. * of tokenization. Longer operators must precede shorter ones.
  123. *
  124. *****************************************************************************/
  125. #define EachEop() \
  126. x2(Shl, <<, 2) \
  127. x2(Shr, >>, 2) \
  128. x2(Le, <=, 2) \
  129. x2(Ge, >=, 2) \
  130. x2(Eq, ==, 2) \
  131. x2(Ne, !=, 2) \
  132. x2(Land, &&, 2) \
  133. x2(Lor, ||, 2) \
  134. x2n(Exp, **, 2) \
  135. x2(Mul, *, 1) \
  136. x2(Div, /, 1) \
  137. x2(Mod, %, 1) \
  138. x2a(Add, +, 1) /* These two must be */ \
  139. x2a(Sub, -, 1) /* in exactly this order */ \
  140. x2(Lt, <, 1) \
  141. x2(Gt, >, 1) \
  142. x2(Band, &, 1) \
  143. x2(Bxor, ^, 1) \
  144. x2(Bor, |, 1) \
  145. x1(Lnot, !, 1) \
  146. x1(Bnot, ~, 1) \
  147. x1a(Plu, +, x) /* These two must be */ \
  148. x1a(Neg, -, x) /* in exactly this order */ \
  149. xp(Flush, @, 0) \
  150. xp(Boe, @, 0) \
  151. /*****************************************************************************
  152. *
  153. * MakeEop
  154. *
  155. * Each binary operator has a handler which returns the combined
  156. * value.
  157. *
  158. * Each unary operator has a handler which returns the operator
  159. * applied to its single argument.
  160. *
  161. * All the operators are C native, except for Exp, which is handled
  162. * directly.
  163. *
  164. *****************************************************************************/
  165. typedef AT (STDCALL *EOP1)(AT at);
  166. typedef AT (STDCALL *EOP2)(AT a, AT b);
  167. #define x1(nm, op, cb) AT STDCALL at##nm##At(AT at) { return op at; }
  168. #define x1a(nm, op, cb) AT STDCALL at##nm##At(AT at) { return op at; }
  169. #define x2(nm, op, cb) AT STDCALL at##nm##AtAt(AT a, AT b) { return a op b; }
  170. #define x2a(nm, op, cb) AT STDCALL at##nm##AtAt(AT a, AT b) { return a op b; }
  171. #define x2n(nm, op, cb)
  172. #define xp(nm, op, cb)
  173. EachEop()
  174. #undef x1
  175. #undef x1a
  176. #undef x2
  177. #undef x2a
  178. #undef x2n
  179. #undef xp
  180. /*****************************************************************************
  181. *
  182. * atExpAtAt
  183. *
  184. * Implement the exponentiation operator.
  185. *
  186. * QUIRK! AT&T returns 1 if $2 < 0. GNU raises an error.
  187. * I side with AT&T on this, only out of laziness.
  188. *
  189. *****************************************************************************/
  190. AT STDCALL
  191. atExpAtAt(AT a, AT b)
  192. {
  193. AT at = 1;
  194. while (b > 0) {
  195. if (b & 1) {
  196. at = at * a;
  197. }
  198. a = a * a;
  199. b = b / 2;
  200. }
  201. return at;
  202. }
  203. TOK tokExpr; /* Current expression context */
  204. /*****************************************************************************
  205. *
  206. * MakeEopTab
  207. *
  208. * Table of operators and operator precedence. Each entry in the
  209. * table contains the name, length, handler, precedence, and
  210. * flags that describe what kind of operator it is.
  211. *
  212. * Items are listed in precedence order here; the EachBop will
  213. * emit the table corrctly.
  214. *
  215. *****************************************************************************/
  216. typedef enum EOPFL {
  217. eopflUn = 1,
  218. eopflBin = 2,
  219. eopflAmb = 4,
  220. } EOPFL;
  221. typedef UINT PREC; /* Operator precedence */
  222. typedef struct EOPI {
  223. PTCH ptch;
  224. CTCH ctch;
  225. union {
  226. EOP1 eop1;
  227. EOP2 eop2;
  228. } u;
  229. PREC prec;
  230. EOPFL eopfl;
  231. } EOPI, *PEOPI;
  232. #define MakeEopi(nm, ctch, pfn, prec, eopfl) \
  233. { TEXT(nm), ctch, { (EOP1)pfn }, prec, eopfl },
  234. enum {
  235. m4precNeg = 14, m4precPlu = 14,
  236. m4precExp = 13,
  237. m4precMul = 12, m4precDiv = 12, m4precMod = 12,
  238. m4precAdd = 11, m4precSub = 11,
  239. m4precShl = 10, m4precShr = 10,
  240. m4precEq = 9, m4precNe = 9,
  241. m4precGt = 9, m4precGe = 9,
  242. m4precLt = 9, m4precLe = 9,
  243. m4precLnot = 8,
  244. m4precBnot = 7,
  245. m4precBand = 6,
  246. m4precBxor = 5,
  247. m4precBor = 4,
  248. m4precLand = 3,
  249. m4precLor = 2,
  250. m4precFlush = 1, /* Flushing out everything but Boe */
  251. m4precBoe = 0, /* Beginning-of-expression */
  252. };
  253. #define x1(nm, op, cb) static TCH rgtch##nm[cb] = #op;
  254. #define x1a(nm, op, cb)
  255. #define x2(nm, op, cb) static TCH rgtch##nm[cb] = #op;
  256. #define x2a(nm, op, cb) static TCH rgtch##nm[cb] = #op;
  257. #define x2n(nm, op, cb) static TCH rgtch##nm[cb] = #op;
  258. #define xp(nm, op, cb)
  259. EachEop()
  260. #undef x1
  261. #undef x1a
  262. #undef x2
  263. #undef x2a
  264. #undef x2n
  265. #undef xp
  266. #define x1(nm, op, cb) MakeEopi(rgtch##nm, cb, at##nm##At, m4prec##nm, eopflUn)
  267. #define x1a(nm, op, cb) MakeEopi(0, 0, at##nm##At, m4prec##nm, eopflUn)
  268. #define x2(nm, op, cb) MakeEopi(rgtch##nm, cb, at##nm##AtAt, m4prec##nm, eopflBin)
  269. #define x2a(nm, op, cb) MakeEopi(rgtch##nm, cb, at##nm##AtAt, m4prec##nm, eopflAmb + eopflBin) /* initially bin */
  270. #define x2n(nm, op, cb) MakeEopi(rgtch##nm, cb, at##nm##AtAt, m4prec##nm, eopflBin)
  271. #define xp(nm, op, cb) MakeEopi(0, 0, 0, m4prec##nm, 0)
  272. EOPI rgeopi[] = {
  273. EachEop()
  274. };
  275. #undef x1
  276. #undef x1a
  277. #undef x2
  278. #undef x2a
  279. #undef x2n
  280. #undef xp
  281. #define x1(nm, op, cb) ieopi##nm,
  282. #define x1a(nm, op, cb) ieopi##nm,
  283. #define x2(nm, op, cb) ieopi##nm,
  284. #define x2a(nm, op, cb) ieopi##nm,
  285. #define x2n(nm, op, cb) ieopi##nm,
  286. #define xp(nm, op, cb) ieopi##nm,
  287. typedef enum IEOPI {
  288. EachEop()
  289. ieopMax,
  290. } IEOPI;
  291. #undef x1
  292. #undef x1a
  293. #undef x2
  294. #undef x2a
  295. #undef x2n
  296. #define peopiBoe (&rgeopi[ieopiBoe])
  297. #define peopiFlush (&rgeopi[ieopiFlush])
  298. /*****************************************************************************
  299. *
  300. * fPrimary, fSecondary, fTertiary
  301. *
  302. * Forward declarations for the recursive-descent parser.
  303. *
  304. * Each parses a token/expression of the appropriate class
  305. * and leaves it on the top of the expression stack, or
  306. * returns 0 if the value could not be parsed.
  307. *
  308. *****************************************************************************/
  309. F STDCALL fPrimary(void);
  310. F STDCALL fSecondary(void);
  311. #define fTertiary fSecondary
  312. /*****************************************************************************
  313. *
  314. * Cells
  315. *
  316. * The expression stack consists of structures which, for lack of
  317. * a better name, are called `cells'. Each cell can hold either
  318. * an expression operator or an integer, distinguished by the fEopi
  319. * field.
  320. *
  321. * In keeping with parser terminology, the act of pushing something
  322. * onto the stack is called `shifting'. Collapsing objects is called
  323. * `reducing'.
  324. *
  325. *****************************************************************************/
  326. typedef struct CELL {
  327. F fEopi;
  328. union {
  329. PEOPI peopi;
  330. AT at;
  331. } u;
  332. } CELL, *PCELL;
  333. typedef UINT CCELL, ICELL;
  334. PCELL rgcellEstack; /* The expression stack */
  335. PCELL pcellMax; /* End of the stack */
  336. PCELL pcellCur; /* Next free cell */
  337. INLINE PCELL
  338. pcellTos(ICELL icell)
  339. {
  340. Assert(pcellCur - 1 - icell >= rgcellEstack);
  341. return pcellCur - 1 - icell;
  342. }
  343. /*****************************************************************************
  344. *
  345. * Stack munging
  346. *
  347. * Quickie routines that poke at the top-of-stack.
  348. *
  349. *****************************************************************************/
  350. INLINE F fWantOp(void) { return !pcellTos(1)->fEopi; }
  351. INLINE F fOpTos(ICELL icell) { return pcellTos(icell)->fEopi; }
  352. INLINE PEOPI
  353. peopiTos(ICELL icell)
  354. {
  355. Assert(fOpTos(icell));
  356. return pcellTos(icell)->u.peopi;
  357. }
  358. INLINE AT
  359. atTos(ICELL icell)
  360. {
  361. Assert(!fOpTos(icell));
  362. return pcellTos(icell)->u.at;
  363. }
  364. INLINE F fBinTos(ICELL icell) { return peopiTos(icell)->eopfl & eopflBin; }
  365. INLINE F fUnTos(ICELL icell) { return peopiTos(icell)->eopfl & eopflUn; }
  366. INLINE F fAmbTos(ICELL icell) { return peopiTos(icell)->eopfl & eopflAmb; }
  367. INLINE PREC precTos(ICELL icell) { return peopiTos(icell)->prec; }
  368. INLINE void
  369. UnFromAmb(ICELL icell)
  370. {
  371. Assert(fOpTos(icell));
  372. pcellTos(icell)->u.peopi += (ieopiPlu - ieopiAdd);
  373. }
  374. /*****************************************************************************
  375. *
  376. * ShiftCell
  377. *
  378. * Shift a cell onto the expression stack.
  379. *
  380. * QShiftCell shifts in a cell assuming that the stack is already
  381. * big enough to handle it.
  382. *
  383. *****************************************************************************/
  384. void STDCALL
  385. QShiftCell(UINT_PTR uiObj, F fEopi)
  386. {
  387. Assert(pcellCur < pcellMax);
  388. pcellCur->fEopi = fEopi;
  389. if (fEopi) {
  390. pcellCur->u.peopi = (PEOPI)uiObj;
  391. } else {
  392. pcellCur->u.at = (INT)uiObj;
  393. }
  394. pcellCur++;
  395. }
  396. void STDCALL
  397. ShiftCell(UINT_PTR uiObj, F fEopi)
  398. {
  399. if (pcellCur >= pcellMax) {
  400. CCELL ccell = (CCELL)(pcellMax - rgcellEstack + 128); /* Should be enough */
  401. rgcellEstack = pvReallocPvCb(rgcellEstack, ccell * sizeof(CELL));
  402. pcellCur = rgcellEstack + ccell - 128;
  403. pcellMax = rgcellEstack + ccell;
  404. }
  405. QShiftCell(uiObj, fEopi);
  406. }
  407. #define ShiftPeopi(peopi) ShiftCell((UINT_PTR)(peopi), 1)
  408. #define ShiftAt(at) ShiftCell((UINT_PTR)(at), 0)
  409. #define QShiftPeopi(peopi) QShiftCell((UINT_PTR)(peopi), 1)
  410. #define QShiftAt(at) QShiftCell((UINT_PTR)(at), 0)
  411. #define Drop(icell) (pcellCur -= (icell))
  412. /*****************************************************************************
  413. *
  414. * ReducePrec
  415. *
  416. * Reduce until everything with higher precedence has been cleaned off.
  417. *
  418. * Tos(0) should be a fresh operator.
  419. * Everything underneath should be a valid partial evaluation.
  420. *
  421. *****************************************************************************/
  422. void STDCALL
  423. Reduce(void)
  424. {
  425. PEOPI peopi;
  426. Assert(fOpTos(0)); /* Tos(0) should be an op */
  427. Assert(!fOpTos(1)); /* Tos(1) should be an int */
  428. Assert(fOpTos(2)); /* Tos(2) should be an op */
  429. peopi = peopiTos(0); /* Save this */
  430. Drop(1); /* before we drop it */
  431. while (precTos(1) > peopi->prec) {
  432. AT at;
  433. if (fUnTos(1)) {
  434. at = peopiTos(1)->u.eop1(atTos(0));
  435. Drop(2); /* Drop the op and the arg */
  436. } else {
  437. Assert(fBinTos(1));
  438. Assert(!fOpTos(2));
  439. at = peopiTos(1)->u.eop2(atTos(2), atTos(0));
  440. Drop(3); /* Drop the op and two args */
  441. }
  442. QShiftAt(at); /* Shift the answer back on */
  443. Assert(!fOpTos(0)); /* Tos(0) should be an int */
  444. Assert(fOpTos(1)); /* Tos(1) should be an op */
  445. }
  446. QShiftPeopi(peopi); /* Restore the original op */
  447. }
  448. /*****************************************************************************
  449. *
  450. * fPrimary
  451. *
  452. * Parse the next expression token and shift it onto the expression
  453. * stack. Zero is returned if there is no next token, or the token
  454. * is invalid.
  455. *
  456. * Here is where parenthesized expressions are handled, in a
  457. * recursive-descent manner.
  458. *
  459. * Ambiguous operators (ones which can be either unary or binary)
  460. * are returned as binary.
  461. *
  462. *****************************************************************************/
  463. F STDCALL
  464. fPrimary(void)
  465. {
  466. SkipWhitePtok(&tokExpr); /* Skip leading whitespace */
  467. /*
  468. * First see if we can find an operator.
  469. */
  470. {
  471. PEOPI peopi;
  472. for (peopi = rgeopi; peopi < &rgeopi[ieopiPlu]; peopi++) {
  473. if (peopi->ctch <= ctchSPtok(&tokExpr) &&
  474. fEqPtchPtchCtch(ptchPtok(&tokExpr), peopi->ptch,
  475. peopi->ctch)) {
  476. EatHeadPtokCtch(&tokExpr, peopi->ctch); /* Eat the op */
  477. ShiftPeopi(peopi);
  478. return 1;
  479. }
  480. }
  481. }
  482. /*
  483. * Didn't find an operator. Look for an integer.
  484. */
  485. {
  486. AT at;
  487. if (fEvalPtokPat(&tokExpr, &at)) {
  488. ShiftAt(at);
  489. return 1;
  490. }
  491. }
  492. /*
  493. * Not an integer either. Maybe a parenthesized expression.
  494. */
  495. {
  496. if (ptchPtok(&tokExpr)[0] == '(') {
  497. EatHeadPtokCtch(&tokExpr, 1); /* Eat the paren */
  498. if (fTertiary()) { /* Leaves answer on top of stack */
  499. if (ptchPtok(&tokExpr)[0] == ')') {
  500. EatHeadPtokCtch(&tokExpr, 1); /* Eat the paren */
  501. return 1;
  502. } else {
  503. return 0;
  504. }
  505. } else {
  506. return 0; /* Trouble down below */
  507. }
  508. }
  509. }
  510. /*
  511. * Unrecognized token. Return failure.
  512. */
  513. return 0;
  514. }
  515. /*****************************************************************************
  516. *
  517. * fSecondary
  518. *
  519. * Parse an expression from the expression stream, leaving the
  520. * result on the top of the expression stack.
  521. *
  522. *****************************************************************************/
  523. F STDCALL
  524. fSecondary(void)
  525. {
  526. ShiftPeopi(peopiBoe); /* Beginning-of-expression marker */
  527. while (fPrimary()) {
  528. if (fWantOp()) {
  529. if (fOpTos(0)) {
  530. if (fBinTos(0)) {
  531. Reduce();
  532. } else {
  533. return 0; /* Unary operator unexpected */
  534. }
  535. } else {
  536. return 0; /* Integer unexpected */
  537. }
  538. } else { /* Integer expected */
  539. if (fOpTos(0)) {
  540. if (fAmbTos(0)) {
  541. UnFromAmb(0); /* Disambiguify */
  542. ; /* Unary operator already shifted */
  543. } else if (fUnTos(0)) {
  544. ; /* Unary operator already shifted */
  545. } else {
  546. return 0; /* Binary operator unexpected */
  547. }
  548. } else {
  549. ; /* Integer already shifted */
  550. }
  551. }
  552. }
  553. if (fOpTos(0)) {
  554. return 0; /* Ended in partial expression */
  555. }
  556. {
  557. AT at;
  558. ShiftPeopi(peopiFlush); /* Flush out the rest of the expr */
  559. Reduce(); /* to get a single number back */
  560. Assert(peopiTos(0) == peopiFlush);
  561. at = atTos(1);
  562. Assert(peopiTos(2) == peopiBoe); /* Should be back to start */
  563. Drop(3);
  564. ShiftAt(at);
  565. }
  566. return 1;
  567. }
  568. /*****************************************************************************
  569. *
  570. * opEval
  571. *
  572. * Evaluate the first expr.
  573. *
  574. * QUIRK! AT&T m4 considers a consisting entirely of whitespace to
  575. * evaluate to zero. (Probably due to a default accumulator in the
  576. * initial state of the evaluator.) GNU considers it an error.
  577. * I side with GNU on this one.
  578. *
  579. * QUIRK! If a negative width is passed, AT&T silently treats it
  580. * as zero. GNU raises an error. I side with A&T out of laziness.
  581. *
  582. * QUIRK! If a width greater than around 8000 is passed, AT&T
  583. * silently treats it as zero. GNU uses the full value. I side
  584. * with GNU on this one.
  585. *
  586. *****************************************************************************/
  587. DeclareOp(opEval)
  588. {
  589. if (ctokArgv) {
  590. SetStaticPtokPtchCtch(&tokExpr, ptchArgv(1), ctchArgv(1));
  591. D(tokExpr.tsfl |= tsflScratch);
  592. if (fTertiary()) {
  593. PushAtRadixCtch(atTos(0), (unsigned)atTraditionalPtok(ptokArgv(2)),
  594. ctokArgv >= 3 ? atTraditionalPtok(ptokArgv(3)) :0);
  595. Drop(1);
  596. Assert(pcellCur == rgcellEstack);
  597. } else {
  598. TOK tokPre;
  599. SetStaticPtokPtchCtch(&tokPre, ptchArgv(1),
  600. ctchArgv(1) - ctchSPtok(&tokExpr));
  601. Die("Expression error at %P <<error>> %P", &tokPre, &tokExpr);
  602. }
  603. }
  604. }