2020-09-30 17:12:29 +02:00

154 lines
5.3 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*** 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 "nmake.h"
#include "nmmsg.h"
#include "proto.h"
#include "globals.h"
#include "grammar.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 NEAR
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());
}
}
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 */
}