Метки позволяют назначить имя определенной строке с инструкцией программы и в дальнейшем ссылаться на эту строку. Также метки позволяют определять переменные в программе и затем чрез метку можно ссылаться на переменную. Обычно метка представляет собой произвольный идентификатор, за которым следует двоеточие:
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}