Метки позволяют назначить имя определенной строке с инструкцией программы и в дальнейшем ссылаться на эту строку. Также метки позволяют определять переменные в программе и затем чрез метку можно ссылаться на переменную. Обычно метка представляет собой произвольный идентификатор, за которым следует двоеточие:
label: инструкция
Например:
_start:
mov r0, 1
mov r1, 2
set_r2: mov r2, 3
Здесь используются две метки: "_start" и "_set_r2". Метка "_start" фактически представляет адрес инструкции mov r0, 1, тогда как
метка "set_r2" - mov r2, 3
Общий принцип обработки меток заключается в том, что определяется некоторая структура данных, которая содержит название метки и адрес, который она представляет. В Python для этой цели можно использовать словарь.
Проблема с обработками меток может заключаться в том, что нам надо решить должны ли метки быть уникальными или нет. Обычно имена меток уникальны, и нельзя определить двух меток с одним именем или переопределить.
Итак, пусть у нас есть файл "hello.s" со следующим кодом:
// парсинг меток на ассемблере
_start: // метка _start
mov r0, 1
mov r1, 2
set_r2: mov r2, 3 // метка set_r2
Для парсинга меток определим следующую программу на языке Python:
instructions = [] # иструкции, разбитые по токенам
sym_tab = {} # таблица символов
addr = 0 # адрес инструкции
# считываем файл hello.s в список инструкций
with open("hello.s", "r", encoding="utf8") as source:
lines = source.readlines()
# обрабатываем строки из файла
for i in range(0,len(lines)):
lines[i] = lines[i].split("//")[0] \
.replace(",", " ") \
.strip().rstrip("\n") \
.lower()
while " " in lines[i]: # заменяем несколько пробелов одним
lines[i] = lines[i].replace(" ", " ")
if(lines[i]) == "": continue # если получилась пустая строка, переходим к следующей строке
tokens = lines[i].split(" ") # разбиваем инструкцию на токены
# если токен заканчивается на двоеточие, то это метка
if(tokens[0][-1]==":"):
label = tokens[0][:-1]
if(label in sym_tab): # проверяем наличие метки
print("Метка", label, "уже существует")
break
sym_tab[label] = addr # добавляем метку в таблицу символов
if(len(tokens)==1): continue # если инструкция на следующей строке, переходим к ней
else: tokens = tokens[1:] # получаем токены инструкции
instructions.append(tokens) # добавляем инструкцию в список instructions
print("adr:",addr, tokens) # для наглядности логгируем инструкцию и адрес
addr = addr + 1 # увеличиваем указатель инструкций
print(sym_tab) # выводим таблицу символов
Здесь вначала определяем список для хранения инструкций instructions. Для хранения меток определяем словарь sym_tab. А для учета адреса инструкции - переменную addr:
instructions = [] # иструкции, разбитые по токенам
sym_tab = {} # таблица символов
addr = 0 # адрес инструкции
После базовой обработки файла разбиваем строку на токены и проверяем первый. Если он завершается на двоеточие, то он представляет метку:
tokens = lines[i].split(" ")
if(tokens[0][-1]==":"):
В этом случае получаем метку и проверяем ее наличие в словаре:
label = tokens[0][:-1]
if(label in sym_tab): # проверяем наличие метки
print("Метка", label, "уже существует")
break
Если метка уже есть, завершаем обработку. Иначе добавляем ее в словарь sym_tab:
sym_tab[label] = addr
Если инструкция размещена на последующей строке, то переходим к этой строке. Если инструкция идет сразу после метки на той же строке, то удаляем из списка токенов метку:
if(len(tokens)==1): continue # если инструкция на следующей строке, переходим к ней else: tokens = tokens[1:] # получаем токены инструкции
После обработки метки добавляем токены (из которых исключена метка) в список инструкций instructions и увеличиваем адрес инструкций addr
instructions.append(tokens) # добавляем инструкцию в список instructions
print("adr:",addr, tokens) # для наглядности логгируем инструкцию и адрес
addr = addr + 1 # увеличиваем указатель инструкций
Таким образом, в словаре sym_tab окажутся всем метки с адресами инструкций, а в списке instructions - инструкции, разбитые по токена.
Запустим программу на примере выше приведенного файла "hello.s" и получим следующий вывод:
adr: 0 ["mov", "r0", "1"]
adr: 1 ["mov", "r1", "2"]
adr: 2 ["mov", "r2", "3"]
{"_start": 0, "set_r2": 2}