/*********************************************************************** * Microsoft (R) Windows (R) Resource Compiler * * Copyright (c) Microsoft Corporation. All rights reserved. * * File Comments: * * ***********************************************************************/ #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() - */ /* */ /*---------------------------------------------------------------------------*/ WCHAR FileChar( void ) { static WCHAR rgchLine[MAXSTR]; static int ibNext = MAXSTR; size_t cch; WCHAR 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'; } } ch = rgchLine[ibNext]; if (ch != L'\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 = 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 = 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 = 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 = FileChar(); } while (curChar != CHQUOTE && curChar != CHNEWLINE); /* don't change curFile or fIgnore if this is just a * #line */ if (curChar == CHNEWLINE) break; /* read the filename. detect the presence of .c or .h */ pch = buf; do { curChar = 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; wcsncpy(curFile, buf, _MAX_PATH); /* read through end of line */ do { curChar = 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" } *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" } *s++ = curChar; } if (curChar == EOFMARK) { LexError1(2103); // "unexpected end of file in string literal" } if (token.val >= 256) { SendError(L"\n"); SET_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'; memcpy(tokenbuf, temptok, sizeof(WCHAR) * (i + 1)); token.val = (USHORT) i; } /*---------------------------------------------------------------------------*/ /* */ /* 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, tokenbuf); //"undefined keyword or key name: %ws" } 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(iMsg, curFile, curLin); SendError(Msg_Text); quit(NULL); } /*---------------------------------------------------------------------------*/ /* */ /* LexError2() - */ /* */ /*---------------------------------------------------------------------------*/ void LexError2(int iMsg, const wchar_t *str) { SET_MSG(iMsg, curFile, curLin, str); SendError(Msg_Text); quit(NULL); } /*---------------------------------------------------------------------------*/ /* */ /* 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); }