Compiler construction Fsyacc的示例语法出错?
因此,我试图用F#编写一个编译器,并一直在研究F#powerpack附带的Fslex和Fsyacc工具。有一个示例项目负责我一直试图理解的外部构建工具。可以下载。该示例为我编译并运行,但我认为语法中有一个微妙的错误。我说微妙,因为语法看起来与我在龙书中看到的解析表达式的语法相似,而我没有发现它的经验 输入“4*5+3”正确计算为23 但是,输入4*5-3会生成一个解析错误。这是Fsyacc生成的代码中的一个错误 如果您能帮助我更好地了解问题所在,我将不胜感激,以便我能更好地了解情况,并对Fsyacc更有信心。我已经在下面发布了*.fsy文件Compiler construction Fsyacc的示例语法出错?,compiler-construction,f#,fsyacc,Compiler Construction,F#,Fsyacc,因此,我试图用F#编写一个编译器,并一直在研究F#powerpack附带的Fslex和Fsyacc工具。有一个示例项目负责我一直试图理解的外部构建工具。可以下载。该示例为我编译并运行,但我认为语法中有一个微妙的错误。我说微妙,因为语法看起来与我在龙书中看到的解析表达式的语法相似,而我没有发现它的经验 输入“4*5+3”正确计算为23 但是,输入4*5-3会生成一个解析错误。这是Fsyacc生成的代码中的一个错误 如果您能帮助我更好地了解问题所在,我将不胜感激,以便我能更好地了解情况,并对Fsya
// 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) }
编辑
我已经发布了lexer定义和驱动解析器的代码,以帮助理解错误
{
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 }
{
模块Lexer
开放系统
开放解析器
打开Microsoft.FSharp.Text.Lexing
let lexeme lexbuf=
LexBuffer.lexemstring lexbuf
}
//下面是一些正则表达式定义
让数字=['0'-'9']
让空白=[''\t']
让
换行符=('\n'|'\r'\n')
规则标记化=解析
|空白{tokenize lexbuf}
|换行符{tokenize lexbuf}
//操作员
|“+”{PLUS}
|“-”{负}
|“*”{ASTER}
|“/”{SLASH}
//杂项
|“({LPAREN}
|“{RPAREN}”
//数常数
|['-']?数字+{INT32(INT32.Parse(lexeme-lexbuf))}
|['-']?数字+('.'digit+)(['e''e']数字+?{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()
//此项目类型需要位于http://fsharppowerpack.codeplex.com/releases
//了解更多关于F#at的信息http://fsharp.net
//Jomo Fisher基于Brian McNamara、Don Syme和Matt Valerio工作的原始项目模板
//此帖子按“原样”提供,不作任何保证,也不授予任何权利。
开放系统
打开Microsoft.FSharp.Text.Lexing
开放式Ast
开放式Lexer
开放解析器
///评估一个因素
let rec evalFactor因子=
匹配因子
|浮动x->x
|整数x->float x
|ParenEx x->evalExpr x
///评估一个术语
和求值项=
匹配术语
|次数(第1、2期)->(评估第1期)*(评估第2期)
|除法(第1条、第2条)->(evalTerm第1条)/(evalTerm第2条)
|因子事实->评估因子事实
///计算表达式的值
和evalExpr expr=
匹配表达式
|Plus(expr1,expr2)->(evalExpr expr1)+(evalExpr expr2)
|减(expr1,expr2)->(evalExpr expr1)-(evalExpr expr2)
|术语->评估术语
///计算方程式
和求值方程=
匹配情商
|方程expr->evalExpr expr
printfn“计算器”
let rec readAndProcess()=
printf:“”
将Console.ReadLine()与
|“退出”->()
|expr->
尝试
printfn“Lexing[%s]”表达式
让lexbuff=LexBuffer.FromString(expr)
printfn“解析…”
让等式=Parser.start Lexer.tokenize lexbuff
printfn“评估方程…”
让结果=求值方程
printfn“
结果:%s“(Result.ToString())
使用ex->
printfn“未处理的异常:%s”例如消息
readAndProcess()
readAndProcess()
编辑:lexer中的可选减号是问题所在。移除它后,示例将按预期工作。我只看了一眼,它看起来可能正在处理lexer
// Numberic constants
| ['-']?digit+ { INT32 (Int32.Parse(lexeme lexbuf)) }
etc
这里是负号
4*5-3
作为一元数,常量“-3”的一部分,而不是作为二进制减号。所以我同意这是样本中的错误。我将在lexer中去掉可选的减号,并在解析器中添加一条规则,沿着因子行,例如“减号INT32”
只是一个如何修复它的草图,希望这能引导你,否则你会得到另一个更深入的答案,并提供完整的代码。你能发布lexer定义吗?它可能对二进制减号有效,但对一元数有效吗?@Roman当我编译并运行它时,在修复lexer的可选减号部分后,一元负号和二元负号都按预期工作。
4*5-3