windows-nt/Source/XPSP1/NT/sdktools/mc/mcparse.c
2020-09-26 16:20:57 +08:00

772 lines
29 KiB
C

/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
mcparse.c
Abstract:
This file contains the parse logic for the Win32 Message Compiler (MC)
Author:
Steve Wood (stevewo) 22-Aug-1991
Revision History:
--*/
#include "mc.h"
WCHAR * wszMessageType = L"DWORD"; // Init to a known state
BOOL
McParseFile( void )
{
unsigned int t;
BOOL FirstMessageDefinition = TRUE;
PNAME_INFO p;
if (!McOpenInputFile()) {
fprintf( stderr, "MC: Unable to open %s for input\n", MessageFileName );
return( FALSE );
}
fprintf( stderr, "MC: Compiling %s\n", MessageFileName );
while ((t = McGetToken( TRUE )) != MCTOK_END_OF_FILE) {
switch (t) {
case MCTOK_MSGIDTYPE_KEYWORD:
if ((t = McGetToken( FALSE )) == MCTOK_EQUAL) {
if ((t = McGetToken( FALSE )) == MCTOK_NAME) {
wszMessageType = MessageIdTypeName = McMakeString( TokenCharValue );
} else {
McInputErrorW( L"Symbol name must follow %s=", TRUE, TokenKeyword->Name );
return( FALSE );
}
} else {
McInputErrorW( L"Equal sign must follow %s", TRUE, TokenKeyword->Name );
return( FALSE );
}
break;
case MCTOK_MSGTYPEDEF_KEYWORD:
if ((t = McGetToken( FALSE )) == MCTOK_EQUAL) {
if ((t = McGetToken( FALSE )) == MCTOK_NAME) {
MessageIdTypeMacro = McMakeString( TokenCharValue );
} else {
McInputErrorW( L"Symbol name must follow %s=", TRUE, TokenKeyword->Name );
return( FALSE );
}
} else {
McInputErrorW( L"Equal sign must follow %s", TRUE, TokenKeyword->Name );
return( FALSE );
}
break;
case MCTOK_OUTBASE_KEYWORD:
if ((t = McGetToken( FALSE )) == MCTOK_EQUAL) {
if ((t = McGetToken( FALSE )) == MCTOK_NUMBER) {
if (TokenNumericValue == 16) {
GenerateDecimalMessageValues = FALSE;
} else if (TokenNumericValue == 10) {
GenerateDecimalMessageValues = TRUE;
} else {
McInputErrorW( L"Illegal value for %s=", TRUE, TokenKeyword->Name );
}
} else {
McInputErrorW( L"Number must follow %s=", TRUE, TokenKeyword->Name );
return( FALSE );
}
} else {
McInputErrorW( L"Equal sign must follow %s", TRUE, TokenKeyword->Name );
return( FALSE );
}
break;
case MCTOK_SEVNAMES_KEYWORD:
if ((t = McGetToken( FALSE )) == MCTOK_EQUAL) {
if ((t = McGetToken( FALSE )) == MCTOK_LEFT_PAREN) {
if (!McParseNameList( &SeverityNames, FALSE, 0x3L )) {
return( FALSE );
}
} else {
McInputErrorW( L"Left parenthesis name must follow %s=", TRUE, TokenKeyword->Name );
return( FALSE );
}
} else {
McInputErrorW( L"Equal sign must follow %s", TRUE, TokenKeyword->Name );
return( FALSE );
}
break;
case MCTOK_FACILITYNAMES_KEYWORD:
if ((t = McGetToken( FALSE )) == MCTOK_EQUAL) {
if ((t = McGetToken( FALSE )) == MCTOK_LEFT_PAREN) {
if (!McParseNameList( &FacilityNames, FALSE, 0xFFFL )) {
return( FALSE );
}
} else {
McInputErrorW( L"Left parenthesis name must follow %s=", TRUE, TokenKeyword->Name );
return( FALSE );
}
} else {
McInputErrorW( L"Equal sign must follow %s", TRUE, TokenKeyword->Name );
return( FALSE );
}
break;
case MCTOK_LANGNAMES_KEYWORD:
if ((t = McGetToken( FALSE )) == MCTOK_EQUAL) {
if ((t = McGetToken( FALSE )) == MCTOK_LEFT_PAREN) {
if (!McParseNameList( &LanguageNames, TRUE, 0xFFFFL )) {
return( FALSE );
}
} else {
McInputErrorW( L"Left parenthesis name must follow %s=", TRUE, TokenKeyword->Name );
return( FALSE );
}
} else {
McInputErrorW( L"Equal sign must follow %s", TRUE, TokenKeyword->Name );
return( FALSE );
}
break;
case MCTOK_MESSAGEID_KEYWORD:
McUnGetToken();
if (FirstMessageDefinition) {
FirstMessageDefinition = FALSE;
McFlushComments();
if (OleOutput) {
fputs(
"//\r\n"
"// Values are 32 bit values layed out as follows:\r\n"
"//\r\n"
"// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1\r\n"
"// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0\r\n"
"// +-+-+-+-+-+---------------------+-------------------------------+\r\n"
"// |S|R|C|N|r| Facility | Code |\r\n"
"// +-+-+-+-+-+---------------------+-------------------------------+\r\n"
"//\r\n"
"// where\r\n"
"//\r\n"
"// S - Severity - indicates success/fail\r\n"
"//\r\n"
"// 0 - Success\r\n"
"// 1 - Fail (COERROR)\r\n"
"//\r\n"
"// R - reserved portion of the facility code, corresponds to NT's\r\n"
"// second severity bit.\r\n"
"//\r\n"
"// C - reserved portion of the facility code, corresponds to NT's\r\n"
"// C field.\r\n"
"//\r\n"
"// N - reserved portion of the facility code. Used to indicate a\r\n"
"// mapped NT status value.\r\n"
"//\r\n"
"// r - reserved portion of the facility code. Reserved for internal\r\n"
"// use. Used to indicate HRESULT values that are not status\r\n"
"// values, but are instead message ids for display strings.\r\n"
"//\r\n"
"// Facility - is the facility code\r\n"
"//\r\n"
"// Code - is the facility's status code\r\n"
"//\r\n",
HeaderFile );
} else {
fputs(
"//\r\n"
"// Values are 32 bit values layed out as follows:\r\n"
"//\r\n"
"// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1\r\n"
"// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0\r\n"
"// +---+-+-+-----------------------+-------------------------------+\r\n"
"// |Sev|C|R| Facility | Code |\r\n"
"// +---+-+-+-----------------------+-------------------------------+\r\n"
"//\r\n"
"// where\r\n"
"//\r\n"
"// Sev - is the severity code\r\n"
"//\r\n"
"// 00 - Success\r\n"
"// 01 - Informational\r\n"
"// 10 - Warning\r\n"
"// 11 - Error\r\n"
"//\r\n"
"// C - is the Customer code flag\r\n"
"//\r\n"
"// R - is a reserved bit\r\n"
"//\r\n"
"// Facility - is the facility code\r\n"
"//\r\n"
"// Code - is the facility's status code\r\n"
"//\r\n",
HeaderFile );
}
fputs(
"//\r\n"
"// Define the facility codes\r\n"
"//\r\n",
HeaderFile );
p = FacilityNames;
while( p ) {
if (p->Value) {
fprintf( HeaderFile, GenerateDecimalSevAndFacValues ?
"#define %-32ws %ld\r\n" :
"#define %-32ws 0x%lX\r\n",
p->Value, p->Id
);
}
p = p->Next;
}
fputs(
"\r\n"
"\r\n"
"//\r\n"
"// Define the severity codes\r\n"
"//\r\n",
HeaderFile );
p = SeverityNames;
while( p ) {
if (p->Value) {
fprintf( HeaderFile, GenerateDecimalSevAndFacValues ?
"#define %-32ws %ld\r\n" :
"#define %-32ws 0x%lX\r\n",
p->Value, p->Id
);
}
p = p->Next;
}
fputs(
"\r\n"
"\r\n",
HeaderFile );
if (GenerateDebugFile) {
fputs(
"//\n"
"// This file maps message Id values in to a text string that contains\n"
"// the symbolic name used for the message Id. Useful for debugging\n"
"// output.\n"
"//\n\n"
"struct {\n",
DebugFile );
fprintf(
DebugFile,
" %ws MessageId;\n"
" char *SymbolicName;\n"
"} %sSymbolicNames[] = {\n",
wszMessageType,
MessageFileNameNoExt );
}
}
if (!McParseMessageDefinition()) {
return( FALSE );
}
break;
default:
McInputErrorW( L"Invalid message file token - '%s'", TRUE, TokenCharValue );
return( FALSE );
break;
}
}
if (GenerateDebugFile) {
fprintf( DebugFile, " (%ws) 0xFFFFFFFF, NULL\n};\n", wszMessageType );
}
McFlushComments();
return( TRUE );
}
BOOL
McParseMessageDefinition( void )
{
unsigned int t;
PMESSAGE_INFO MessageInfo;
BOOL MessageIdSeen;
PMESSAGE_INFO MessageInfoTemp, *pp;
McFlushComments();
MessageInfo = malloc( sizeof( *MessageInfo ) );
if (!MessageInfo) {
McInputErrorA( "Out of memory parsing memory definitions.", TRUE, NULL );
return( FALSE );
}
MessageInfo->Next = NULL;
MessageInfo->Id = 0;
MessageInfo->Method = MSG_PLUS_ONE;
MessageInfo->SymbolicName = NULL;
MessageInfo->EndOfLineComment = NULL;
MessageInfo->MessageText = NULL;
MessageIdSeen = FALSE;
while ((t = McGetToken( TRUE )) != MCTOK_END_OF_FILE) {
switch (t) {
case MCTOK_MESSAGEID_KEYWORD:
if (MessageIdSeen) {
McInputErrorA( "Invalid message definition - text missing.", TRUE, NULL );
return( FALSE );
}
MessageIdSeen = TRUE;
if ((t = McGetToken( FALSE )) == MCTOK_EQUAL) {
if ((t = McGetToken( FALSE )) == MCTOK_NUMBER) {
MessageInfo->Id = TokenNumericValue;
MessageInfo->Method = MSG_ABSOLUTE;
} else
if (t == MCTOK_PLUS) {
if ((t = McGetToken( FALSE )) == MCTOK_NUMBER) {
MessageInfo->Id = TokenNumericValue;
MessageInfo->Method = MSG_PLUS_VALUE;
} else {
McInputErrorW( L"Number must follow %s=+", TRUE, TokenKeyword->Name );
return( FALSE );
}
} else {
McUnGetToken();
}
} else {
McInputErrorW( L"Equal sign must follow %s", TRUE, TokenKeyword->Name );
return( FALSE );
}
break;
case MCTOK_SEVERITY_KEYWORD:
if ((t = McGetToken( FALSE )) == MCTOK_EQUAL) {
if (!McParseName( SeverityNames, &CurrentSeverityName )) {
return( FALSE );
}
} else {
McInputErrorW( L"Equal sign must follow %s", TRUE, TokenKeyword->Name );
return( FALSE );
}
break;
case MCTOK_FACILITY_KEYWORD:
if ((t = McGetToken( FALSE )) == MCTOK_EQUAL) {
if (!McParseName( FacilityNames, &CurrentFacilityName )) {
return( FALSE );
}
} else {
McInputErrorW( L"Equal sign must follow %s", TRUE, TokenKeyword->Name );
return( FALSE );
}
break;
case MCTOK_SYMBOLNAME_KEYWORD:
if ((t = McGetToken( FALSE )) == MCTOK_EQUAL) {
if ((t = McGetToken( FALSE )) == MCTOK_NAME) {
MessageInfo->SymbolicName = McMakeString( TokenCharValue );
} else {
McInputErrorW( L"Symbol name must follow %s=+", TRUE, TokenKeyword->Name );
return( FALSE );
}
} else {
McInputErrorW( L"Equal sign must follow %s", TRUE, TokenKeyword->Name );
return( FALSE );
}
break;
case MCTOK_END_OF_LINE_COMMENT:
MessageInfo->EndOfLineComment = McMakeString( TokenCharValue );
break;
case MCTOK_LANGUAGE_KEYWORD:
McUnGetToken();
if (MessageInfo->Method == MSG_PLUS_ONE) {
MessageInfo->Id = CurrentFacilityName->LastId + 1;
} else
if (MessageInfo->Method == MSG_PLUS_VALUE) {
MessageInfo->Id = CurrentFacilityName->LastId + MessageInfo->Id;
}
if (MessageInfo->Id > 0xFFFFL) {
McInputErrorA( "Message Id value (%lx) too large", TRUE, (PVOID)UlongToPtr(MessageInfo->Id) );
return( FALSE );
}
MessageInfo->Id |= (CurrentSeverityName->Id << 30) |
CustomerMsgIdBit |
(CurrentFacilityName->Id << 16);
fprintf( HeaderFile, "//\r\n" );
if (MessageInfo->SymbolicName) {
fprintf( HeaderFile, "// MessageId: %ws\r\n",
MessageInfo->SymbolicName
);
} else {
fprintf( HeaderFile, "// MessageId: 0x%08lXL (No symbolic name defined)\r\n",
MessageInfo->Id
);
}
fprintf( HeaderFile, "//\r\n" );
fprintf( HeaderFile, "// MessageText:\r\n" );
fprintf( HeaderFile, "//\r\n" );
if (McParseMessageText( MessageInfo )) {
fprintf( HeaderFile, "//\r\n" );
if (MessageInfo->SymbolicName) {
if (GenerateDebugFile) {
fprintf( DebugFile, " (%ws) %ws, \"%ws\",\n",
wszMessageType,
MessageInfo->SymbolicName,
MessageInfo->SymbolicName
);
}
if (MessageIdTypeMacro != NULL) {
fprintf( HeaderFile, GenerateDecimalMessageValues ?
"#define %-32ws %ws(%ldL)" :
"#define %-32ws %ws(0x%08lXL)",
MessageInfo->SymbolicName,
MessageIdTypeMacro,
MessageInfo->Id
);
} else {
if (MessageIdTypeName != NULL) {
fprintf( HeaderFile, GenerateDecimalMessageValues ?
"#define %-32ws ((%ws)%ldL)" :
"#define %-32ws ((%ws)0x%08lXL)",
MessageInfo->SymbolicName,
wszMessageType,
MessageInfo->Id
);
} else {
fprintf( HeaderFile, GenerateDecimalMessageValues ?
"#define %-32ws %ldL" :
"#define %-32ws 0x%08lXL",
MessageInfo->SymbolicName,
MessageInfo->Id
);
}
}
}
if (MessageInfo->EndOfLineComment) {
fprintf( HeaderFile, " %ws", MessageInfo->EndOfLineComment );
} else {
fprintf( HeaderFile, "\r\n" );
}
fprintf( HeaderFile, "\r\n" );
//
// Scan the existing messages to see if this message
// exists in the message file.
//
// If it does, generate and error for the user. Otherwise
// insert new message in list in ascending Id order.
//
pp = &Messages;
while (MessageInfoTemp = *pp) {
if (MessageInfoTemp->Id == MessageInfo->Id) {
if (MessageInfo->SymbolicName && MessageInfoTemp->SymbolicName) {
fprintf( stderr,
"%s(%d) : error : Duplicate message ID - 0x%x (%ws and %ws)\n",
MessageFileName,
MessageFileLineNumber,
MessageInfo->Id,
MessageInfoTemp->SymbolicName,
MessageInfo->SymbolicName
);
} else {
McInputErrorA( "Duplicate message ID - 0x%lx", TRUE, (PVOID)UlongToPtr(MessageInfo->Id) );
}
} else {
if (MessageInfoTemp->Id > MessageInfo->Id) {
break;
}
}
pp = &MessageInfoTemp->Next;
}
MessageInfo->Next = *pp;
*pp = MessageInfo;
CurrentMessage = MessageInfo;
CurrentFacilityName->LastId = MessageInfo->Id & 0xFFFF;
return( TRUE );
} else {
return( FALSE );
}
default:
McInputErrorW( L"Invalid message definition token - '%s'", TRUE, TokenCharValue );
return( FALSE );
}
}
return( FALSE );
}
WCHAR MessageTextBuffer[ 32767 ];
BOOL
McParseMessageText(
PMESSAGE_INFO MessageInfo
)
{
PLANGUAGE_INFO MessageText, *pp;
WCHAR *src, *dst;
unsigned int t, n;
BOOL FirstLanguageProcessed;
pp = &MessageInfo->MessageText;
FirstLanguageProcessed = FALSE;
while ((t = McGetToken( TRUE )) != MCTOK_END_OF_FILE) {
if (t == MCTOK_LANGUAGE_KEYWORD) {
if ((t = McGetToken( FALSE )) == MCTOK_EQUAL) {
if (!McParseName( LanguageNames, &CurrentLanguageName )) {
return( FALSE );
}
GetCPInfo(CurrentLanguageName->CodePage, &CPInfo);
} else {
McInputErrorW( L"Equal sign must follow %s", TRUE, TokenKeyword->Name );
return( FALSE );
}
} else {
McUnGetToken();
break;
}
MessageText = malloc( sizeof( *MessageText ) );
MessageText->Next = NULL;
MessageText->Id = CurrentLanguageName->Id;
MessageText->Length = 0;
MessageText->Text = NULL;
dst = MessageTextBuffer;
*MessageTextBuffer = L'\0';
while (src = McGetLine()) {
n = wcslen( MessageTextBuffer );
// If the message buffer is complete, see if this is a '.' record.
if (((n == 0) || *(MessageTextBuffer+n-1) == L'\n') &&
!wcscmp( src, L".\r\n" )) {
if (MessageText->Length == 0) {
if (MessageInfo->SymbolicName) {
wcscpy( dst, MessageInfo->SymbolicName );
} else {
swprintf( dst, L"No symbolic name defined for0x%08lXL" );
}
wcscat( dst, L"\r\n" );
if (!FirstLanguageProcessed) {
fprintf( HeaderFile, "// %ws", dst );
}
n = wcslen( dst );
dst += n;
MessageText->Length += n;
}
McSkipLine();
break;
}
else if (!_wcsnicmp( src, L"LanguageId=", 11 ) ||
!_wcsnicmp( src, L"MessageId=", 10 )) {
McInputErrorA( "Unterminated message definition", TRUE, NULL );
return( FALSE );
}
if (!FirstLanguageProcessed) {
// To write DBCS comments to the header file.
//
// fprintf() does not work correctly with Unicode
// to write DBCS characters. Convert Unicode to
// MultiByte and use the Ansi string instead...
char * pch;
int len = WideCharToMultiByte(CurrentLanguageName->CodePage,
0, // No flags
src, // The buffer to convert
-1, // It's zero terminated
NULL,
0, // Tell us how much to allocate
NULL, // No default char
NULL); // No used default char
pch = malloc(len + 1);
WideCharToMultiByte(CurrentLanguageName->CodePage,
0,
src,
-1,
pch, // The buffer to fill in
len, // How big it is
NULL,
NULL);
fprintf( HeaderFile, "// %s", pch );
free(pch);
}
n = wcslen( src );
if (MessageText->Length + n > sizeof( MessageTextBuffer )) {
McInputErrorA( "Message text too long (> %ld)", TRUE,
(PVOID)UlongToPtr((ULONG)sizeof( MessageTextBuffer ))
);
return( FALSE );
}
wcscpy( dst, src );
dst += n;
MessageText->Length += n;
if (MaxMessageLength != 0 && (MessageText->Length > (ULONG)MaxMessageLength)) {
McInputErrorA( "Message text larger than size specified by -m %d",
TRUE,
(PVOID)IntToPtr(MaxMessageLength)
);
}
}
*dst = L'\0';
// Add NULL terminator if requested
if (NULLTerminate)
{
MessageText->Length -= 2;
MessageTextBuffer[MessageText->Length] = L'\0';
}
n = (((USHORT)MessageText->Length) + 1) * sizeof( WCHAR );
MessageText->Text = malloc( n );
memcpy( MessageText->Text, MessageTextBuffer, n );
if (UnicodeOutput)
MessageText->Length = n - sizeof( WCHAR );
else
MessageText->Length = WideCharToMultiByte(
CurrentLanguageName->CodePage,
0, MessageTextBuffer, MessageText->Length,
NULL, 0, NULL, NULL );
*pp = MessageText;
pp = &MessageText->Next;
FirstLanguageProcessed = TRUE;
}
return( TRUE );
}
BOOL
McParseNameList(
PNAME_INFO *NameListHead,
BOOL ValueRequired,
ULONG MaximumValue
)
{
unsigned int t;
PNAME_INFO p = NULL;
WCHAR *Name;
ULONG Id;
PVOID Value;
Name = NULL;
Id = 0;
while ((t = McGetToken( FALSE )) != MCTOK_END_OF_FILE) {
if (t == MCTOK_RIGHT_PAREN) {
return( TRUE );
}
if (t == MCTOK_NAME) {
Name = McMakeString( TokenCharValue );
Id = 0;
Value = NULL;
if ((t = McGetToken( FALSE )) == MCTOK_EQUAL) {
if ((t = McGetToken( FALSE )) == MCTOK_NUMBER) {
Id = TokenNumericValue;
if ((t = McGetToken( FALSE )) == MCTOK_COLON) {
if ((t = McGetToken( FALSE )) == MCTOK_NAME) {
Value = McMakeString( TokenCharValue );
} else {
McInputErrorA( "File name must follow =%ld:", TRUE, (PVOID)UlongToPtr(Id) );
return( FALSE );
}
} else {
if (ValueRequired) {
McInputErrorA( "Colon must follow =%ld", TRUE, (PVOID)UlongToPtr(Id) );
return( FALSE );
}
McUnGetToken();
}
} else {
McInputErrorW( L"Number must follow %s=", TRUE, Name );
return( FALSE );
}
} else {
McInputErrorW( L"Equal sign name must follow %s", TRUE, Name );
return( FALSE );
}
if (Id > MaximumValue) {
McInputErrorA( "Value is too large (> %lx)", TRUE, (PVOID)UlongToPtr(MaximumValue) );
return( FALSE );
}
p = McAddName( NameListHead, Name, Id, Value );
free( Name );
}
else if (t == MCTOK_COLON && p) {
if ((t = McGetToken( FALSE )) == MCTOK_NUMBER) {
p->CodePage = (USHORT)TokenNumericValue;
if (!IsValidCodePage(TokenNumericValue)) {
McInputErrorW( L"CodePage %d is invalid", TRUE, (PVOID)UlongToPtr(TokenNumericValue) );
return( FALSE );
}
if (VerboseOutput) {
fprintf( stderr, "Using CodePage %d for Language %04x\n", TokenNumericValue, Id);
}
} else {
McInputErrorW( L"CodePage must follow %s=:", TRUE, Name );
return( FALSE );
}
}
}
return( FALSE );
}
BOOL
McParseName(
PNAME_INFO NameListHead,
PNAME_INFO *Result
)
{
unsigned int t;
PNAME_INFO p;
if ((t = McGetToken( FALSE )) == MCTOK_NAME) {
p = McFindName( NameListHead, TokenCharValue );
if (p != NULL) {
*Result = p;
return( TRUE );
} else {
McInputErrorW( L"Invalid name - %s", TRUE, TokenCharValue );
}
} else {
McInputErrorW( L"Missing name after %s=", TRUE, TokenKeyword->Name );
}
return( FALSE );
}