我正在尝试在Haskell中生成一些汇编指令,并且需要生成一些唯一的ID来标记jmp
指令的节。我相信我可以使用State monad来做到这一点,但是我对Haskell还是陌生的,对State monad不太满意,在这种情况下需要一些帮助。
以下是我需要唯一ID的示例之一
generateExpression :: AST.Expr -> String
generateExpression (AST.BinOpExpr AST.Or e1 e2) =
(generateExpression e1) ++
" cmpl $0, %eax\n" ++
" je _or_clause2\n" ++
" movl $1, %eax\n" ++
" jmp _or_end\n" ++
"_or_clause2:\n" ++ -- need to use a unique id here instead of clause 2
(generateExpression e2) ++
" cmpl $0, %eax\n" ++
" movl $0, %eax\n" ++
" setne %al\n" ++
"_or_end:\n" -- need to use a unique id here to label the end
编辑:我已经阅读了有关State Monad的一些教程,并且可以实现一个简单的计数器,例如
import Control.Monad.State
counter :: State Int Int
counter = do
x <- get
put (x+1)
return x
runState counter 1 -- outputs (1,2) where the state has been incremented
,它将跟踪计数器作为状态。但是我不确定如何在需要在递归调用中保持状态的函数中使用它。
答案 0 :(得分:4)
因此返回类型中必须包含State Int
,不能为String
。关键是您需要使状态通过。在这里,您似乎对此感到满意,所以使用了do
表示法。
counter :: State Int Int
counter = do
n <- get
put (n + 1)
pure n
generateASM :: AST.Expr -> State Int String
generateASM (AST.BinOpExpr AST.Or e1 e2) = do
e1ASM <- generateASM e1
n <- counter
e2ASM <- generateASM e2
pure $
e1ASM ++
" cmpl $0, %eax\n" ++
" je _or_clause" ++ show n ++ "\n" ++
" movl $1, %eax\n" ++
" jmp _or_end" ++ show n ++ "\n" ++
"_or_clause" ++ show n ++ ":\n" ++ show n ++
e2ASM ++
" cmpl $0, %eax\n" ++
" movl $0, %eax\n" ++
" setne %al\n" ++
"_or_end" ++ show n ++ ":\n"
generateASM (..) = .. -- other branches defined similarly...
generateASMFull :: AST.Expr -> String
generateASMFull e = evalState (generateASM e) 0
P.S。我没有检查您的汇编逻辑是否正确。