Fsyacc 示例语法错误?
因此,我尝试用 F# 编写编译器,并一直在研究 F# powerpack 附带的 Fslex 和 Fsyacc 工具。有一个示例项目负责处理我一直试图理解的外部构建工具。可以下载此处。该示例可以为我编译并运行,但我认为语法中有一个微妙的错误。我说微妙,因为语法看起来类似于我在《龙》书中看到的解析表达式的语法,而我没有经验来发现它。
输入“4*5+3”正确计算为 23。
但是,输入 4*5-3 会生成解析错误。这是 Fsyacc 生成的代码中的错误。
我非常感谢您帮助我更好地理解问题所在,以便我可以更好地了解情况并对 Fsyacc 更有信心。我已在下面发布了 *.fsy 文件。
// This is the type of the data produced by a successful reduction of the 'start'
// symbol:
%type < Ast.Equation > start
%%
// These are the rules of the grammar along with the F# code of the
// actions executed as rules are reduced. In this case the actions
// produce data using F# data construction terms.
start: Prog { Equation($1) }
Prog:
| Expr EOF { $1 }
Expr:
| Expr PLUS Term { Plus($1, $3) }
| Expr MINUS Term { Minus($1, $3) }
| Term { Term($1) }
Term:
| Term ASTER Factor { Times($1, $3) }
| Term SLASH Factor { Divide($1, $3) }
| Factor { Factor($1) }
Factor:
| FLOAT { Float($1) }
| INT32 { Integer($1) }
| LPAREN Expr RPAREN { ParenEx($2) }
这是 AST 数据类型的定义
namespace Ast
open System
type Factor =
| Float of Double
| Integer of Int32
| ParenEx of Expr
and Term =
| Times of Term * Factor
| Divide of Term * Factor
| Factor of Factor
and Expr =
| Plus of Expr * Term
| Minus of Expr * Term
| Term of Term
and Equation =
| Equation of Expr
编辑
我已经发布了词法分析器定义和驱动解析器的代码,以帮助理解错误。
{
module Lexer
open System
open Parser
open Microsoft.FSharp.Text.Lexing
let lexeme lexbuf =
LexBuffer<char>.LexemeString lexbuf
}
// These are some regular expression definitions
let digit = ['0'-'9']
let whitespace = [' ' '\t' ]
let
newline = ('\n' | '\r' '\n')
rule tokenize = parse
| whitespace { tokenize lexbuf }
| newline { tokenize lexbuf }
// Operators
| "+" { PLUS }
| "-" { MINUS }
| "*" { ASTER }
| "/" { SLASH }
// Misc
| "(" { LPAREN }
| ")" { RPAREN }
// Numberic constants
| ['-']?digit+ { INT32 (Int32.Parse(lexeme lexbuf)) }
| ['-']?digit+('.'digit+)?(['e''E']digit+)? { FLOAT (Double.Parse(lexeme lexbuf)) }
// EOF
| eof { EOF }
最后是驱动解析器的代码。
// This project type requires the F# PowerPack at http://fsharppowerpack.codeplex.com/releases
// Learn more about F# at http://fsharp.net
// Original project template by Jomo Fisher based on work of Brian McNamara, Don Syme and Matt Valerio
// This posting is provided "AS IS" with no warranties, and confers no rights.
open System
open Microsoft.FSharp.Text.Lexing
open Ast
open Lexer
open Parser
/// Evaluate a factor
let rec evalFactor factor =
match factor with
| Float x -> x
| Integer x -> float x
| ParenEx x -> evalExpr x
/// Evaluate a term
and evalTerm term =
match term with
| Times (term1, term2) -> (evalTerm term1) * (evalTerm term2)
| Divide (term1, term2) -> (evalTerm term1) / (evalTerm term2)
| Factor fact -> evalFactor fact
/// Evaluate an expression
and evalExpr expr =
match expr with
| Plus (expr1, expr2) -> (evalExpr expr1) + (evalExpr expr2)
| Minus (expr1, expr2) -> (evalExpr expr1) - (evalExpr expr2)
| Term term -> evalTerm term
/// Evaluate an equation
and evalEquation eq =
match eq with
| Equation expr -> evalExpr expr
printfn "Calculator"
let rec readAndProcess() =
printf ":"
match Console.ReadLine() with
| "quit" -> ()
| expr ->
try
printfn "Lexing [%s]" expr
let lexbuff = LexBuffer<char>.FromString(expr)
printfn "Parsing..."
let equation = Parser.start Lexer.tokenize lexbuff
printfn "Evaluating Equation..."
let result = evalEquation equation
printfn "
Result: %s" (result.ToString())
with ex ->
printfn "Unhandled Exception: %s" ex.Message
readAndProcess()
readAndProcess()
编辑:词法分析器中可选的减号是问题所在。删除后,示例按预期工作。
So I am trying to write a compiler in F# and have been looking at the Fslex and Fsyacc tools that come with the F# powerpack. There is a sample project that takes care of the external build tools that I have been trying to understand. It can be downloaded here. The example compiles and runs for me, but I think there is a subtle error in the grammar. I say subtle, because the grammar looks similar to what I have seen in the Dragon book for parsing expressions and I don't have the experience to spot it.
The input "4*5+3" correctly evaluated to 23.
The input 4*5-3, however, generates a parse error. That is an error in the code generated by Fsyacc.
I would appreciate your help in better understanding what the problem so I can be better informed and have more confidence in Fsyacc. I have posted the *.fsy file below.
// This is the type of the data produced by a successful reduction of the 'start'
// symbol:
%type < Ast.Equation > start
%%
// These are the rules of the grammar along with the F# code of the
// actions executed as rules are reduced. In this case the actions
// produce data using F# data construction terms.
start: Prog { Equation($1) }
Prog:
| Expr EOF { $1 }
Expr:
| Expr PLUS Term { Plus($1, $3) }
| Expr MINUS Term { Minus($1, $3) }
| Term { Term($1) }
Term:
| Term ASTER Factor { Times($1, $3) }
| Term SLASH Factor { Divide($1, $3) }
| Factor { Factor($1) }
Factor:
| FLOAT { Float($1) }
| INT32 { Integer($1) }
| LPAREN Expr RPAREN { ParenEx($2) }
And here is the definition for AST data type
namespace Ast
open System
type Factor =
| Float of Double
| Integer of Int32
| ParenEx of Expr
and Term =
| Times of Term * Factor
| Divide of Term * Factor
| Factor of Factor
and Expr =
| Plus of Expr * Term
| Minus of Expr * Term
| Term of Term
and Equation =
| Equation of Expr
EDIT
I have posted the lexer definition and the code to drive the parser as well to help with understanding the error.
{
module Lexer
open System
open Parser
open Microsoft.FSharp.Text.Lexing
let lexeme lexbuf =
LexBuffer<char>.LexemeString lexbuf
}
// These are some regular expression definitions
let digit = ['0'-'9']
let whitespace = [' ' '\t' ]
let
newline = ('\n' | '\r' '\n')
rule tokenize = parse
| whitespace { tokenize lexbuf }
| newline { tokenize lexbuf }
// Operators
| "+" { PLUS }
| "-" { MINUS }
| "*" { ASTER }
| "/" { SLASH }
// Misc
| "(" { LPAREN }
| ")" { RPAREN }
// Numberic constants
| ['-']?digit+ { INT32 (Int32.Parse(lexeme lexbuf)) }
| ['-']?digit+('.'digit+)?(['e''E']digit+)? { FLOAT (Double.Parse(lexeme lexbuf)) }
// EOF
| eof { EOF }
Lastly, the code to drive the parser.
// This project type requires the F# PowerPack at http://fsharppowerpack.codeplex.com/releases
// Learn more about F# at http://fsharp.net
// Original project template by Jomo Fisher based on work of Brian McNamara, Don Syme and Matt Valerio
// This posting is provided "AS IS" with no warranties, and confers no rights.
open System
open Microsoft.FSharp.Text.Lexing
open Ast
open Lexer
open Parser
/// Evaluate a factor
let rec evalFactor factor =
match factor with
| Float x -> x
| Integer x -> float x
| ParenEx x -> evalExpr x
/// Evaluate a term
and evalTerm term =
match term with
| Times (term1, term2) -> (evalTerm term1) * (evalTerm term2)
| Divide (term1, term2) -> (evalTerm term1) / (evalTerm term2)
| Factor fact -> evalFactor fact
/// Evaluate an expression
and evalExpr expr =
match expr with
| Plus (expr1, expr2) -> (evalExpr expr1) + (evalExpr expr2)
| Minus (expr1, expr2) -> (evalExpr expr1) - (evalExpr expr2)
| Term term -> evalTerm term
/// Evaluate an equation
and evalEquation eq =
match eq with
| Equation expr -> evalExpr expr
printfn "Calculator"
let rec readAndProcess() =
printf ":"
match Console.ReadLine() with
| "quit" -> ()
| expr ->
try
printfn "Lexing [%s]" expr
let lexbuff = LexBuffer<char>.FromString(expr)
printfn "Parsing..."
let equation = Parser.start Lexer.tokenize lexbuff
printfn "Evaluating Equation..."
let result = evalEquation equation
printfn "
Result: %s" (result.ToString())
with ex ->
printfn "Unhandled Exception: %s" ex.Message
readAndProcess()
readAndProcess()
EDIT: The optional minus sign in the lexer was the problem. After removing it the sample works as expected.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我只看了一眼,看起来词法分析器可能将
这里的减号
视为一元,常量“-3”的一部分,而不是视为二进制减号。所以我同意这是样本中的错误。我将摆脱词法分析器中的可选减号,并在解析器中沿着 Factor 行添加一条规则,例如“MINUS INT32”。
只是如何修复它的一个草图,希望这能指导您,或者您将得到另一个带有完整代码的更深入的答案。
I have only glanced, it looks like the lexer perhaps is treating
the minus sign here
as unary, part of the constant "-3" rather than as a binary minus. So I agree it is an error in the sample. I would get rid of the optional minus in the lexer, and add a rule in the parser along the lines of Factor going to e.g. "MINUS INT32".
Just a sketch of how to fix it, hopefully this will steer you or you'll get another more in-depth answer with full code.