1

I am writing a simple arithmetic expression parser in the Haskell platform's Happy. The Happy tutorial (labeled "Documentation") from the Haskell site implements a similar grammar to what I need. The difference is that I want to include floating point numbers in my expressions and I do not need to define variables (i.e. expressions will not contain "let", "in", "=", or "x" or "y").

When I compile my grammar file with Happy it outputs:

unused terminals: 1
happy: no token type given
CallStack (from HasCallStack):
  error, called at src/AbsSyn.lhs:93:24 in main:AbsSyn

I've searched StackOverflow for questions mentioning "no token type given" and found nothing mentioning this error. I also can't figure out what the "CallStack" trace means. (I'm quite new to Haskell).

I've defined a helper function to tell whether a token is a float:

isNum :: [Token] -> a -> Bool
isNum x = typeOf (read x) == typeOf 1.1

I've copied the documentation page's grammar file almost exactly, except where I've removed any production rules for variables, "=", or other alphabetic input, and where I've added rules for floating point numbers, i.e.

%token
    int    { TokenInt $$ }
    float { TokenNum $$ }
...
Exp    : Expl { Expl $1 }
Exp    : Expl '+' Term { Plus $1 $3}
...
Factor    : int    { Int $1 }
          | float { Float $1 }
...
data Exp
    = Let String Exp Exp
    | Expl Expl
    deriving Show

data Expl
    = Plus Expl Term
    | Minus Expl Term
    | Term Term
    deriving Show
...
data Token
    = TokenInt Int
    | TokenFloat Float
    | TokenNum Float
    | TokenPlus
...
lexer (c:cs)
    | isSpace c = lexer cs
    | isDigit c = lexNum (c:cs)
lexer ('=':cs) = TokenEq : lexer cs
...
lexNum cs = TokenInt (read num) : lexer rest
    where (num,rest) = span isDigit cs
lexFloat cs = TokenFloat (read num) : lexer rest
    where (num,rest) = span isNum cs

That's about it, so far.

nau5ea
  • 13
  • 4
  • `typeOf (read x)` is fundamentally wrong. `read x` doesn't attempt to parse `x` using all the parsers for all types and then return a result of the type whose parser happens to succeed. Instead, `read x` only tries _one_ parser of a single specific type and returns such a value or crashes. The type must be inferred by the compiler or specified by the user as in `read x :: Float`, and can not be chosen at runtime. `typeOf (read x)` is inherently ambiguous and will be rejected by the compiler. – chi Dec 06 '22 at 09:07
  • Rather, you could try to use [`Text.Read.readMaybe`](https://hackage.haskell.org/package/base-4.17.0.0/docs/Text-Read.html#v:readMaybe) on a specific type and check whether it succeeded. E.g. `case readMaybe x :: Maybe Double of Nothing -> False ; Just _ -> True`. This will only try the `Double` parser -- again, only a single given type is used. – chi Dec 06 '22 at 09:08
  • Thank you - I realized I don't need to parse Ints separately from Floats and preserve their type; I can fall back to parsing all numeric tokens as Floats, so that problem goes away. – nau5ea Dec 06 '22 at 22:42

0 Answers0