/* * Copyright (c) 2021-2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include "assembly-type.h" #include "libpandafile/type_helper.h" #include "ins_emit.h" #include "modifiers.h" #include "opcode_parsing.h" #include "operand_types_print.h" #include "utils/number-utils.h" namespace ark::pandasm { bool Parser::ParseRecordFields() { if (!open_ && *context_ == Token::Type::DEL_BRACE_L) { currRecord_->bodyLocation.begin = GetCurrentPosition(false); open_ = true; ++context_; } currRecord_->bodyPresence = true; if (!open_) { context_.err = GetError("Expected keyword.", Error::ErrorType::ERR_BAD_KEYWORD); return false; } if (context_.Mask()) { return true; } if (open_ && *context_ == Token::Type::DEL_BRACE_R) { currRecord_->bodyLocation.end = GetCurrentPosition(true); ++context_; open_ = false; return true; } currRecord_->fieldList.emplace_back(program_.lang); currFld_ = &(currRecord_->fieldList[currRecord_->fieldList.size() - 1]); currFld_->lineOfDef = lineStric_; context_.insNumber = currRecord_->fieldList.size(); LOG(DEBUG, ASSEMBLER) << "parse line " << lineStric_ << " as field (.field name)"; if (!ParseRecordField()) { if (context_.err.err != Error::ErrorType::ERR_NONE) { return false; } if (open_ && *context_ == Token::Type::DEL_BRACE_R) { currRecord_->bodyLocation.end = GetCurrentPosition(true); ++context_; open_ = false; } else { context_.err = GetError("Expected a new field on the next line.", Error::ErrorType::ERR_BAD_KEYWORD); return false; } } return true; } bool Parser::ParseFieldName() { if (PrefixedValidName()) { std::string fieldName = std::string(context_.GiveToken().data(), context_.GiveToken().length()); auto matchNames = [&fieldName](const pandasm::Field &f) { return fieldName == f.name; }; const auto iter = std::find_if(currRecord_->fieldList.begin(), currRecord_->fieldList.end(), matchNames); if (iter != currRecord_->fieldList.end()) { if (iter->isDefined) { context_.err = GetError("Repeating field names in the same record.", Error::ErrorType::ERR_REPEATING_FIELD_NAME); return false; } currRecord_->fieldList.erase(iter); } currFld_ = &(currRecord_->fieldList[currRecord_->fieldList.size() - 1]); currFld_->name = fieldName; ++context_; return true; } context_.err = GetError("Invalid name of field.", Error::ErrorType::ERR_BAD_OPERATION_NAME); return false; } bool Parser::ParseType(Type *type) { ASSERT(TypeValidName()); std::string componentName(context_.GiveToken()); size_t rank = 0; ++context_; while (*context_ == Token::Type::DEL_SQUARE_BRACKET_L) { ++context_; if (*context_ != Token::Type::DEL_SQUARE_BRACKET_R) { context_.err = GetError("Expected ']'.", Error::ErrorType::ERR_BAD_ARRAY_TYPE_BOUND); return false; } ++context_; ++rank; } *type = Type(componentName, rank); if (type->IsArray()) { program_.arrayTypes.insert(*type); } return true; } bool Parser::ParseFieldType() { LOG(DEBUG, ASSEMBLER) << "started searching field type value (line " << lineStric_ << "): " << context_.tokens[context_.number - 1].wholeLine; if (!TypeValidName()) { context_.err = GetError("Not a correct type.", Error::ErrorType::ERR_BAD_FIELD_VALUE_TYPE); return false; } if (!ParseType(&currFld_->type)) { return false; } currFld_->metadata->SetFieldType(currFld_->type); LOG(DEBUG, ASSEMBLER) << "field type found (line " << lineStric_ << "): " << context_.GiveToken(); return true; } bool Parser::ParseRecordField() { if (!ParseFieldType()) { return false; } if (context_.Mask()) { context_.err = GetError("Expected field name.", Error::ErrorType::ERR_BAD_FIELD_MISSING_NAME, +1); return false; } if (!ParseFieldName()) { return false; } if (open_ && *context_ == Token::Type::DEL_BRACE_R) { currRecord_->bodyLocation.end = GetCurrentPosition(true); ++context_; open_ = false; return true; } metadata_ = currFld_->metadata.get(); ParseMetaDef(); return context_.Mask(); } bool Parser::IsConstArray() { return isConstArray_; } bool Parser::ArrayElementsValidNumber() { if (!IsConstArray()) { return true; } ASSERT(currArray_->literals.size() > 1); auto initSize = std::get(currArray_->literals[1].value); if (initSize < 1) { return false; } if (currArray_->literals.size() != initSize + INTRO_CONST_ARRAY_LITERALS_NUMBER) { return false; } return true; } void Parser::ParseAsArray(const std::vector &tokens) { LOG(DEBUG, ASSEMBLER) << "started parsing of array (line " << lineStric_ << "): " << tokens[0].wholeLine; funcDef_ = false; recordDef_ = false; arrayDef_ = true; if (!open_) { ++context_; } else { context_.err = GetError("No one array can be defined inside another array.", Error::ErrorType::ERR_BAD_DEFINITION); return; } if (ParseArrayFullSign()) { if (!open_ && *context_ == Token::Type::DEL_BRACE_L) { ++context_; LOG(DEBUG, ASSEMBLER) << "array body is open, line " << lineStric_ << ": " << tokens[0].wholeLine; open_ = true; } uint32_t iterNumber = 1; if (IsConstArray()) { iterNumber = std::get(currArray_->literals[1].value); } if (iterNumber < 1) { context_.err = GetError("Сonstant array must contain at least one element.", Error::ErrorType::ERR_BAD_ARRAY_SIZE); return; } for (uint32_t i = 0; i < iterNumber; i++) { if (open_ && !context_.Mask() && *context_ != Token::Type::DEL_BRACE_R) { ParseArrayElements(); } else { break; } } if (open_ && *context_ == Token::Type::DEL_BRACE_R) { if (!ArrayElementsValidNumber()) { context_.err = GetError("Constant array must contain at least one element.", Error::ErrorType::ERR_BAD_ARRAY_SIZE); return; } LOG(DEBUG, ASSEMBLER) << "array body is closed, line " << lineStric_ << ": " << tokens[0].wholeLine; ++context_; open_ = false; } } } bool Parser::ParseArrayElements() { if (!open_ && *context_ == Token::Type::DEL_BRACE_L) { open_ = true; ++context_; } if (!open_) { context_.err = GetError("Expected keyword.", Error::ErrorType::ERR_BAD_KEYWORD); return false; } if (context_.Mask()) { return true; } if (open_ && *context_ == Token::Type::DEL_BRACE_R) { if (!ArrayElementsValidNumber()) { context_.err = GetError("Constant array must contain at least one element.", Error::ErrorType::ERR_BAD_ARRAY_SIZE); return false; } ++context_; open_ = false; return true; } currArray_->literals.emplace_back(); currArrayElem_ = &(currArray_->literals[currArray_->literals.size() - 1]); LOG(DEBUG, ASSEMBLER) << "parse line " << lineStric_ << " as array elem (.array_elem value)"; if (!ParseArrayElement()) { if (context_.err.err != Error::ErrorType::ERR_NONE) { return false; } if (open_ && *context_ == Token::Type::DEL_BRACE_R) { ++context_; open_ = false; if (!ArrayElementsValidNumber()) { context_.err = GetError("Constant array must contain at least one element.", Error::ErrorType::ERR_BAD_ARRAY_SIZE); return false; } } else { context_.err = GetError("Expected a new array element on the next line.", Error::ErrorType::ERR_BAD_KEYWORD); return false; } } return true; } bool Parser::ParseArrayElement() { if (IsConstArray()) { currArrayElem_->tag = static_cast(std::get(currArray_->literals[0].value)); } else { if (!ParseArrayElementType()) { return false; } auto valTag = currArrayElem_->tag; currArrayElem_->value = static_cast(currArrayElem_->tag); currArrayElem_->tag = panda_file::LiteralTag::TAGVALUE; currArray_->literals.emplace_back(); currArrayElem_ = &(currArray_->literals[currArray_->literals.size() - 1]); currArrayElem_->tag = valTag; } if (context_.Mask()) { context_.err = GetError("Expected array element value.", Error::ErrorType::ERR_BAD_ARRAY_ELEMENT_MISSING_VALUE, +1); return false; } if (!ParseArrayElementValue()) { return false; } if (open_ && *context_ == Token::Type::DEL_BRACE_R) { ++context_; open_ = false; if (!ArrayElementsValidNumber()) { context_.err = GetError("Constant array must contain at least one element.", Error::ErrorType::ERR_BAD_ARRAY_SIZE); return false; } return true; } return IsConstArray() ? true : context_.Mask(); } bool Parser::ParseArrayElementType() { LOG(DEBUG, ASSEMBLER) << "started searching array element type value (line " << lineStric_ << "): " << context_.tokens[context_.number - 1].wholeLine; if (!TypeValidName()) { context_.err = GetError("Not a correct type.", Error::ErrorType::ERR_BAD_ARRAY_ELEMENT_VALUE_TYPE); return false; } Type type; if (!ParseType(&type)) { return false; } // workaround until #5776 is done auto typeName = type.GetName(); std::replace(typeName.begin(), typeName.end(), '.', '/'); auto typeWithSlash = Type(typeName, 0); if (ark::pandasm::Type::IsPandaPrimitiveType(type.GetName())) { if (IsConstArray()) { currArrayElem_->tag = ark::pandasm::LiteralArray::GetArrayTagFromComponentType(type.GetId()); } else { currArrayElem_->tag = ark::pandasm::LiteralArray::GetLiteralTagFromComponentType(type.GetId()); } if (program_.arrayTypes.find(type) == program_.arrayTypes.end()) { program_.arrayTypes.emplace(type, 1); } } else if (ark::pandasm::Type::IsStringType(typeWithSlash.GetName(), program_.lang)) { if (IsConstArray()) { currArrayElem_->tag = panda_file::LiteralTag::ARRAY_STRING; } else { currArrayElem_->tag = panda_file::LiteralTag::STRING; } if (program_.arrayTypes.find(typeWithSlash) == program_.arrayTypes.end()) { program_.arrayTypes.emplace(typeWithSlash, 1); } } else { return false; } LOG(DEBUG, ASSEMBLER) << "array element type found (line " << lineStric_ << "): " << context_.GiveToken(); return true; } bool Parser::ParseArrayElementValueInteger() { int64_t n; if (!ParseInteger(&n)) { context_.err = GetError("Invalid value of array integer element.", Error::ErrorType::ERR_BAD_ARRAY_ELEMENT_VALUE_INTEGER); return false; } if (currArrayElem_->IsBoolValue()) { currArrayElem_->value = static_cast(n); } if (currArrayElem_->IsByteValue()) { currArrayElem_->value = static_cast(n); } if (currArrayElem_->IsShortValue()) { currArrayElem_->value = static_cast(n); } if (currArrayElem_->IsIntegerValue()) { currArrayElem_->value = static_cast(n); } if (currArrayElem_->IsLongValue()) { currArrayElem_->value = static_cast(n); } return true; } bool Parser::ParseArrayElementValueFloat() { double n; if (!ParseFloat(&n, !currArrayElem_->IsFloatValue())) { context_.err = GetError("Invalid value of array float element.", Error::ErrorType::ERR_BAD_ARRAY_ELEMENT_VALUE_FLOAT); return false; } if (currArrayElem_->IsFloatValue()) { currArrayElem_->value = static_cast(n); } else { currArrayElem_->value = static_cast(n); } return true; } bool Parser::ParseArrayElementValueString() { if (context_.err.err != Error::ErrorType::ERR_NONE) { return false; } auto res = ParseStringLiteral(); if (!res) { context_.err = GetError("Invalid value of array string element.", Error::ErrorType::ERR_BAD_ARRAY_ELEMENT_VALUE_STRING); return false; } currArrayElem_->value = res.value(); return true; } bool Parser::ParseArrayElementValue() { if (currArrayElem_->IsBoolValue() || currArrayElem_->IsByteValue() || currArrayElem_->IsShortValue() || currArrayElem_->IsIntegerValue() || currArrayElem_->IsLongValue()) { if (!ParseArrayElementValueInteger()) { return false; } } if (currArrayElem_->IsFloatValue() || currArrayElem_->IsDoubleValue()) { if (!ParseArrayElementValueFloat()) { return false; } } if (currArrayElem_->IsStringValue()) { if (!ParseArrayElementValueString()) { return false; } } ++context_; return true; } bool Parser::ParseFunctionCode() { if (!open_ && *context_ == Token::Type::DEL_BRACE_L) { open_ = true; currFunc_->bodyLocation.begin = GetCurrentPosition(false); ++context_; } currFunc_->bodyPresence = true; if (!open_) { context_.err = GetError("Expected keyword.", Error::ErrorType::ERR_BAD_KEYWORD); return false; } if (context_.Mask()) { return true; } if (open_ && *context_ == Token::Type::DEL_BRACE_R) { currFunc_->bodyLocation.end = GetCurrentPosition(true); ++context_; open_ = false; return true; } currIns_ = &currFunc_->ins.emplace_back(); LOG(DEBUG, ASSEMBLER) << "parse line " << lineStric_ << " as instruction ([label:] operation [operand,] [# comment])"; ParseFunctionInstruction(); if (open_ && *context_ == Token::Type::DEL_BRACE_R) { currFunc_->bodyLocation.end = GetCurrentPosition(true); ++context_; open_ = false; } return true; } void Parser::ParseAsRecord(const std::vector &tokens) { LOG(DEBUG, ASSEMBLER) << "started parsing of record (line " << lineStric_ << "): " << tokens[0].wholeLine; funcDef_ = false; recordDef_ = true; arrayDef_ = false; if (!open_) { ++context_; } else { context_.err = GetError("No one record can be defined inside another record.", Error::ErrorType::ERR_BAD_DEFINITION); return; } if (ParseRecordFullSign()) { metadata_ = currRecord_->metadata.get(); if (ParseMetaDef()) { if (!open_ && *context_ == Token::Type::DEL_BRACE_L) { currRecord_->bodyLocation.begin = GetCurrentPosition(false); ++context_; LOG(DEBUG, ASSEMBLER) << "record body is open, line " << lineStric_ << ": " << tokens[0].wholeLine; open_ = true; } if (open_ && !context_.Mask() && *context_ != Token::Type::DEL_BRACE_R) { ParseRecordFields(); } else if (open_) { currRecord_->bodyPresence = true; } if (open_ && *context_ == Token::Type::DEL_BRACE_R) { LOG(DEBUG, ASSEMBLER) << "record body is closed, line " << lineStric_ << ": " << tokens[0].wholeLine; currRecord_->bodyLocation.end = GetCurrentPosition(true); ++context_; open_ = false; } } } } void Parser::ParseAsFunction(const std::vector &tokens) { LOG(DEBUG, ASSEMBLER) << "started parsing of function (line " << lineStric_ << "): " << tokens[0].wholeLine; recordDef_ = false; funcDef_ = true; arrayDef_ = false; if (!open_) { ++context_; } else { context_.err = GetError("No one function can be defined inside another function.", Error::ErrorType::ERR_BAD_DEFINITION); return; } if (ParseFunctionFullSign()) { metadata_ = currFunc_->metadata.get(); if (ParseMetaDef()) { if (!open_ && *context_ == Token::Type::DEL_BRACE_L) { currFunc_->bodyLocation.begin = GetCurrentPosition(false); ++context_; LOG(DEBUG, ASSEMBLER) << "function body is open, line " << lineStric_ << ": " << tokens[0].wholeLine; open_ = true; } if (open_ && !context_.Mask() && *context_ != Token::Type::DEL_BRACE_R) { ParseFunctionCode(); } else if (open_) { currFunc_->bodyPresence = true; } if (open_ && *context_ == Token::Type::DEL_BRACE_R) { LOG(DEBUG, ASSEMBLER) << "function body is closed, line " << lineStric_ << ": " << tokens[0].wholeLine; currFunc_->bodyLocation.end = GetCurrentPosition(true); ++context_; open_ = false; } } } } void Parser::ParseAsUnionField(const std::vector &tokens) { LOG(DEBUG, ASSEMBLER) << "started parsing of union field (line " << lineStric_ << "): " << tokens[0].wholeLine; if (!open_) { ++context_; } else { context_.err = GetError("No union field can be defined inside record or function.", Error::ErrorType::ERR_BAD_DEFINITION); return; } auto dummyRecord = program_.recordTable.find(panda_file::GetDummyClassName()); if (dummyRecord == program_.recordTable.end()) { SetRecordInformation(panda_file::GetDummyClassName()); } currRecord_->fieldList.emplace_back(program_.lang); currFld_ = &(currRecord_->fieldList[currRecord_->fieldList.size() - 1]); currFld_->lineOfDef = lineStric_; ParseRecordField(); } void Parser::ParseAsBraceRight(const std::vector &tokens) { if (!open_) { context_.err = GetError("Delimiter '}' for the code area is outside a function.", Error::ErrorType::ERR_BAD_BOUND); return; } LOG(DEBUG, ASSEMBLER) << "body is closed (line " << lineStric_ << "): " << tokens[0].wholeLine; open_ = false; if (funcDef_) { currFunc_->bodyLocation.end = GetCurrentPosition(true); } else if (recordDef_) { currRecord_->bodyLocation.end = GetCurrentPosition(true); } else if (arrayDef_) { if (!ArrayElementsValidNumber()) { context_.err = GetError("Constant array must contain at least one element.", Error::ErrorType::ERR_BAD_ARRAY_SIZE); return; } } else { LOG(FATAL, ASSEMBLER) << "Internal error: either function or record must be parsed here"; } ++context_; } void Parser::ParseResetFunctionLabelsAndParams() { if (open_ || err_.err != Error::ErrorType::ERR_NONE) { return; } for (const auto &f : program_.functionTable) { for (const auto &k : f.second.labelTable) { if (!k.second.fileLocation->isDefined) { context_.err = Error("This label does not exist.", lineStric_, Error::ErrorType::ERR_BAD_LABEL_EXT, "", k.second.fileLocation->boundLeft, k.second.fileLocation->boundRight, k.second.fileLocation->wholeLine); SetError(); } } } for (const auto &t : context_.functionArgumentsLists) { currFunc_ = &(program_.functionTable.at(t.first)); currFunc_->regsNum = static_cast(currFunc_->valueOfFirstParam + 1); for (const auto &v : t.second) { if (currFunc_->ins.empty() && currFunc_->ins.size() < v.first && currFunc_->ins[v.first - 1].regs.empty()) { continue; } currFunc_->ins[v.first - 1].regs[v.second] += static_cast(currFunc_->valueOfFirstParam + 1); // NOLINTNEXTLINE(hicpp-signed-bitwise) size_t maxRegNumber = (1 << currFunc_->ins[v.first - 1].MaxRegEncodingWidth()); if (currFunc_->ins[v.first - 1].regs[v.second] >= maxRegNumber) { const auto &debug = currFunc_->ins[v.first - 1].insDebug; context_.err = Error("Register width mismatch.", debug.lineNumber, Error::ErrorType::ERR_BAD_NAME_REG, "", debug.boundLeft, debug.boundRight, debug.wholeLine); SetError(); break; } } } } void Parser::ParseInsFromFuncTable(ark::pandasm::Function &func) { for (auto &insn : func.ins) { if (!insn.HasFlag(InstFlags::METHOD_ID)) { // we need to correct all method_id's continue; } bool isInitobj = insn.opcode == Opcode::INITOBJ || insn.opcode == Opcode::INITOBJ_SHORT || insn.opcode == Opcode::INITOBJ_RANGE; size_t diff = isInitobj ? 0 : 1; auto funcName = insn.ids[0]; if (!IsSignatureOrMangled(funcName)) { const auto itSynonym = program_.functionSynonyms.find(funcName); if (itSynonym == program_.functionSynonyms.end()) { continue; } if (itSynonym->second.size() > 1) { const auto &debug = insn.insDebug; context_.err = Error("Unable to resolve ambiguous function call", debug.lineNumber, Error::ErrorType::ERR_FUNCTION_MULTIPLE_ALTERNATIVES, "", debug.boundLeft, debug.boundRight, debug.wholeLine); SetError(); break; } insn.ids[0] = program_.functionSynonyms.at(funcName)[0]; } if (insn.OperandListLength() - diff < program_.functionTable.at(insn.ids[0]).GetParamsNum()) { if (insn.IsCallRange() && (static_cast(insn.regs.size()) - static_cast(diff) >= 0)) { continue; } const auto &debug = insn.insDebug; context_.err = Error("Function argument mismatch.", debug.lineNumber, Error::ErrorType::ERR_FUNCTION_ARGUMENT_MISMATCH, "", debug.boundLeft, debug.boundRight, debug.wholeLine); SetError(); } } } void Parser::ParseResetFunctionTable() { for (auto &[unusedKey, func] : program_.functionTable) { (void)unusedKey; if (!func.fileLocation->isDefined) { context_.err = Error("This function does not exist.", func.fileLocation->lineNumber, Error::ErrorType::ERR_BAD_ID_FUNCTION, "", func.fileLocation->boundLeft, func.fileLocation->boundRight, func.fileLocation->wholeLine); SetError(); } else if (func.HasImplementation() != func.bodyPresence) { context_.err = Error("Inconsistency of the definition of the function and its metadata.", func.fileLocation->lineNumber, Error::ErrorType::ERR_BAD_DEFINITION_FUNCTION, "", func.fileLocation->boundLeft, func.fileLocation->boundRight, func.fileLocation->wholeLine); SetError(); } else { ParseInsFromFuncTable(func); } } } void Parser::ParseResetRecords(const ark::pandasm::Record &record) { for (const auto &fld : record.fieldList) { if (!record.HasImplementation() && !fld.metadata->IsForeign()) { context_.err = Error("External record may have only external fields", fld.lineOfDef, Error::ErrorType::ERR_BAD_FIELD_METADATA, "", fld.boundLeft, fld.boundRight, fld.wholeLine); SetError(); } if (!fld.isDefined) { context_.err = Error("This field does not exist.", fld.lineOfDef, Error::ErrorType::ERR_BAD_ID_FIELD, "", fld.boundLeft, fld.boundRight, fld.wholeLine); SetError(); } } } void Parser::ParseResetRecordTable() { for (const auto &[unusedKey, record] : program_.recordTable) { (void)unusedKey; if (!record.fileLocation->isDefined) { context_.err = Error("This record does not exist.", record.fileLocation->lineNumber, Error::ErrorType::ERR_BAD_ID_RECORD, "", record.fileLocation->boundLeft, record.fileLocation->boundRight, record.fileLocation->wholeLine); SetError(); } else { ParseResetRecords(record); } } } void Parser::ParseResetTables() { if (err_.err != Error::ErrorType::ERR_NONE) { return; } ParseResetFunctionTable(); if (err_.err != Error::ErrorType::ERR_NONE) { return; } ParseResetRecordTable(); } void Parser::ParseAsLanguageDirective() { ++context_; if (context_.Mask()) { context_.err = GetError("Incorrect .language directive: Expected language", Error::ErrorType::ERR_BAD_DIRECTIVE_DECLARATION); return; } auto lang = context_.GiveToken(); auto res = ark::panda_file::LanguageFromString(lang); if (!res) { context_.err = GetError("Incorrect .language directive: Unknown language", Error::ErrorType::ERR_UNKNOWN_LANGUAGE); return; } ++context_; if (!context_.Mask()) { context_.err = GetError("Incorrect .language directive: Unexpected token", Error::ErrorType::ERR_BAD_DIRECTIVE_DECLARATION); } program_.lang = res.value(); } Function::CatchBlock Parser::PrepareCatchBlock(bool isCatchall, size_t size, size_t catchallTokensNum, size_t catchTokensNum) { constexpr size_t TRY_BEGIN = 0; constexpr size_t TRY_END = 1; constexpr size_t CATCH_BEGIN = 2; constexpr size_t CATCH_END = 3; Function::CatchBlock catchBlock; catchBlock.wholeLine = context_.tokens[0].wholeLine; std::vector labelNames {"try block begin", "try block end", "catch block begin"}; std::vector labels; bool fullCatchBlock = (isCatchall && size == catchallTokensNum) || (!isCatchall && size == catchTokensNum); if (fullCatchBlock) { labelNames.emplace_back("catch block end"); } if (!isCatchall) { catchBlock.exceptionRecord = context_.GiveToken(); ++context_; } bool skipComma = isCatchall; for (const auto &labelName : labelNames) { if (!skipComma) { if (*context_ != Token::Type::DEL_COMMA) { context_.err = GetError("Expected comma.", Error::ErrorType::ERR_BAD_DIRECTIVE_DECLARATION); return catchBlock; } ++context_; } skipComma = false; if (!LabelValidName()) { context_.err = GetError(std::string("Invalid name of the ") + labelName + " label.", Error::ErrorType::ERR_BAD_LABEL); return catchBlock; } labels.emplace_back(context_.GiveToken()); AddObjectInTable(false, *labelTable_); ++context_; } ASSERT(context_.Mask()); catchBlock.tryBeginLabel = labels[TRY_BEGIN]; catchBlock.tryEndLabel = labels[TRY_END]; catchBlock.catchBeginLabel = labels[CATCH_BEGIN]; if (fullCatchBlock) { catchBlock.catchEndLabel = labels[CATCH_END]; } else { catchBlock.catchEndLabel = labels[CATCH_BEGIN]; } return catchBlock; } void Parser::ParseAsCatchDirective() { ASSERT(*context_ == Token::Type::ID_CATCH || *context_ == Token::Type::ID_CATCHALL); constexpr size_t CATCH_DIRECTIVE_TOKENS_NUM = 8; constexpr size_t CATCHALL_DIRECTIVE_TOKENS_NUM = 6; constexpr size_t CATCH_FULL_DIRECTIVE_TOKENS_NUM = 10; constexpr size_t CATCHALL_FULL_DIRECTIVE_TOKENS_NUM = 8; bool isCatchall = *context_ == Token::Type::ID_CATCHALL; size_t size = context_.tokens.size(); if (isCatchall && size != CATCHALL_DIRECTIVE_TOKENS_NUM && size != CATCHALL_FULL_DIRECTIVE_TOKENS_NUM) { context_.err = GetError( "Incorrect catch block declaration. Must be in the format: .catchall , , " "[, ]", Error::ErrorType::ERR_BAD_DIRECTIVE_DECLARATION); return; } if (!isCatchall && size != CATCH_DIRECTIVE_TOKENS_NUM && size != CATCH_FULL_DIRECTIVE_TOKENS_NUM) { context_.err = GetError( "Incorrect catch block declaration. Must be in the format: .catch , , " ", [, ]", Error::ErrorType::ERR_BAD_DIRECTIVE_DECLARATION); return; } ++context_; if (!isCatchall && !RecordValidName()) { context_.err = GetError("Invalid name of the exception record.", Error::ErrorType::ERR_BAD_RECORD_NAME); return; } Function::CatchBlock catchBlock = PrepareCatchBlock(isCatchall, size, CATCHALL_FULL_DIRECTIVE_TOKENS_NUM, CATCH_FULL_DIRECTIVE_TOKENS_NUM); currFunc_->catchBlocks.push_back(catchBlock); } void Parser::ParseAsCatchall(const std::vector &tokens) { std::string directiveName = *context_ == Token::Type::ID_CATCH ? ".catch" : ".catchall"; if (!funcDef_) { context_.err = GetError(directiveName + " directive is located outside of a function body.", Error::ErrorType::ERR_INCORRECT_DIRECTIVE_LOCATION); return; } LOG(DEBUG, ASSEMBLER) << "started parsing of " << directiveName << " directive (line " << lineStric_ << "): " << tokens[0].wholeLine; ParseAsCatchDirective(); } void Parser::ParseAsLanguage(const std::vector &tokens, bool &isLangParsed, bool &isFirstStatement) { if (isLangParsed) { context_.err = GetError("Multiple .language directives", Error::ErrorType::ERR_MULTIPLE_DIRECTIVES); return; } if (!isFirstStatement) { context_.err = GetError(".language directive must be specified before any other declarations", Error::ErrorType::ERR_INCORRECT_DIRECTIVE_LOCATION); return; } LOG(DEBUG, ASSEMBLER) << "started parsing of .language directive (line " << lineStric_ << "): " << tokens[0].wholeLine; ParseAsLanguageDirective(); isLangParsed = true; } bool Parser::ParseAfterLine(bool &isFirstStatement) { SetError(); if (!context_.Mask() && err_.err == Error::ErrorType::ERR_NONE) { context_.err = GetError("There can be nothing after.", Error::ErrorType::ERR_BAD_END); } if (err_.err != Error::ErrorType::ERR_NONE) { LOG(DEBUG, ASSEMBLER) << "processing aborted (error detected)"; return false; } LOG(DEBUG, ASSEMBLER) << "parsing of line " << lineStric_ << " is successful"; SetError(); isFirstStatement = false; return true; } Expected Parser::ParseAfterMainLoop(const std::string &fileName) { ParseResetFunctionLabelsAndParams(); if (open_ && err_.err == Error::ErrorType::ERR_NONE) { context_.err = Error("Code area is not closed.", currFunc_->fileLocation->lineNumber, Error::ErrorType::ERR_BAD_CLOSE, "", 0, currFunc_->name.size(), currFunc_->name); SetError(); } ParseResetTables(); if (err_.err != Error::ErrorType::ERR_NONE) { return Unexpected(err_); } for (auto &func : program_.functionTable) { if (func.second.metadata->HasImplementation()) { func.second.sourceFile = fileName; } } for (auto &rec : program_.recordTable) { if (rec.second.HasImplementation()) { rec.second.sourceFile = fileName; } } return std::move(program_); } void Parser::ParseContextByType(const std::vector &tokens, bool &isLangParsed, bool &isFirstStatement) { switch (*context_) { case Token::Type::ID_CATCH: case Token::Type::ID_CATCHALL: { ParseAsCatchall(tokens); break; } case Token::Type::ID_LANG: { ParseAsLanguage(tokens, isLangParsed, isFirstStatement); break; } case Token::Type::ID_REC: { ParseAsRecord(tokens); break; } case Token::Type::ID_FUN: { ParseAsFunction(tokens); break; } case Token::Type::ID_UNION: { ParseAsUnionField(tokens); break; } case Token::Type::ID_ARR: { ParseAsArray(tokens); break; } case Token::Type::DEL_BRACE_R: { ParseAsBraceRight(tokens); break; } default: { if (funcDef_) { ParseFunctionCode(); } else if (recordDef_) { ParseRecordFields(); } else if (arrayDef_) { ParseArrayElements(); } } } } Expected Parser::Parse(TokenSet &vectorsTokens, const std::string &fileName) { bool isLangParsed = false; bool isFirstStatement = true; for (const auto &tokens : vectorsTokens) { ++lineStric_; if (tokens.empty()) { continue; } LOG(DEBUG, ASSEMBLER) << "started parsing of line " << lineStric_ << ": " << tokens[0].wholeLine; context_.Make(tokens); ParseContextByType(tokens, isLangParsed, isFirstStatement); if (!ParseAfterLine(isFirstStatement)) { break; } } return ParseAfterMainLoop(fileName); } Expected Parser::Parse(const std::string &source, const std::string &fileName) { auto ss = std::stringstream(source); std::string line; Lexer l; std::vector> v; while (std::getline(ss, line)) { auto [tokens, error] = l.TokenizeString(line); if (error.err != Error::ErrorType::ERR_NONE) { return Unexpected(error); } v.push_back(tokens); } return Parse(v, fileName); } void Parser::SetError() { err_ = context_.err; } bool Parser::RegValidName() { if (context_.err.err != Error::ErrorType::ERR_NONE) { return false; } if (currFunc_->GetParamsNum() > 0) { return context_.ValidateRegisterName('v') || context_.ValidateRegisterName('a', currFunc_->GetParamsNum() - 1); } return context_.ValidateRegisterName('v'); } bool Parser::ParamValidName() { return context_.ValidateParameterName(currFunc_->GetParamsNum()); } bool IsAlphaNumeric(char c) { return std::isalnum(c) != 0 || c == '_' || c == '$'; } bool IsNonDigit(char c) { return std::isalpha(c) != 0 || c == '_' || c == '$'; } bool Parser::PrefixedValidName(bool allowBrackets) { auto s = context_.GiveToken(); if (!IsNonDigit(s[0])) { return false; } size_t i = 1; while (i < s.size()) { if (s[i] == '.') { ++i; if (i >= s.size() || !IsNonDigit(s[i])) { return false; } } else { if (!allowBrackets && !IsAlphaNumeric(s[i]) && s[i] != '-') { return false; } if (allowBrackets && !(IsAlphaNumeric(s[i]) || s[i] == ']' || s[i] == '[') && s[i] != '-') { return false; } } ++i; } return true; } bool Parser::RecordValidName() { return PrefixedValidName(true); } bool Parser::FunctionValidName() { return PrefixedValidName(true); } bool Parser::ArrayValidName() { return PrefixedValidName(); } bool Parser::LabelValidName() { auto token = context_.GiveToken(); if (!IsNonDigit(token[0])) { return false; } token.remove_prefix(1); for (auto i : token) { if (!IsAlphaNumeric(i)) { return false; } } return true; } bool Parser::ParseLabel() { LOG(DEBUG, ASSEMBLER) << "label search started (line " << lineStric_ << "): " << context_.tokens[0].wholeLine; context_++; if (*context_ == Token::Type::DEL_COLON) { context_--; if (LabelValidName()) { if (AddObjectInTable(true, *labelTable_)) { currIns_->setLabel = true; currIns_->label = context_.GiveToken(); LOG(DEBUG, ASSEMBLER) << "label detected (line " << lineStric_ << "): " << context_.GiveToken(); context_++; context_++; return !context_.Mask(); } LOG(DEBUG, ASSEMBLER) << "label is detected (line " << lineStric_ << "): " << context_.GiveToken() << ", but this label already exists"; context_.err = GetError("This label already exists.", Error::ErrorType::ERR_BAD_LABEL_EXT); } else { LOG(DEBUG, ASSEMBLER) << "label with non-standard character is detected, attempt to create a label is " "supposed, but this cannot be any label name (line " << lineStric_ << "): " << context_.GiveToken(); context_.err = GetError( "Invalid name of label. Label contains only characters: '_', '0' - '9', 'a' - 'z', 'A' - 'Z'; and " "starts with any letter or with '_'.", Error::ErrorType::ERR_BAD_LABEL); } return false; } context_--; LOG(DEBUG, ASSEMBLER) << "label is not detected (line " << lineStric_ << ")"; return true; } static Opcode TokenToOpcode(Token::Type id) { ASSERT(id > Token::Type::OPERATION && id < Token::Type::KEYWORD); using Utype = std::underlying_type_t; return static_cast(static_cast(id) - static_cast(Token::Type::OPERATION) - 1); } bool Parser::ParseOperation() { if (context_.Mask()) { LOG(DEBUG, ASSEMBLER) << "no more tokens (line " << lineStric_ << "): " << context_.tokens[0].wholeLine; return false; } if (open_ && *context_ == Token::Type::DEL_BRACE_R) { return false; } LOG(DEBUG, ASSEMBLER) << "operaion search started (line " << lineStric_ << "): " << context_.tokens[0].wholeLine; if (*context_ > Token::Type::OPERATION && *context_ < Token::Type::KEYWORD) { SetOperationInformation(); context_.UpSignOperation(); currIns_->opcode = TokenToOpcode(context_.id); LOG(DEBUG, ASSEMBLER) << "operatiuon is detected (line " << lineStric_ << "): " << context_.GiveToken() << " (operand type: " << OperandTypePrint(currIns_->opcode) << ")"; context_++; return true; } LOG(DEBUG, ASSEMBLER) << "founded " << context_.GiveToken() << ", it is not an operation (line " << lineStric_ << ")"; context_.err = GetError("Invalid operation.", Error::ErrorType::ERR_BAD_OPERATION_NAME); return false; } bool Parser::ParseOperandVreg() { if (context_.err.err != Error::ErrorType::ERR_NONE) { return false; } if (*context_ != Token::Type::ID) { context_.err = GetError("Expected register.", Error::ErrorType::ERR_BAD_OPERAND, +1); return false; } std::string_view p = context_.GiveToken(); if (p[0] == 'v') { p.remove_prefix(1); auto number = static_cast(ToNumber(p)); if (number > *(context_.maxValueOfReg)) { *(context_.maxValueOfReg) = number; } currIns_->regs.push_back(static_cast(number)); } else if (p[0] == 'a') { p.remove_prefix(1); currIns_->regs.push_back(static_cast(ToNumber(p))); context_.functionArgumentsList->emplace_back(context_.insNumber, currIns_->regs.size() - 1); } ++context_; return true; } bool Parser::ParseOperandCall() { if (context_.err.err != Error::ErrorType::ERR_NONE) { return false; } if (!FunctionValidName()) { context_.err = GetError("Invalid name of function.", Error::ErrorType::ERR_BAD_NAME_REG); return false; } const auto p = std::string(context_.GiveToken().data(), context_.GiveToken().length()); currIns_->ids.emplace_back(p); AddObjectInTable(false, program_.functionTable); ++context_; std::string funcSignature {}; if (!ParseOperandSignature(&funcSignature)) { return false; } if (funcSignature.empty()) { const auto itSynonym = program_.functionSynonyms.find(currIns_->ids.back()); if (itSynonym == program_.functionSynonyms.end()) { return true; } if (itSynonym->second.size() > 1) { context_.err = GetError("Unable to resolve ambiguous function call", Error::ErrorType::ERR_FUNCTION_MULTIPLE_ALTERNATIVES); return false; } program_.functionTable.erase(p); } else { currIns_->ids.back() += funcSignature; if (program_.functionTable.find(currIns_->ids.back()) == program_.functionTable.end()) { auto nodeHandle = program_.functionTable.extract(p); nodeHandle.key() = currIns_->ids.back(); program_.functionTable.insert(std::move(nodeHandle)); } else { program_.functionTable.erase(p); } } return true; } bool Parser::ParseOperandSignature(std::string *sign) { if (*context_ != Token::Type::DEL_COLON) { // no signature provided return true; } ++context_; if (*context_ != Token::Type::DEL_BRACKET_L) { context_.err = GetError("Expected \'(\' before signature", Error::ErrorType::ERR_BAD_SIGNATURE); return false; } ++context_; *sign += ":("; if (!ParseOperandSignatureTypesList(sign)) { return false; } if (*context_ != Token::Type::DEL_BRACKET_R) { context_.err = GetError("Expected \')\' at the end of the signature", Error::ErrorType::ERR_BAD_SIGNATURE); return false; } *sign += ")"; ++context_; return true; } bool Parser::ParseOperandSignatureTypesList(std::string *sign) { bool comma = false; while (true) { if (context_.Mask()) { return true; } if (*context_ != Token::Type::DEL_COMMA && *context_ != Token::Type::ID) { break; } if (comma) { *sign += ","; } if (!ParseFunctionArgComma(comma)) { return false; } if (*context_ != Token::Type::ID) { context_.err = GetError("Expected signature arguments", Error::ErrorType::ERR_BAD_SIGNATURE_PARAMETERS); return false; } if (!TypeValidName()) { context_.err = GetError("Expected valid type", Error::ErrorType::ERR_BAD_TYPE); return false; } Type type; if (!ParseType(&type)) { return false; } *sign += type.GetName(); } return true; } static bool IsOctal(char c) { return c >= '0' && c <= '7'; } static bool IsHex(char c) { return std::isxdigit(c) != 0; } static uint8_t FromHex(char c) { constexpr size_t DIGIT_NUM = 10; if (c >= '0' && c <= '9') { return c - '0'; } if (c >= 'A' && c <= 'F') { return c - 'A' + DIGIT_NUM; } return c - 'a' + DIGIT_NUM; } static uint8_t FromOctal(char c) { return c - '0'; } Expected Parser::ParseOctalEscapeSequence(std::string_view s, size_t *i) { constexpr size_t OCT_SHIFT = 3; size_t idx = *i; size_t n = 0; uint32_t r = 0; while (idx < s.length() && IsOctal(s[idx]) && n < OCT_SHIFT) { r |= FromOctal(s[idx++]); r <<= 3U; ++n; } r >>= 3U; *i += n; return r; } Expected Parser::ParseHexEscapeSequence(std::string_view s, size_t *i) { constexpr size_t HEX_SHIFT = 2; uint32_t r = 0; size_t idx = *i; for (size_t j = 0; j < HEX_SHIFT; j++) { char v = s[(*i)++]; if (!IsHex(v)) { return Unexpected(GetError("Invalid \\x escape sequence", Error::ErrorType::ERR_BAD_STRING_INVALID_HEX_ESCAPE_SEQUENCE, idx - HEX_SHIFT)); } r |= FromHex(v); r <<= 4U; } r >>= 4U; return r; } Expected Parser::ParseEscapeSequence(std::string_view s, size_t *i) { size_t idx = *i; char c = s[idx]; if (IsOctal(c)) { return ParseOctalEscapeSequence(s, i); } ++(*i); switch (c) { case '\'': case '"': case '\\': return c; case 'a': return '\a'; case 'b': return '\b'; case 'f': return '\f'; case 'n': return '\n'; case 'r': return '\r'; case 't': return '\t'; case 'v': return '\v'; default: break; } if (c == 'x') { return ParseHexEscapeSequence(s, i); } return Unexpected( GetError("Unknown escape sequence", Error::ErrorType::ERR_BAD_STRING_UNKNOWN_ESCAPE_SEQUENCE, idx - 1)); } std::optional Parser::ParseStringLiteral() { auto token = context_.GiveToken(); if (*context_ != Token::Type::ID_STRING) { context_.err = GetError("Expected string literal", Error::ErrorType::ERR_BAD_OPERAND); return {}; } size_t i = 1; /* skip leading quote */ size_t len = token.length(); std::string s; while (i < len - 1) { char c = token[i++]; if (c != '\\') { s.append(1, c); continue; } auto res = ParseEscapeSequence(token, &i); if (!res) { context_.err = res.Error(); return {}; } s.append(1, res.Value()); } program_.strings.insert(s); return s; } bool Parser::ParseOperandString() { if (context_.err.err != Error::ErrorType::ERR_NONE) { return false; } auto res = ParseStringLiteral(); if (!res) { return false; } currIns_->ids.push_back(res.value()); ++context_; return true; } bool Parser::ParseOperandComma() { if (context_.err.err != Error::ErrorType::ERR_NONE) { return false; } if (context_++ != Token::Type::DEL_COMMA) { if (!context_.Mask() && *context_ != Token::Type::DEL_BRACKET_R) { --context_; } context_.err = GetError("Expected comma.", Error::ErrorType::ERR_BAD_NUMBER_OPERANDS); return false; } return true; } bool Parser::ParseInteger(int64_t *value) { if (context_.err.err != Error::ErrorType::ERR_NONE) { return false; } if (*context_ != Token::Type::ID) { if (*context_ == Token::Type::DEL_BRACE_R) { --context_; } context_.err = GetError("Expected immediate.", Error::ErrorType::ERR_BAD_OPERAND, +1); return false; } std::string_view p = context_.GiveToken(); if (!ValidateInteger(p)) { context_.err = GetError("Expected integer.", Error::ErrorType::ERR_BAD_INTEGER_NAME); return false; } *value = IntegerNumber(p); if (errno == ERANGE) { context_.err = GetError("Too large immediate (length is more than 64 bit).", Error::ErrorType::ERR_BAD_INTEGER_WIDTH); return false; } return true; } bool Parser::ParseFloat(double *value, bool is64bit) { if (context_.err.err != Error::ErrorType::ERR_NONE) { return false; } if (*context_ != Token::Type::ID) { if (*context_ == Token::Type::DEL_BRACE_R) { --context_; } context_.err = GetError("Expected immediate.", Error::ErrorType::ERR_BAD_OPERAND, +1); return false; } std::string_view p = context_.GiveToken(); if (!ValidateFloat(p)) { context_.err = GetError("Expected float.", Error::ErrorType::ERR_BAD_FLOAT_NAME); return false; } *value = FloatNumber(p, is64bit); if (errno == ERANGE) { context_.err = GetError("Too large immediate (length is more than 64 bit).", Error::ErrorType::ERR_BAD_FLOAT_WIDTH); return false; } return true; } bool Parser::ParseOperandInteger() { int64_t n; if (!ParseInteger(&n)) { return false; } currIns_->imms.emplace_back(n); ++context_; return true; } bool Parser::ParseOperandFloat(bool is64bit) { double n; if (!ParseFloat(&n, is64bit)) { return false; } currIns_->imms.emplace_back(n); ++context_; return true; } bool Parser::ParseOperandLabel() { if (context_.err.err != Error::ErrorType::ERR_NONE) { return false; } if (!LabelValidName()) { context_.err = GetError("Invalid name of Label.", Error::ErrorType::ERR_BAD_NAME_ID); return false; } std::string_view p = context_.GiveToken(); currIns_->ids.emplace_back(p.data(), p.length()); AddObjectInTable(false, *labelTable_); ++context_; return true; } bool Parser::ParseOperandId() { if (context_.err.err != Error::ErrorType::ERR_NONE) { return false; } if (*context_ != Token::Type::ID) { context_.err = GetError("Expected Label.", Error::ErrorType::ERR_BAD_OPERAND); return false; } if (!LabelValidName()) { context_.err = GetError("Invalid name of Label.", Error::ErrorType::ERR_BAD_NAME_ID); return false; } std::string_view p = context_.GiveToken(); currIns_->ids.emplace_back(p.data(), p.length()); AddObjectInTable(false, *labelTable_); ++context_; return true; } bool Parser::ParseOperandType(Type::VerificationType verType) { if (context_.err.err != Error::ErrorType::ERR_NONE) { return false; } if (*context_ != Token::Type::ID) { context_.err = GetError("Expected type.", Error::ErrorType::ERR_BAD_OPERAND); return false; } if (!TypeValidName()) { context_.err = GetError("Invalid name of type.", Error::ErrorType::ERR_BAD_NAME_ID); return false; } Type type; if (!ParseType(&type)) { return false; } bool isObject = context_.GiveToken() != "]"; if (isObject) { AddObjectInTable(false, program_.recordTable); if (verType == Type::VerificationType::TYPE_ID_ARRAY) { GetWarning("Unexpected type_id recieved! Expected array, but object given", Error::ErrorType::WAR_UNEXPECTED_TYPE_ID); } } else { if (!type.IsArrayContainsPrimTypes() && program_.recordTable.find(type.GetComponentName()) == program_.recordTable.end()) { std::string componentName = type.GetComponentName(); context_.token = componentName; AddObjectInTable(false, program_.recordTable); } if (verType == Type::VerificationType::TYPE_ID_OBJECT) { GetWarning("Unexpected type_id recieved! Expected object, but array given", Error::ErrorType::WAR_UNEXPECTED_TYPE_ID); } } currIns_->ids.push_back(type.GetName()); return true; } bool Parser::ParseOperandLiteralArray() { if (context_.err.err != Error::ErrorType::ERR_NONE) { return false; } if (*context_ != Token::Type::ID) { context_.err = GetError("Expected array id.", Error::ErrorType::ERR_BAD_OPERAND); return false; } if (!ArrayValidName()) { context_.err = GetError("Invalid name of array.", Error::ErrorType::ERR_BAD_NAME_ID); return false; } std::string_view p = context_.GiveToken(); auto arrayId = std::string(p.data(), p.length()); if (program_.literalarrayTable.find(arrayId) == program_.literalarrayTable.end()) { context_.err = GetError("No array was found for this array id", Error::ErrorType::ERR_BAD_ID_ARRAY); return false; } currIns_->ids.emplace_back(p.data(), p.length()); ++context_; return true; } bool Parser::ParseOperandField() { if (context_.err.err != Error::ErrorType::ERR_NONE) { return false; } if (*context_ != Token::Type::ID) { context_.err = GetError("Expected field.", Error::ErrorType::ERR_BAD_OPERAND); return false; } if (!PrefixedValidName()) { context_.err = GetError("Invalid name of field.", Error::ErrorType::ERR_BAD_NAME_ID); return false; } std::string_view p = context_.GiveToken(); std::string recordFullName = std::string(p); // Some names of records in pandastdlib starts with 'panda.', therefore, // the record name is before the second dot, and the field name is after the second dot auto posPoint = recordFullName.find_last_of('.'); std::string recordName; std::string fieldName; if (posPoint == std::string::npos) { recordName = panda_file::GetDummyClassName(); fieldName = recordFullName; } else { recordName = recordFullName.substr(0, posPoint); fieldName = recordFullName.substr(posPoint + 1); } auto itRecord = program_.recordTable.find(recordName); if (itRecord == program_.recordTable.end()) { context_.token = recordName; AddObjectInTable(false, program_.recordTable); itRecord = program_.recordTable.find(recordName); } auto itField = std::find_if(itRecord->second.fieldList.begin(), itRecord->second.fieldList.end(), [&fieldName](pandasm::Field &field) { return fieldName == field.name; }); if (!fieldName.empty() && itField == itRecord->second.fieldList.end()) { itRecord->second.fieldList.emplace_back(program_.lang); auto &field = itRecord->second.fieldList.back(); field.name = fieldName; field.lineOfDef = lineStric_; field.wholeLine = context_.tokens[context_.number - 1].wholeLine; field.boundLeft = context_.tokens[context_.number - 1].boundLeft + recordName.length() + 1; field.boundRight = context_.tokens[context_.number - 1].boundRight; field.isDefined = false; } currIns_->ids.emplace_back(p.data(), p.length()); ++context_; return true; } bool Parser::ParseOperandNone() { if (context_.err.err != Error::ErrorType::ERR_NONE) { return false; } if (open_ && *context_ == Token::Type::DEL_BRACE_R) { return false; } if (!context_.Mask()) { context_.err = GetError("Invalid number of operands.", Error::ErrorType::ERR_BAD_NUMBER_OPERANDS); --context_; return false; } return true; } bool Parser::ParseRecordFullSign() { return ParseRecordName(); } bool Parser::ParseFunctionFullSign() { if (!ParseFunctionReturn()) { return false; } if (!ParseFunctionName()) { return false; } if (*context_ == Token::Type::DEL_BRACKET_L) { ++context_; if (ParseFunctionArgs()) { if (*context_ == Token::Type::DEL_BRACKET_R) { ++context_; return UpdateFunctionName(); } context_.err = GetError("Expected ')'.", Error::ErrorType::ERR_BAD_ARGS_BOUND); } } else { context_.err = GetError("Expected '('.", Error::ErrorType::ERR_BAD_ARGS_BOUND); } return false; } bool Parser::UpdateFunctionName() { auto signature = GetFunctionSignatureFromName(currFunc_->name, currFunc_->params); auto iter = program_.functionTable.find(signature); if (iter == program_.functionTable.end() || !iter->second.fileLocation->isDefined) { program_.functionSynonyms[currFunc_->name].push_back(signature); program_.functionTable.erase(signature); auto nodeHandle = program_.functionTable.extract(currFunc_->name); nodeHandle.key() = signature; program_.functionTable.insert(std::move(nodeHandle)); currFunc_->name = signature; context_.maxValueOfReg = &(currFunc_->valueOfFirstParam); context_.functionArgumentsList = &(context_.functionArgumentsLists[currFunc_->name]); return true; } context_.err = GetError("This function already exists.", Error::ErrorType::ERR_BAD_ID_FUNCTION); return false; } bool Parser::ParseArrayFullSign() { if (!ParseArrayName()) { return false; } if (*context_ == Token::Type::DEL_BRACE_L) { isConstArray_ = false; return true; } isConstArray_ = true; currArray_->literals.emplace_back(); currArrayElem_ = &(currArray_->literals[currArray_->literals.size() - 1]); if (!ParseArrayElementType()) { context_.err = GetError("Invalid array type for static array.", Error::ErrorType::ERR_BAD_ARRAY_TYPE); return false; } currArrayElem_->value = static_cast(currArrayElem_->tag); currArrayElem_->tag = panda_file::LiteralTag::TAGVALUE; if (*context_ == Token::Type::DEL_BRACE_L) { context_.err = GetError("No array size for static array.", Error::ErrorType::ERR_BAD_ARRAY_SIZE); return false; } currArray_->literals.emplace_back(); currArrayElem_ = &(currArray_->literals[currArray_->literals.size() - 1]); currArrayElem_->tag = panda_file::LiteralTag::INTEGER; if (!ParseArrayElementValueInteger()) { context_.err = GetError("Invalid value for static array size value.", Error::ErrorType::ERR_BAD_ARRAY_SIZE_VALUE); return false; } ++context_; return true; } bool Parser::ParseRecordName() { LOG(DEBUG, ASSEMBLER) << "started searching for record name (line " << lineStric_ << "): " << context_.tokens[context_.number - 1].wholeLine; if (!RecordValidName()) { if (*context_ == Token::Type::DEL_BRACKET_L) { context_.err = GetError("No record name.", Error::ErrorType::ERR_BAD_RECORD_NAME); return false; } context_.err = GetError("Invalid name of the record.", Error::ErrorType::ERR_BAD_RECORD_NAME); return false; } auto recordName = std::string(context_.GiveToken()); context_++; if (*context_ == Token::Type::DEL_SQUARE_BRACKET_L) { auto dim = ParseMultiArrayHallmark(); if (context_.err.err != Error::ErrorType::ERR_NONE) { return false; } for (uint8_t i = 0; i < dim; i++) { recordName += "[]"; } } if (!context_.Mask()) { context_--; } auto iter = program_.recordTable.find(recordName); if (iter == program_.recordTable.end() || !iter->second.fileLocation->isDefined) { SetRecordInformation(recordName); } else { context_.err = GetError("This record already exists.", Error::ErrorType::ERR_BAD_ID_RECORD); return false; } LOG(DEBUG, ASSEMBLER) << "record name found (line " << lineStric_ << "): " << context_.GiveToken(); ++context_; return true; } void Parser::SetRecordInformation(const std::string &recordName) { AddObjectInTable(true, program_.recordTable, recordName); currRecord_ = &(program_.recordTable.at(recordName)); } bool Parser::ParseFunctionName() { LOG(DEBUG, ASSEMBLER) << "started searching for function name (line " << lineStric_ << "): " << context_.tokens[context_.number - 1].wholeLine; if (!FunctionValidName()) { if (*context_ == Token::Type::DEL_BRACKET_L) { context_.err = GetError("No function name.", Error::ErrorType::ERR_BAD_FUNCTION_NAME); return false; } context_.err = GetError("Invalid name of the function.", Error::ErrorType::ERR_BAD_FUNCTION_NAME); return false; } // names are mangled, so no need to check for same names here SetFunctionInformation(); if (context_.err.err != Error::ErrorType::ERR_NONE) { return false; } LOG(DEBUG, ASSEMBLER) << "function name found (line " << lineStric_ << "): " << context_.GiveToken(); ++context_; return true; } void Parser::SetFunctionInformation() { auto p = std::string(context_.GiveToken()); context_++; if (*context_ == Token::Type::DEL_SQUARE_BRACKET_L || context_.Mask()) { auto dim = ParseMultiArrayHallmark(); for (uint8_t i = 0; i < dim; i++) { p += "[]"; } if (context_.GiveToken() == ".ctor") { p += ".ctor"; AddObjectInTable(true, program_.functionTable, p); } } else { context_--; AddObjectInTable(true, program_.functionTable); } currFunc_ = &(program_.functionTable.at(p)); labelTable_ = &(currFunc_->labelTable); currFunc_->returnType = context_.currFuncReturnType; } bool Parser::ParseArrayName() { LOG(DEBUG, ASSEMBLER) << "started searching for array name (line " << lineStric_ << "): " << context_.tokens[context_.number - 1].wholeLine; if (!ArrayValidName()) { if (*context_ == Token::Type::DEL_BRACKET_L) { context_.err = GetError("No array name.", Error::ErrorType::ERR_BAD_ARRAY_NAME); return false; } context_.err = GetError("Invalid name of the array.", Error::ErrorType::ERR_BAD_ARRAY_NAME); return false; } auto iter = program_.literalarrayTable.find(std::string(context_.GiveToken().data(), context_.GiveToken().length())); if (iter == program_.literalarrayTable.end()) { SetArrayInformation(); } else { context_.err = GetError("This array already exists.", Error::ErrorType::ERR_BAD_ID_ARRAY); return false; } LOG(DEBUG, ASSEMBLER) << "array id found (line " << lineStric_ << "): " << context_.GiveToken(); ++context_; return true; } void Parser::SetArrayInformation() { program_.literalarrayTable.try_emplace(std::string(context_.GiveToken().data(), context_.GiveToken().length()), ark::pandasm::LiteralArray()); currArray_ = &(program_.literalarrayTable.at(std::string(context_.GiveToken().data(), context_.GiveToken().length()))); } void Parser::SetOperationInformation() { context_.insNumber = currFunc_->ins.size(); auto &currDebug = currFunc_->ins.back().insDebug; currDebug.lineNumber = lineStric_; currDebug.wholeLine = context_.tokens[context_.number - 1].wholeLine; currDebug.boundLeft = context_.tokens[context_.number - 1].boundLeft; currDebug.boundRight = context_.tokens[context_.number - 1].boundRight; } bool Parser::ParseFunctionReturn() { LOG(DEBUG, ASSEMBLER) << "started searching for return function value (line " << lineStric_ << "): " << context_.tokens[context_.number - 1].wholeLine; if (!TypeValidName()) { if (*context_ == Token::Type::DEL_BRACKET_L) { context_.err = GetError("No return type.", Error::ErrorType::ERR_BAD_FUNCTION_RETURN_VALUE); return false; } context_.err = GetError("Not a return type.", Error::ErrorType::ERR_BAD_FUNCTION_RETURN_VALUE); return false; } if (!ParseType(&context_.currFuncReturnType)) { return false; } LOG(DEBUG, ASSEMBLER) << "return type found (line " << lineStric_ << "): " << context_.GiveToken(); return true; } bool Parser::TypeValidName() { if (Type::GetId(context_.GiveToken()) != panda_file::Type::TypeId::REFERENCE) { return true; } return PrefixedValidName(true); } bool Parser::ParseFunctionArg() { if (*context_ != Token::Type::ID) { context_.err = GetError("Expected identifier.", Error::ErrorType::ERR_BAD_FUNCTION_PARAMETERS); return false; } if (!TypeValidName()) { context_.err = GetError("Expected parameter type.", Error::ErrorType::ERR_BAD_TYPE); return false; } Type type; if (!ParseType(&type)) { return false; } if (context_.Mask()) { return false; } if (*context_ != Token::Type::ID) { context_.err = GetError("Expected identifier.", Error::ErrorType::ERR_BAD_FUNCTION_PARAMETERS); return false; } if (!ParamValidName()) { context_.err = GetError("Incorrect name of parameter.", Error::ErrorType::ERR_BAD_PARAM_NAME); return false; } ++context_; Function::Parameter parameter(type, program_.lang); metadata_ = parameter.metadata.get(); if (*context_ == Token::Type::DEL_LT && !ParseMetaDef()) { return false; } currFunc_->params.push_back(std::move(parameter)); return true; } bool Parser::ParseFunctionArgComma(bool &comma) { if (comma && *context_ != Token::Type::DEL_COMMA) { context_.err = GetError("Expected comma.", Error::ErrorType::ERR_BAD_NUMBER_OPERANDS); return false; } if (comma) { ++context_; } comma = true; return true; } bool Parser::ParseFunctionArgs() { LOG(DEBUG, ASSEMBLER) << "started searching for function parameters (line " << lineStric_ << "): " << context_.tokens[context_.number - 1].wholeLine; bool comma = false; while (true) { if (context_.Mask()) { return false; } if (context_.id != Token::Type::DEL_COMMA && context_.id != Token::Type::ID) { break; } if (!ParseFunctionArgComma(comma)) { return false; } if (!ParseFunctionArg()) { return false; } } LOG(DEBUG, ASSEMBLER) << "parameters found (line " << lineStric_ << "): "; return true; } bool Parser::ParseMetaDef() { LOG(DEBUG, ASSEMBLER) << "started searching for meta information (line " << lineStric_ << "): " << context_.tokens[context_.number - 1].wholeLine; bool flag = false; if (context_.Mask()) { return false; } if (*context_ == Token::Type::DEL_LT) { flag = true; ++context_; } if (!ParseMetaList(flag)) { return false; } if (!flag && *context_ == Token::Type::DEL_GT) { context_.err = GetError("Expected '<'.", Error::ErrorType::ERR_BAD_METADATA_BOUND); ++context_; return false; } LOG(DEBUG, ASSEMBLER) << "searching for meta information (line " << lineStric_ << ") is successful"; if (flag && context_.err.err == Error::ErrorType::ERR_NONE) { ++context_; } return true; } void Parser::SetMetadataContextError(const Metadata::Error &err, bool hasValue) { constexpr int64_t NO_VALUE_OFF = -1; constexpr int64_t SPECIAL_OFF = -2; constexpr int64_t STANDARD_OFF = -3; switch (err.GetType()) { case Metadata::Error::Type::UNKNOWN_ATTRIBUTE: { context_.err = GetError(err.GetMessage(), Error::ErrorType::ERR_BAD_METADATA_UNKNOWN_ATTRIBUTE, 0, hasValue ? STANDARD_OFF : NO_VALUE_OFF); break; } case Metadata::Error::Type::MISSING_ATTRIBUTE: { context_.err = GetError(err.GetMessage(), Error::ErrorType::ERR_BAD_METADATA_MISSING_ATTRIBUTE); break; } case Metadata::Error::Type::MISSING_VALUE: { context_.err = GetError(err.GetMessage(), Error::ErrorType::ERR_BAD_METADATA_MISSING_VALUE); break; } case Metadata::Error::Type::UNEXPECTED_ATTRIBUTE: { context_.err = GetError(err.GetMessage(), Error::ErrorType::ERR_BAD_METADATA_UNEXPECTED_ATTRIBUTE, 0, hasValue ? STANDARD_OFF : NO_VALUE_OFF); break; } case Metadata::Error::Type::UNEXPECTED_VALUE: { context_.err = GetError(err.GetMessage(), Error::ErrorType::ERR_BAD_METADATA_UNEXPECTED_VALUE, 0, SPECIAL_OFF); break; } case Metadata::Error::Type::INVALID_VALUE: { context_.err = GetError(err.GetMessage(), Error::ErrorType::ERR_BAD_METADATA_INVALID_VALUE, 0, -1); break; } case Metadata::Error::Type::MULTIPLE_ATTRIBUTE: { context_.err = GetError(err.GetMessage(), Error::ErrorType::ERR_BAD_METADATA_MULTIPLE_ATTRIBUTE, 0, hasValue ? STANDARD_OFF : NO_VALUE_OFF); break; } default: { UNREACHABLE(); } } } bool Parser::ParseMetaListComma(bool &comma, bool eq) { if (!eq && comma && *context_ != Token::Type::DEL_COMMA) { context_.err = GetError("Expected comma.", Error::ErrorType::ERR_BAD_NUMBER_OPERANDS); return false; } if (!eq && comma) { ++context_; } comma = true; return true; } bool Parser::MeetExpMetaList(bool eq) { if (!eq && *context_ != Token::Type::ID) { context_.err = GetError("Expected identifier.", Error::ErrorType::ERR_BAD_DEFINITION_METADATA, +1); return false; } if (eq && *context_ != Token::Type::ID && *context_ != Token::Type::ID_STRING) { context_.err = GetError("Expected identifier or string literal.", Error::ErrorType::ERR_BAD_DEFINITION_METADATA, +1); return false; } if (!eq && !PrefixedValidName()) { context_.err = GetError("Invalid attribute name.", Error::ErrorType::ERR_BAD_NAME_ID); return false; } return true; } bool Parser::BuildMetaListAttr(bool &eq, std::string &attributeName, std::string &attributeValue) { if (eq && *context_ == Token::Type::ID_STRING) { auto res = ParseStringLiteral(); if (!res) { return false; } attributeValue = res.value(); } else if (eq) { std::string sign {}; attributeValue = context_.GiveToken(); ++context_; if (!ParseOperandSignature(&sign)) { return false; } --context_; attributeValue += sign; } else { attributeName = context_.GiveToken(); } ++context_; if (context_.Mask()) { return false; } if (*context_ == Token::Type::DEL_EQ) { if (eq) { context_.err = GetError("'=' was not expected.", Error::ErrorType::ERR_BAD_NOEXP_DELIM); return false; } ++context_; eq = true; } else { std::optional res; bool hasValue = eq; if (hasValue) { res = metadata_->SetAttributeValue(attributeName, attributeValue); } else { res = metadata_->SetAttribute(attributeName); } eq = false; if (res) { auto err = res.value(); SetMetadataContextError(err, hasValue); return false; } } return true; } bool Parser::ParseMetaList(bool flag) { if (!flag && !context_.Mask() && *context_ != Token::Type::DEL_GT && *context_ != Token::Type::DEL_BRACE_L) { context_.err = GetError("No meta data expected.", Error::ErrorType::ERR_BAD_DEFINITION_METADATA); return false; } bool comma = false; bool eq = false; std::string attributeName; std::string attributeValue; while (true) { if (context_.Mask()) { context_.err = GetError("Expected '>'.", Error::ErrorType::ERR_BAD_METADATA_BOUND, +1); return false; } if (context_.id != Token::Type::DEL_COMMA && context_.id != Token::Type::ID && context_.id != Token::Type::ID_STRING && context_.id != Token::Type::DEL_EQ) { break; } if (!ParseMetaListComma(comma, eq)) { return false; } if (!MeetExpMetaList(eq)) { return false; } if (!BuildMetaListAttr(eq, attributeName, attributeValue)) { return false; } } if (flag && *context_ != Token::Type::DEL_GT) { context_.err = GetError("Expected '>'.", Error::ErrorType::ERR_BAD_METADATA_BOUND); ++context_; return false; } auto res = metadata_->ValidateData(); if (res) { auto err = res.value(); SetMetadataContextError(err, false); return false; } return true; } bool Parser::ParseFunctionInstruction() { if (ParseLabel()) { if (ParseOperation()) { if (ParseOperands()) { return true; } } } return context_.Mask(); } static std::string GetFuncNameWithoutArgs(const std::string &fullName) { auto pos = fullName.find(':'); return fullName.substr(0, pos); } bool Parser::ParseOperandInitobj() { if (context_.err.err != Error::ErrorType::ERR_NONE) { return false; } if (!FunctionValidName()) { context_.err = GetError("Invalid name of function.", Error::ErrorType::ERR_BAD_FUNCTION_NAME); return false; } auto cid = std::string(context_.GiveToken().data(), context_.GiveToken().length()); context_++; if (*context_ == Token::Type::DEL_COMMA || *context_ == Token::Type::DEL_COLON || context_.Mask()) { if (!context_.Mask()) { context_--; } return ParseOperandCall(); } auto dim = ParseMultiArrayHallmark(); if (context_.err.err != Error::ErrorType::ERR_NONE) { return false; } if (dim < 2U) { context_.err = GetError("Invalid name of function.", Error::ErrorType::ERR_BAD_FUNCTION_NAME); return false; } for (uint8_t i = 0; i < dim; i++) { cid += "[]"; } if (context_.GiveToken() == ".ctor") { cid += ".ctor"; currIns_->ids.emplace_back(cid); bool findFuncInTable = false; for (const auto &func : program_.functionTable) { if (GetFuncNameWithoutArgs(func.first) == cid) { findFuncInTable = true; break; } } if (!findFuncInTable) { AddObjectInTable(false, program_.functionTable, cid); } context_++; return true; } return false; } uint8_t Parser::ParseMultiArrayHallmark() { uint8_t counter = 0; do { if (*context_ == Token::Type::DEL_SQUARE_BRACKET_L) { context_++; if (*context_ == Token::Type::DEL_SQUARE_BRACKET_R) { context_++; counter++; } else { context_.err = GetError("] expected.", Error::ErrorType::ERR_BAD_FUNCTION_NAME); return counter; } } else { context_.err = GetError("[ expected.", Error::ErrorType::ERR_BAD_FUNCTION_NAME); return counter; } } while (!context_.Mask() && (*context_ == Token::Type::DEL_SQUARE_BRACKET_L || *context_ == Token::Type::DEL_SQUARE_BRACKET_R)); return counter; } } // namespace ark::pandasm