windows-nt/Source/XPSP1/NT/sdktools/nmake/parser.cpp
2020-09-26 16:20:57 +08:00

146 lines
5.6 KiB
C++

// PARSER.C -- parsing routines
//
// Copyright (c) 1988-1989, Microsoft Corporation. All rights reserved.
//
// Purpose:
// This module contains the NMAKE grammar parser. It parses input and uses the
// getToken() routine to get the next token.
//
// Revision History:
// 05-Apr-1989 SB made all funcs NEAR; Reqd to make all function calls NEAR
// 17-Aug-1988 RB Clean up.
#include "precomp.h"
#pragma hdrstop
#include "table.h"
// macros that deal w/ the productions stack and the actions function table
#define topStack() (stack[top])
#define popStack() (stack[top--])
#define pushStack(A) (stack[++top] = A)
#define doAction(A) (*(actions[A & LOW_NIBBLE]))()
// parse() table-driven parser for makefile grammar
//
// arguments: init global boolean value -- TRUE if tools.ini is the
// file being parsed
//
// actions: initializes the stack (by pushing the empty-stack symbol
// and the start symbol)
// keeps track of current line (because the lexer may have
// read '\n' as a delimiter, and will thus be one line
// ahead of the parser)
// while the stack is not empty
// if the top symbol on the stack is an action
// do the action, popping the stack
// if the symbol on top of the stack now is a token
// if it's not the token we're expecting
// syntax error, halt
// else
// pop token off the stack
// if the top symbol on the stack is an action
// do the action, popping the stack
// reset curent line to lexer's current line
// get another token (use the lookahead token
// if it exists, and if it had caused the
// lexer's line count to be incremented,
// decrement our local count because we're
// still parsing the preceding line)
// else the symbol on top of the stack is a production
// find next production to do in production table
// (based on current input token and current
// production on stack)
// if the table entry is an error condition
// print appropriate error message, halt
// pop current production off stack
// if the "next production" can be one of two
// things, decide which one to use by peeking
// at the next input token and looking in the
// "useAlternate" decision table (using the last
// production and next input token as indexes)
// if the appropriate table entry is YES,
// use the next larger production from the one
// we found in the production table
// push each symbol in the production on the stack
// loop
//
// modifies: stack production stack, static to this module
// top index of current symbol at top of stack
//
// Use extreme care in modifying this code or any of the tables associated
// with it. The methods used to build the tables are described in detail
// in grammar.h and table.h. This parser is based on the predictive parser
// described on pages 186-191 of Aho & Ullman "Principles of Compiler Design."
// I have modified it to use an extra symbol of lookahead to deal w/ an
// ambiguous grammar and have added code to perform appropriate actions as
// it parses the productions.
void
parse()
{
UCHAR stackTop, token, nextToken = 0;
register unsigned n, i;
firstToken = TRUE; // global var
pushStack(ACCEPT); // init stack
pushStack(START);
currentLine = line;
token = getToken(MAXBUF,START); // get first token
while ((stackTop = topStack()) != ACCEPT) {
if (ON(stackTop,ACTION_MASK)) {
doAction(popStack());
} else if (ON(stackTop,TOKEN_MASK)) {
if (stackTop != token) {
makeError(currentLine,SYNTAX+FATAL_ERR,buf);
} else {
popStack();
#ifdef DEBUG_ALL
printf ("DEBUG: parse 1: %d\n", line);
#endif
if (ON(topStack(),ACTION_MASK)) {
doAction(popStack());
}
#ifdef DEBUG_ALL
printf ("DEBUG: parse 2: %d\n", line);
#endif
currentLine = line;
if (nextToken) { // if we already
if (*buf == '\n') --currentLine; // have a token,
token = nextToken; // use it . . .
nextToken = 0;
} else {
token = getToken(MAXBUF,topStack());
currentLine = line;
}
}
} else {
n = table[stackTop][token & LOW_NIBBLE];
#ifdef DEBUG_ALL
printf ("DEBUG: parse 3: %x %d %x %x\n", n, stackTop, token & LOW_NIBBLE, token);
#endif
if (ON(n,ERROR_MASK)) {
#ifdef DEBUG_ALL
printf ("DEBUG: parse 4: %d %s\n", line, buf);
#endif
makeError(currentLine,n+FATAL_ERR,buf);
}
popStack();
if (ON(n,AMBIG_MASK)) { // 2 possible prod
n &= LOW_NIBBLE; // only use 4 bits
if (!nextToken) { // peek to decide
nextToken = getToken(MAXBUF,stackTop);
}
n += (useAlternate[stackTop][nextToken & LOW_NIBBLE]);
}
for (i = productions[n][0]; i; --i) { // put production
pushStack(productions[n][i]); // on stack
}
} // 1st elt in prod
} // is its length
popStack(); // pop the ACCEPT off the stack
}