146 lines
5.6 KiB
C++
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
|
||
|
}
|