module CodeGen (
  generateAssembly, -- esta função será exportada
) where

import AST

-- Função principal -> gera Assembly a partir do AST
generateAssembly :: AST -> String
generateAssembly :: AST -> String
generateAssembly AST
ast =
  String
generateHeader String -> String -> String
forall a. [a] -> [a] -> [a]
++ (String, Int) -> String
forall a b. (a, b) -> a
fst (AST -> Int -> (String, Int)
astToAsm AST
ast Int
0) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
generateFooter
-- ** fst (a, b) -> a **

-- Função de tradução
astToAsm :: AST -> Int -> (String, Int)
astToAsm :: AST -> Int -> (String, Int)
astToAsm [] Int
countr = (String
"", Int
countr)
astToAsm (Cmd
cmd : AST
restoDaAst) Int
countr =
  case Cmd -> Int -> (String, Int)
translateCmd Cmd
cmd Int
countr of -- executa a tradução da primeira instrução
    (String
asm1, Int
countr1) ->
      -- se deu certo, códido asm1 e countr1 são retornados
      -- com o contador atualizado, executamos a tradução do resto da lista
      case AST -> Int -> (String, Int)
astToAsm AST
restoDaAst Int
countr1 of
        (String
asm2, Int
countr2) ->
          -- se deu certo, temos agora o asm2 e o contador atualizado
          (String
asm1 String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
asm2, Int
countr2) -- junta o codigo da primeira instrução com o resto e passa o contador final

-- Função auxiliar do asmToAst
translateCmd :: Cmd -> Int -> (String, Int) -- Através de Pattern Matching, analisa cada Cmd do AST
translateCmd :: Cmd -> Int -> (String, Int)
translateCmd Cmd
Incr Int
countr = (String
"    inc byte [rbx]\n", Int
countr)
translateCmd Cmd
Decr Int
countr = (String
"    dec byte [rbx]\n", Int
countr)
translateCmd Cmd
Next Int
countr = (String
"    inc rbx\n", Int
countr)
translateCmd Cmd
Prev Int
countr = (String
"    dec rbx\n", Int
countr)
translateCmd Cmd
Print Int
countr =
  ( [String] -> String
unlines
      [ String
"    movzx rdi, byte [rbx]" -- movzx é mais seguro pra copiar um byte para um registrador maior
      , String
"    call putchar" -- imprime com a função do C
      ]
  , Int
countr
  )
translateCmd Cmd
Input Int
countr =
  ( [String] -> String
unlines
      [ String
"    call getchar" -- lê um caractere com a função do C
      , String
"    mov [rbx], al" -- Salva o resultado na memória
      ]
  , Int
countr
  )
translateCmd (Loop AST
innerAst) Int
countr =
  case AST -> Int -> (String, Int)
astToAsm AST
innerAst (Int
countr Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1) of
    (String
asmDoLoop, Int
countrFinal) ->
      ( [String] -> String
unlines
          [ (String
"loop_start_" String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
countr) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
":"
          , String
"    cmp byte [rbx], 0"
          , String
"    je " String -> String -> String
forall a. [a] -> [a] -> [a]
++ (String
"loop_end_" String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
countr)
          , String
asmDoLoop
          , String
"    jmp " String -> String -> String
forall a. [a] -> [a] -> [a]
++ (String
"loop_start_" String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
countr)
          , (String
"loop_end_" String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
countr) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
":"
          ]
      , Int
countrFinal
      )

-- Funções auxiliares do generateAssembly
generateHeader :: String -- Cabeçalho Assembly
generateHeader :: String
generateHeader =
  [String] -> String
unlines
    [ -- unlines pega um [String] e retorna todos os elementos os separando por \n
      String
"section .data"
    , String
"    memory: times 30000 db 0" -- tape de 30K bytes, tudo como 0
    , String
"    pointer: dq memory" -- ponteiro apontando para a posição de memória atual
    , String
""
    , String
"section .text"
    , String
"    global main" -- torna o main visível para o Linker do C (gcc)
    , String
"    extern putchar" -- extern pega funções do C para usar no Assembly
    , String
"    extern getchar"
    , String
""
    , String
"main:" -- seguindo as regras do C, não se usa _start, mas sim 'main'
    , String
"    push rbp"
    , String
"    mov rbp, rsp"
    , String
"    mov rbx, [pointer]" -- carega o ponteiro para rbx no inicio
    ]

generateFooter :: String -- Rodapé do Assembly
generateFooter :: String
generateFooter =
  [String] -> String
unlines
    [ -- Fim padrão de um programa Assembly
      String
"    mov [pointer], rbx" -- Salva a posição final do ponteiro
    , String
"    mov rax, 0"
    , String
"    pop rbp"
    , String
"    ret"
    ]