2015-01-15 1 views
1
변수

내가 그것을 실행하면 나는이하스켈 행복

terms 
    : term     { [$1] } 
    | term terms    { $1 : $2 } 

term 
    : var '=' int    { Assign $1 $3 } 
    | print var    { Print $2 } 

같은 구조물이 행복 지금까지 정의한 문법 하스켈을 사용하여, X = 4 pritn X 몇 가지 언어를 구현하기 위해 노력하고있어에 할당 구현

x = 4 
print x 
y = 5 
print y 

같은 이상 나는 교류를하고 싶은 이제

[Assign "x" 4, Print "x", Assign "y" 5, Print "y"] 

를 얻을 수 구현을 구현하는 방법을 모르겠지만 "할당"을 구현하는 방법을 모르겠다.

행복한 문서가 좋지 않아서 "구현"을하고 일부 환경에 대한 아이디어를 얻었습니다.

Exp : let var '=' Exp in Exp { \p -> $6 (($2,$4 p):p) } 
    | Exp1     { $1 } 

Exp1 : Exp1 '+' Term   { \p -> $1 p + $3 p } 
    | Exp1 '-' Term   { \p -> $1 p - $3 p } 
    | Term     { $1 } 

Term : Term '*' Factor   { \p -> $1 p * $3 p } 
    | Term '/' Factor   { \p -> $1 p `div` $3 p } 
    | Factor     { $1 } 

Factor    
    : int      { \p -> $1 } 
    | var      { \p -> case lookup $1 p of 
            Nothing -> error "no var" 
        Just i -> i } 
    | '(' Exp ')'    { $2 } 

"할당"구현은이 env를 사용하여 수행해야한다고 생각하지만 예제를 찾을 수 없습니다. 어떻게 할당 및 인쇄를 구현할 수 있습니까? 또는 정보 또는 예제를 어디에서 찾을 수 있습니까?

+0

아마도이 유용한 질문이 유용 할 것입니다. http://stackoverflow.com/questions/16970431/implementing-a-language-interpreter-in-haskell – ErikR

답변

5

파서와 매우 흡사합니다. 그러나 구문 분석 로직과 별도로 표현식 언어를 구현하기 위해 인터프리터을 작성해야합니다. 파서는 프로그램에 대한 AST를 생성 한 다음 별도로 평가할 것입니다.

코드는 실제로 아주 작은,하지만이 요점 여기에 넣어 있도록 여러 모듈로 분할 것 :

data Expr 
    = Var String 
    | Num Int 
    | Print Expr 
    | Assign String Int 
    deriving (Eq,Show) 

파서 외모 : https://gist.github.com/sdiehl/c2dd1880e0ec6b65a120

나는 당신의 AST는 다음과 같이 보입니다 추정 맞습니다. var 프로덕션을 추가해야하는데, print xprint 1과 같은 표현식은 모두 구문에서 올바른 형식이 될 수 있습니다. 우리가 할당 된 변수를 유지하고 우리 프로그램의 각 인쇄 기능에 대한 하스켈의 인쇄 기능을 호출 할 StateT + IO 모나드를 사용합니다 인터프리터를 들어

%token 
    int { TokenNum $$ } 
    var { TokenSym $$ } 
    print { TokenPrint } 
    '=' { TokenEq } 

%% 

terms 
    : term     { [$1] } 
    | term terms    { $1 : $2 } 

term 
    : var      { Var $1 } 
    | var '=' int    { Assign $1 $3 } 
    | print term    { Print $2 } 

. 상태 모나드는 변수의 연관 목록을 값으로 유지합니다. Assign은 단순히 목록에 새 참조를 추가하고 Var 참조는 해당 상태에 대해 lookup 함수를 사용합니다.

data Value 
    = VInt Int 
    | VUnit 

instance Show Value where 
    show (VInt x) = show x 

type Eval = StateT Env IO 
type Env = [(String, Value)] 

eval1 :: Expr -> Eval Value 
eval1 expr = case expr of 
    Num a -> return (VInt a) 
    Var a -> do 
    env <- get 
    case lookup a env of 
     Just val -> return val 
     Nothing -> error "Not in scope" 
    Print a -> do 
    a' <- eval1 a 
    liftIO $ print a' 
    return VUnit 
    Assign ref val -> do 
    modify $ \s -> (ref, VInt val) : s 
    return VUnit 

eval :: [Expr] -> IO() 
eval xs = evalStateT (mapM_ eval1 xs) [] 

그게 전부입니다.

+0

자세한 답변을 주셔서 감사합니다. 자세한 소스 예제는 어디에서 찾을 수 있습니까? 그러한 통역사 구현에? – Herokiller

+0

필 와들러 (Phil Wadler)는 좋은 종이를 여기에두고 있습니다 : http://homepages.inf.ed.ac.uk/wadler/papers/marktoberdorf/baastad.pdf. 아직 끝나지 않았지만 주제에 대한 긴 안내서를 작성하고 있습니다. http://dev.stephendiehl.com/fun/WYAH.pdf –