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.

145 lines
5.6 KiB

  1. // PARSER.C -- parsing routines
  2. //
  3. // Copyright (c) 1988-1989, Microsoft Corporation. All rights reserved.
  4. //
  5. // Purpose:
  6. // This module contains the NMAKE grammar parser. It parses input and uses the
  7. // getToken() routine to get the next token.
  8. //
  9. // Revision History:
  10. // 05-Apr-1989 SB made all funcs NEAR; Reqd to make all function calls NEAR
  11. // 17-Aug-1988 RB Clean up.
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. #include "table.h"
  15. // macros that deal w/ the productions stack and the actions function table
  16. #define topStack() (stack[top])
  17. #define popStack() (stack[top--])
  18. #define pushStack(A) (stack[++top] = A)
  19. #define doAction(A) (*(actions[A & LOW_NIBBLE]))()
  20. // parse() table-driven parser for makefile grammar
  21. //
  22. // arguments: init global boolean value -- TRUE if tools.ini is the
  23. // file being parsed
  24. //
  25. // actions: initializes the stack (by pushing the empty-stack symbol
  26. // and the start symbol)
  27. // keeps track of current line (because the lexer may have
  28. // read '\n' as a delimiter, and will thus be one line
  29. // ahead of the parser)
  30. // while the stack is not empty
  31. // if the top symbol on the stack is an action
  32. // do the action, popping the stack
  33. // if the symbol on top of the stack now is a token
  34. // if it's not the token we're expecting
  35. // syntax error, halt
  36. // else
  37. // pop token off the stack
  38. // if the top symbol on the stack is an action
  39. // do the action, popping the stack
  40. // reset curent line to lexer's current line
  41. // get another token (use the lookahead token
  42. // if it exists, and if it had caused the
  43. // lexer's line count to be incremented,
  44. // decrement our local count because we're
  45. // still parsing the preceding line)
  46. // else the symbol on top of the stack is a production
  47. // find next production to do in production table
  48. // (based on current input token and current
  49. // production on stack)
  50. // if the table entry is an error condition
  51. // print appropriate error message, halt
  52. // pop current production off stack
  53. // if the "next production" can be one of two
  54. // things, decide which one to use by peeking
  55. // at the next input token and looking in the
  56. // "useAlternate" decision table (using the last
  57. // production and next input token as indexes)
  58. // if the appropriate table entry is YES,
  59. // use the next larger production from the one
  60. // we found in the production table
  61. // push each symbol in the production on the stack
  62. // loop
  63. //
  64. // modifies: stack production stack, static to this module
  65. // top index of current symbol at top of stack
  66. //
  67. // Use extreme care in modifying this code or any of the tables associated
  68. // with it. The methods used to build the tables are described in detail
  69. // in grammar.h and table.h. This parser is based on the predictive parser
  70. // described on pages 186-191 of Aho & Ullman "Principles of Compiler Design."
  71. // I have modified it to use an extra symbol of lookahead to deal w/ an
  72. // ambiguous grammar and have added code to perform appropriate actions as
  73. // it parses the productions.
  74. void
  75. parse()
  76. {
  77. UCHAR stackTop, token, nextToken = 0;
  78. register unsigned n, i;
  79. firstToken = TRUE; // global var
  80. pushStack(ACCEPT); // init stack
  81. pushStack(START);
  82. currentLine = line;
  83. token = getToken(MAXBUF,START); // get first token
  84. while ((stackTop = topStack()) != ACCEPT) {
  85. if (ON(stackTop,ACTION_MASK)) {
  86. doAction(popStack());
  87. } else if (ON(stackTop,TOKEN_MASK)) {
  88. if (stackTop != token) {
  89. makeError(currentLine,SYNTAX+FATAL_ERR,buf);
  90. } else {
  91. popStack();
  92. #ifdef DEBUG_ALL
  93. printf ("DEBUG: parse 1: %d\n", line);
  94. #endif
  95. if (ON(topStack(),ACTION_MASK)) {
  96. doAction(popStack());
  97. }
  98. #ifdef DEBUG_ALL
  99. printf ("DEBUG: parse 2: %d\n", line);
  100. #endif
  101. currentLine = line;
  102. if (nextToken) { // if we already
  103. if (*buf == '\n') --currentLine; // have a token,
  104. token = nextToken; // use it . . .
  105. nextToken = 0;
  106. } else {
  107. token = getToken(MAXBUF,topStack());
  108. currentLine = line;
  109. }
  110. }
  111. } else {
  112. n = table[stackTop][token & LOW_NIBBLE];
  113. #ifdef DEBUG_ALL
  114. printf ("DEBUG: parse 3: %x %d %x %x\n", n, stackTop, token & LOW_NIBBLE, token);
  115. #endif
  116. if (ON(n,ERROR_MASK)) {
  117. #ifdef DEBUG_ALL
  118. printf ("DEBUG: parse 4: %d %s\n", line, buf);
  119. #endif
  120. makeError(currentLine,n+FATAL_ERR,buf);
  121. }
  122. popStack();
  123. if (ON(n,AMBIG_MASK)) { // 2 possible prod
  124. n &= LOW_NIBBLE; // only use 4 bits
  125. if (!nextToken) { // peek to decide
  126. nextToken = getToken(MAXBUF,stackTop);
  127. }
  128. n += (useAlternate[stackTop][nextToken & LOW_NIBBLE]);
  129. }
  130. for (i = productions[n][0]; i; --i) { // put production
  131. pushStack(productions[n][i]); // on stack
  132. }
  133. } // 1st elt in prod
  134. } // is its length
  135. popStack(); // pop the ACCEPT off the stack
  136. }