Re: Problems with GET.E

new topic     » goto parent     » topic index » view thread      » older message » newer message

Gals & Guys,

Since I felt at least partially responsible for the get.e fiasco, I
thought I should try to fix it. Attached is my first go at it, a
little kludgy, but it seems to work. I have done only a couple of
quick tests, so be careful. I altered only the routines for get() and
value() functions, I left the rest of the clutter untouched.

Test results, comments & other brutalities will be very much
appreciated.

If it rains tonight (no tennis!), I'll try to improve it. Then you will
find a copy on my Euphoria page. jiri


-- snip --------------------------------------------------------------

--  file    : get.e
--  author  : jiri babor
--  email   : jbabor at paradise.net.nz
--  project : get.e replacement
--  tool    : euphoria 2.1
--  date    : 99-11-17

------------------------------------
-- Input and Conversion Routines: --
-- get()                          --
-- value()                        --
-- wait_key()                     --
------------------------------------

-- error status values returned from get() and value():
global constant
    GET_SUCCESS = 0,
     GET_EOF = -1,
     GET_FAIL = 1

constant M_WAIT_KEY = 26

constant
    TRUE = 1,
    FALSE=0,
    DIGITS = "0123456789",
     HEX_DIGITS = DIGITS & "ABCDEF",
     START_NUMERIC = DIGITS & "-+.#"


type natural(integer x)
    return x >= 0
end type

type char(integer x)
    return x >= -1 and x <= 255
end type

object input_string -- string to be read from
integer error_flag  -- error flag
natural input_file  -- file to be read from
natural string_next
char ch             -- the current character


global function wait_key()
    -- Get the next key pressed by the user.
    -- Wait until a key is pressed.

    return machine_func(M_WAIT_KEY, 0)
end function

procedure get_ch()
    -- set ch to the next character in the input stream (either string or file)

    if sequence(input_string) then
     if string_next <= length(input_string) then
         ch = input_string[string_next]
         string_next += 1
     else
         ch = GET_EOF
     end if
    else
         ch = getc(input_file)
    end if
end procedure

procedure skip_blanks()
    -- skip white space
    -- ch is "live" at entry and exit

    while find(ch, " \t\n") do
     get_ch()
    end while
end procedure

constant
    ESCAPE_CHARS = "nt'\"\\r",
     ESCAPED_CHARS = "\n\t'\"\\\r"

function escape_char(char c)
    -- return escape character

    natural i

    i = find(c, ESCAPE_CHARS)
    if i = 0 then
         return GET_FAIL
    else
         return ESCAPED_CHARS[i]
    end if
end function

function get_qchar()
    -- get a single-quoted character
    -- ch is "live" at exit

    char c

    get_ch()
    c = ch
    if ch = '\\' then
         get_ch()
         c = escape_char(ch)
         if c = GET_FAIL then
            error_flag=GET_FAIL
              return 0
         end if
    elsif ch = '\'' then
        error_flag=GET_FAIL
        return 0
    end if
    get_ch()
    if ch != '\'' then
        error_flag=GET_FAIL
        return 0
    else
         get_ch()
         return c
    end if
end function -- get_qchar

function get_string()
    -- get a double-quoted character string
    -- ch is "live" at exit

    sequence text

    text = ""
    while TRUE do
     get_ch()
     if ch = GET_EOF or ch = '\n' then
            error_flag=GET_FAIL
            return 0
     elsif ch = '"' then
         get_ch()
         return text
     elsif ch = '\\' then
         get_ch()
         ch = escape_char(ch)
         if ch = GET_FAIL then
                error_flag=GET_FAIL
                return 0
         end if
     end if
     text &= ch
    end while
end function

type plus_or_minus(integer x)
    return x = -1 or x = +1
end type

function get_number()
    -- read a number
    -- ch is "live" at entry and exit

    plus_or_minus sign, e_sign
    natural ndigits
    integer hex_digit
    atom mantissa, dec, e_mag

    sign = +1
    mantissa = 0
    ndigits = 0

    -- process sign
    if ch = '-' then
     sign = -1
     get_ch()
        elsif ch = '+' then
     get_ch()
    end if

    -- get mantissa
    if ch = '#' then         -- process hex integer and return
     get_ch()
     while TRUE do
         hex_digit = find(ch, HEX_DIGITS)-1
         if hex_digit >= 0 then
              ndigits += 1
              mantissa = mantissa * 16 + hex_digit
              get_ch()
         else
               if ndigits > 0 then
                   return sign * mantissa
               else
                    error_flag=GET_FAIL
                    return 0
               end if
         end if
     end while
    end if

    -- decimal integer or floating point
    while ch >= '0' and ch <= '9' do
     ndigits += 1
     mantissa = mantissa * 10 + (ch - '0')
     get_ch()
    end while

    if ch = '.' then         -- get fraction
     get_ch()
     dec = 10
     while ch >= '0' and ch <= '9' do
         ndigits += 1
         mantissa += (ch - '0') / dec
         dec *= 10
         get_ch()
     end while
    end if

    if ndigits = 0 then
        error_flag=GET_FAIL
        return 0
    end if

    mantissa = sign * mantissa

    if ch = 'e' or ch = 'E' then         -- get exponent sign
     e_sign = +1
     e_mag = 0
     get_ch()
     if ch = '-' then
         e_sign = -1
         get_ch()
     elsif ch = '+' then
         get_ch()
     end if
     -- get exponent magnitude
     if ch >= '0' and ch <= '9' then
         e_mag = ch - '0'
         get_ch()
         while ch >= '0' and ch <= '9' do
          e_mag = e_mag * 10 + ch - '0'
          get_ch()
         end while
     else                    -- no exponent
            error_flag=GET_FAIL
            return 0
     end if
     e_mag *= e_sign
     if e_mag > 308 then
         -- rare case: avoid power() overflow
         mantissa *= power(10, 308)
         if e_mag > 1000 then
          e_mag = 1000
         end if
         for i = 1 to e_mag - 308 do
          mantissa *= 10
         end for
     else
         mantissa *= power(10, e_mag)
     end if
    end if

    return mantissa
