{-
?????????: 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 ??§??????
13:28 AC????????????Haskell
13:29 ?????£??????????????§?????¢?????????????????§???????£?????????£?????????????????????????????????????????????AOJ?????¨??????????????????
-}
import Control.Applicative hiding(many)
import Control.Monad
import Data.List
import Control.Monad.Reader
import Control.Monad.State

type Table = [Atom] 

----------------------------
type Parse2 a = StateT String (ReaderT Table Maybe) a

parse :: Parse2 a -> Table -> String -> Maybe (a, String)
parse p t str = runReaderT (runStateT p str) t

skip :: String -> Parse2 ()
skip str = do
 input <- get
 if str `isPrefixOf` input then put $ length str `drop` input
  else fail "No match"

oneOf :: String -> Parse2 Char
oneOf str = do
 input <- get
 if null input then fail "EOF" 
  else if head input `notElem` str then fail "No match"
   else put(tail input) >> return(head input)

(?|) :: Parse2 a -> Parse2 a -> Parse2 a
h ?| i = do
 t <- ask
 input <- get
 case parse h t input of
  Nothing -> i
  Just (u,v) -> put v >> return u

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



type Atom = (String,Int)

atom :: Parse2 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 :: Parse2 Int
molecule = sum <$> many m2

m2 :: Parse2 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 :: Parse2 Int
number = do
 n <- many (oneOf "0123456789")
 if null n then fail "" else return $ read n

main :: IO ()
main = do
 table <- readFirstPart
 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

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

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

Measured memory_bytes: 4216