2013-12-07 4 views
2

Я хочу сделать синтаксический анализатор счастливым для языка let-in-expression. Например, я хочу разобрать следующую строку:noob хочет сделать синтаксический анализатор для небольшого языка

let x = 4 in x*x 

В университете мы изучаем атрибут грамматики, и я хочу использовать эти приемы, чтобы непосредственно вычислить значение разобранного вставленный-выражения. Поэтому в счастливом файле я устанавливаю тип данных функции синтаксического анализа в Int, и я создал новый атрибут, называемый env. Этот атрибут является функцией от String to Int, которая связывает имя переменной со значением. Ссылаясь на моем примере:

env "x" = 4 

Теперь я ставлю здесь ниже счастливый файл, где есть моя грамматика:

{ 
module Parser where 

import Token 
import Lexer 
} 

%tokentype { Token } 

%token 
     let    { TLet } 
     in    { TIn } 
     int    { TInt $$ } 
     var    { TVar $$ } 
     '='    { TEq } 
     '+'    { TPlus } 
     '-'    { TMinus } 
     '*'    { TMul } 
     '/'    { TDiv } 
     '('    { TOB } 
     ')'    { TCB } 

%name parse 

%attributetype { Int } 

%attribute env { String -> Int } 

%error { parseError } 

%% 

Exp : let var '=' Exp in Exp 
      { 
       $4.env = $$.env; 
       $2.env = (\_ -> 0); 
       $6.env = (\str -> if str == $2 then $4 else 0); 
       $$ = $6; 
      } 
     | Exp1      
      { 
       $1.env = $$.env; 
       $$ = $1; 
      } 

Exp1 : Exp1 '+' Term 
      { 
       $1.env = $$.env; 
       $2.env = $$.env; 
       $$ = $1 + $3; 
      } 
     | Exp1 '-' Term 
      { 
       $1.env = $$.env; 
       $2.env = $$.env; 
       $$ = $1 - $3; 
      } 
     | Term 
      { 
       $1.env = $$.env; 
       $$ = $1; 
      } 

Term : Term '*' Factor 
      { 
       $1.env = $$.env; 
       $2.env = $$.env; 
       $$ = $1 * $3; 
      } 
     | Term '/' Factor 
      { 
       $1.env = $$.env; 
       $2.env = $$.env; 
       $$ = div $1 $3; 
      } 
     | Factor 
      { 
       $1.env = $$.env; 
       $$ = $1; 
      } 

Factor    
     : int 
      { 
       $$ = $1; 
      } 
     | var 
      { 
       $$ = $$.env $1; 
      } 
     | '(' Exp ')' 
      { 
       $1.env = $$.env; 
       $$ = $1; 
      } 

{ 
parseError :: [Token] -> a 
parseError _ = error "Parse error" 

} 

Когда я загрузить файл Haskell генерируемый из счастливого файла выше, я получаю следующее сообщение об ошибке:

Ambiguous occurrence `Int' 
It could refer to either `Parser.Int', defined at parser.hs:271:6 
         or `Prelude.Int', 
         imported from `Prelude' at parser.hs:2:8-13 
         (and originally defined in `GHC.Types') 

Я не знаю, почему я получаю это, потому что я не определяю тип Parser.Int в моем счастливом файле. Я попытался заменить Int с Prelude.Int, но я получаю другие ошибки.

Как я могу решить? Могу ли я иметь и некоторые общие советы, если я делаю что-то не оптимальное?

+1

Вместо этого я бы использовал комбинаторы парсера, например parsec. – augustss

+2

Если вас интересуют грамматики атрибутов, система UUAG, как правило, является лучшим выбором, чем Happy. Он гораздо лучше документирован (хотя документы иногда устаревают) и активно поддерживается (из-за того, что он используется компилятором UHC Haskell). –

+0

Спасибо, но я должен использовать счастливый. – optimusfrenk

ответ