end function

function get_sequence()
    sequence s
    integer comma, first    -- flags

    get_ch()
    skip_blanks()
    s={}
    comma=FALSE
    first=TRUE
    while ch!='}' do
        if comma or first then
            if find(ch, START_NUMERIC) then
              s=append(s, get_number())
            elsif ch = '{' then
                s=append(s, get_sequence())
                get_ch()
                skip_blanks()
            elsif ch = '\"' then
              s=append(s, get_string())
            elsif ch = '\'' then
              s=append(s, get_qchar())
            elsif ch = -1 then
                error_flag=GET_EOF
                return 0
            else
                error_flag=GET_FAIL
                return 0
            end if
            comma=FALSE
            first=FALSE
        elsif ch=',' then
            comma=TRUE
            get_ch()
            skip_blanks()
        else
            error_flag=GET_FAIL
            return 0
        end if
    end while
    if comma then
        error_flag=GET_FAIL
        return 0
    end if
    return s
end function -- get_sequence

function Get()
    -- read a Euphoria data object as a string of characters
    -- set error_flag and return value

    skip_blanks()

    if find(ch, START_NUMERIC) then
         return get_number()
    elsif ch = '{' then
        return get_sequence()
    elsif ch = '\"' then
         return get_string()
    elsif ch = '\'' then
         return get_qchar()
    elsif ch = -1 then
        error_flag=GET_EOF
        return 0
    else
        error_flag=GET_FAIL
        return 0
    end if
end function -- Get()

global function get(integer file)
    -- Read the string representation of a Euphoria object
    -- from a file. Convert to the value of the object.
    -- Return {error_status, value}.

    input_file = file
    input_string = 0
    error_flag=GET_SUCCESS
    get_ch()
    return {error_flag, Get()}
end function

global function value(sequence string)
    -- Read the representation of a Euphoria object
    -- from a sequence of characters. Convert to the value of the object.
    -- Return {error_status, value).

    input_string = string
    string_next = 1
    error_flag=GET_SUCCESS
    get_ch()
    return {error_flag, Get()}
end function

global function prompt_number(sequence prompt, sequence range)
-- Prompt the user to enter a number.
-- A range of allowed values may be specified.
    object answer

    while 1 do
      puts(1, prompt)
      answer = gets(0) -- make sure whole line is read
      puts(1, '\n')

      answer = value(answer)
      if answer[1] != GET_SUCCESS or sequence(answer[2]) then
           puts(1, "A number is expected - try again\n")
      else
          if length(range) = 2 then
            if range[1] <= answer[2] and answer[2] <= range[2] then
                return answer[2]
            else
                printf(1,
                "A number from %g to %g is expected here - try again\n",
                 range)
            end if
           else
            return answer[2]
           end if
      end if
    end while
end function

global function prompt_string(sequence prompt)
    -- Prompt the user to enter a string

    object answer

    puts(1, prompt)
    answer = gets(0)
    puts(1, '\n')
    if sequence(answer) and length(answer) > 0 then
         return answer[1..length(answer)-1] -- trim the \n
    else
         return ""
    end if
end function

global function get_bytes(integer fn, integer n)
    -- Return a sequence of n bytes (maximum) from an open file.
    -- If n > 0 and fewer than n bytes are returned,
    -- you've reached the end of file.

    sequence s
    integer c

    if n = 0 then
     return {}
    end if
    c = getc(fn)
    if c = -1 then
     return {}
    end if
    s = repeat(c, n)
    for i = 2 to n do
     s[i] = getc(fn)
    end for
    while s[n] = -1 do
     n -= 1
    end while
    return s[1..n]
end function

new topic     » goto parent     » topic index » view thread      » older message » newer message

Search



Quick Links

User menu

Not signed in.

Misc Menu