Чтобы сгенерировать ассемблерный код x86, я определил пользовательский тип с именем X86
:
data X86 a = X86 { code :: String, counter :: Integer, value :: (X86 a -> a) }
Этот тип используется в do-нотации, как показано ниже. Это упрощает написание шаблонов для создания операторов if, циклов for и т. д.
generateCode :: X86 ()
generateCode = do
label1 <- allocateUniqueLabel
label2 <- allocateUniqueLabel
jmp label1
label label1
jmp label2
label label2
Инструкции определяются следующим образом:
jmp :: String -> X86 ()
jmp l = X86 { code = "jmp " ++ l ++ ";\n", counter = 0, value = const () }
label :: String -> X86 ()
label l = X86 { code = l ++ ":\n", counter = 0, value = const () }
И готовый файл сборки печатается так:
printAsm :: X86 a -> String
printAsm X86{code=code} = code
main = do
putStrLn (printAsm generateCode)
Я реализовал монаду X86
следующим образом. По сути, оператор последовательности объединяет блоки ассемблерного кода по порядку и обеспечивает увеличение счетчиков.
instance Monad X86 where
x >> y = X86 { code = code x ++ code y, counter = counter x + counter y, value = value y }
x >>= f = x >> y
where y = f (value x x)
Проблема в том, что метки не увеличиваются должным образом, поэтому они не уникальны! Вывод следующий:
jmp Label1;
Label1:
jmp Label1;
Label1:
Я хочу, чтобы вывод имел уникальное значение для каждой метки:
jmp Label1;
Label1:
jmp Label2;
Label2:
Чтобы завершить пример, вот реализация функции allocatedUniqueLabel
:
allocateUniqueId :: X86 Integer
allocateUniqueId = X86 { code = "", counter = 1, value = counter }
allocateUniqueLabel :: X86 String
allocateUniqueLabel = do
id <- allocateUniqueId
return ("Label" ++ show id)
Как я могу исправить свою монаду X86
, чтобы метки были уникальными?
Вот что я пробовал:
- Увеличение глобального счетчика. => Haskell не позволяет безопасно разрешить глобальное состояние вне монады IO.
- Использование монады
State
. => Я просмотрел несколько примеров, но не понимаю, как интегрировать их в мою существующую монадуX86
. - Следите за счетчиком вне монады. => У меня скорее счетчик обновляется "за кадром"; в противном случае во многих шаблонах кода, не использующих метки, потребуется распространять счетчик вручную.
Monad
для удобства или есть какой-то законный экземпляр? - person Li-yao Xia   schedule 27.03.2018X86
на самом деле даже неFunctor
(которым должен был бы бытьMonad
). - person Li-yao Xia   schedule 27.03.2018counter
должен быть скорееInteger -> Integer
- person max630   schedule 27.03.2018Label
для результатаallocateUniqueLabel
. Это сделает ваш код более безопасным, так как вы будете переходить только к меткам, а не к произвольным строкам. - person Petr   schedule 31.03.2018