2011-01-14 2 views
1

Also versuche ich einen Compiler in F # zu schreiben und habe mir die Fslex- und Fsyacc-Tools angesehen, die mit dem F # Powerpack geliefert werden. Es gibt ein Beispielprojekt, das sich um die externen Build-Tools kümmert, die ich zu verstehen versucht habe. Es kann heruntergeladen werden here. Das Beispiel kompiliert und läuft für mich, aber ich denke, es gibt einen subtilen Fehler in der Grammatik. Ich sage subtil, weil die Grammatik dem ähnelt, was ich im Dragon-Buch zum Parsen von Ausdrücken gesehen habe, und ich habe nicht die Erfahrung, es zu erkennen.Fehler in Beispielgrammatik für Fsyacc?

Der Eingang "4 * 5 + 3" richtig bis 23 bewertet

der Eingang 4 * 5-3 erzeugt jedoch einen Analysefehler. Das ist ein Fehler in dem von Fsyacc generierten Code.

Ich würde Ihre Hilfe schätzen, um besser zu verstehen, was das Problem ist, damit ich besser informiert werden kann und mehr Vertrauen in Fsyacc habe. Ich habe die * .fsy Datei unten gepostet.

// 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) } 

Und hier ist die Definition für AST-Datentyp

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

ich die Lexer Definition und den Code geschrieben haben, als auch den Parser fahren mit dem Verständnis, den Fehler zu helfen.

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

Schließlich der Code, um den Parser zu fahren.

EDIT: Das optionale Minuszeichen im Lexer war das Problem. Nach dem Entfernen funktioniert das Beispiel wie erwartet.

+0

Können Sie die Lexer-Definition auch posten? – Juliet

+0

Es könnte funktionieren für binäre minus, aber funktioniert es für die unären? –

+0

@ Román Als ich es kompilierte und ausführte, funktionierte nach dem Fixieren des optionalen Minus-Teils des Lexers sowohl das unäre als auch das binäre Minus wie erwartet. – Samsdram

Antwort

3

Ich habe nur einen Blick zu, es sieht aus wie die Lexer vielleicht

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

das Minuszeichen hier

4*5-3 

als einstelliger, einen Teil des konstanten behandelt „-3“ und nicht als einen Binär minus. Ich stimme zu, dass es sich um einen Fehler in der Stichprobe handelt. Ich würde das fakultative Minus im Lexer loswerden und eine Regel in den Parser gemäß den Faktoren von Faktor hinzufügen, die z. "MINUS INT32".

Nur eine Skizze, wie es zu beheben, hoffentlich wird dies Sie steuern, oder Sie werden eine weitere tiefergehende Antwort mit vollem Code erhalten.