使用一元减号扩展Fsyacc的示例语法

时间:2011-04-23 22:35:18

标签: f# fsyacc

我尝试扩展作为“F#Parsed Language Starter”一部分的示例语法,以支持一元减号(对于像2 * -5这样的表达式)。

我遇到像Samsdram here

这样的街区

基本上,我扩展了.fsy文件的头部,以包含优先级,如:

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

然后语法规则如下:

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

另外,AST的定义:

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

但在尝试解析上面提到的表达式时仍然会出现解析器错误。

任何想法缺少什么?我阅读了F#编译器的源代码,目前还不清楚他们如何解决这个问题,看起来非常相似

编辑

优先顺序是这样排序的:

%left ASSIGN
%left AND OR
%left EQ NOTEQ LT LTE GTE GT
%left PLUS MINUS
%left ASTER SLASH
%nonassoc UMINUS

2 个答案:

答案 0 :(得分:0)

玩得开心并设法让优先工作,而不需要%prec。虽然修改了一些启动器(更有意义的名字)

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 }

我还将表达式分组为单个变体,因为我不喜欢初学者完成它的方式。 (很难走过它)。

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

答案 1 :(得分:0)

从我的文章Parsing text with Lex and Yacc(2007年10月)中获取代码。

我的优先顺序如下:

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

和yacc解析代码是:

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 }
;

看起来相同。我不认为问题是您在大写字母中使用UMINUS而不是prec_uminus吗?

另一种选择是将expr分成几个相互递归的部分,每个部分对应一个优先级。