title: Differentiate between 'minus' operator and negative numbers in F# lex/yacc parser
body: <p>I am trying to parse a simple script language using FsLex and FsYacc, and I have a problem with distinguishing the minus operator from negative numbers. </p>
  
  <p>If I evaluate the term "1 - 2", the parser will return the desired AST: <code>Minus(NumberLiteral(1.0),NumberLiteral(2.0))</code>. But if I evaluate the term "1-2", the lexer will produce the number 1, followed by the number -2, which is not a valid input.</p>
  
  <p>I have made a minimal program to reproduce my problem. Ast defined like this:</p>
  
  <pre><code>module Ast
  
  type Expression =
    | NumberLiteral of double
    | Minus of Expression * Expression
  </code></pre>
  
  <p>The lexer code looks like this:</p>
  
  <pre><code>{
  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 |&gt; LexBuffer&lt;_&gt;.LexemeString |&gt; System.Double.Parse |&gt; NUMBER }
      | eof           { EOF }
  </code></pre>
  
  <p>The parser looks like this:</p>
  
  <pre><code>%{
  open Ast
  %}
  %start start
  %token EOF MINUS
  %token &lt;double&gt; NUMBER
  %type &lt; Expression &gt; start
  %%
  
  start: 
      | expression EOF    { $1 }
  
  expression:
      | NUMBER            { NumberLiteral $1 }
      | expression
        MINUS expression  { Minus($1, $3) }
  </code></pre>
  
  <p>My initial thought was to not handle the <code>-</code> as part of the number in the lexer, and let the parser determine if the <code>MINUS</code> token should result in a minus operator or a negative number. Unfortunately that would also result in the input "- 2" to be evaluated as a negative number, because the whitespace would be consumed.</p>
  
  <p>But I assume that this must be a common problem, and a common solution must exist. So how do I best handle this?</p>