MCPARSE.C

/*++ 

Copyright 1991-1998 Microsoft Corporation

Module Name:

mcparse.c

Abstract:

This file contains the parse logic for the Win32 Message Compiler (MC)


--*/

#include "mc.h"

BOOLEAN
McParseFile( void )
{
unsigned int t;
BOOLEAN 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) {
MessageIdTypeName = McMakeString( TokenCharValue );
}
else {
McInputError( "Symbol name must follow %s=", TRUE, TokenKeyword->Name );
return( FALSE );
}
}
else {
McInputError( "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 {
McInputError( "Left parenthesis name must follow %s=", TRUE, TokenKeyword->Name );
return( FALSE );
}
}
else {
McInputError( "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 {
McInputError( "Left parenthesis name must follow %s=", TRUE, TokenKeyword->Name );
return( FALSE );
}
}
else {
McInputError( "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 {
McInputError( "Left parenthesis name must follow %s=", TRUE, TokenKeyword->Name );
return( FALSE );
}
}
else {
McInputError( "Equal sign must follow %s", TRUE, TokenKeyword->Name );
return( FALSE );
}
break;

case MCTOK_MESSAGEID_KEYWORD:
McUnGetToken();
if (FirstMessageDefinition) {
FirstMessageDefinition = FALSE;
McFlushComments();
fprintf( HeaderFile, "//\r\n" );
fprintf( HeaderFile, "// Values are 32 bit values layed out as follows:\r\n" );
fprintf( HeaderFile, "//\r\n" );
fprintf( HeaderFile, "// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1\r\n" );
fprintf( HeaderFile, "// 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" );
fprintf( HeaderFile, "// +---+-+-+-----------------------+-------------------------------+\r\n" );
fprintf( HeaderFile, "// |Sev|C|R| Facility | Code |\r\n" );
fprintf( HeaderFile, "// +---+-+-+-----------------------+-------------------------------+\r\n" );
fprintf( HeaderFile, "//\r\n" );
fprintf( HeaderFile, "// where\r\n" );
fprintf( HeaderFile, "//\r\n" );
fprintf( HeaderFile, "// Sev - is the severity code\r\n" );
fprintf( HeaderFile, "//\r\n" );
fprintf( HeaderFile, "// 00 - Success\r\n" );
fprintf( HeaderFile, "// 01 - Informational\r\n" );
fprintf( HeaderFile, "// 10 - Warning\r\n" );
fprintf( HeaderFile, "// 11 - Error\r\n" );
fprintf( HeaderFile, "//\r\n" );
fprintf( HeaderFile, "// C - is the Customer code flag\r\n" );
fprintf( HeaderFile, "//\r\n" );
fprintf( HeaderFile, "// R - is a reserved bit\r\n" );
fprintf( HeaderFile, "//\r\n" );
fprintf( HeaderFile, "// Facility - is the facility code\r\n" );
fprintf( HeaderFile, "//\r\n" );
fprintf( HeaderFile, "// Code - is the facility's status code\r\n" );
fprintf( HeaderFile, "//\r\n" );

fprintf( HeaderFile, "//\r\n" );
fprintf( HeaderFile, "// Define the facility codes\r\n" );
fprintf( HeaderFile, "//\r\n" );
p = FacilityNames;
while( p ) {
if (p->Value) {
fprintf( HeaderFile, GenerateDecimalValues ?
"#define %-32s %ld\r\n" :
"#define %-32s 0x%lX\r\n",
p->Value, p->Id
);
}

p = p->Next;
}
fprintf( HeaderFile, "\r\n" );
fprintf( HeaderFile, "\r\n" );

fprintf( HeaderFile, "//\r\n" );
fprintf( HeaderFile, "// Define the severity codes\r\n" );
fprintf( HeaderFile, "//\r\n" );
p = SeverityNames;
while( p ) {
if (p->Value) {
fprintf( HeaderFile, GenerateDecimalValues ?
"#define %-32s %ld\r\n" :
"#define %-32s 0x%lX\r\n",
p->Value, p->Id
);
}

p = p->Next;
}
fprintf( HeaderFile, "\r\n" );
fprintf( HeaderFile, "\r\n" );
}

if (!McParseMessageDefinition()) {
return( FALSE );
}
break;

default:
McInputError( "Invalid message file token - '%s'", TRUE, TokenCharValue );
return( FALSE );
break;
}
}

McFlushComments();
return( TRUE );
}


