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

348 lines
13 KiB
C

// GRAMMAR.H -- Contains grammar of NMAKE ************************************
//
// Copyright (c) 1988-1989, Microsoft Corporation. All rights reserved.
//
// Purpose:
// Module contains grammar of NMAKE and definitions used by lexer & parser
//
// Revision History:
// 08-Oct-1989 SB Added QUOTE_ and NOQ and QUO to handle OS/2 1.2 quoted names
// 31-Jul-1989 SB Added BKS, DEF and BEG to add lookahead to the lexer
// 18-May-1989 SB Added BKSLH_ definition for use by lexer's nameStates[]
// This file contains the grammar for nmake.
//
//
//
// e is the symbol epsilon
//
//
// nonterminals begin w/ capitals
//
//
// terminals begin w/ lower-case letters
//
//
// terminals: name newline newlineWhitespace semicolon colon equals string e
// doublecolon value
//
//
// Makefile -> e |
// BlankLines Makefile |
// newline name Body Makefile
//
// Body -> NameList Separator BuildInfo |
// equals value
//
// NameList -> e |
// name NameList
//
// Commands -> e |
// MoreBuildLines |
// semicolon string MoreBuildLines
//
// MoreBuildLines -> e |
// newlineWhitespace string MoreBuildLines |
// newline MoreBuildLines
//
// BlankLines -> e |
// newline BlankLines |
// newlineWhitespace BlankLines
//
// BuildInfo -> e |
// NameList Commands
//
// Separator -> colon | doublecolon
//
//
//
//
//
// note: a "string" is everything from the current input character up
// to the first newline which is not preceded by a backslash, or
// end of file (whichever comes first). a macro "value" is the
// same as a "string" with the exception that comments are stripped
// from it (a comment ending in a backslash does not cause the
// value to be continued on the next line).
// Compute FIRST() and FOLLOW() for each nonterminal in order to construct
// parse table (it'd be nice to have a simple utility to build the
// table, but it's still a pretty easy thing to do by hand).
//
//
// FIRST(Makefile) = e newline FIRST(BlankLines)
// = e newline newlineWhitespace
//
// FIRST(Body) = equals FIRST(NameList) FIRST(Separator)
// = equals name colon doublecolon
//
// FIRST(NameList) = e name
//
// FIRST(Commands) = e semicolon FIRST(BuildLine)
// = e semicolon newlineWhitespace
//
// FIRST(MoreBuildLines) = e FIRST(BuildLine) FIRST(BlankLines)
// = e newlineWhitespace newline
//
// FIRST(BlankLines) = e newline newlineWhitespace
//
// FIRST(BuildInfo) = FIRST(NameList) FIRST(Commands)
// = e name semicolon newlineWhitespace
//
// FIRST(Separator) = colon doublecolon
// ---------------------------------------------------------------
//
//
// FOLLOW(Makefile) = $
//
// FOLLOW(Body) = FIRST(Makefile) FOLLOW(Makefile)
// = newline newlineWhitespace $
//
// FOLLOW(NameList) = FIRST(Commands) FIRST(MoreBuildLines)
// colon FOLLOW(Body)
// = colon semicolon newlineWhitespace
// newline $
//
// FOLLOW(Commands) = FOLLOW(Body)
// = newline newlineWhitespace $
//
// FOLLOW(MoreBuildLines) = FOLLOW(Commands)
// = newline newlineWhitespace $
//
// FOLLOW(BlankLines) = FIRST(Body) FOLLOW(Makefile)
// = newlineWhitespace newline $
//
// FOLLOW(BuildInfo) = FOLLOW(Body)
// = newline newlineWhitespace $
//
// FOLLOW(Separator) = FIRST(BuildInfo) FOLLOW(Body)
// = name semicolon newlineWhitespace
// newline $
//
//------------------------------------------------------------------------------
//
// for building the table, I number the productions:
//
//
//
// 0. Makefile -> e
//
// 1. Makefile -> BlankLines Makefile
//
// 2. MakeFile -> newline name Body Makefile
//
// 3. Body -> NameList Separator BuildInfo
//
// 4. Body -> equals value
//
// 5. NameList -> e
//
// 6. NameList -> name NameList
//
// 7. Commands -> e
//
// 8. Commands -> MoreBuildLines
//
// 9. Commands -> semicolon string MoreBuildLines
//
// 10. MoreBuildLines -> newlineWhiteSpace string MoreBuildLines
//
// 11. MoreBuildLines -> e
//
// 12. MoreBuildLines -> newline MoreBuildLines
//
// 13. BlankLines -> e
//
// 14. BlankLines -> newline BlankLines
//
// 15. BlankLines -> newlineWhitespace BlankLines
//
// 16. BuildInfo -> e
//
// 17. BuildInfo -> NameList Commands
//
// 18. Separator -> colon
//
// 19. Separator -> doublecolon
//
//------------------------------------------------------------------------------
//
// NOTE THAT THIS GRAMMAR IS NOT LL(1) (it's really LL(2) because we need
// an extra symbol of lookahead to decide which production to use in
// a few cases)
//
//
// the resulting parse table (empty entries are error conditions):
//
//
// newline-
// White- semi- double-
// |name |newline| space | colon | colon | colon |equals |$ |
// -----------------------------------------------------------------
// A | | | | | | | | |
// Makefile | | 1,2 | 1 | | | | | 0 |
// | | | | | | | | |
// -----------------------------------------------------------------
// B | | | | | | | | |
// Blank- | | 13,14 | 13[15]| | | | | 13 |
// Lines | | | -- | | | | | |
// -----------------------------------------------------------------
// C | | | | | | | | |
// More- | | 11,12 | 10 | | | | | 11 |
// Build- | | | | | | | | |
// Lines -----------------------------------------------------------------
// D | | | | | | | | |
// Commands | | 7 | [7]8 | 9 | | | | 7 |
// | | | - | | | | | |
// -----------------------------------------------------------------
// E | | | | | | | | |
// Body | 3 | | | | 3 | | 4 | |
// | | | | | | | | |
// -----------------------------------------------------------------
// F | | | | | | | | |
// NameList | 6 | 5 | 5 | 5 | 5 | 5 | | 5 |
// | | | | | | | | |
// -----------------------------------------------------------------
// G | | | | | | | | |
// Build- | 17 | 16 |[16]17 | 17 | | | | 16 |
// Info | | | -- | | | | | |
// -----------------------------------------------------------------
// H | | | | | | | | |
// Separ- | | | | | 18 | 19 | | |
// ator | | | | | | | | |
// -----------------------------------------------------------------
//
// G2 -- always uses 17 -- anytime the user puts a line beginning w/
// whitespace immediately after a target-dependency line, it's
// a build line. Same for D2.
// IMPORTANT: IF YOU CHANGE THE VALUES OF ANY OF THE FOLLOWING
// CONSTANTS FOR TERMINAL OR NONTERMINAL SYMBOLS, YOU MUST ADJUST
// THE APPROPRIATE TABLES (AND STRING LITERALS) ACCORDINGLY.
//
// Nonterminal symbols first (these are used to index the parse table
// along the first dimension):
//
// define nonterminals . . .
#define MAKEFILE 0x00 // productions w/ 2
#define BLANKLINES 0x01 // alternatives in a
#define MOREBUILDLINES 0x02 // table entry must
#define COMMANDS 0x03 // come first (so
#define BODY 0x04 // that I can use
#define NAMELIST 0x05 // them as array
#define BUILDINFO 0x06 // subscripts when
#define SEPARATOR 0x07 // resolving the
// conflict)
#define START MAKEFILE
#define LAST_PRODUCTION SEPARATOR
// Now the terminal symbols (the 4 low bits of which are used to index
// the parse table alone 2nd dimension -- bit 5 simply distinguishes
// tokens from nonterminals in productions):
#define NAME 0x10 // TOKEN_MASK | 0
#define NEWLINE 0x11 // TOKEN_MASK | 1
#define NEWLINESPACE 0x12 // TOKEN_MASK | 2
#define SEMICOLON 0x13 // TOKEN_MASK | 3
#define COLON 0x14 // TOKEN_MASK | 4
#define DOUBLECOLON 0x15 // etc.
#define EQUALS 0x16
#define ACCEPT 0x17 // this is $
#define STRING 0x18 // no columns in table
#define VALUE 0x19 // for these two
// Error values -- these are equal to the error exit code minus 1000
// if you change them, you must change the corresponding values in
// nmmsg.txt
#define MACRO 0x20 // ERROR_MASK | 0
#define SYNTAX 0x21 // ERROR_MASK | 1
#define SEPRTR 0x22 // ERROR_MASK | 2
#define SEPEQU 0x23 // ERROR_MASK | 3
#define NAMES 0x24 // ERROR_MASK | 4
#define NOTARG 0x25 // ERROR_MASK | 5
#define LEXER 0x26 // ERROR_MASK | 6
#define PARSER 0x27 // ERROR_MASK | 7
// Parser actions -- these are indexes into the "action" function table,
// telling the parser which function to call at a certain point in
// a production
#define DONAME 0x40 // ACTION_MASK | 0
#define DONAMELIST 0x41
#define DOMACRO 0x42
#define DODEPENDS 0x43
#define DOLASTNAME 0x44
#define DOBUILDCMDS 0x45
// a few macros to simplify dealing w/ tokens:
#define TOKEN_MASK 0x10
#define ERROR_MASK 0x20
#define ACTION_MASK 0x40
#define AMBIG_MASK 0x80 // conflict in table
#define LOW_NIBBLE 0x0F
// values for alternate productions table
// (a YES in the slot for a given input token and a given nonterminal
// on top of the stack means use the next production (+1) from the
// one given in the production table)
#define YES 1
#define NO 0
// values for lexer's state machine that recognizes names
// append an underscore to distinguish these from parser's tokens
#define DEFAULT_ 0x00 // char not defined
#define COMMENT_ 0x01 // below
#define EQUALS_ 0x02
#define SEMICOLON_ 0x03
#define COLON_ 0x04
#define WHITESPACE_ 0x05 // \t and ' '
#define NEWLINE_ 0x06 // \n and EOF
#define DOLLAR_ 0x07
#define OPENPAREN_ 0x08
#define CLOSEPAREN_ 0x09
#define MACROCHAR_ 0x0A // A-Z,a-z,0-9,_
#define OPENCURLY_ 0x0B
#define CLOSECURLY_ 0x0C
#define BKSLSH_ 0x0D
#define QUOTE_ 0x0E
#define STAR_ 0x0B // only for strings:
#define SPECIAL1_ 0x0C // @ * < ?
#define SPECIAL2_ 0x0D // B F D R
#define BACKSLASH_ 0x03 // don't need semi if
// we have backslash
// (names need ; but
// strings need \)
// values for state tables -- for error values, mask off the error bit (0x20)
// to get the message number.
#define OK 0x40 // means accept token
#define BEG 0x00 // means beginning
#define DEF 0x01 // means normal name
#define BKS 0x0f // processing bkslash
#define PAR 0x20 // close paren missing
#define CHR 0x21 // bad char in macro
#define BAD 0x22 // single $ w/o macro
#define EQU 0x23 // substitution w/o =
#define NAM 0x24 // illegal macro name
#define SEQ 0x25 // subst w/o strings
#define NOQ 0x26 // no matching quote
#define QUO 0x27 // illegal " in name