アドレス情報を保持するコンパイラ

宣言された変数に対して,順番にアドレスを確保していくコンパイラ

Parse> r "var a; var b; a=3; b=a+2;"
Loading package parsec-2.0 ... linking ... done.
Found value[ ["VarDecl","0"],
["VarDecl","1"],
["0","3","=","POP"],
["1","0","Read","2","+","=","POP"] ]
Parse> 

昨日のMap.hsが別途必要です

module Parse where
import Text.ParserCombinators.Parsec
import Data.HashTable
import Map

 --main
r :: String -> IO ()
r input = 
   case runParser source (PStat 0 []) "lisp" input of
     Left err  -> putStrLn $ "No match: " 
                  ++ show err
     Right val -> putStrLn $ "Found value" 
                  ++ (show $ map (toCode RVal) val)

newSym = new (==) hashString :: IO (HashTable String Int)
 --util
data ParserState = PStat Int [(String,Int)]
getNum :: ParserState -> Int
getNum (PStat i _) = i
getSyms :: ParserState -> [(String,Int)]
getSyms (PStat _ h) = h

type SParser a = GenParser Char ParserState a

mny :: SParser a -> SParser [a] 
mny p = many (do { spc; p } )
toks1 :: SParser Char -> SParser String 
toks1 p = do {res<-many1 p ; spc; return res } 

spc :: SParser ()
spc = skipMany space

tok :: String -> SParser String
tok str = do { s <- string str; spc ; return s }

 --grammar
source :: SParser [Decl]
source = do { bodies <- mny ( vardecl <|> statement)
            ; return bodies 
            }

vardecl :: SParser Decl

変数宣言をして,変数のアドレスを割り当てている部分.
ここで使っているlet は,ふつけるP279 にある「特別なlet節」.実はうっかりinを書き忘れたことで偶然みつけた.便利.

vardecl = do { tok "var" 
             ; name <- symbol; tok ";"
             ; st <- getState 
             ; let syms = getSyms st 
             ; let addr = getNum  st 
             ; setState (PStat (addr+1) 
                               (put syms name addr))
             ; return $ VarDecl name addr 
             } 


statement :: SParser Decl
statement = do { e <- expr
               ; tok ";"
               ; return $ StmtDecl $ ExprStmt e
               }


expr :: SParser Expr
expr = do {
         left <- add ;
         option left (do {
             tok "=" ; a<-add ;
             return (BinOp left "=" a) 
         })
       }
add = do { left <- element
          ; rights <- mny (do { op   <- operators 
                              ; e    <- element 
                              ; return (op,e) } )
          ; return (makeBinOp left rights)
          }
operators :: SParser String
operators = tok "+" <|> tok "-" 

element :: SParser Expr
element = intConst <|> varRef

ここは,変数を見て,その変数のアドレスを取り出しているところ

varRef :: SParser Expr
varRef = do {
   n <- symbol ;
   st <- getState ;
   return $ VarRef (defMaybe (-1) (get (getSyms st) n))
}
defMaybe:: a -> (Maybe a) -> a
defMaybe def (Just x) = x
defMaybe def Nothing = def 
intConst :: SParser Expr
intConst = do { v <- digits 
              ; return $ IntConst v 
              }

symbol  :: SParser String
symbol  = toks1 letter
digits  :: SParser Int
digits  = do { d <- toks1 (oneOf "0123456789")
             ; return (read d::Int)  -- ???
             }

 --semantics
makeBinOp :: Expr -> [(String,Expr)] -> Expr
makeBinOp left [] = left
makeBinOp left ((op,elem):rest) = 
   makeBinOp (BinOp left op elem) rest

data Decl = VarDecl String Int  |
            StmtDecl Statement  -- !
            
data Statement = ExprStmt Expr
			
data Expr = BinOp Expr String Expr |
            IntConst Int  |
            VarRef Int 
data CodeState = LVal | RVal

class ToCodable a where
     toCode:: CodeState -> a -> [String]

instance ToCodable Statement where
  toCode c (ExprStmt e) = (toCode c e)  ++ ["POP"] 
  
instance ToCodable Expr where
  toCode c (BinOp l "=" r) =
     (toCode LVal l) ++ (toCode RVal r) ++ ["="]  
  toCode c (BinOp l o r)   = 
     (toCode RVal l) ++ (toCode RVal r) ++ [o]
  toCode c (IntConst i)    = [show i] 
  toCode RVal (VarRef addr )  = [show addr , "Read"];
  toCode LVal (VarRef addr )  = [show addr ];

instance ToCodable Decl where
  toCode c (StmtDecl st)  = toCode c st
  toCode c (VarDecl name addr) = ["VarDecl", show addr]