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

发布于 2024-11-03 05:04:27 字数 738 浏览 4 评论 0原文

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

我遇到了像 Samsdram 这样的块 这里

基本上,我扩展了 . 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

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

沧笙踏歌 2024-11-10 05:04:28

从我的文章 使用 Lex 和 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 拆分为几个相互递归的部分,每个部分对应一个优先级。

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.

小伙你站住 2024-11-10 05:04:27

经过一番尝试,并设法在不需要 %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

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文