Source code of Windows XP (NT5)
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.

247 lines
6.8 KiB

  1. /*****************************************************************************
  2. *
  3. * xtoken.c
  4. *
  5. * Expanding tokens via macro expansion.
  6. *
  7. *****************************************************************************/
  8. #include "m4.h"
  9. /*****************************************************************************
  10. *
  11. * ptokGet
  12. *
  13. * Allocate the next available token in the argv array, possibly realloc'ing
  14. * the array as well.
  15. *
  16. *****************************************************************************/
  17. PTOK STDCALL
  18. ptokGet(void)
  19. {
  20. if (ptokTop >= ptokMax) {
  21. ITOK itok = itokTop();
  22. PTOK ptok;
  23. ctokArg += ctokGrow;
  24. ptok = pvReallocPvCb(rgtokArgv, ctokArg * sizeof(TOK));
  25. ptokTop = ptok + itok;
  26. ptokMax = ptok + ctokArg;
  27. rgtokArgv = ptok;
  28. Assert(ptokTop < ptokMax);
  29. }
  30. #ifdef DEBUG
  31. ptokTop->tsfl = 0;
  32. D(ptokTop->sig = sigUPtok);
  33. #endif
  34. return ptokTop++;
  35. }
  36. /*****************************************************************************
  37. *
  38. * PopPtok
  39. *
  40. * Free all the tokens in the token array starting at ptok.
  41. *
  42. *****************************************************************************/
  43. void STDCALL
  44. PopPtok(PTOK ptok)
  45. {
  46. Assert(ptok >= rgtokArgv && ptok < ptokTop);
  47. ptokTop = ptok;
  48. }
  49. /*****************************************************************************
  50. *
  51. * CrackleArgv
  52. *
  53. * All the arguments to a macro have been parsed, collected, and snapped.
  54. * All that's left to do is dispatch it.
  55. *
  56. * If the macro has no value, it got undefined behind our back.
  57. * Emit the macro name with any possible arguments, quoted.
  58. * In other words, pretend its expansion is ``$0ifelse($#,0,,($*))''.
  59. *
  60. * If the macro value is precisely a magic, then do the magic.
  61. *
  62. * Otherwise, perform substitution into the macro value.
  63. *
  64. *****************************************************************************/
  65. void STDCALL
  66. CrackleArgv(ARGV argv)
  67. {
  68. PMAC pmac = pmacFindPtok(ptokArgv(0));
  69. if (pmac) { /* Found a real macro */
  70. if (g_fTrace | pmac->pval->fTrace) { /* Not a typo */
  71. TraceArgv(argv);
  72. }
  73. if (ctchSPtok(&pmac->pval->tok) == 2 &&
  74. ptchPtok(&pmac->pval->tok)[0] == tchMagic) { /* Builtin */
  75. Assert(fValidMagicTch(ptchPtok(&pmac->pval->tok)[1]));
  76. rgop[ptchPtok(&pmac->pval->tok)[1]](argv);
  77. } else { /* User-level macro */
  78. PushSubstPtokArgv(&pmac->pval->tok, argv);
  79. }
  80. } else { /* Macro vanished behind our back */
  81. /* SOMEDAY -- DefCracklePtok */ /* not even quoted! */
  82. PushPtok(ptokArgv(0)); /* Just dump its name */
  83. }
  84. }
  85. /*****************************************************************************
  86. *
  87. * argvParsePtok
  88. *
  89. * Parse a macro and its arguments, leaving everything unsnapped.
  90. *
  91. * Entry:
  92. *
  93. * ptok -> token that names the macro
  94. *
  95. * Returns:
  96. * argv = argument vector cookie
  97. *
  98. *****************************************************************************/
  99. ARGV STDCALL
  100. argvParsePtok(PTOK ptok)
  101. {
  102. ITOK itok;
  103. ARGV argv;
  104. ptokGet(); /* ctok */
  105. itok = itokTop(); /* Unsnap it in case it grows */
  106. *ptokGet() = *ptok; /* $0 */
  107. if (tchPeek() == tchLpar) {
  108. TOK tok;
  109. tchGet(); /* Eat the lparen */
  110. do { /* Collect arguments */
  111. int iDepth;
  112. /*
  113. * Eat leading whitespace. Note that this is *not*
  114. * via expansion. Only literal leading whitespace
  115. * is eaten.
  116. */
  117. #ifdef fWhiteTch
  118. #error fWhiteTch cannot be a macro
  119. #endif
  120. while (fWhiteTch(tchPeek())) {
  121. tchGet();
  122. }
  123. /*
  124. * If the argv buffer moves, ptokTop will move with it,
  125. * so it's safe to read directly into it.
  126. */
  127. OpenArgPtok(ptokGet());
  128. D(ptokTop[-1].tsfl |= tsflScratch);
  129. /*
  130. * The loop is complicated by the need to maintain
  131. * proper parenthesis nesting during argument collection.
  132. */
  133. iDepth = 0;
  134. for (;;) {
  135. TYP typ = typXtokPtok(&tok);
  136. /* SOMEDAY -- Assert the hold buffer and stuff */
  137. if (typ == typPunc) {
  138. if (ptchPtok(&tok)[0] == tchLpar) {
  139. ++iDepth;
  140. } else if (ptchPtok(&tok)[0] == tchRpar) {
  141. if (--iDepth < 0) {
  142. break; /* End of argument */
  143. }
  144. } else if (ptchPtok(&tok)[0] == tchComma && iDepth == 0) {
  145. break; /* End of argument */
  146. }
  147. }
  148. DesnapArg();
  149. }
  150. DesnapArg();
  151. CloseArgPtok(ptokTop-1); /* $n */
  152. EatTailUPtokCtch(ptokTop-1, 1); /* That comma doesn't count */
  153. } while (ptchPtok(&tok)[0] == tchComma);
  154. }
  155. argv = rgtokArgv + itok; /* Hooray, we have an argv! */
  156. SetArgvCtok(itokTop() - itok - 1); /* $# (ctokArgv uses argv) */
  157. OpenArgPtok(ptokGet()); /* Create extra null arg */
  158. CloseArgPtok(ptokTop-1); /* SOMEDAY - could be better */
  159. return argv;
  160. }
  161. /*****************************************************************************
  162. *
  163. * XmacPtok
  164. *
  165. * Parse and expand a macro, pushing the expansion back onto
  166. * the input stream.
  167. *
  168. * Entry:
  169. *
  170. * ptok -> token that names the macro
  171. *
  172. * Exit:
  173. * None
  174. *
  175. *****************************************************************************/
  176. void STDCALL
  177. XmacPtok(PTOK ptok)
  178. {
  179. ITOK itok;
  180. ARGV argv;
  181. UnsnapArgPtok(ptok); /* Unsnap it because it's gonna move */
  182. argv = argvParsePtok(ptok); /* Argv is not yet snapped */
  183. for (itok = 0; itok <= ctokArgv + 1; itok++) { /* $0 to $(n+1) */
  184. SnapArgPtok(ptokArgv(itok)); /* Snap the args */
  185. }
  186. CrackleArgv(argv); /* Dispatch the macro */
  187. PopArgPtok(ptokArgv(0));
  188. PopPtok(ptokArgv(-1)); /* Pop off the args */
  189. /* Part of this nutritious breakfast */
  190. }
  191. /*****************************************************************************
  192. *
  193. * XtokPtok
  194. *
  195. * Read and expand tokens until something unexpandable comes back,
  196. * which is returned unsnapped.
  197. *
  198. *****************************************************************************/
  199. TYP STDCALL
  200. typXtokPtok(PTOK ptok)
  201. {
  202. TYP typ;
  203. /*
  204. * While the next token is a macro, expand it.
  205. */
  206. while ( (typ = typGetPtok(ptok)) == typId && pmacFindPtok(ptok)) {
  207. Gc();
  208. XmacPtok(ptok);
  209. Gc();
  210. }
  211. return typ;
  212. }