2
votes

I want make a parser in happy for the let-in-expression language. For example, i want parse the following string:

let x = 4 in x*x

At the university we study attribute grammars, and i want use this tricks to calculate directly the value of the parsed let-in-expression. So in the happy file, i set the data type of the parsing function to Int, and i created a new attribute called env. This attribute is a function from String to Int that associates variable name to value. Referring to my example:

env "x" = 4

Now i put here below the happy file, where there is my grammar:

{
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"

}

When i load the haskell file generated from the happy file above, i get the following error:

    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')

I don't know why i get this, because i don't define the type Parser.Int in my happy file. I tried to replace Int with Prelude.Int, but i get other errors.

How can i resolve? Can i have also some general tips if I'm doing something not optimal?

1
I'd use parser combinators instead, like parsec.augustss
If you are interested in attribute grammars the UUAG system is generally a better choice than Happy. It is much better documented (though the docs sometimes go out of date) and actively maintained (due to it being used by the UHC Haskell compiler).stephen tetley
Thanks, but i must use happy.optimusfrenk

1 Answers

0
votes

See the happy explaination of attributetype: http://www.haskell.org/happy/doc/html/sec-AtrributeGrammarsInHappy.html

Your line:

%attributetype { Int }

Is declaring a type named Int. This is what causes the ambiguity.