2011-01-14 6 views
1

私はF#でコンパイラを作成しようとしており、F#powerpackに付属のFslexとFsyaccツールを見ています。私が理解しようとしている外部ビルドツールを処理するサンプルプロジェクトがあります。それはhereをダウンロードすることができます。この例は私のためにコンパイルされて実行されますが、文法には微妙な誤りがあると思います。文法は、式を解析するためのドラゴンブックで見たものと似ていて、私はそれを見つけ出す経験がないので、微妙に言います。正しく入力4 * 5-3 23.Fsyaccの文法のエラー?

に評価

入力 "* 5 4 + 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 

あるEDIT

私は、字句解析の定義およびエラーの理解を助けるためにだけでなく、パーサーを駆動するためのコードを掲載しています。

{ 
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() 

編集:レクサーのオプションのマイナス記号が問題でした。それを取り除いた後、サンプルは期待通りに機能します。

+0

レクサー定義も投稿できますか? – Juliet

+0

バイナリマイナスでも動作するかもしれませんが、単項式では機能しますか? –

+0

@Románコンパイルして実行したとき、レクサーのオプションのマイナス部分を修正した後、単項マイナスとバイナリマイナスの両方が期待どおりに機能しました。 – Samsdram

答えて

3

私は目をやっている、それはレクサーは、おそらく「-3」の定数の単項、一部としてここに

4*5-3 

マイナス記号

// Numberic constants 
| ['-']?digit+         { INT32 (Int32.Parse(lexeme lexbuf)) } 
etc 

の治療としてではなくているように見えます2進マイナスだから私はそれがサンプルのエラーであることに同意します。私はレクサーのオプションのマイナスを取り除き、Factorの行に沿ってパーザにルールを追加します。 "MINUS INT32"。

これを修正する方法の概略を説明します。うまくいけば、これがあなたを導くか、完全なコードでさらに深い答えを得るでしょう。