{-
?????????: Molecular Formula
URL: http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=1244
?????°:
19:54 Encryption System??????????§£???????????§??????????????£????????????Haskell???
19:55 ??????TLE????????????????????§???????????????
19:55 ?????????AOJ??£???Parsec??\??£???????????§??????????????\??£??????????????????????????????
19:56 ?????£????????????????????????????????¨???????????¨???Parsec??\??£??¨?????????
19:56 ??????????????????????????????????????\??£?????????????????????????????????
19:57 ??¨???????????¨??§???????????????????????????
20:06 ?????????????§??????????????????£??¨??´??£??????
20:17 ??\??????????????????????????????????????????????????????????????????Parsec???????????§???????????????
20:19 ??¨??????????????????Parsec???????????°??????

7/4
13:26 ??§??????
-}
import Control.Applicative hiding(many)
import Control.Monad
import Data.List

type Table = [Atom] 

----------------------------

newtype Parse a = Parse{unParse :: Table -> String -> Maybe(String,a)}

instance Functor Parse where
 fmap f (Parse g) = Parse $ \a b -> fmap f `fmap` (g a b)

joindre :: Parse(Parse a) -> Parse a
joindre (Parse f) = Parse $ \a b -> do{ (str,Parse g) <- f a b; g a str}

instance Applicative Parse where
 pure = return
 (<*>) = ap

instance Monad Parse where
 return a = Parse $ \_ s -> Just(s,a) 
 m >>= f = joindre(fmap f m)
 fail _ = Parse $ \_ _ -> Nothing

skip :: String -> Parse ()
skip str = Parse f where
 f _ input
  | str `isPrefixOf` input = Just(length str `drop` input,())
  | otherwise = Nothing

oneOf :: String -> Parse Char
oneOf str = Parse f where
 f _ input
  | null input = Nothing
  | head input `elem` str = Just(tail input,head input)
  | otherwise = Nothing

(?|) :: Parse a -> Parse a -> Parse a
Parse f ?| Parse g = Parse $ \t input -> case f t input of
 Nothing -> g t input
 j -> j

(??|) :: Parse a -> Parse b -> Parse (Either b a)
Parse f ??| Parse g = Parse $ \t input -> case f t input of
 Nothing -> fmap Left `fmap` (g t input)
 j -> fmap Right `fmap` j

many :: Parse a -> Parse [a]
many p = do
 a' <- p ??| return ()
 case a' of
  Left () -> return []
  Right a -> (a:) `fmap` many p

ask :: Parse Table
ask = Parse $ \t a -> Just(a,t)
-------------------------------------



type Atom = (String,Int)

atom :: Parse Atom
atom = do
 name <- (:) <$> oneOf ['A'..'Z'] <*> many (oneOf ['a'..'z'])
 table <- ask
 Just weight <- return $ name `lookup` table -- Nothing calls fail
 return (name,weight)

molecule :: Parse Int
molecule = sum <$> many m2

m2 :: Parse Int
m2 = p1 ?| p2 where
 p1 = do
  weight <- skip "(" *> molecule <* skip ")"
  num <- number
  return (weight*num)
 p2 = do
  weight <- snd <$> atom
  num <- number ?| return 1
  return (weight*num)


number :: Parse Int
number = do
 n <- many (oneOf "0123456789")
 if null n then fail "" else return $ read n

main = do
 table <- read_first_part
 latter table

latter :: [(String,Int)] -> IO ()
latter table = do
 dat <- getLine
 unless (dat == "0") $ do
  putStrLn $ case analyze table dat of
   Nothing -> "UNKNOWN"
   Just a -> show a
  latter table

read_first_part :: IO [(String,Int)]
read_first_part = do
 info <- getLine
 if (info == "END_OF_FIRST_PART") then return [] else do
  let [atom, num'] = words info
  let num = read num'
  arr <- read_first_part
  return $ (atom,num) : arr

analyze :: [(String,Int)] -> String -> Maybe Int
analyze table str = do
 ("",ans) <- unParse molecule table str
 return ans

Measured memory_bytes: 4116