Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Operator precedence and associativity in a parser (Haskell)

I am trying to extend a recursive-descent parser to handle new operators and make them associate correctly. Originally there were only four operators (+ - / *) and they all had the same precedence. The function I am looking at is the parseExpRec function:

parseExpRec               :: Exp -> [Token] -> (Exp, [Token])    
parseExpRec e  []         =  (e, [])
parseExpRec e1 (op : ts)  = 
 let (e2, ts') = parsePrimExp ts in
   case op of
    T_Power     -> parseExpRec (BinOpApp Power  e1 e2) ts'
    T_Plus      -> parseExpRec (BinOpApp Plus   e1 e2) ts'
    T_Minus     -> parseExpRec (BinOpApp Minus  e1 e2) ts'
    T_Times     -> parseExpRec (BinOpApp Times  e1 e2) ts'
    T_Divide    -> parseExpRec (BinOpApp Divide e1 e2) ts'
    T_GreaterThan   -> parseExpRec (BinOpApp GreaterThan    e1 e2) ts'
    T_LessThan      -> parseExpRec (BinOpApp LessThan       e1 e2) ts'
    T_GreaterOrEqual -> parseExpRec (BinOpApp GreaterOrEqual e1 e2) ts'
    T_LessOrEqual   -> parseExpRec (BinOpApp LessOrEqual    e1 e2) ts'
    T_EqualTo       -> parseExpRec (BinOpApp EqualTo        e1 e2) ts'
    _           -> (e1, op : ts)

All of the pattern matching lines except T_Plus, T_Minus, T_Times and T_Divide have been added by me (and so have the associated tokens and extensions to the Exp datatype). However, none of them seem to associate correctly. For example, the string "3^4 + 2^3" evaluates to:

BinOpApp Power (BinOpApp Plus (BinOpApp Power (LitInt 3) (LitInt 4)) (LitInt 2)) (LitInt 3)

Which is equivalent to this in infix notation (with brackets included):

((3^4)+2)^3

How would I fix this?

like image 338
benwad Avatar asked Feb 24 '10 13:02

benwad


People also ask

Does parser follow operator precedence?

Operator precedence parsers use precedence functions that map terminal symbols to integers, and the precedence relations between the symbols are implemented by numerical comparison. The parsing table can be encoded by two precedence functions f and g that map terminal symbols to integers.

What is operator precedence and operator associativity?

Precedence is the priority for grouping different types of operators with their operands. Associativity is the left-to-right or right-to-left order for grouping operands to operators that have the same precedence.

Is Haskell right or left associative?

Haskell also has a binary operator called $ . f $ x does function application just like f x , but it is right-associative, which means you can write f $ g $ h $ x to mean f(g(h(x))) .

What is precedence and associativity explain with example?

We use associativity when two or more than two operators with the same precedence are present in the same expression. Example, The precedence of Division and Multiplication arithmetic operators is the same. So, let's say we have an expression with us which is 6 * 3 / 20.


1 Answers

I've written a paper on unparsing expressions using operator precedence. The appendix to the paper has an operator-precedence parser written in ML, which you could easily adapt to Haskell. The code is downloadable from the page above.

While Haskell has many fine libraries of parsing combinators, I have never seen one that was both (a) simple enough for me to understand easily and (b) supported operator-precedence parsing with arbitrary levels of precedence.

like image 89
Norman Ramsey Avatar answered Sep 22 '22 10:09

Norman Ramsey