HyperDbg/hyperdbg/script-engine/code/scanner.c
Claude 1abdde7702
Fix memory-safety and robustness issues in script engine and PCI ID parser
Code audit of the script engine's scanner/token handling and of the PCI ID
database parser. Each of the issues below was reproduced against the current
code before the fix and re-checked afterwards.

script-engine/scanner.c

  * An unterminated string literal ("abc or L"abc) hung the scanner in an
    endless loop: sgetc() returns EOF without consuming input, and neither
    string loop tested for it, so the token grew until allocation failed.
    Both loops now stop at EOF and report the token as UNKNOWN.

script-engine/common.c

  * AppendByte()/AppendWchar() doubled Token->MaxLen before checking whether
    the larger buffer was actually allocated. After a failed allocation MaxLen
    described memory that did not exist and the next append wrote past the end
    of the old buffer. MaxLen is now committed only on success.

  * CopyToken() allocated strlen(Value) + 1 bytes but carried over the source
    token's Len and MaxLen, so the copy's advertised capacity did not match its
    allocation, and WSTRING payloads were truncated at their first embedded
    null byte. The copy is now sized from Len/MaxLen and copied by length, with
    a fallback to the string length for the grammar tokens in parse-table.c,
    which only initialize Type and Value.

  * NewToken() set MaxLen to the value length, which is zero for an empty
    value. The 'Len >= MaxLen - 1' test in the append routines is unsigned, so
    a zero MaxLen wrapped and disabled buffer growth entirely.

  * IsUnderscore() tested 'c >= '_'', which also accepted the backtick, the
    lowercase letters, '{', '|', '}', '~' and DEL. Register scanning uses it,
    so '@rax|1' was lexed as one malformed register name instead of a register,
    an operator and a number. The pseudo-register path already compared against
    '_' directly.

  * NewTokenList() did not check the allocation of its Head buffer.

  * NewTemp() kept the last handed-out id in a static, so an exhausted temp
    list produced a token aliasing a temporary still in use, and it derived
    MaxTempNumber from an out-of-range index. It also dereferenced the new
    token without a null check.

  * FreeTemp() indexed the MAX_TEMP_COUNT-entry map with an unchecked value
    parsed out of the token text.

  * RotateLeftStringOnce() wrote to str[-1] when handed an empty string.

libhyperdbg/debugger/misc/pci-id.cpp

  * The database file was read into a malloc(Length) buffer that was never
    null-terminated, while ReadLine() walks it with strchr(). Looking up an
    absent vendor scans to the end and reads past the allocation.

  * The matched Vendor was allocated with malloc() and its Devices list head
    was only assigned once a device line was parsed, so a vendor with no
    device entries left it uninitialized and FreeVendor() walked a garbage
    pointer.

  * FreeVendor() released the device and subdevice lists but never the Vendor
    itself, leaking one per lookup for every enumerated PCI device.

  * The file handle leaked when the buffer allocation failed, ftell() and
    fread() results were unused, and several error paths leaked the Vendor or
    the not-yet-linked Device/SubDevice.

  * strncmp() compared sizeof(VendorId) bytes, which is the size of the
    pointer rather than the length of a vendor id.

  * ReadLine() passed an unclamped count to strncpy_s(), which triggers the
    invalid parameter handler for a line longer than the destination.

  * GetVendorById() ignored the GetModuleFileName() result and overwrote the
    tail of the path buffer without checking the room left in it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W3C1DuhHtqK64eEkHjKCHM
2026-08-01 14:22:52 +00:00

1177 lines
31 KiB
C

