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

1380 lines
40 KiB
C

/****************************************************************************/
/* */
/* RCL.C - */
/* */
/* Windows 3.0 Resource Compiler - Lexical analyzer */
/* */
/* */
/****************************************************************************/
#include "rc.h"
#define EOLCHAR L';'
#define STRCHAR L'"'
#define CHRCHAR L'\''
#define SGNCHAR L'-'
#define iswhite( c ) ((c != SYMUSESTART) && (c != SYMDEFSTART) &&\
((WCHAR)c <= L' ') ? TRUE : FALSE)
static WCHAR curChar;
static WCHAR curCharFTB; /* Cur char From Token Buf */
static PWCHAR CurPtrTB;
static PFILE inpfh;
static int curLin, curCol;
extern BOOL bExternParse;
/* Must be sorted */
KEY keyList[] =
{
{ L"ALT", TKALT },
{ L"ASCII", TKASCII },
{ L"AUTO3STATE", TKAUTO3 },
{ L"AUTOCHECKBOX", TKAUTOCHECK },
{ L"AUTORADIOBUTTON", TKAUTORADIO },
{ L"BEGIN", BEGIN },
{ L"BEDIT", TKBEDIT },
{ L"BITMAP", TKBITMAP },
{ L"BLOCK", TKBLOCK },
{ L"BUTTON", TKBUTTON },
{ L"CAPTION", TKCAPTION },
{ L"CHARACTERISTICS", TKCHARACTERISTICS },
{ L"CHECKBOX", TKCHECKBOX },
{ L"CHECKED", TKCHECKED },
{ L"CLASS", TKCLASS },
{ L"COMBOBOX", TKCOMBOBOX },
{ L"CONTROL", TKCONTROL },
{ L"CTEXT", TKCTEXT },
{ L"DEFPUSHBUTTON", TKDEFPUSHBUTTON },
{ L"DISCARDABLE", TKDISCARD },
{ L"DLGINCLUDE", TKDLGINCLUDE },
{ L"DLGINIT", TKDLGINIT },
{ L"EDIT", TKEDIT },
{ L"EDITTEXT", TKEDITTEXT },
{ L"END", END },
{ L"EXSTYLE", TKEXSTYLE },
{ L"FILEFLAGS", TKFILEFLAGS },
{ L"FILEFLAGSMASK", TKFILEFLAGSMASK },
{ L"FILEOS", TKFILEOS },
{ L"FILESUBTYPE", TKFILESUBTYPE },
{ L"FILETYPE", TKFILETYPE },
{ L"FILEVERSION", TKFILEVERSION },
{ L"FIXED", TKFIXED },
{ L"FONT", TKFONT },
{ L"GRAYED", TKGRAYED },
{ L"GROUPBOX", TKGROUPBOX },
{ L"HEDIT", TKHEDIT },
{ L"HELP", TKHELP },
{ L"ICON", TKICON },
{ L"IEDIT", TKIEDIT },
{ L"IMPURE", TKIMPURE },
{ L"INACTIVE", TKINACTIVE },
{ L"LANGUAGE", TKLANGUAGE },
{ L"LISTBOX", TKLISTBOX },
{ L"LOADONCALL", TKLOADONCALL },
{ L"LTEXT", TKLTEXT },
{ L"MENU", TKMENU },
{ L"MENUBARBREAK", TKBREAKWBAR },
{ L"MENUBREAK", TKBREAK },
{ L"MENUITEM", TKMENUITEM },
{ L"MESAGETABLE", TKMESSAGETABLE },
{ L"MOVEABLE", TKMOVEABLE },
{ L"NOINVERT", TKNOINVERT },
{ L"NONSHARED", TKIMPURE },
{ L"NOT", TKNOT },
{ L"OWNERDRAW", TKOWNERDRAW },
{ L"POPUP", TKPOPUP },
{ L"PRELOAD", TKPRELOAD },
{ L"PRODUCTVERSION", TKPRODUCTVERSION },
{ L"PURE", TKPURE },
{ L"PUSHBOX", TKPUSHBOX },
{ L"PUSHBUTTON", TKPUSHBUTTON },
{ L"RADIOBUTTON", TKRADIOBUTTON },
{ L"RCDATA", TKRCDATA },
{ L"RTEXT", TKRTEXT },
{ L"SCROLLBAR", TKSCROLLBAR },
{ L"SEPARATOR", TKSEPARATOR },
{ L"SHARED", TKPURE },
{ L"SHIFT", TKSHIFT },
{ L"STATE3", TK3STATE },
{ L"STATIC", TKSTATIC },
{ L"STYLE", TKSTYLE },
{ L"USERBUTTON", TKUSERBUTTON },
{ L"VALUE", TKVALUE },
{ L"VERSION", TKVERSION },
{ L"VIRTKEY", TKVIRTKEY },
{ NULL, 0 }
};
SKEY skeyList[] =
{
{ L',', COMMA },
{ L'|', OR },
{ L'(', LPAREN },
{ L')', RPAREN },
{ L'{', BEGIN },
{ L'}', END },
{ L'~', TILDE },
{ L'+', TKPLUS },
{ L'-', TKMINUS },
{ L'&', AND },
{ L'=', EQUAL },
{ EOFMARK, EOFMARK },
{ L'\000', 0 }
};
/*---------------------------------------------------------------------------*/
/* */
/* LexInit() - */
/* */
/*---------------------------------------------------------------------------*/
int
LexInit(
PFILE fh
)
{
/* zero errors so far */
errorCount = 0;
curLin = 1;
curCol = 0;
inpfh = fh;
/* Read initial character */
OurGetChar();
return TRUE;
}
/*---------------------------------------------------------------------------*/
/* */
/* GetCharFTB() - */
/* */
/*---------------------------------------------------------------------------*/
WCHAR
GetCharFTB(
void
)
{
return(curCharFTB = *CurPtrTB++);
}
/*---------------------------------------------------------------------------*/
/* */
/* OurGetChar() - */
/* */
/* Read a character, treating semicolon as an end of line comment char */
/* */
/*---------------------------------------------------------------------------*/
WCHAR
OurGetChar(
void
)
{
if ((LitChar() != EOFMARK) && (curChar == CHCOMMENT))
// if comment, HARD LOOP until EOLN
while ((LitChar() != EOFMARK) && (curChar != CHNEWLINE));
return(curChar);
}
/*---------------------------------------------------------------------------*/
/* */
/* FileChar() - */
/* */
/*---------------------------------------------------------------------------*/
int
FileChar(
void
)
{
static WCHAR rgchLine[MAXSTR];
static int ibNext = MAXSTR;
int cch, ch;
if (ibNext >= MAXSTR) {
ibNext = 0;
cch = MyRead (inpfh, rgchLine, MAXSTR * sizeof(WCHAR));
if (cch < (MAXSTR * sizeof(WCHAR))) {
fclose(inpfh);
// NULL terminate the input buffer
*(rgchLine + (cch / sizeof(WCHAR))) = L'\0';
}
}
if ((ch = rgchLine[ibNext]) != 0)
ibNext++;
return(ch);
}
/*---------------------------------------------------------------------------*/
/* */
/* CopyToken() - */
/* */
/*---------------------------------------------------------------------------*/
void
CopyToken(
PTOKEN ptgt_token,
PTOKEN psrc_token
)
{
ptgt_token->longval = psrc_token->longval;
ptgt_token->row = psrc_token->row;
ptgt_token->col = psrc_token->col;
ptgt_token->flongval = psrc_token->flongval;
ptgt_token->val = psrc_token->val;
ptgt_token->type = psrc_token->type;
ptgt_token->realtype = psrc_token->realtype;
wcscpy(ptgt_token->sym.name, psrc_token->sym.name);
wcscpy(ptgt_token->sym.file, psrc_token->sym.file);
ptgt_token->sym.line = psrc_token->sym.line;
ptgt_token->sym.nID = psrc_token->sym.nID;
}
/*---------------------------------------------------------------------------*/
/* */
/* LitChar() - */
/* */
/*---------------------------------------------------------------------------*/
/* Read a literal character, without interpreting EOL comments */
WCHAR
LitChar(
void
)
{
static int fNewLine = TRUE;
int fIgnore = FALSE;
int fBackSlash = FALSE;
int fDot;
PWCHAR pch;
WCHAR buf[ _MAX_PATH ];
TOKEN token_save;
for (; ; ) {
switch (curChar = (WCHAR)FileChar()) {
case 0:
curChar = EOFMARK;
goto char_return;
case 0xFEFF: // skip Byte Order Mark
continue;
case SYMDEFSTART:
{
int fNewLineSave = fNewLine;
GetSymbolDef(TRUE, curChar);
fNewLine = fNewLineSave;
break;
}
case CHCARRIAGE:
curChar = CHSPACE;
if (!fIgnore)
goto char_return;
break;
case CHNEWLINE:
fNewLine = TRUE;
curLin++;
{
static long lTotalLin = 0;
if ((lTotalLin++ & RC_COMPILE_UPDATE) == 0)
UpdateStatus(2, lTotalLin);
}
if (!fIgnore)
goto char_return;
break;
/* skip whitespace before #line - don't clear fNewLine */
case CHSPACE:
case CHTAB:
if (!fIgnore)
goto char_return;
break;
case CHDIRECTIVE:
if (fNewLine) {
WCHAR tch;
fDot = FALSE;
/* also, leave fNewLine set, since we read thru \n */
/* read the 'line' part */
if ((tch = (WCHAR)FileChar()) != L'l') {
if (tch == L'p') {
if (FileChar() != L'r')
goto DirectiveError;
if (FileChar() != L'a')
goto DirectiveError;
if (FileChar() != L'g')
goto DirectiveError;
if (FileChar() != L'm')
goto DirectiveError;
if (FileChar() != L'a')
goto DirectiveError;
/*
** This is very specific, as any #pragma will
** be a code_page pragma written by p0prepro.c.
*/
CopyToken( &token_save, &token );
GetToken(FALSE); /* get #pragma and ignore */
GetToken(FALSE); /* get code_page and ignore */
GetToken(TOKEN_NOEXPRESSION); /* get codepage value only*/
/* don't check return value */
uiCodePage = token.val; /* assume ok */
/* read through end of line */
while (curChar != CHNEWLINE) {
curChar = (WCHAR)FileChar();
}
CopyToken( &token, &token_save );
continue;
} else {
goto DirectiveError;
}
}
if (FileChar() != L'i')
goto DirectiveError;
if (FileChar() != L'n')
goto DirectiveError;
if (FileChar() != L'e')
goto DirectiveError;
/* up to filename, grabbing line number as we go */
/* note that curChar first contains '#', because */
/* we don't read a new character into curChar */
curLin = 0;
do {
if (curChar >= L'0' && curChar <= L'9') {
curLin *= 10;
curLin += curChar - L'0';
}
curChar = (WCHAR)FileChar();
} while (curChar != CHQUOTE && curChar != CHNEWLINE);
/* don't change curFile or fIgnore if this is just a
* #line <lineno>
*/
if (curChar == CHNEWLINE)
break;
/* read the filename. detect the presence of .c or .h */
pch = buf;
do {
curChar = (WCHAR)FileChar();
switch (towlower(curChar)) {
/* treat backslash like normal char, set flag. */
case L'\\':
if (fBackSlash) {
fBackSlash = FALSE;
} else {
fBackSlash = TRUE;
fIgnore = FALSE;
fDot = FALSE;
*pch++ = curChar;
}
break;
/* line format sanity check: no embedded newlines */
case CHNEWLINE:
case 0:
DirectiveError:
LexError1(2101);
/* stop reading filename when we hit a quote */
case CHQUOTE:
break;
/* if we see a ., prepare to find extension */
case CHEXTENSION:
fBackSlash = FALSE;
fDot = TRUE;
*pch++ = curChar;
break;
/* if there's a C or H after a '.', its not RCINCLUDE'd */
case CHCSOURCE:
case CHCHEADER:
fBackSlash = FALSE;
fIgnore = fDot;
fDot = FALSE;
*pch++ = curChar;
break;
/* any other character in a file means the next character
won't be after a dot, and the last char up to now
wasn't C or H.
*/
default:
fIgnore = FALSE;
fDot = FALSE;
*pch++ = curChar;
break;
}
} while (curChar != CHQUOTE);
*pch = 0;
WideCharToMultiByte(uiCodePage, 0, buf, -1, (LPSTR) curFile, _MAX_PATH, NULL, NULL);
/* read through end of line */
do {
curChar = (WCHAR)FileChar();
} while (curChar != CHNEWLINE);
break;
}
/* else, fall through, treat like normal char */
default:
fNewLine = FALSE;
if (!fIgnore)
goto char_return;
}
}
char_return:
if (bExternParse)
*((WCHAR*) GetSpace(sizeof(WCHAR))) = curChar;
return curChar;
}
/*---------------------------------------------------------------------------*/
/* */
/* GetStr() - */
/* */
/*---------------------------------------------------------------------------*/
VOID
GetStr(
void
)
{
PWCHAR s;
WCHAR ch;
WCHAR temptok[ MAXSTR ];
SHORT i = 0;
int inc;
UCHAR Octal_Num;
UCHAR HexNum;
/* token type is string literal */
token.realtype = STRLIT;
/*
** NB: FloydR
** The use of token.realtype is a hack for RCDATA.
**
** When we converted RC to be Unicode-based, all the
** separate "case STRLIT:" code was removed, and the LSTRLIT
** cases took over for them. Alternatively, we could have
** left the STRLIT case, but removed the code it accessed
** and move the STRLIT case prior/after the LSTRLIT case,
** since they were now identical. They were removed in favor
** of smaller/faster code.
**
** However, RCDATA still had a need to discern the difference,
** so I added token.realtype, set it to STRLIT in GetStr(),
** set it to LSTRLIT in GetLStr() (below), and check it in
** GetRCData() in rctg.c.
**
*/
token.type = LSTRLIT;
token.val = 0;
s = tokenbuf;
/* read string until " or EOF */
while (LitChar() != EOFMARK) {
if (curChar == STRCHAR)
if (OurGetChar() != STRCHAR)
goto gotstr;
if (token.val++ == MAXSTR)
LexError1(2102); //"string literal too long"
else
*s++ = curChar;
}
if (curChar == EOFMARK)
LexError1(2103); //"unexpected end of file in string literal"
gotstr:
*s++ = 0;
s = tokenbuf;
/* process escape characters in the string */
while (*s != 0) {
if (*s == L'\\') {
s++;
if (*s == L'\\')
temptok[i++] = L'\\';
else if (*s == L'T' || *s == L't')
temptok[i++] = L'\011'; /* Tab */
else if (*s == 0x0a) /* continuation slash */
; /* ignore and let it go trough the s++ at the end so we skip the 0x0a char*/
else if (*s == L'A' || *s == L'a')
temptok[i++] = L'\010'; /* Right Align */
else if (*s == L'n')
temptok[i++] = fMacRsrcs ? 13 : 10; /* linefeed */
else if (*s == L'r')
temptok[i++] = fMacRsrcs ? 10 : 13; /* carriage return */
else if (*s == L'"')
temptok[i++] = L'"'; /* quote character */
else if (*s == L'X' || *s == L'x') { /* Hexidecimal digit */
USHORT wCount;
HexNum = 0;
++s;
for (wCount = 2 ;
wCount && iswxdigit((ch=(WCHAR)towupper(*s)));
--wCount) {
if (ch >= L'A')
inc = ch - L'A' + 10;
else
inc = ch - L'0';
HexNum = HexNum * 16 + inc;
s++;
}
MultiByteToWideChar(uiCodePage, MB_PRECOMPOSED, (LPCSTR) &HexNum, 1, &temptok[i], 1);
i++;
s--;
} else if (*s >= L'0' && *s <= L'7') { /* octal character */
USHORT wCount;
Octal_Num = 0;
for (wCount = 3; wCount && *s >= L'0' && *s <= L'7'; --wCount) {
Octal_Num = (Octal_Num * 8 + (*s - L'0'));
s++;
}
MultiByteToWideChar(uiCodePage, MB_PRECOMPOSED, (LPCSTR) &Octal_Num, 1, &temptok[i], 1);
i++;
s--;
}
else {
temptok[i++] = L'\\';
s--;
}
} else
temptok[i++] = *s;
s++;
}
/* zero terminate */
temptok[i] = L'\0';
memcpy ( tokenbuf, temptok, sizeof(WCHAR)*(i + 1));
token.val = (USHORT)i;
}
/*---------------------------------------------------------------------------*/
/* */
/* GetLStr() - */
/* */
/*---------------------------------------------------------------------------*/
VOID
GetLStr(
void
)
{
PWCHAR s;
WCHAR ch;
WCHAR temptok[ MAXSTR ];
SHORT i = 0;
int inc;
int Octal_Num;
int HexNum;
/* token type is string literal */
token.realtype = token.type = LSTRLIT;
token.val = 0;
s = tokenbuf;
/* read string until " or EOF */
while (LitChar() != EOFMARK) {
if (curChar == STRCHAR)
if (OurGetChar() != STRCHAR)
goto gotstr;
if (token.val++ == MAXSTR)
LexError1(2102); //"string literal too long"
else
*s++ = curChar;
}
if (curChar == EOFMARK)
LexError1(2103); //"unexpected end of file in string literal"
if (token.val >= 256) {
SendError("\n");
SET_MSG(Msg_Text, sizeof(Msg_Text), GET_MSG(4205), curFile, token.row);
SendError(Msg_Text);
}
gotstr:
*s++ = 0;
s = tokenbuf;
/* process escape characters in the string */
while (*s != 0) {
if (*s == L'\\') {
s++;
if (*s == L'\\')
temptok[i++] = L'\\';
else if (*s == L'T' || *s == L't')
temptok[i++] = L'\011'; /* Tab */
else if (*s == L'A' || *s == L'a')
temptok[i++] = L'\010'; /* Right Align */
else if (*s == L'n')
temptok[i++] = fMacRsrcs ? 13 : 10; /* linefeed */
else if (*s == L'r')
temptok[i++] = fMacRsrcs ? 10 : 13; /* carriage return */
else if (*s == L'"')
temptok[i++] = L'"'; /* quote character */
else if (*s == L'X' || *s == L'x') { /* Hexidecimal digit */
USHORT wCount;
HexNum = 0;
++s;
for (wCount = 4 ;
wCount && iswxdigit((ch=(WCHAR)towupper(*s)));
--wCount) {
if (ch >= L'A')
inc = ch - L'A' + 10;
else
inc = ch - L'0';
HexNum = HexNum * 16 + inc;
s++;
}
temptok[i++] = (WCHAR)HexNum;
s--;
}
else if (*s >= L'0' && *s <= L'7') { /* octal character */
USHORT wCount;
Octal_Num = 0;
for (wCount = 7; wCount && *s >= L'0' && *s <= L'7'; --wCount) {
Octal_Num = (Octal_Num * 8 + (*s - L'0'));
s++;
}
temptok[i++] = (WCHAR)Octal_Num;
s--;
}
}
else
temptok[i++] = *s;
s++;
}
/* zero terminate */
temptok[i] = L'\0';
token.val = (USHORT)i;
memcpy ( tokenbuf, temptok, sizeof(WCHAR)*(i + 1));
}
/*---------------------------------------------------------------------------*/
/* */
/* GetToken() - */
/* */
/*---------------------------------------------------------------------------*/
int
GetToken(
int fReportError
)
{
for (; ; ) {
/* skip whitespace */
while (iswhite( curChar))
OurGetChar();
/* take care of 'random' symbols use */
if (curChar == SYMUSESTART)
GetSymbol(fReportError, curChar);
token.sym.name[0] = L'\0';
/* remember location of token */
token.row = curLin;
token.col = curCol;
/* determine if token is EOF, number, string, or keyword */
token.type = EOFMARK;
switch (curChar) {
case EOFMARK:
break;
case SGNCHAR:
case L'~':
if (fReportError & TOKEN_NOEXPRESSION)
GetNumNoExpression();
else
GetNum();
break;
case STRCHAR:
GetStr();
break;
default:
if (curChar == L'(' && !(fReportError & TOKEN_NOEXPRESSION))
GetNum();
else if (iswdigit( curChar)) {
if (fReportError & TOKEN_NOEXPRESSION)
GetNumNoExpression();
else
GetNum();
if (curChar == SYMUSESTART)
GetSymbol(fReportError, curChar);
} else {
if (!GetKwd( fReportError))
continue;
if (token.type == TKLSTR) {
GetLStr();
break;
}
}
}
break;
}
return token.type;
}
/*---------------------------------------------------------------------------*/
/* */
/* GetXNum() - */
/* */
/*---------------------------------------------------------------------------*/
/* get hexadecimal number */
LONG
GetXNum(
void
)
{
LONG n = 0;
while (iswxdigit (GetCharFTB()))
n = n * 16 + ( ((curCharFTB = (WCHAR)towupper(curCharFTB)) >= L'A') ?
(WCHAR)(curCharFTB - L'A' + 10) :
(WCHAR)(curCharFTB - L'0'));
return (n);
}
/*---------------------------------------------------------------------------*/
/* */
/* GetONum() - */
/* */
/*---------------------------------------------------------------------------*/
/* get octal number */
LONG
GetONum(
void
)
{
LONG n = 0;
while (GetCharFTB() >= L'0' && curCharFTB <= L'7')
n = n * 8 + (curCharFTB - L'0');
return (n);
}
/*---------------------------------------------------------------------------*/
/* */
/* GetDNum() - */
/* */
/*---------------------------------------------------------------------------*/
/* get decimal number */
LONG
GetDNum(
void
)
{
LONG n = 0;
while (iswdigit(curCharFTB)) {
n = n * 10 + (curCharFTB - L'0');
GetCharFTB();
}
return (n);
}
PWSTR
GetWord(
PWSTR pStr
)
{
WCHAR ch;
PSKEY pskey;
*pStr++ = curCharFTB = curChar;
while (TRUE) {
ch = OurGetChar();
if (ch <= L' ')
goto FoundBreak;
switch (ch) {
case EOFMARK:
case EOLCHAR:
case STRCHAR:
case CHRCHAR:
goto FoundBreak;
default:
for (pskey = skeyList; pskey->skwd; pskey++)
if (pskey->skwd == ch)
goto FoundBreak;
}
*pStr++ = ch;
}
FoundBreak:
*pStr = 0;
return(pStr);
}
/* GetNumFTB
* This function was previously added as a hack to handle converting
* radices. I'm treating this as a (ugly) black box to read a number.
*/
VOID
GetNumFTB(
void
)
{
int signFlag;
USHORT wNotFlag;
LONG n;
/* Small hack to support NOT: If we have a tilde, skip whitespace
* before the number.
*/
if (curChar == L'~')
while (iswhite(curChar))
OurGetChar();
/* Get the entire number in tokenbuf before computing radix */
GetWord(tokenbuf);
/* Skip the first char. It is already in curCharFTB */
CurPtrTB = tokenbuf + 1;
/* mark token type as numeric literal */
token.type = NUMLIT;
/* find sign of number */
if (curCharFTB == SGNCHAR) {
signFlag = TRUE;
GetCharFTB();
} else {
signFlag = FALSE;
}
/* Check for a NOT (~) */
if (curCharFTB == L'~') {
wNotFlag = TRUE;
GetCharFTB();
} else {
wNotFlag = FALSE;
}
/* determine radix of number */
if (curCharFTB == L'0') {
GetCharFTB();
if (curCharFTB == L'x')
n = GetXNum();
else if (curCharFTB == L'o')
n = GetONum();
else
n = GetDNum();
} else {
n = GetDNum();
}
/* find size of number */
if ((curCharFTB == L'L') || (curCharFTB == L'l')) {
token.flongval = TRUE;
GetCharFTB();
} else {
token.flongval = FALSE;
}
/* account for sign */
if (signFlag)
n = -n;
/* Account for the NOT */
if (wNotFlag)
n = ~n;
/* Set longval regardless of flongval because Dialog Styles
* always have to be be long
*/
token.longval = n;
token.val = (USHORT)n;
}
/* ----- Static information needed for parsing ----- */
static int wLongFlag;
static int nParenCount;
/*---------------------------------------------------------------------------*/
/* */
/* GetNum() - */
/* */
/*---------------------------------------------------------------------------*/
VOID
GetNum(
void
)
{
LONG lValue;
/* Initialize */
wLongFlag = 0;
nParenCount = 0;
/* Return the number */
lValue = GetExpression();
/* Make sure we had matched parens */
if (nParenCount)
ParseError1(1013); //"Mismatched parentheses"
/* Return as the proper token */
if (wLongFlag)
token.flongval = TRUE;
token.type = NUMLIT;
token.longval = lValue;
token.val = (USHORT)lValue;
}
/* GetNumNoExpression
* Gets a number without doing expression parsing on it.
*/
VOID
GetNumNoExpression(
VOID
)
{
/* Call the single number parser */
GetNumFTB();
}
/* GetExpression
* Gets an expression, which is defined as any number of
* operators and operands inside one set of parens.
*/
LONG
GetExpression(
VOID
)
{
LONG op1;
LONG op2;
WCHAR byOperator;
UINT wFlags;
/* Get the first operand */
op1 = GetOperand();
/* take care of symbol use */
if (curChar == SYMUSESTART) {
GetSymbol(TRUE, curChar);
token.sym.nID = token.val;
}
/* Loop until end of expression */
for (; ; ) {
/* Get the operator */
wFlags = GetOperator(&byOperator);
/* If this is a right paren, dec the count */
if (byOperator == L')') {
/* Bring the paren count back down */
--nParenCount;
/* Skip the paren and any trailing whitespace */
OurGetChar();
SkipWhitespace();
}
/* If this isn't an operator, we're done with the expression */
if (!wFlags) {
token.sym.nID = (unsigned)op1;
return op1;
}
token.sym.name[0] = L'\0';
/* Get the second operand */
op2 = GetOperand();
/* Compute the value of the expression */
switch (byOperator) {
case L'+':
op1 += op2;
break;
case L'-':
op1 -= op2;
break;
case L'&':
op1 &= op2;
break;
case L'|':
op1 |= op2;
break;
}
}
}
/* GetOperand
* Gets an operand, which may either be a single number or may
* be an entire expression.
*/
LONG
GetOperand(
VOID
)
{
/* Check to see if we need to descend a level */
if (curChar == L'(') {
/* Bump paren count so we can match them up */
++nParenCount;
/* Skip past the paren char */
OurGetChar();
SkipWhitespace();
/* Return the value of the computed expression for the operand */
return GetExpression();
}
/* If this isn't a number, return an error */
if (curChar != L'-' && curChar != L'~' && !iswdigit(curChar)) {
GetKwd(FALSE);
ParseError2(2237, tokenbuf);
return 0;
}
/* Get the number in the token structure */
GetNumFTB();
/* See if we need to force the result long */
if (token.flongval)
wLongFlag = TRUE;
/* Skip trailing whitespace */
SkipWhitespace();
/* Return the value */
return token.longval;
}
/* GetOperator
* Gets the next character and decides if it should be an operator.
* If it should, it returns TRUE, which causes the expression
* parser to continue. Otherwise, it returns FALSE which causes
* the expression parser to pop up a level.
*/
int
GetOperator(
PWCHAR pOperator
)
{
static WCHAR byOps[] = L"+-|&";
PWCHAR pOp;
/* take care of symbol use */
if (curChar == SYMUSESTART)
GetSymbol(TRUE, curChar);
/* See if this character is an operator */
pOp = wcschr(byOps, curChar);
*pOperator = curChar;
/* If we didn't find it, get out */
if (!pOp)
return FALSE;
/* Otherwise, read trailing whitespace */
OurGetChar();
SkipWhitespace();
/* Return the operator */
return TRUE;
}
/* SkipWhitespace
* Skips past whitespace in the current stream.
*/
VOID
SkipWhitespace(
VOID
)
{
while (iswhite(curChar))
OurGetChar();
}
/*---------------------------------------------------------------------------*/
/* */
/* GetKwd() - */
/* */
/*---------------------------------------------------------------------------*/
int
GetKwd(
int fReportError
)
{
PSKEY sk;
/* see if a special character */
for (sk = &skeyList[ 0 ]; sk->skwd; sk++) {
if (curChar == sk->skwd) {
token.type = (UCHAR)sk->skwdval;
token.val = 0;
OurGetChar();
return (token.type >= FIRSTKWD);
}
}
/* else read characters up to the next seperator */
GetWord(tokenbuf);
// Check for TKLSTR -- new for NT
if (!tokenbuf[1] && (towupper(tokenbuf[0]) == L'L') && (curChar == STRCHAR)) {
token.type = TKLSTR;
return TRUE;
}
/* look up keyword in table */
if ((token.val = FindKwd( tokenbuf)) != (USHORT)-1) {
token.type = (UCHAR)token.val;
} else if (fReportError) {
LexError2(2104, (PCHAR)tokenbuf); //"undefined keyword or key name: %ws"
return FALSE;
}
else
token.type = 0;
return TRUE;
}
/*---------------------------------------------------------------------------*/
/* */
/* FindKwd() - */
/* */
/*---------------------------------------------------------------------------*/
USHORT
FindKwd(
PWCHAR str
)
{
PKEY k;
int t;
/* linear search the keyword table for the key */
for (k = &keyList[0]; k->kwd; k++)
if (!(t = _wcsicmp( str, k->kwd)))
return k->kwdval;
else if (t < 0)
break;
/* if not found, return -1 as keyword id */
return (USHORT)-1;
}
/*---------------------------------------------------------------------------*/
/* */
/* LexError1() - */
/* */
/*---------------------------------------------------------------------------*/
void
LexError1(
int iMsg
)
{
SET_MSG(Msg_Text, sizeof(Msg_Text), GET_MSG(iMsg), curFile, curLin);
SendError(Msg_Text);
quit("\n");
}
/*---------------------------------------------------------------------------*/
/* */
/* LexError2() - */
/* */
/*---------------------------------------------------------------------------*/
void
LexError2(
int iMsg,
PCHAR str
)
{
SET_MSG(Msg_Text, sizeof(Msg_Text), GET_MSG(iMsg), curFile, curLin, str);
SendError(Msg_Text);
quit("\n");
}
/*---------------------------------------------------------------------------*/
/* */
/* GetNameOrd() - */
/* */
/*---------------------------------------------------------------------------*/
/* For reading in resource names and types. */
int
GetNameOrd(
void
)
{
PWCHAR pch;
int fString;
/* get space delimited string */
if (!GetGenText())
return FALSE;
/* convert to upper case */
_wcsupr(tokenbuf);
/* is it a string or number */
for (pch=tokenbuf,fString=0 ; *pch ; pch++ )
if (!iswdigit(*pch))
fString = 1;
/* determine if ordinal */
if (tokenbuf[0] == L'0' && tokenbuf[1] == L'X') {
int HexNum;
int inc;
USHORT wCount;
PWCHAR s;
HexNum = 0;
s = &tokenbuf[2];
for (wCount = 4 ; wCount && iswxdigit(*s) ; --wCount) {
if (*s >= L'A')
inc = *s - L'A' + 10;
else
inc = *s - L'0';
HexNum = HexNum * 16 + inc;
s++;
}
token.val = (USHORT)HexNum;
} else if (fString) {
token.val = 0;
} else {
token.val = (USHORT)wcsatoi(tokenbuf);
}
return TRUE;
}
/*---------------------------------------------------------------------------*/
/* */
/* GetGenText() - */
/* */
/*---------------------------------------------------------------------------*/
/* returns a pointer to a string of generic text */
PWCHAR
GetGenText(
void
)
{
PWCHAR s;
s = tokenbuf;
/* skip white space */
while (iswhite(curChar))
OurGetChar();
if (curChar == EOFMARK) {
token.type = EOFMARK;
return NULL;
}
/* random symbol */
if (curChar == SYMUSESTART)
GetSymbol(TRUE, curChar);
token.sym.name[0] = L'\0';
/* read space delimited string */
*s++ = curChar;
while (( LitChar() != EOFMARK) && ( !iswhite(curChar)))
*s++ = curChar;
*s++ = 0; /* put a \0 on the end of the string */
OurGetChar(); /* read in the next character */
if (curChar == EOFMARK)
token.type = EOFMARK;
if (curChar == SYMUSESTART) {
GetSymbol(TRUE, curChar);
token.sym.nID = token.val;
}
return (tokenbuf);
}