1

I tried to extend the example grammar that comes as part of the "F# Parsed Language Starter" to support unary minus (for expressions like 2 * -5).

I hit a block like Samsdram here

Basically, I extended the header of the .fsy file to include precedence like so:

......
%nonassoc UMINUS
....

and then the rules of the grammar like so:

...
Expr: 
| MINUS Expr %prec UMINUS   { Negative ($2) }
...

also, the definition of the AST:

...
and Expr =
    | Negative of Expr
.....

but still get a parser error when trying to parse the expression mentioned above.

Any ideas what's missing? I read the source code of the F# compiler and it is not clear how they solve this, seems quite similar

EDIT

The precedences are ordered this way:

%left ASSIGN
%left AND OR
%left EQ NOTEQ LT LTE GTE GT
%left PLUS MINUS
%left ASTER SLASH
%nonassoc UMINUS
Community
  • 1
  • 1
Román
  • 1,943
  • 2
  • 18
  • 28

2 Answers2

0

Had a play around and managed to get the precedence working without the need for %prec. Modified the starter a little though (more meaningful names)

Prog:
    | Expression EOF { $1 }

Expression:
    | Additive { $1 }

Additive:
    | Multiplicative { $1 }
    | Additive PLUS  Multiplicative { Plus($1, $3)  }
    | Additive MINUS Multiplicative { Minus($1, $3) }

Multiplicative:
    | Unary { $1 }
    | Multiplicative ASTER Unary { Times($1, $3)  }
    | Multiplicative SLASH Unary { Divide($1, $3) }

Unary:
    | Value { $1 }
    | MINUS Value { Negative($2) }

Value:
    | FLOAT { Value(Float($1)) }
    | INT32 { Value(Integer($1)) }
    | LPAREN Expression RPAREN { $2 }

I also grouped the expressions into a single variant, as I didn't like the way the starter done it. (was awkward to walk through it).

type Value =
    | Float   of Double
    | Integer of Int32
    | Expression of Expression

and Expression =
    | Value of Value
    | Negative of Expression
    | Times  of Expression * Expression
    | Divide of Expression * Expression
    | Plus  of Expression * Expression
    | Minus of Expression * Expression

and Equation =
    | Equation of Expression
Mark H
  • 13,797
  • 4
  • 31
  • 45
  • Yeah, I didn't want to change the grammar though. Thing is my grammar is way bigger than that...Will try Harrop's suggestion first, otherwise will change the grammar. Many thanks! – Román Apr 24 '11 at 13:56
0

Taking code from my article Parsing text with Lex and Yacc (October 2007).

My precedences look like:

%left PLUS MINUS
%left TIMES DIVIDE
%nonassoc prec_uminus
%right POWER
%nonassoc FACTORIAL

and the yacc parsing code is:

expr:
| NUM                          { Num(float_of_string $1) }
| MINUS expr %prec prec_uminus { Neg $2 }
| expr FACTORIAL               { Factorial $1 }
| expr PLUS expr               { Add($1, $3) }
| expr MINUS expr              { Sub($1, $3) }
| expr TIMES expr              { Mul($1, $3) }
| expr DIVIDE expr             { Div($1, $3) }
| expr POWER expr              { Pow($1, $3) }
| OPEN expr CLOSE              { $2 }
;

Looks equivalent. I don't suppose the problem is your use of UMINUS in capitals instead of prec_uminus in my case?

Another option is to split expr into several mutually-recursive parts, one for each precedence level.

J D
  • 48,105
  • 13
  • 171
  • 274
  • Will try your change, but to be honest don't see how that will help..are you assuming fsyacc is completely equivalent yo yacc? If that doesn't work will have to change the grammar (really didn't want to) as suggested by Mark H. Thanks! – Román Apr 24 '11 at 13:58
  • No, I'm actually talking about fsyacc here. That code worked in fsyacc when I wrote it. I'm not sure why yours doesn't because it looks the same. Let me know if you find out what the problem was! – J D Apr 25 '11 at 17:40