계산기프로그램 만들기
GtkHs와 Glade 편집툴을 이용해서 만든 간단한 계산기 프로그램입니다.
Parsec.Expr 모듈을 이용하면 EBNF 문법을 거의 그대로 이용해서 파서를 만들 수 있습니다.
exprParser 함수가 바로 그렇게 구현한 파서입니다.
아래 소스는 크게 두 부분으로 나뉩니다.
glade를 이용해서 기술한 UI description file을 읽어서 UI를 만들고 각 버튼 클릭 메시지를 처리하는 등의 GUI 처리 부분이 한 부분이고, GUI를 통해 화면에 출력된 수식을 파싱하여 계산 결과를 처리하는 계산 엔진 부분이 있습니다. 그리고 이 둘은 거의 완벽하게 분리가 가능합니다.
UI용 Glade 소스 - calculator(1).glade
하스켈 소스
- module Calculator where
- import Graphics.UI.Gtk
import Graphics.UI.Gtk.Glade
import Text.ParserCombinators.Parsec - import Text.ParserCombinators.Parsec.Expr
import Data.IORef - buttons = [("button0", "0"), ("button1", "1"), ("button2", "2"), ("button3", "3"), ("button4", "4"),
- ("button5", "5"), ("button6", "6"), ("button7", "7"), ("button8", "8"), ("button9", "9"),
- ("button_add", "+"), ("button_sub", "-"), ("button_times", "*"), ("button_div", "/") ]
- main = do
initGUI
state <- newIORef True -- True: clear previous value
Just xml <- xmlNew "calculator.glade"
window <- xmlGetWidget xml castToWindow "window1"
field <- xmlGetWidget xml castToEntry "entry1"
result <- xmlGetWidget xml castToButton "button_result"
onDestroy window mainQuit
mapM_ (\(widgetName,text) -> do
widget <- xmlGetWidget xml castToButton widgetName
onClicked widget $ do
clear <- readIORef state
prev <- (\clear -> if (clear)
then writeIORef state False >> return ""
else get field entryText >>= return) =<< readIORef state
entrySetText field (prev ++ text)
) buttons
onClicked result $ do
expr <- get field entryText
case (parse exprParser "" expr) of
Left err -> entrySetText field "0"
Right ret -> entrySetText field $ show ret
writeIORef state True
widgetShowAll window
mainGUI - exprParser :: Parser Float
- exprParser = buildExpressionParser table factor
<?> "expression"
table = [[op "*" (*) AssocLeft, op "/" (/) AssocLeft]
,[op "+" (+) AssocLeft, op "-" (-) AssocLeft] - ]
where
op s f assoc
= Infix (do {string s; return f}) assoc
factor = do { char '('
; x <- exprParser
; char ')'
; return x
}
<|> number
<?> "simple expression"
number :: Parser Float
number = do { ds <- many1 digit
; return (read ds) }
<?> "number"
History
Last edited on 03/31/2008 18:04 by gimmesilver
Comments (0)