2

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" が負の数として評価されることにもなります。

しかし、これは共通の問題であり、共通の解決策が存在するに違いないと思います。では、これをどのように処理するのが最善でしょうか?

4

1 に答える 1

3

通常の解決策は、-2実際には式です。評価するのが非効率的であると思われる場合は、「定数の折り畳み」、つまり引数が定数である式を直接評価することが-2できます (または、プロダクションで特殊なケースとして処理することができますMINUS expression)。

于 2014-11-03T22:35:32.587 に答える