27 case ASMSX:
return "asMSX";
29 case HTC:
return "htc";
31 case NOICE:
return "NoICE";
32 case VASM:
return "vasm";
42 if (str ==
"asMSX")
return ASMSX;
43 if (str ==
"generic")
return GENERIC;
44 if (str ==
"htc")
return HTC;
45 if (str ==
"linkmap")
return LINKMAP;
46 if (str ==
"NoICE")
return NOICE;
47 if (str ==
"vasm")
return VASM;
54 : commandController(commandController_)
64 if (fname.ends_with(
".noi")) {
67 }
else if (fname.ends_with(
".map")) {
75 }
else if (fname.ends_with(
".sym")) {
78 if (line.starts_with(
"; Symbol table")) {
86 }
else if (line.starts_with(
"; this file was created with wlalink")) {
93 }
else if (fname.ends_with(
".symbol") || fname.ends_with(
".publics") || fname.ends_with(
".sys")) {
106 function_ref<std::optional<Symbol>(std::span<std::string_view>)> lineParser)
112 static constexpr std::string_view whitespace =
" \t\r";
117 view::take(StringOp::split_view<StringOp::EmptyParts::REMOVE>(line, whitespace), 3 + 1)};
118 if (
auto symbol = lineParser(tokens)) {
119 result.
symbols.push_back(std::move(*symbol));
129 if (str.ends_with(
'h') || str.ends_with(
'H')) {
130 str.remove_suffix(1);
131 return StringOp::stringToBase<16, T>(str);
133 if (str.starts_with(
'$') || str.starts_with(
'#')) {
134 str.remove_prefix(1);
135 return StringOp::stringToBase<16, T>(str);
137 if (str.starts_with(
'%')) {
138 str.remove_prefix(1);
139 return StringOp::stringToBase<2, T>(str);
145 return StringOp::stringTo<T>(str);
149template std::optional<uint16_t> SymbolManager::parseValue<uint16_t>(std::string_view);
150template std::optional<uint32_t> SymbolManager::parseValue<uint32_t>(std::string_view);
154 if (label.ends_with(
':')) label.remove_suffix(1);
155 if (label.empty())
return {};
157 auto tmp{value > 0xFFFF ? std::optional<uint16_t>(
static_cast<uint16_t
>(value >> 16)) : std::nullopt};
158 return Symbol{std::string(label),
static_cast<uint16_t
>(value), {}, tmp};
163 if (
auto num = parseValue<uint16_t>(value)) {
171 if (
auto num = parseValue<uint32_t>(value)) {
179 auto parseLine = [](std::span<std::string_view> tokens) -> std::optional<Symbol> {
180 if (tokens.size() != 3)
return {};
181 auto label = tokens[0];
182 auto equ = tokens[1];
183 auto value = tokens[2];
185 if (!cmp(equ,
"equ") &&
187 (equ !=
"="))
return {};
195 bool anySegment =
false;
196 auto parseLine = [&](std::span<std::string_view> tokens) -> std::optional<Symbol> {
197 if (tokens.size() != 3)
return {};
198 auto def = tokens[0];
199 auto label = tokens[1];
200 auto value = tokens[2];
204 anySegment |= symbol->segment.has_value();
211 for (
auto& symbol: file.getSymbols()) {
212 if (!symbol.segment) symbol.segment = 0;
221 auto parseLine = [](std::span<std::string_view> tokens) -> std::optional<Symbol> {
222 if (tokens.size() != 3)
return {};
223 auto label = tokens[0];
224 auto value = tokens[1];
227 auto val = StringOp::stringToBase<16, uint16_t>(value);
240 static constexpr std::string_view whitespace =
" \t\r";
241 bool skipLines =
true;
244 if (line.starts_with(
"Symbols by value:")) {
251 view::take(StringOp::split_view<StringOp::EmptyParts::REMOVE>(line, whitespace), 2 + 1)};
252 if (tokens.size() != 2)
continue;
253 auto value = tokens[0];
254 auto label = tokens[1];
256 if (
auto val = StringOp::stringToBase<16, uint16_t>(value)) {
258 result.
symbols.push_back(std::move(*symbol));
268 auto parseLine = [](std::span<std::string_view> tokens) -> std::optional<Symbol> {
269 if (tokens.size() != 2)
return {};
270 auto value = tokens[0];
271 auto label = tokens[1];
272 if (!value.starts_with(
"00:"))
return {};
273 std::optional<uint16_t> num = StringOp::stringToBase<16, uint16_t>(value.substr(3));
274 if (!num.has_value())
return {};
286 static constexpr std::string_view whitespace =
" \t\r";
287 bool symbolPart =
false;
289 if (line.starts_with(
';')) {
290 if (line.starts_with(
"; global and local")) {
292 }
else if (line.starts_with(
"; other")) {
297 if (!symbolPart)
continue;
304 view::take(StringOp::split_view<StringOp::EmptyParts::REMOVE>(line, whitespace), 2 + 1)};
305 if (tokens.size() != 2)
continue;
306 auto value = tokens[0];
307 auto label = tokens[1];
310 value = l.empty() ? f : l;
313 result.
symbols.push_back(std::move(*symbol));
322 if (
'0' <= c && c <=
'9')
return c -
'0';
323 if (
'A' <= c && c <=
'F')
return c -
'A' + 10;
324 if (
'a' <= c && c <=
'f')
return c -
'a' + 10;
329 if (s.size() != 4)
return {};
331 for (
int i = 0; i < 4; ++i) {
333 if (!digit)
return {};
334 value = (value << 4) | *digit;
336 return narrow<uint16_t>(value);
347 static constexpr std::string_view whitespace =
" \t\r";
348 bool symbolPart =
false;
351 if (line.find(
"Symbol Table") != std::string_view::npos) {
368 auto tokens = StringOp::split_view<StringOp::EmptyParts::REMOVE>(line, whitespace);
369 auto it = tokens.begin();
370 auto et = tokens.end();
377 result.
symbols.emplace_back(std::string(label), *val, std::nullopt, std::nullopt);
385 result.
symbols.emplace_back(std::string(label), *val, std::nullopt, std::nullopt);
395 auto buf = file.
mmap();
396 std::string_view buffer(std::bit_cast<const char*>(buf.data()), buf.size());
399 if (type == AUTO_DETECT) {
402 assert(type != AUTO_DETECT);
404 auto symbolFile = [&]{
411 return loadHTC(filename, buffer);
425 symbolFile.slot = slot;
426 for (
auto& symbol: symbolFile.getSymbols()) {
433void SymbolManager::refresh()
436 lookupValueCache.clear();
441 interp.unsetVariable(arrayName.getString().c_str());
442 for (
const auto& file : files) {
443 for (
const auto& sym : file.symbols) {
458 files.push_back(std::move(file));
460 *it = std::move(file);
469 if (it == files.end())
return;
484 for (
const auto& file : files) {
486 it != file.symbols.end()) {
491 for (
const auto& file : files) {
493 return StringOp::casecmp{}(str, sym.name); });
494 it != file.symbols.end()) {
499 return parseValue<uint16_t>(str);
502std::span<Symbol const * const> SymbolManager::lookupValue(uint16_t value)
504 if (lookupValueCache.empty()) {
505 for (
const auto& file : files) {
506 for (
const auto& sym : file.symbols) {
507 auto [it, inserted] = lookupValueCache.try_emplace(sym.value, std::vector<const Symbol*>{});
508 it->second.push_back(&sym);
512 if (
auto* sym =
lookup(lookupValueCache, value)) {
518SymbolFile* SymbolManager::findFile(std::string_view filename)
520 if (
auto it =
ranges::find(files, filename, &SymbolFile::filename); it == files.end()) {
523 return std::to_address(it);
527std::string SymbolManager::getFileFilters()
529 return "Auto-detect file type (*){.*},"
530 "asMSX 0.x symbol files (*.sym){.sym},"
531 "HiTech C link map files (*.map){.map},"
532 "HiTech C symbol files (*.sym){.sym},"
533 "NoICE command files (*.noi){.noi},"
534 "pasmo symbol files (*.symbol *.publics *.sys){.symbol,.publics,.sys},"
535 "tniASM 0.x symbol files (*.sym){.sym},"
536 "tniASM 1.x symbol files (*.sym){.sym},"
537 "vasm symbol files (*.sym){.sym},"
538 "wlalink no$gmb symbol files (*.sym){.sym}";
544 if (filter.starts_with(
"Auto")) {
546 }
else if (filter.starts_with(
"asMSX")) {
548 }
else if (filter.starts_with(
"HiTechC link")) {
550 }
else if (filter.starts_with(
"HiTechC symbol")) {
552 }
else if (filter.starts_with(
"NoICE")) {
554 }
else if (filter.starts_with(
"vasm")) {
556 }
else if (filter.starts_with(
"wlalink")) {
557 return WLALINK_NOGMB;
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 loadNoGmb(std::string_view filename, std::string_view buffer)
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