2014-11-03 134 views
1

我想使用FsLex和FsYacc來分析一個簡單的腳本語言,並且我在區分minus運算符和負數時遇到了問題。在F#lex/yacc分析器中區分'負'運算符和負數

如果我評估術語「1 - 2」,解析器將返回所需的AST:Minus(NumberLiteral(1.0),NumberLiteral(2.0))。但是,如果我評估術語「1-2」,詞法分析器將產生數字1,然後是數字-2,這不是有效的輸入。

我已經做了一個最小的程序來重現我的問題。 AST這樣定義:

module Ast 

type Expression = 
    | NumberLiteral of double 
    | Minus of Expression * Expression 

詞法分析器代碼如下所示:

{ 
module Lexer 
open Microsoft.FSharp.Text.Lexing 
open Parser 
} 

let whitespace = ' ' 
let digit = ['0' - '9'] 
let number = '-'?digit+ 

rule token = parse 
    | whitespace* { token lexbuf } 
    | '-'   { MINUS } 
    | number  { lexbuf |> LexBuffer<_>.LexemeString |> System.Double.Parse |> NUMBER } 
    | eof   { EOF } 

解析器是這樣的:

%{ 
open Ast 
%} 
%start start 
%token EOF MINUS 
%token <double> NUMBER 
%type <Expression> start 
%% 

start: 
    | expression EOF { $1 } 

expression: 
    | NUMBER   { NumberLiteral $1 } 
    | expression 
     MINUS expression { Minus($1, $3) } 

我最初的想法是不處理-的一部分在詞法分析器中的數字,並讓解析器確定MINUS標記是否應產生負運算符或負數。不幸的是,這也會導致輸入「-2」被評估爲負數,因爲空白將被消耗。

但我認爲這一定是一個普遍問題,必須有一個通用的解決方案。那麼我該如何最好地處理這個問題?

回答

1

通常的解決方案是-2實際上是一個表達式。如果您覺得評估-2(或者您可以在生產MINUS expression中將其作爲特例處理)效率太低,則可以「不斷摺疊」 - 直接評估其參數爲常量的表達式。