BOOLEAN
McParseMessageDefinition( void )
{
unsigned int t;
PMESSAGE_INFO MessageInfo;
BOOLEAN MessageIdSeen;
PMESSAGE_INFO MessageInfoTemp;

McFlushComments();

MessageInfo = malloc( sizeof( *MessageInfo ) );
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) {
McInputError( "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 {
McInputError( "Number must follow %s=+", TRUE, TokenKeyword->Name );
return( FALSE );
}
}
else {
McUnGetToken();
}

}
else {
McInputError( "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 {
McInputError( "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 {
McInputError( "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 {
McInputError( "Symbol name must follow %s=+", TRUE, TokenKeyword->Name );
return( FALSE );
}
}
else {
McInputError( "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) {
McInputError( "Message Id value (%lx) too large", TRUE, (PVOID)MessageInfo->Id );
return( FALSE );
}

MessageInfo->Id |= (CurrentSeverityName->Id << 30) |
CustomerMsgIdBit |
(CurrentFacilityName->Id << 16);

fprintf( HeaderFile, "//\r\n" );
if (MessageInfo->SymbolicName) {
fprintf( HeaderFile, "// MessageId: %s\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 (MessageIdTypeName != NULL) {
fprintf( HeaderFile, GenerateDecimalValues ?
"#define %-32s ((%s)%ldL)" :
"#define %-32s ((%s)0x%08lXL)",
MessageInfo->SymbolicName,
MessageIdTypeName,
MessageInfo->Id
);
}
else {
fprintf( HeaderFile, GenerateDecimalValues ?
"#define %-32s %ldL" :
"#define %-32s 0x%08lXL",
MessageInfo->SymbolicName,
MessageInfo->Id
);
}
}

if (MessageInfo->EndOfLineComment) {
fprintf( HeaderFile, " %s", MessageInfo->EndOfLineComment );
}
else {
fprintf( HeaderFile, "\r\n" );
}
fprintf( HeaderFile, "\r\n" );

if (Messages == NULL) {
Messages = MessageInfo;
}
else {
MessageInfoTemp = Messages;

//
// Scan the existing messages to see if this message
// exists in the message file.
//
// If it does, generate and error for the user.
//

while (MessageInfoTemp != NULL) {

if (MessageInfoTemp->Id == MessageInfo->Id) {
McInputError( "Duplicate message ID - 0x%lx", FALSE, (PVOID)MessageInfo->Id );
}

MessageInfoTemp = MessageInfoTemp->Next;
}

CurrentMessage->Next = MessageInfo;
}

CurrentMessage = MessageInfo;
CurrentFacilityName->LastId = MessageInfo->Id & 0xFFFF;
return( TRUE );
}
else {
return( FALSE );
}

default:
McInputError( "Invalid message definition token - '%s'", TRUE, TokenCharValue );
return( FALSE );
}
}

return( FALSE );
}


char MessageTextBuffer[ 8192 ];

BOOLEAN
McParseMessageText(
PMESSAGE_INFO MessageInfo
)
{
PLANGUAGE_INFO MessageText, *pp;
char *src, *dst;
unsigned int t, n;
BOOLEAN 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 );
}
}
else {
McInputError( "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;
while (src = McGetLine()) {
if (!strcmp( src, ".\r\n" )) {
if (MessageText->Length == 0) {
if (MessageInfo->SymbolicName) {
strcpy( dst, MessageInfo->SymbolicName );
}
else {
sprintf( dst, "No symbolic name defined for0x%08lXL" );
}

strcat( dst, "\r\n" );
if (!FirstLanguageProcessed) {
fprintf( HeaderFile, "// %s", dst );
}

n = strlen( dst );
dst += n;
MessageText->Length += n;
}

McSkipLine();
break;
}
else
if (!strnicmp( src, "LanguageId=", 11 ) ||
!strnicmp( src, "MessageId=", 10 )
) {
McInputError( "Unterminated message definition", TRUE, NULL );
return( FALSE );
}

if (!FirstLanguageProcessed) {
fprintf( HeaderFile, "// %s", src );
}

n = strlen( src );
if (MessageText->Length + n > sizeof( MessageTextBuffer )) {
McInputError( "Message text too long - > %ld", TRUE,
(PVOID)(ULONG)sizeof( MessageTextBuffer )
);
return( FALSE );
}

strcpy( dst, src );
dst += n;
MessageText->Length += n;
}
*dst = '\0';

n = ((USHORT)MessageText->Length)+1;
MessageText->Text = malloc( n );
memcpy( MessageText->Text, MessageTextBuffer, n );
*pp = MessageText;
pp = &MessageText->Next;
FirstLanguageProcessed = TRUE;
}

return( TRUE );
}


BOOLEAN
McParseNameList(
PNAME_INFO *NameListHead,
BOOLEAN ValueRequired,
ULONG MaximumValue
)
{
unsigned int t;
PNAME_INFO p;
char *Name;
ULONG Id;
PVOID Value;

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 {
McInputError( "File name must follow =%ld:", TRUE, (PVOID)Id );
return( FALSE );
}
}
else {
if (ValueRequired) {
McInputError( "Colon must follow =%ld", TRUE, (PVOID)Id );
return( FALSE );
}

McUnGetToken();
}
}
else {
McInputError( "Number must follow %s=", TRUE, Name );
return( FALSE );
}
}
else {
McInputError( "Equal sign name must follow %s", TRUE, Name );
return( FALSE );
}

if (Id > MaximumValue) {
McInputError( "Value is too large (> %lx)", TRUE, (PVOID)MaximumValue );
return( FALSE );
}

p = McAddName( NameListHead, Name, Id, Value );
free( Name );
}
}

return( FALSE );
}

BOOLEAN
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 {
McInputError( "Invalid name - %s", TRUE, TokenCharValue );
}
}
else {
McInputError( "Missing name after %s=", TRUE, TokenKeyword->Name );
}

return( FALSE );
}