/*** scanasl.c - ASL scanner * * Copyright (c) 1996,1997 Microsoft Corporation * Author: Michael Tsang (MikeTs) * Created: 09/05/96 * * This module provides the token scanning functions for the ASL language. * * MODIFICATION HISTORY */ #include "pch.h" /*** Local function prototypes */ int LOCAL ScanSym(int c, PTOKEN ptoken); int LOCAL ScanSpace(int c, PTOKEN ptoken); int LOCAL ScanID(int c, PTOKEN ptoken); int LOCAL ScanNum(int c, PTOKEN ptoken); int LOCAL ScanString(int c, PTOKEN ptoken); int LOCAL ScanChar(int c, PTOKEN ptoken); int LOCAL ProcessInLineComment(PTOKEN ptoken); int LOCAL ProcessComment(PTOKEN ptoken); int LOCAL LookupSym(PTOKEN ptoken, int iTable); LONG LOCAL LookupID(PTOKEN ptoken); int LOCAL GetEscapedChar(PLINE pline); BOOL EXPORT StrToQWord(PSZ psz, DWORD dwBase, QWORD *pqw); /*** Local data */ PFNTOKEN apfnToken[] = { ScanSym, ScanSpace, ScanID, ScanNum, ScanString, ScanChar, (PFNTOKEN)NULL }; #ifdef TUNE WORD awcTokenType[] = { 0, //TOKTYPE_SYMBOL 0, //TOKTYPE_SPACE 0, //TOKTYPE_ID 0, //TOKTYPE_NUM 0, //TOKTYPE_STRING 0 //TOKTYPE_CHAR }; #endif // // The string positions of the symbol characters in SymCharTable // is used as an index into the SymTokTable. Therefore, if anything // is changed in either SymCharTable or SymTokTable, the other // table has to be changed correspondingly. // typedef struct symtok_s { char chSym; int iSymType; int iLink; } SYMTOK; // // Note that the symbol position in the following array must be the same // position as in the SymCharTable array. // SYMTOK SymTokTable[] = { '{', SYM_LBRACE, 0, //0 '}', SYM_RBRACE, 0, //1 '(', SYM_LPARAN, 0, //2 ')', SYM_RPARAN, 0, //3 ',', SYM_COMMA, 0, //4 '/', SYM_SLASH, 7, //5 '*', SYM_ASTERISK, 9, //6 '/', SYM_INLINECOMMENT, 8, //7 '*', SYM_OPENCOMMENT, 0, //8 '/', SYM_CLOSECOMMENT, 0, //9 }; #define SYMTOK_TABLE_SIZE (sizeof(SymTokTable)/sizeof(SYMTOK)) /***EP OpenScan - scanner initialization * * ENTRY * pfileSrc -> source file * * EXIT-SUCCESS * returns the pointer to the allocated token structure; * EXIT-FAILURE * returns NULL */ PTOKEN EXPORT OpenScan(FILE *pfileSrc) { PTOKEN ptoken; ENTER((4, "OpenScan(pfileSrc=%p)\n", pfileSrc)); #ifdef TUNE ptoken = OpenToken(pfileSrc, apfnToken, awcTokenType); #else ptoken = OpenToken(pfileSrc, apfnToken); #endif EXIT((4, "OpenScan=%p\n", ptoken)); return ptoken; } //OpenScan /***EP CloseScan - scanner cleanup * * ENTRY * ptoken->token structure * EXIT * None */ VOID EXPORT CloseScan(PTOKEN ptoken) { ENTER((4, "CloseScan(ptoken=%p)\n", ptoken)); CloseToken(ptoken); EXIT((4, "CloseScan!\n")); } //CloseScan /***LP ScanSym - scan symbols token * * ENTRY * c - first character of the token * ptoken -> token structure * * EXIT-SUCCESS * returns TOKERR_NONE * EXIT-FAILURE * returns TOKERR_NO_MATCH - not a symbol token */ int LOCAL ScanSym(int c, PTOKEN ptoken) { int rc = TOKERR_NO_MATCH; char *pch; ENTER((4, "ScanSym(c=%c,ptoken=%p)\n", c, ptoken)); if ((pch = strchr(SymCharTable, c)) != NULL) { int i, j; i = (int)(pch - SymCharTable); if (i != (j = LookupSym(ptoken, i))) { i = j; ptoken->szToken[ptoken->wTokenLen++] = SymTokTable[i].chSym; } ptoken->iTokenType = TOKTYPE_SYMBOL; ptoken->llTokenValue = SymTokTable[i].iSymType; ptoken->szToken[ptoken->wTokenLen] = '\0'; if (ptoken->llTokenValue == SYM_INLINECOMMENT) rc = ProcessInLineComment(ptoken); else if (ptoken->llTokenValue == SYM_OPENCOMMENT) rc = ProcessComment(ptoken); else rc = TOKERR_NONE; } EXIT((4, "ScanSym=%d (SymType=%I64d,Symbol=%s)\n", rc, ptoken->llTokenValue, ptoken->szToken)); return rc; } //ScanSym /***LP ScanSpace - scans and skips all white spaces * * ENTRY * c - first character of the token * ptoken -> token structure * * EXIT-SUCCESS * returns TOKERR_NONE * EXIT-FAILURE * returns TOKTYPE_NO_MATCH - not a space token */ int LOCAL ScanSpace(int c, PTOKEN ptoken) { int rc = TOKERR_NO_MATCH; ENTER((4, "ScanSpace(c=%c,ptoken=%p)\n", c, ptoken)); if (isspace(c)) { rc = TOKERR_NONE; while (((c = LineGetC(ptoken->pline)) != EOF) && isspace(c)) ; LineUnGetC(c, ptoken->pline); if (ptoken->wfToken & TOKF_NOIGNORESPACE) { strcpy(ptoken->szToken, " "); ptoken->wTokenLen = 1; ptoken->iTokenType = TOKTYPE_SPACE; } else ptoken->iTokenType = TOKTYPE_NULL; } EXIT((4, "ScanSpace=%d\n", rc)); return rc; } //ScanSpace /***LP ScanID - scan ID token * * ENTRY * c - first character of the token * ptoken -> token structure * * EXIT-SUCCESS * returns TOKERR_NONE * EXIT-FAILURE * returns TOKTYPE_NO_MATCH - not an ID token * TOKERR_TOKEN_TOO_LONG - ID too long */ int LOCAL ScanID(int c, PTOKEN ptoken) { int rc = TOKERR_NO_MATCH; ENTER((4, "ScanID(c=%c,ptoken=%p)\n", c, ptoken)); if (isalpha(c) || (c == '_') || (c == CH_ROOT_PREFIX) || (c == CH_PARENT_PREFIX)) { BOOL fParentPrefix = (c == CH_PARENT_PREFIX); rc = TOKERR_NONE; ptoken->iTokenType = TOKTYPE_ID; while (((c = LineGetC(ptoken->pline)) != EOF) && (fParentPrefix && (c == CH_PARENT_PREFIX) || isalnum(c) || (c == '_') || (c == CH_NAMESEG_SEP))) { fParentPrefix = (c == CH_PARENT_PREFIX); if (rc == TOKERR_TOKEN_TOO_LONG) continue; else if (ptoken->wTokenLen < MAX_TOKEN_LEN) ptoken->szToken[ptoken->wTokenLen++] = (char)c; else { ptoken->wErrLine = ptoken->pline->wLineNum; ptoken->wErrPos = ptoken->pline->wLinePos; rc = TOKERR_TOKEN_TOO_LONG; } } ptoken->szToken[ptoken->wTokenLen] = '\0'; LineUnGetC(c, ptoken->pline); if (rc == TOKERR_NONE) { ptoken->llTokenValue = LookupID(ptoken); } } EXIT((4, "ScanID=%d (IDType=%I64d,ID=%s)\n", rc, ptoken->llTokenValue, ptoken->szToken)); return rc; } //ScanID /***LP ScanNum - scan number token * * ENTRY * c - first character of the token * ptoken -> token structure * * EXIT-SUCCESS * returns TOKERR_NONE * EXIT-FAILURE * returns TOKTYPE_NO_MATCH - not a number token * TOKERR_TOKEN_TOO_LONG - number too long */ int LOCAL ScanNum(int c, PTOKEN ptoken) { int rc = TOKERR_NO_MATCH; ENTER((4, "ScanNum(c=%c,ptoken=%p)\n", c, ptoken)); if (isdigit(c)) { BOOL fHex = FALSE; rc = TOKERR_NONE; ptoken->iTokenType = TOKTYPE_NUMBER; if ((c == '0') && ((c = LineGetC(ptoken->pline)) != EOF)) { if (c != 'x') LineUnGetC(c, ptoken->pline); else { ptoken->szToken[ptoken->wTokenLen++] = (char)c; fHex = TRUE; } } while (((c = LineGetC(ptoken->pline)) != EOF) && ((!fHex && isdigit(c)) || fHex && isxdigit(c))) { if (rc == TOKERR_TOKEN_TOO_LONG) continue; else if (ptoken->wTokenLen < MAX_TOKEN_LEN) ptoken->szToken[ptoken->wTokenLen++] = (char)c; else { ptoken->wErrLine = ptoken->pline->wLineNum; ptoken->wErrPos = ptoken->pline->wLinePos; rc = TOKERR_TOKEN_TOO_LONG; } } ptoken->szToken[ptoken->wTokenLen] = '\0'; LineUnGetC(c, ptoken->pline); if (rc == TOKERR_NONE) { if (!StrToQWord(ptoken->szToken, 0, (QWORD *)&ptoken->llTokenValue)) { ptoken->wErrLine = ptoken->pline->wLineNum; ptoken->wErrPos = ptoken->pline->wLinePos; rc = TOKERR_TOKEN_TOO_LONG; } } } EXIT((4, "ScanNum=%d (Num=%I64d,Token=%s)\n", rc, ptoken->llTokenValue, ptoken->szToken)); return rc; } //ScanNum /***LP ScanString - scan string token * * ENTRY * c - first character of the token * ptoken -> token structure * * EXIT-SUCCESS * returns TOKERR_NONE * EXIT-FAILURE * returns TOKTYPE_NO_MATCH - not a string token * TOKERR_TOKEN_TOO_LONG - string too long * TOKERR_UNCLOSED_STRING - EOF before string close */ int LOCAL ScanString(int c, PTOKEN ptoken) { int rc = TOKERR_NO_MATCH; ENTER((4, "ScanString(c=%c,ptoken=%p)\n", c, ptoken)); if (c == '"') { rc = TOKERR_NONE; ptoken->iTokenType = TOKTYPE_STRING; ptoken->wTokenLen--; while (((c = LineGetC(ptoken->pline)) != EOF) && (c != '"')) { if (rc == TOKERR_TOKEN_TOO_LONG) continue; else if (ptoken->wTokenLen >= MAX_TOKEN_LEN) { ptoken->wErrLine = ptoken->pline->wLineNum; ptoken->wErrPos = ptoken->pline->wLinePos; rc = TOKERR_TOKEN_TOO_LONG; } else { if (c == '\\') c = GetEscapedChar(ptoken->pline); ptoken->szToken[ptoken->wTokenLen++] = (char)c; } } ptoken->szToken[ptoken->wTokenLen] = '\0'; if (c == EOF) { ptoken->wErrLine = ptoken->pline->wLineNum; if ((ptoken->wErrPos = ptoken->pline->wLinePos) != 0) ptoken->wErrPos--; rc = TOKERR_UNCLOSED_STRING; } } EXIT((4, "ScanString=%d (string=%s)\n", rc, ptoken->szToken)); return rc; } //ScanString /***LP ScanChar - scan character token * * ENTRY * c - first character of the token * ptoken -> token structure * * EXIT-SUCCESS * returns TOKERR_NONE * EXIT-FAILURE * returns TOKERR_NO_MATCH - not a character token * TOKERR_TOKEN_TOO_LONG - token too long * TOKERR_UNCLOSED_CHAR - cannot find character close */ int LOCAL ScanChar(int c, PTOKEN ptoken) { int rc = TOKERR_NO_MATCH; ENTER((4, "ScanChar(c=%c,ptoken=%p)\n", c, ptoken)); if (c == '\'') { rc = TOKERR_NONE; ptoken->iTokenType = TOKTYPE_CHAR; ptoken->wTokenLen--; if (((c = LineGetC(ptoken->pline)) == EOF) || (c == '\\') && ((c = GetEscapedChar(ptoken->pline)) == EOF)) { rc = TOKERR_UNCLOSED_CHAR; } else { ptoken->szToken[ptoken->wTokenLen++] = (char)c; ptoken->szToken[ptoken->wTokenLen] = '\0'; ptoken->llTokenValue = c; if ((c = LineGetC(ptoken->pline)) == EOF) rc = TOKERR_UNCLOSED_CHAR; else if (c != '\'') rc = TOKERR_TOKEN_TOO_LONG; } if (rc != TOKERR_NONE) { ptoken->wErrLine = ptoken->pline->wLineNum; if ((ptoken->wErrPos = ptoken->pline->wLinePos) != 0) ptoken->wErrPos--; if (rc == TOKERR_TOKEN_TOO_LONG) { while (((c = LineGetC(ptoken->pline)) != EOF) && (c != '\'')) ; if (c == EOF) rc = TOKERR_UNCLOSED_CHAR; } } } EXIT((4, "ScanChar=%d (Value=%I64d,Char=%s)\n", rc, ptoken->llTokenValue, ptoken->szToken)); return rc; } //ScanChar /***LP ProcessInLineComment - handle inline comment * * ENTRY * ptoken -> token structure * * EXIT * always returns TOKERR_NONE */ int LOCAL ProcessInLineComment(PTOKEN ptoken) { ENTER((4, "ProcessInLineComment(ptoken=%p,Token=%s,Comment=%s)\n", ptoken, ptoken->szToken, &ptoken->pline->szLineBuff[ptoken->pline->wLinePos])); LineFlush(ptoken->pline); ptoken->iTokenType = TOKTYPE_NULL; EXIT((4, "ProcessInLineComment=%d\n", TOKERR_NONE)); return TOKERR_NONE; } //ProcessInLineComment /***LP ProcessComment - handle comment * * ENTRY * ptoken -> token structure * * EXIT * always returns TOKERR_NONE */ int LOCAL ProcessComment(PTOKEN ptoken) { int rc = TOKERR_UNCLOSED_COMMENT; int c; char *pch; ENTER((4, "ProcessComment(ptoken=%p,Token=%s,Comment=%s)\n", ptoken, ptoken->szToken, &ptoken->pline->szLineBuff[ptoken->pline->wLinePos])); while ((c = LineGetC(ptoken->pline)) != EOF) { if ((pch = strchr(SymCharTable, c)) != NULL) { int i; i = LookupSym(ptoken, (int)(pch - SymCharTable)); if (SymTokTable[i].iSymType == SYM_CLOSECOMMENT) { ptoken->iTokenType = TOKTYPE_NULL; rc = TOKERR_NONE; break; } } } if (rc != TOKERR_NONE) { ptoken->wErrLine = ptoken->pline->wLineNum; if ((ptoken->wErrPos = ptoken->pline->wLinePos) != 0) ptoken->wErrPos--; } EXIT((4, "ProcessComment=%d\n", rc)); return rc; } //ProcessComment /***LP LookupSym - match for 2-char. symbols * * ENTRY * ptoken -> token structure * iTable = SymCharTable index * * EXIT-SUCCESS * returns a different index than iTable; * EXIT-FAILURE * returns iTable; */ int LOCAL LookupSym(PTOKEN ptoken, int iTable) { int i = iTable; int c; ENTER((4, "LookupSym(ptoken=%p,iTable=%d)\n", ptoken, iTable)); if ((SymTokTable[iTable].iLink != 0) && ((c = LineGetC(ptoken->pline)) != EOF)) { i = SymTokTable[iTable].iLink; while ((c != SymTokTable[i].chSym) && (SymTokTable[i].iLink != 0)) i = SymTokTable[i].iLink; if (c != SymTokTable[i].chSym) { LineUnGetC(c, ptoken->pline); i = iTable; } } EXIT((4, "LookupSym=%d\n", i)); return i; } //LookupSym /***LP LookupID - lookup the token in our reserved ID list * * ENTRY * ptoken -> token structure * * EXIT-SUCCESS * returns index of TermTable * EXIT-FAILURE * returns ID_USER */ LONG LOCAL LookupID(PTOKEN ptoken) { LONG lID = ID_USER; LONG i; ENTER((4, "LookupID(ptoken=%p)\n", ptoken)); for (i = 0; TermTable[i].pszID != NULL; ++i) { if (_stricmp(TermTable[i].pszID, ptoken->szToken) == 0) { lID = i; break; } } EXIT((4, "LookupID=%ld\n", lID)); return lID; } //LookupID /***LP GetEscapedChar - read and translate escape character * * ENTRY * pline -> line structure * * EXIT-SUCCESS * returns the escape character * EXIT-FAILURE * returns EOF - eof encountered */ int LOCAL GetEscapedChar(PLINE pline) { int c; #define ESCAPE_BUFF_SIZE 5 char achEscapedBuff[ESCAPE_BUFF_SIZE]; int i; ENTER((4, "GetEscapedChar(pline=%p)\n", pline)); if ((c = LineGetC(pline)) != EOF) { switch(c) { case '0': achEscapedBuff[0] = (char)c; for (i = 1; i < 4; i++) //maximum 3 digits { if (((c = LineGetC(pline)) != EOF) && (c >= '0') && (c <= '7')) { achEscapedBuff[i] = (char)c; } else { LineUnGetC(c, pline); break; } } achEscapedBuff[i] = '\0'; c = (int)strtoul(achEscapedBuff, NULL, 8); break; case 'a': c = '\a'; //alert (bell) break; case 'b': c = '\b'; //backspace break; case 'f': c = '\f'; //form feed break; case 'n': c = '\n'; //newline break; case 'r': c = '\r'; //carriage return break; case 't': c = '\t'; //horizontal tab break; case 'v': c = '\v'; //vertical tab break; case 'x': for (i = 0; i < 2; i++) //maximum 2 digits { if (((c = LineGetC(pline)) != EOF) && isxdigit(c)) achEscapedBuff[i] = (char)c; else { LineUnGetC(c, pline); break; } } achEscapedBuff[i] = '\0'; c = (int)strtoul(achEscapedBuff, NULL, 16); } } EXIT((4, "GetEscapedChar=%x\n", c)); return c; } //GetEscapedChar /***EP PrintScanErr - print scan error * * ENTRY * ptoken -> token structure * rcErr - error code * * EXIT * None */ VOID EXPORT PrintScanErr(PTOKEN ptoken, int rcErr) { WORD i; ENTER((4, "PrintScanErr(ptoken=%p,Err=%d)\n", ptoken, rcErr)); ASSERT(ptoken->wTokenLine == ptoken->wErrLine); ErrPrintf("%5u: %s\n ", ptoken->wTokenLine, ptoken->pline->szLineBuff); for (i = 0; i < ptoken->wErrPos; ++i) { if (ptoken->pline->szLineBuff[i] == '\t') { ErrPrintf("\t"); } else { ErrPrintf(" "); } } ErrPrintf("^***\n"); switch (rcErr) { case TOKERR_TOKEN_TOO_LONG: ErrPrintf("ScanErr: Token too long\n"); break; case TOKERR_UNCLOSED_STRING: ErrPrintf("ScanErr: Unclosed string\n"); break; case TOKERR_UNCLOSED_CHAR: ErrPrintf("ScanErr: Unclosed character quote\n"); break; default: ErrPrintf("ScanErr: Syntax error\n"); break; } EXIT((4, "PrintScanErr!\n")); } //PrintScanErr /***EP StrToQWord - convert the number in a string to a QWord * * ENTRY * psz -> string * dwBase - the base of the number (if 0, auto-detect base) * pqw -> to hold the resulting QWord * * EXIT-SUCCESS * returns TRUE * EXIT-FAILURE * returns FALSE */ BOOL EXPORT StrToQWord(PSZ psz, DWORD dwBase, QWORD *pqw) { BOOL rc = TRUE; ULONG m; ENTER((4, "StrToQWord(Str=%s,Base=%x,pqw=%p)\n", psz, dwBase, pqw)); *pqw = 0; if (dwBase == 0) { if (psz[0] == '0') { if ((psz[1] == 'x') || (psz[1] == 'X')) { dwBase = 16; psz += 2; } else { dwBase = 8; psz++; } } else dwBase = 10; } while (*psz != '\0') { if ((*psz >= '0') && (*psz <= '9')) m = *psz - '0'; else if ((*psz >= 'A') && (*psz <= 'Z')) m = *psz - 'A' + 10; else if ((*psz >= 'a') && (*psz <= 'z')) m = *psz - 'a' + 10; else { rc = FALSE; break; } if (m < dwBase) { *pqw = (*pqw * dwBase) + m; psz++; } else { rc = FALSE; break; } } EXIT((4, "StrToQWord=%x (QWord=0x%I64x)\n", rc, *pqw)); return rc; } //StrToQWord