在F#lex / yacc解析器中区分'减'运算符和负数

时间:2014-11-03 22:10:43

标签: parsing f# fsyacc fslex

我正在尝试使用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) }

我最初的想法是不将-作为词法分析器中数字的一部分来处理,并让解析器确定MINUS令牌是否应该导致减号运算符或负号。不幸的是,这也会导致输入&#34; - 2&#34;被评估为负数,因为空白将被消耗。

但我认为这必须是一个常见问题,必须有一个共同的解决方案。那我该如何最好地处理这个?

1 个答案:

答案 0 :(得分:1)

通常的解决方案是-2实际上是一个表达式。你可以&#34;不断折叠&#34; - 直接评估其参数是常量的表达式 - 如果您认为评估-2效率太低(或者您可以将其作为生产MINUS expression中的特殊情况处理)。