/** * @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" /** * @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); 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 { 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); 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; } if (ReturnEndOfString) { Token = NewToken(END_OF_STACK, "$"); return Token; } if (str[InputIdx - 1] == '\0') { } while (1) { CurrentTokenIdx = InputIdx - 1; 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; } 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; }