27 case ASMSX:
return "asMSX";
29 case HTC:
return "htc";
31 case NOICE:
return "NoICE";
32 case VASM:
return "vasm";
41 if (str ==
"asMSX")
return ASMSX;
42 if (str ==
"generic")
return GENERIC;
43 if (str ==
"htc")
return HTC;
44 if (str ==
"linkmap")
return LINKMAP;
45 if (str ==
"NoICE")
return NOICE;
46 if (str ==
"vasm")
return VASM;
52 : commandController(commandController_)
62 if (fname.ends_with(
".noi")) {
65 }
else if (fname.ends_with(
".map")) {
68 }
else if (fname.ends_with(
".sym")) {
71 if (line.starts_with(
"; Symbol table")) {
84 }
else if (fname.ends_with(
".symbol") || fname.ends_with(
".publics") || fname.ends_with(
".sys")) {
97 function_ref<std::optional<Symbol>(std::span<std::string_view>)> lineParser)
103 static constexpr std::string_view whitespace =
" \t\r";
108 view::take(StringOp::split_view<StringOp::EmptyParts::REMOVE>(line, whitespace), 3 + 1)};
109 if (
auto symbol = lineParser(tokens)) {
110 result.
symbols.push_back(std::move(*symbol));
120 if (str.ends_with(
'h') || str.ends_with(
'H')) {
121 str.remove_suffix(1);
122 return StringOp::stringToBase<16, T>(str);
124 if (str.starts_with(
'$') || str.starts_with(
'#')) {
125 str.remove_prefix(1);
126 return StringOp::stringToBase<16, T>(str);
128 if (str.starts_with(
'%')) {
129 str.remove_prefix(1);
130 return StringOp::stringToBase<2, T>(str);
136 return StringOp::stringTo<T>(str);
140template std::optional<uint16_t> SymbolManager::parseValue<uint16_t>(std::string_view);
141template std::optional<uint32_t> SymbolManager::parseValue<uint32_t>(std::string_view);
145 if (label.ends_with(
':')) label.remove_suffix(1);
146 if (label.empty())
return {};
148 auto tmp{value > 0xFFFF ? std::optional<uint16_t>(
static_cast<uint16_t
>(value >> 16)) : std::nullopt};
149 return Symbol{std::string(label),
static_cast<uint16_t
>(value), {}, tmp};
154 if (
auto num = parseValue<uint16_t>(value)) {
162 if (
auto num = parseValue<uint32_t>(value)) {
170 auto parseLine = [](std::span<std::string_view> tokens) -> std::optional<Symbol> {
171 if (tokens.size() != 3)
return {};
172 auto label = tokens[0];
173 auto equ = tokens[1];
174 auto value = tokens[2];
176 if (!cmp(equ,
"equ") &&
177 !cmp(equ,
"%equ"))
return {};
185 bool anySegment =
false;
186 auto parseLine = [&](std::span<std::string_view> tokens) -> std::optional<Symbol> {
187 if (tokens.size() != 3)
return {};
188 auto def = tokens[0];
189 auto label = tokens[1];
190 auto value = tokens[2];
194 anySegment |= symbol->segment.has_value();
201 for (
auto& symbol: file.getSymbols()) {
202 if (!symbol.segment) symbol.segment = 0;
211 auto parseLine = [](std::span<std::string_view> tokens) -> std::optional<Symbol> {
212 if (tokens.size() != 3)
return {};
213 auto label = tokens[0];
214 auto value = tokens[1];
217 auto val = StringOp::stringToBase<16, uint16_t>(value);
230 static constexpr std::string_view whitespace =
" \t\r";
231 bool skipLines =
true;
234 if (line.starts_with(
"Symbols by value:")) {
241 view::take(StringOp::split_view<StringOp::EmptyParts::REMOVE>(line, whitespace), 2 + 1)};
242 if (tokens.size() != 2)
continue;
243 auto value = tokens[0];
244 auto label = tokens[1];
246 if (
auto val = StringOp::stringToBase<16, uint16_t>(value)) {
248 result.
symbols.push_back(std::move(*symbol));
262 static constexpr std::string_view whitespace =
" \t\r";
263 bool symbolPart =
false;
265 if (line.starts_with(
';')) {
266 if (line.starts_with(
"; global and local")) {
268 }
else if (line.starts_with(
"; other")) {
273 if (!symbolPart)
continue;
280 view::take(StringOp::split_view<StringOp::EmptyParts::REMOVE>(line, whitespace), 2 + 1)};
281 if (tokens.size() != 2)
continue;
282 auto value = tokens[0];
283 auto label = tokens[1];
286 value = l.empty() ? f : l;
289 result.
symbols.push_back(std::move(*symbol));
298 if (
'0' <= c && c <=
'9')
return c -
'0';
299 if (
'A' <= c && c <=
'F')
return c -
'A' + 10;
300 if (
'a' <= c && c <=
'f')
return c -
'a' + 10;
305 if (s.size() != 4)
return {};
307 for (
int i = 0; i < 4; ++i) {
309 if (!digit)
return {};
310 value = (value << 4) | *digit;
312 return narrow<uint16_t>(value);
323 static constexpr std::string_view whitespace =
" \t\r";
324 bool symbolPart =
false;
327 if (line.find(
"Symbol Table") != std::string_view::npos) {
344 auto tokens = StringOp::split_view<StringOp::EmptyParts::REMOVE>(line, whitespace);
345 auto it = tokens.begin();
346 auto et = tokens.end();
353 result.
symbols.emplace_back(std::string(label), *val, std::nullopt, std::nullopt);
361 result.
symbols.emplace_back(std::string(label), *val, std::nullopt, std::nullopt);
371 auto buf = file.
mmap();
372 std::string_view buffer(std::bit_cast<const char*>(buf.data()), buf.size());
375 if (type == AUTO_DETECT) {
378 assert(type != AUTO_DETECT);
380 auto symbolFile = [&]{
387 return loadHTC(filename, buffer);
399 symbolFile.slot = slot;
400 for (
auto& symbol: symbolFile.getSymbols()) {
407void SymbolManager::refresh()
410 lookupValueCache.clear();
415 interp.unsetVariable(arrayName.getString().c_str());
416 for (
const auto& file : files) {
417 for (
const auto& sym : file.symbols) {
432 files.push_back(std::move(file));
434 *it = std::move(file);
443 if (it == files.end())
return;
458 for (
const auto& file : files) {
460 it != file.symbols.end()) {
465 for (
const auto& file : files) {
467 return StringOp::casecmp{}(str, sym.name); });
468 it != file.symbols.end()) {
473 return parseValue<uint16_t>(str);
476std::span<Symbol const * const> SymbolManager::lookupValue(uint16_t value)
478 if (lookupValueCache.empty()) {
479 for (
const auto& file : files) {
480 for (
const auto& sym : file.symbols) {
481 auto [it, inserted] = lookupValueCache.try_emplace(sym.value, std::vector<const Symbol*>{});
482 it->second.push_back(&sym);
486 if (
auto* sym =
lookup(lookupValueCache, value)) {
492SymbolFile* SymbolManager::findFile(std::string_view filename)
494 if (
auto it =
ranges::find(files, filename, &SymbolFile::filename); it == files.end()) {
501std::string SymbolManager::getFileFilters()
503 return "Auto-detect file type (*){.*},"
504 "asMSX 0.x symbol files (*.sym){.sym},"
505 "HiTech C link map files (*.map){.map},"
506 "HiTech C symbol files (*.sym){.sym},"
507 "NoICE command files (*.noi){.noi},"
508 "pasmo symbol files (*.symbol *.publics *.sys){.symbol,.publics,.sys},"
509 "tniASM 0.x symbol files (*.sym){.sym},"
510 "tniASM 1.x symbol files (*.sym){.sym},"
511 "vasm symbol files (*.sym){.sym}";
517 if (filter.starts_with(
"Auto")) {
519 }
else if (filter.starts_with(
"asMSX")) {
521 }
else if (filter.starts_with(
"HiTechC link")) {
523 }
else if (filter.starts_with(
"HiTechC symbol")) {
525 }
else if (filter.starts_with(
"NoICE")) {
527 }
else if (filter.starts_with(
"vasm")) {
virtual Interpreter & getInterpreter()=0
std::span< const uint8_t > mmap()
Map file in memory.
static std::optional< unsigned > isHexDigit(char c)
static SymbolFile loadLines(std::string_view filename, std::string_view buffer, SymbolFile::Type type, function_ref< std::optional< Symbol >(std::span< std::string_view >)> lineParser)
static std::optional< Symbol > checkLabelSegmentAndValue(std::string_view label, std::string_view value)
static SymbolFile::Type detectType(std::string_view filename, std::string_view buffer)
static SymbolFile loadNoICE(std::string_view filename, std::string_view buffer)
static SymbolFile loadHTC(std::string_view filename, std::string_view buffer)
static SymbolFile loadGeneric(std::string_view filename, std::string_view buffer)
static SymbolFile loadSymbolFile(const std::string &filename, SymbolFile::Type type, std::optional< uint8_t > slot={})
static SymbolFile loadVASM(std::string_view filename, std::string_view buffer)
static std::optional< uint16_t > is4DigitHex(std::string_view s)
void removeFile(std::string_view filename)
static std::optional< Symbol > checkLabel(std::string_view label, uint32_t value)
bool reloadFile(const std::string &filename, LoadEmpty loadEmpty, SymbolFile::Type type, std::optional< uint8_t > slot={})
static SymbolFile loadASMSX(std::string_view filename, std::string_view buffer)
std::optional< uint16_t > parseSymbolOrValue(std::string_view s) const
static SymbolFile loadLinkMap(std::string_view filename, std::string_view buffer)
static std::optional< T > parseValue(std::string_view str)
SymbolManager(CommandController &commandController)
static std::optional< Symbol > checkLabelAndValue(std::string_view label, std::string_view value)
Like std::string_view, but with the extra guarantee that it refers to a zero-terminated string.
const Value * lookup(const hash_map< Key, Value, Hasher, Equal > &map, const Key2 &key)
std::pair< string_view, string_view > splitOnFirst(string_view str, string_view chars)
std::string toLower(std::string_view str)
bool containsCaseInsensitive(std::string_view haystack, std::string_view needle)
auto split_view(std::string_view str, Separators separators)
This file implemented 3 utility functions:
auto find_if(InputRange &&range, UnaryPredicate pred)
auto find(InputRange &&range, const T &value)
constexpr auto take(ForwardRange &&range, size_t n)
constexpr from_range_t from_range
static std::optional< Type > parseType(std::string_view str)
static zstring_view toString(Type type)
std::vector< Symbol > symbols
virtual void notifySymbolsChanged()=0