/**
* @file scanner.c
* @author M.H. Gholamrezaei (mh@hyperdbg.org)
*
* @details Script Engine Scanner
* @version 0.1
* @date 2020-10-22
*
* @copyright This project is released under the GNU Public License v3.
*
*/
#include "pch.h"
static BOOLEAN PreviousTokenCanEndExpression;
/**
* @brief reads a token from the input string
*
* @param c
* @param str
* @return PSCRIPT_ENGINE_TOKEN
*/
PSCRIPT_ENGINE_TOKEN
GetToken(char * c, char * str)
{
PSCRIPT_ENGINE_TOKEN Token = NewUnknownToken();
switch (*c)
{
case '"':
do
{
*c = sgetc(str);
//
// An unterminated string literal would otherwise spin here forever,
// since sgetc() keeps returning EOF without consuming any input
//
if ((int)*c == EOF)
{
Token->Type = UNKNOWN;
return Token;
}
if (*c == '\\')
{
*c = sgetc(str);
if (*c == 'n')
{
AppendByte(Token, '\n');
continue;
}
if (*c == '\\')
{
AppendByte(Token, '\\');
continue;
}
else if (*c == 't')
{
AppendByte(Token, '\t');
continue;
}
else if (*c == 'x')
{
char ByteString[] = "000";
INT Len = (INT)strlen(ByteString);
int i = 0;
for (; i < Len; i++)
{
*c = sgetc(str);
if (!IsHex(*c))
break;
RotateLeftStringOnce(ByteString);
ByteString[Len - 1] = *c;
}
if (i == 0 || i == 3)
{
Token->Type = UNKNOWN;
*c = sgetc(str);
return Token;
}
else
{
InputIdx--;
CHAR Num = (CHAR)strtol(ByteString, NULL, 16);
AppendByte(Token, Num);
}
}
else if (*c == '"')
{
AppendByte(Token, '"');
continue;
}
else
{
Token->Type = UNKNOWN;
*c = sgetc(str);
return Token;
}
}
else if (*c == '"')
{
break;
}
else
{
AppendByte(Token, *c);
}
} while (1);
Token->Len++;
Token->Type = STRING;
*c = sgetc(str);
return Token;
case '~':
strcpy(Token->Value, "~");
Token->Type = SPECIAL_TOKEN;
*c = sgetc(str);
return Token;
case '+':
*c = sgetc(str);
if (*c == '+')
{
strcpy(Token->Value, "++");
Token->Type = SPECIAL_TOKEN;
*c = sgetc(str);
return Token;
}
else if (*c == '=')
{
strcpy(Token->Value, "+=");
Token->Type = SPECIAL_TOKEN;
*c = sgetc(str);
return Token;
}
else
{
strcpy(Token->Value, "+");
Token->Type = SPECIAL_TOKEN;
return Token;
}
case '-':
*c = sgetc(str);
if (*c == '>')
{
strcpy(Token->Value, "->");
Token->Type = SPECIAL_TOKEN;
*c = sgetc(str);
return Token;
}
else if (*c == '-')
{
strcpy(Token->Value, "--");
Token->Type = SPECIAL_TOKEN;
*c = sgetc(str);
return Token;
}
else if (*c == '=')
{
strcpy(Token->Value, "-=");
Token->Type = SPECIAL_TOKEN;
*c = sgetc(str);
return Token;
}
else
{
strcpy(Token->Value, "-");
Token->Type = SPECIAL_TOKEN;
return Token;
}
case '*':
*c = sgetc(str);
if (*c == '=')
{
strcpy(Token->Value, "*=");
Token->Type = SPECIAL_TOKEN;
*c = sgetc(str);
return Token;
}
else
{
strcpy(Token->Value, "*");
Token->Type = SPECIAL_TOKEN;
return Token;
}
case '>':
*c = sgetc(str);
if (*c == '>')
{
*c = sgetc(str);
if (*c == '=')
{
strcpy(Token->Value, ">>=");
Token->Type = SPECIAL_TOKEN;
*c = sgetc(str);
return Token;
}
else
{
strcpy(Token->Value, ">>");
Token->Type = SPECIAL_TOKEN;
return Token;
}
}
else if (*c == '=')
{
strcpy(Token->Value, ">=");
Token->Type = SPECIAL_TOKEN;
*c = sgetc(str);
return Token;
}
else
{
strcpy(Token->Value, ">");
Token->Type = SPECIAL_TOKEN;
return Token;
}
case '<':
*c = sgetc(str);
if (*c == '<')
{
*c = sgetc(str);
if (*c == '=')
{
strcpy(Token->Value, "<<=");
Token->Type = SPECIAL_TOKEN;
*c = sgetc(str);
return Token;
}
else
{
strcpy(Token->Value, "<<");
Token->Type = SPECIAL_TOKEN;
return Token;
}
}
else if (*c == '=')
{
strcpy(Token->Value, "<=");
Token->Type = SPECIAL_TOKEN;
*c = sgetc(str);
return Token;
}
else
{
strcpy(Token->Value, "<");
Token->Type = SPECIAL_TOKEN;
return Token;
}
case '/':
*c = sgetc(str);
if (*c == '=')
{
strcpy(Token->Value, "/=");
Token->Type = SPECIAL_TOKEN;
*c = sgetc(str);
return Token;
}
else if (*c == '/')
{
do
{
*c = sgetc(str);
} while (*c != '\n' && (int)*c != EOF);
Token->Type = COMMENT;
*c = sgetc(str);
return Token;
}
else if (*c == '*')
{
do
{
*c = sgetc(str);
if (*c == '*')
{
*c = sgetc(str);
if (*c == '/')
{
Token->Type = COMMENT;
*c = sgetc(str);
return Token;
}
}
if ((int)*c == EOF)
break;
} while (1);
Token->Type = UNKNOWN;
*c = sgetc(str);
return Token;
}
else
{
strcpy(Token->Value, "/");
Token->Type = SPECIAL_TOKEN;
return Token;
}
case '=':
*c = sgetc(str);
if (*c == '=')
{
strcpy(Token->Value, "==");
Token->Type = SPECIAL_TOKEN;
*c = sgetc(str);
return Token;
}
else
{
strcpy(Token->Value, "=");
Token->Type = SPECIAL_TOKEN;
return Token;
}
case '!':
*c = sgetc(str);
if (*c == '=')
{
strcpy(Token->Value, "!=");
Token->Type = SPECIAL_TOKEN;
*c = sgetc(str);
return Token;
}
else
{
strcpy(Token->Value, "!");
Token->Type = UNKNOWN;
return Token;
}
case '%':
*c = sgetc(str);
if (*c == '=')
{
strcpy(Token->Value, "%=");
Token->Type = SPECIAL_TOKEN;
*c = sgetc(str);
return Token;
}
else
{
strcpy(Token->Value, "%");
Token->Type = SPECIAL_TOKEN;
}
return Token;
case ',':
strcpy(Token->Value, ",");
Token->Type = SPECIAL_TOKEN;
*c = sgetc(str);
return Token;
case ';':
strcpy(Token->Value, ";");
Token->Type = SPECIAL_TOKEN;
*c = sgetc(str);
return Token;
case ':':
strcpy(Token->Value, ":");
Token->Type = SPECIAL_TOKEN;
*c = sgetc(str);
return Token;
case '(':
strcpy(Token->Value, "(");
Token->Type = SPECIAL_TOKEN;
*c = sgetc(str);
return Token;
case ')':
strcpy(Token->Value, ")");
Token->Type = SPECIAL_TOKEN;
*c = sgetc(str);
return Token;
case '{':
strcpy(Token->Value, "{");
Token->Type = SPECIAL_TOKEN;
*c = sgetc(str);
return Token;
case '}':
strcpy(Token->Value, "}");
Token->Type = SPECIAL_TOKEN;
*c = sgetc(str);
return Token;
case '[':
strcpy(Token->Value, "[");
Token->Type = SPECIAL_TOKEN;
*c = sgetc(str);
return Token;
case ']':
strcpy(Token->Value, "]");
Token->Type = SPECIAL_TOKEN;
*c = sgetc(str);
return Token;
case '|':
*c = sgetc(str);
if (*c == '|')
{
strcpy(Token->Value, "||");
Token->Type = SPECIAL_TOKEN;
*c = sgetc(str);
return Token;
}
else if (*c == '=')
{
strcpy(Token->Value, "|=");
Token->Type = SPECIAL_TOKEN;
*c = sgetc(str);
return Token;
}
else
{
strcpy(Token->Value, "|");
Token->Type = SPECIAL_TOKEN;
return Token;
}
case '&':
*c = sgetc(str);
if (*c == '&')
{
strcpy(Token->Value, "&&");
Token->Type = SPECIAL_TOKEN;
*c = sgetc(str);
return Token;
}
else if (*c == '=')
{
strcpy(Token->Value, "&=");
Token->Type = SPECIAL_TOKEN;
*c = sgetc(str);
return Token;
}
else
{
strcpy(Token->Value, "&");
Token->Type = SPECIAL_TOKEN;
return Token;
}
case '^':
*c = sgetc(str);
if (*c == '=')
{
strcpy(Token->Value, "^=");
Token->Type = SPECIAL_TOKEN;
*c = sgetc(str);
return Token;
}
else
{
strcpy(Token->Value, "^");
Token->Type = SPECIAL_TOKEN;
}
return Token;
case '@':
*c = sgetc(str);
if (IsLetter(*c))
{
while (IsLetter(*c) || IsDecimal(*c) || IsUnderscore(*c))
{
AppendByte(Token, *c);
*c = sgetc(str);
}
if (RegisterToInt(Token->Value) != INVALID)
{
Token->Type = REGISTER;
}
else
{
Token->Type = UNKNOWN;
}
return Token;
}
case '$':
*c = sgetc(str);
if (IsLetter(*c))
{
//
// Append valid characters for pseudo registers' name
//
while (IsLetter(*c) || IsDecimal(*c) || *c == '_')
{
AppendByte(Token, *c);
*c = sgetc(str);
}
if (PseudoRegToInt(Token->Value) != INVALID)
{
Token->Type = PSEUDO_REGISTER;
}
else
{
Token->Type = UNKNOWN;
}
return Token;
}
case '.':
AppendByte(Token, *c);
*c = sgetc(str);
if (IsLetter(*c) || IsHex(*c) || (*c == '_') || (*c == '!'))
{
do
{
AppendByte(Token, *c);
*c = sgetc(str);
} while (IsLetter(*c) || IsHex(*c) || (*c == '_') || (*c == '!'));
BOOLEAN WasFound = FALSE;
BOOLEAN HasBang = strstr(Token->Value, "!") != 0;
UINT64 Address = 0;
if (HasBang)
{
Address = ScriptEngineConvertNameToAddress(Token->Value, &WasFound);
}
if (WasFound)
{
RemoveToken(&Token);
char HexStr[20] = {0};
sprintf(HexStr, "%llx", Address);
Token = NewToken(HEX, HexStr);
}
else
{
if (HasBang)
{
Token->Type = UNKNOWN;
return Token;
}
else
{
if (GetGlobalIdentifierVal(Token) != -1)
{
Token->Type = GLOBAL_ID;
Token->VariableType = GetGlobalIdentifierVariableType(Token);
}
else
{
Token->Type = GLOBAL_UNRESOLVED_ID;
}
}
}
}
else
{
Token->Type = UNKNOWN;
return Token;
}
return Token;
case '#':
do
{
if (*c != '`')
AppendByte(Token, *c);
*c = sgetc(str);
} while (IsLetter(*c) || IsHex(*c) || (*c == '_') || (*c == '!'));
if (IsKeyword(Token->Value))
{
Token->Type = KEYWORD;
}
else
{
Token->Type = UNKNOWN;
}
return Token;
case ' ':
case '\t':
strcpy(Token->Value, "");
Token->Type = WHITE_SPACE;
*c = sgetc(str);
return Token;
case '\n':
strcpy(Token->Value, "\n");
Token->Type = WHITE_SPACE;
*c = sgetc(str);
return Token;
case '0':
*c = sgetc(str);
if (*c == 'x')
{
*c = sgetc(str);
while (IsHex(*c) || *c == '`')
{
if (*c != '`')
AppendByte(Token, *c);
*c = sgetc(str);
}
Token->Type = HEX;
return Token;
}
else if (*c == 'o')
{
*c = sgetc(str);
while (IsOctal(*c) || *c == '`')
{
if (*c != '`')
AppendByte(Token, *c);
*c = sgetc(str);
}
Token->Type = OCTAL;
return Token;
}
else if (*c == 'n')
{
*c = sgetc(str);
while (IsDecimal(*c) || *c == '`')
{
if (*c != '`')
AppendByte(Token, *c);
*c = sgetc(str);
}
Token->Type = DECIMAL;
return Token;
}
else if (*c == 'y')
{
*c = sgetc(str);
while (IsBinary(*c) || *c == '`')
{
if (*c != '`')
AppendByte(Token, *c);
*c = sgetc(str);
}
Token->Type = BINARY;
return Token;
}
else if (IsHex(*c))
{
do
{
if (*c != '`')
AppendByte(Token, *c);
*c = sgetc(str);
} while (IsHex(*c) || *c == '`');
Token->Type = HEX;
return Token;
}
else
{
strcpy(Token->Value, "0");
Token->Type = HEX;
return Token;
}
case 'L':
if (*(str + InputIdx) == '"')
{
InputIdx++;
do
{
*c = sgetc(str);
//
// An unterminated wide string literal would otherwise spin here
// forever, since sgetc() keeps returning EOF without consuming input
//
if ((int)*c == EOF)
{
Token->Type = UNKNOWN;
return Token;
}
if (*c == '\\')
{
*c = sgetc(str);
if (*c == 'n')
{
AppendWchar(Token, L'\n');
continue;
}
if (*c == '\\')
{
AppendWchar(Token, L'\\');
continue;
}
else if (*c == 't')
{
AppendWchar(Token, L'\t');
continue;
}
else if (*c == 'x')
{
char ByteString[] = "00000";
INT Len = (INT)strlen(ByteString);
int i = 0;
for (; i < Len; i++)
{
*c = sgetc(str);
if (!IsHex(*c))
break;
RotateLeftStringOnce(ByteString);
ByteString[Len - 1] = *c;
}
if (i == 0 || i == 5)
{
Token->Type = UNKNOWN;
*c = sgetc(str);
return Token;
}
else
{
InputIdx--;
WCHAR Num = (WCHAR)strtol(ByteString, NULL, 16);
AppendWchar(Token, Num);
}
}
else if (*c == '"')
{
AppendWchar(Token, L'"');
continue;
}
else
{
Token->Type = UNKNOWN;
*c = sgetc(str);
return Token;
}
}
else if (*c == '"')
{
break;
}
else
{
AppendWchar(Token, (wchar_t)*c);
}
} while (1);
Token->Len += 2;
Token->Type = WSTRING;
*c = sgetc(str);
return Token;
}
default:
if (*c >= '0' && *c <= '9')
{
do
{
if (*c != '`')
AppendByte(Token, *c);
*c = sgetc(str);
} while (IsHex(*c) || *c == '`');
Token->Type = HEX;
return Token;
}
else if ((*c >= 'a' && *c <= 'f') || (*c >= 'A' && *c <= 'F') || (*c == '_') || (*c == '!'))
{
UINT8 NotHex = 0;
do
{
if (*c != '`')
AppendByte(Token, *c);
*c = sgetc(str);
if (IsHex(*c) || *c == '`' || *c == '_')
{
// Nothing
}
else if ((*c >= 'G' && *c <= 'Z') || (*c >= 'g' && *c <= 'z'))
{
NotHex = 1;
break;
}
else
{
break;
}
} while (1);
if (NotHex)
{
do
{
if (*c != '`')
AppendByte(Token, *c);
*c = sgetc(str);
} while (IsLetter(*c) || IsHex(*c) || (*c == '_') || (*c == '!'));
if (IsKeyword(Token->Value))
{
Token->Type = KEYWORD;
}
else if (IsRegister(Token->Value))
{
Token->Type = REGISTER;
}
else if (IsVariableType(Token->Value))
{
Token->Type = SCRIPT_VARIABLE_TYPE;
}
else
{
BOOLEAN WasFound = FALSE;
BOOLEAN HasBang = strstr(Token->Value, "!") != 0;
UINT64 Address = 0;
if (HasBang)
{
Address = ScriptEngineConvertNameToAddress(Token->Value, &WasFound);
}
if (WasFound)
{
RemoveToken(&Token);
char str[20] = {0};
sprintf(str, "%llx", Address);
Token = NewToken(HEX, str);
}
else
{
if (HasBang)
{
Token->Type = UNKNOWN;
return Token;
}
else
{
if (GetUserDefinedFunctionNode(Token))
{
Token->Type = FUNCTION_ID;
}
else if (GetFunctionParameterIdentifier(Token) != -1)
{
Token->Type = FUNCTION_PARAMETER_ID;
}
else if (GetLocalIdentifierVal(Token) != -1)
{
Token->Type = LOCAL_ID;
Token->VariableType = GetLocalIdentifierVariableType(Token);
}
else
{
Token->Type = LOCAL_UNRESOLVED_ID;
}
}
}
}
return Token;
}
else
{
if (IsKeyword(Token->Value))
{
Token->Type = KEYWORD;
}
else if (IsRegister(Token->Value))
{
Token->Type = REGISTER;
}
else if (IsVariableType(Token->Value))
{
Token->Type = SCRIPT_VARIABLE_TYPE;
}
else if (IsId(Token->Value))
{
BOOLEAN WasFound = FALSE;
BOOLEAN HasBang = strstr(Token->Value, "!") != 0;
UINT64 Address = 0;
if (HasBang)
{
Address = ScriptEngineConvertNameToAddress(Token->Value, &WasFound);
}
if (WasFound)
{
RemoveToken(&Token);
char HexStr[20] = {0};
sprintf(HexStr, "%llx", Address);
Token = NewToken(HEX, HexStr);
}
else
{
if (HasBang)
{
Token->Type = UNKNOWN;
return Token;
}
else
{
if (GetUserDefinedFunctionNode(Token))
{
Token->Type = FUNCTION_ID;
}
else if (GetFunctionParameterIdentifier(Token) != -1)
{
Token->Type = FUNCTION_PARAMETER_ID;
}
else if (GetLocalIdentifierVal(Token) != -1)
{
Token->Type = LOCAL_ID;
Token->VariableType = GetLocalIdentifierVariableType(Token);
}
else
{
Token->Type = LOCAL_UNRESOLVED_ID;
}
Token->VariableType;
}
}
}
else
{
Token->Type = HEX;
}
return Token;
}
}
else if ((*c >= 'G' && *c <= 'Z') || (*c >= 'g' && *c <= 'z') || (*c == '_') || (*c == '!'))
{
do
{
if (*c != '`')
AppendByte(Token, *c);
*c = sgetc(str);
} while (IsLetter(*c) || IsHex(*c) || (*c == '_') || (*c == '!'));
if (IsKeyword(Token->Value))
{
Token->Type = KEYWORD;
}
else if (IsRegister(Token->Value))
{
Token->Type = REGISTER;
}
else if (IsVariableType(Token->Value))
{
Token->Type = SCRIPT_VARIABLE_TYPE;
}
else
{
BOOLEAN WasFound = FALSE;
BOOLEAN HasBang = strstr(Token->Value, "!") != 0;
UINT64 Address = 0;
if (HasBang)
{
Address = ScriptEngineConvertNameToAddress(Token->Value, &WasFound);
}
if (WasFound)
{
RemoveToken(&Token);
char HexStr[20] = {0};
sprintf(HexStr, "%llx", Address);
Token = NewToken(HEX, HexStr);
}
else
{
if (HasBang)
{
Token->Type = UNKNOWN;
return Token;
}
else
{
if (GetUserDefinedFunctionNode(Token))
{
Token->Type = FUNCTION_ID;
}
else if (GetFunctionParameterIdentifier(Token) != -1)
{
Token->Type = FUNCTION_PARAMETER_ID;
}
else if (GetLocalIdentifierVal(Token) != -1)
{
Token->Type = LOCAL_ID;
Token->VariableType = GetLocalIdentifierVariableType(Token);
}
else
{
Token->Type = LOCAL_UNRESOLVED_ID;
}
}
}
}
return Token;
}
Token->Type = UNKNOWN;
*c = sgetc(str);
return Token;
}
return Token;
}
/**
* @brief Perform scanning the script engine
*
* @param str
* @param c
* @return PSCRIPT_ENGINE_TOKEN
*/
PSCRIPT_ENGINE_TOKEN
Scan(char * str, char * c)
{
static BOOLEAN ReturnEndOfString;
PSCRIPT_ENGINE_TOKEN Token;
if (InputIdx <= 1)
{
ReturnEndOfString = FALSE;
PreviousTokenCanEndExpression = FALSE;
}
if (ReturnEndOfString)
{
Token = NewToken(END_OF_STACK, "$");
return Token;
}
if (str[InputIdx - 1] == '\0')
{
}
while (1)
{
CurrentTokenIdx = InputIdx - 1;
if (*c == '.' && PreviousTokenCanEndExpression)
{
Token = NewToken(SPECIAL_TOKEN, ".");
*c = sgetc(str);
}
else
{
Token = GetToken(c, str);
}
if ((int)*c == EOF)
{
ReturnEndOfString = TRUE;
}
if (Token->Type == WHITE_SPACE)
{
if (!strcmp(Token->Value, "\n"))
{
CurrentLine++;
CurrentLineIdx = InputIdx;
}
RemoveToken(&Token);
if (ReturnEndOfString)
{
Token = NewToken(END_OF_STACK, "$");
return Token;
}
continue;
}
else if (Token->Type == COMMENT)
{
RemoveToken(&Token);
if (ReturnEndOfString)
{
Token = NewToken(END_OF_STACK, "$");
return Token;
}
continue;
}
PreviousTokenCanEndExpression =
Token->Type == GLOBAL_ID || Token->Type == GLOBAL_UNRESOLVED_ID ||
Token->Type == LOCAL_ID || Token->Type == LOCAL_UNRESOLVED_ID ||
Token->Type == FUNCTION_PARAMETER_ID || Token->Type == REGISTER ||
Token->Type == PSEUDO_REGISTER || Token->Type == HEX ||
Token->Type == DECIMAL || Token->Type == OCTAL || Token->Type == BINARY ||
(Token->Type == SPECIAL_TOKEN &&
(!strcmp(Token->Value, ")") || !strcmp(Token->Value, "]")));
return Token;
}
}
/**
* @brief Returns the next character in the input string
*
* @param str
* @return CHAR the next character at the current position in the string
*/
char
sgetc(char * str)
{
char c = str[InputIdx];
if (c)
{
InputIdx++;
return c;
}
else
{
return EOF;
}
}
/**
* @brief Check whether a string is a keyword or not
*
* @param str
* @return char
*/
char
IsKeyword(char * str)
{
int n = KEYWORD_LIST_LENGTH;
for (int i = 0; i < n; i++)
{
if (!strcmp(str, KeywordList[i]))
{
return 1;
}
}
n = TERMINAL_COUNT;
for (int i = 0; i < n; i++)
{
if (!strcmp(str, TerminalMap[i]))
{
return 1;
}
}
return 0;
}
/**
* @brief Check if string is register or not
*
* @param str
* @return char
*/
char
IsRegister(char * str)
{
if (RegisterToInt(str) == INVALID)
return 0;
return 1;
}
/**
* @brief Check if string is variable type or not
*
* @param str
* @return char
*/
char
IsVariableType(char * str)
{
for (int i = 0; i < SCRIPT_VARIABLE_TYPE_LIST_LENGTH; i++)
{
if (!strcmp(str, ScriptVariableTypeList[i]))
{
return 1;
}
}
return 0;
}
/**
* @brief Check if string is Id or not
*
* @param str
* @return char
*/
char
IsId(char * str)
{
// TODO: Check the str is a id or not
return 0;
}