2015-01-15 3 views
1

Я пытаюсь реализовать некоторый язык с й = 4 и pritn х, конструкции с использованием Haskell счастливой До сих пор я определил грамматику как этогоHaskell Счастливых реализаций присвоить переменную

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

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

Когда я запускаю его над чем-то вроде

x = 4 
print x 
y = 5 
print y 

Я получаю

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

Теперь я хочу сделать переменный ток но я не знаю, как реализовать «присваивать»

Хотя я плохо разбираюсь в haskell, из счастливых документов я увидел реализацию «let» и получил представление о некоторой среде p, переданной и оцененной в

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 для программы, а затем мы будем оценивать его отдельно.

код на самом деле очень мало, но это разбито на несколько модулей, так что я положил его здесь, в этом суть: https://gist.github.com/sdiehl/c2dd1880e0ec6b65a120

Я полагаю, ваш AST выглядит примерно так:

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

синтаксический анализатор выглядит право, за исключением того, что я думаю, вам нужно будет добавить var, поэтому выражения, подобные print x и print 1, могут быть хорошо сформированы в синтаксисе.

%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 } 

Для переводчика мы будем использовать монаду StateT + IO, чтобы держать присвоенные переменные и вызвать функцию печати Haskell для каждой функции печати в нашей программе. Государственная монада будет содержать список переменных переменных. 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

У Фила Вадлера есть хорошая статья: http://homepages.inf.ed.ac.uk/wadler/papers/marktoberdorf/baastad.pdf. Это еще не сделано, но я пишу длинный учебник по этому вопросу: http://dev.stephendiehl.com/fun/WYAH.pdf –

Смежные вопросы