FsLex と FsYacc を使用して単純なスクリプト言語を解析しようとしていますが、マイナス演算子と負の数値を区別するのに問題があります。
「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) }
私が最初に考えた-
のは、レキサーで as を数値の一部として処理せず、パーサーにMINUS
トークンの結果がマイナス演算子になるかマイナス数値になるかを判断させることでした。残念ながら、空白が消費されるため、入力 "- 2" が負の数として評価されることにもなります。
しかし、これは共通の問題であり、共通の解決策が存在するに違いないと思います。では、これをどのように処理するのが最善でしょうか?