#!/usr/bin/env python3

import sys
import os
from optparse import OptionParser

# Parse a ulp description file returning a set of (ulps) for each operation.
# Lines starting with '#' are ignored.
# Each test is decribed as:
# test <function name>
# decimal<N> <ulp expected>
#
# If not described, ULP is assumed to be 0.
def parse_file (filename):
  try:
    ulp = None
    ulps = dict()
    dmap = {'decimal32' : 2, 'decimal64' : 1, 'decimal128' : 0}
    f = ""

    for line in open(filename, 'r').readlines():
      # Ignore comments and blank lines
      if line.rstrip().startswith ("#"):
        continue
      fields = line.split()
      if len(fields) is 0:
        continue

      if fields[0] == 'test':
        f = fields[1]
        if f not in ulps:
            ulps[f] = [0,0,0]
      elif fields[0] in dmap.keys():
        slot = dmap[fields[0]]
        val = int(fields[1])
        if val > ulps[f][slot]:
            ulps[f][slot] = val

    return ulps

  except (IOError, OSError) as e:
    print ("error: open (%s) failed: %s\n" % (filename, e.strerror))
    exit (1)


def print_header (filename):
  print ("/* This file is automatically generated")
  print (" * from %s with gen-libdfp-ulps.py.  */" % filename)
  print ("")
  print ("#if defined(DECIMAL32)")
  print ("# define CHOOSE(decimal128, decimal64, decimal32) decimal32")
  print ("#elif defined(DECIMAL64)")
  print ("# define CHOOSE(decimal128, decimal64, decimal32) decimal64")
  print ("#elif defined(DECIMAL128)")
  print ("# define CHOOSE(decimal128, decimal64, decimal32) decimal128")
  print ("#endif")
  print ("")
  print ("struct ulp_data {")
  print ("  const char *name;")
  print ("  FLOAT max_ulp;")
  print ("};")
  print ("")


def print_ulps (ulps):
  print ("/* Maximal error of functions.  */")
  print ("static const struct ulp_data test_ulps[] = {")
  # The array will be used in a bsearch call, so the itens must be sorted
  for ulp in sorted (ulps.keys ()):
    print ("  { \"%s\", CHOOSE(%d, %d, %d) }," %
      tuple ([ulp] + ulps[ulp]))
  print ("};")
    

def print_output (filename):
  ulps = parse_file (filename)
  print_header (filename)
  print_ulps (ulps)


if __name__ == "__main__":
  parser = OptionParser ()
  parser.add_option ("-o", "--output", dest="filename",
                     help="white output to FILE")
  (options, args) = parser.parse_args()

  try:
    if options.filename:
      sys.stdout = open (options.filename, "w")

    if len(args) == 0:
      sys.stderr.write ("usage: gen-libdfp-ulps.py <options> <input file>\n")
      raise Exception()

    print_output (args[0])

  except:
    if options.filename:
      os.remove (options.filename)
    exit (1)
