Re: Problems with GET.E
- Posted by Jiri Babor <J.Babor at GNS.CRI.NZ> Nov 17, 1999
- 588 views
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