Re: eval() function
- Posted by "Juergen Luethje" <j.lue at gmx.de> Nov 02, 2005
- 585 views
Me wrote: > Alex Chamberlain wrote: > >> After my unsuccessful attempt at using OOEU's eval() function, >> I thought would write my own that will work with the normal rds >> download. >> But it won't work! >> >> }}} <eucode> >> constant EVAL_FILE_NAME = "tmp_evalfile.ex" >> constant EVAL_ERROR = -1 >> >> global function eval(sequence data) >> integer tmp_fn, ret >> sequence plat >> >> tmp_fn = open(EVAL_FILE_NAME, "w") >> if tmp_fn = -1 then >> puts(1, "Could not opne temporary eval file ... Sorry!") >> return EVAL_ERROR >> end if >> >> puts(tmp_fn, data) >> >> if platform() = DOS32 then >> plat = "ex" >> elsif platform() = WIN32 then >> plat = "exw" >> elsif (platform() = LINUX) or (platform() = FREEBSD) then >> plat = "exu" >> end if >> puts(1, plat & " " & EVAL_FILE_NAME & " > eval.out") >> ret = system_exec(plat & " " & EVAL_FILE_NAME, 0) >> system("DELE " & EVAL_FILE_NAME, 0) >> return ret >> end function >> </eucode> {{{ >> >> Can somebody help me? > > > When I try to run that program, I get the following error message: > DOS32 has not been declared > if platform() = DOS32 then > ^ > So at least you should write at the beginning of the program: > include misc.e > > Also when you have opened a file, don't forget to close it! > > And you have mixed up some things. > Besides the missing 'include' statement, the program can not work, > because you are redirecting the wrong command, you never read the output > of the temporary program, and the function returns the wrong value. > Additionally it looks to me that system_exec() can not be used for > output redirection. But redirecting the output is not necessary at all > here. > > Make a clear concept, you need 4 steps: > a) write a temporary program for evaluating the expression and writing > the result to another temporary file > b) run the temporary program (and delete the program file) > c) read the content of the temporary result file, and convert it to > a number (and delete the file) > d) return this number (do *not* return the return value of > system_exec()!) > > Now you have important hints. I'll not give you the complete program at > the moment. Trying yourself is more fun! Here comes the second part of my reply, firstly some more remarks: It is often useful to write a function like this in a way, so that it is as versatile as possible, and useful for different types of programs. Now imagine a program with a nice looking GUI, and then a black console window pops up with the message: "Could not open temporary eval file ... Sorry!" Since this would look ugly, a versatile library function should not output such messages itself, but return a specific error code, and let the main program display the appropriate message (see code below). Your function returns -1 to indicate an error. But -1 can also be a valid result of the function, e.g. eval("-2*0.5") => -1. When eval() returns -1, how can the main program know whether this special -1 is a valid result or an error flag? Answer: It cannot! We must return error flags in a different way. From the top of my head three possibilities come to my mind: 1) Always return a sequence of 2 elements, where the first element is a special flag, and the second element is the desired value, in case there is no error. This way is used e.g. by the Euphoria functions get() (see below) and value(). 2) Always return an atom, and use a separate local or global error variable, which is set by eval() e.g. atom result integer error result = eval("1+1") if error then puts(1, "Can't calculate that.\n") else printf(1, "Result: %g\n", {result}) end if This is not working code, but I hope you'll get the idea. 3) Always return an atom for a valid result, and a sequence in case of an error (or vice versa, like gets() does). This method is used in the code below. In your code you used "DELE", I don't know that. On DOS and Windows it must be "DEL". If "DELE" is not a typo, but a valid Linux/FreeBSD command, you must change the code of the function, so that it uses the proper command according to the current platform. Like you did, I use 2 files. But my files both have the same extension, so I only need 1 command to delete them. This command is deliberately commented out currently. After running the code, you should look at the contents of the file "eval_prg.tmp". Then you probably will see what's going on.
include misc.e include get.e constant EVAL_PROG_NAME = "eval_prg.tmp", EVAL_RES_NAME = "eval_res.tmp", EVAL_WRITE_ERR = {1}, EVAL_READ_ERR = {2} global function eval (sequence expression) sequence plat, ret integer fn, sys -- write a temporary program for evaluating the expression and -- writing the result to another temporary file fn = open(EVAL_PROG_NAME, "w") if fn = -1 then return EVAL_WRITE_ERR end if printf(fn, "integer fn\n" & "fn = open(\"%s\", \"w\")\n" & "print(fn, %s)\n" & "close(fn)\n", {EVAL_RES_NAME, expression}) close(fn) -- run the temporary program if platform() = DOS32 then plat = "ex" elsif platform() = WIN32 then plat = "exw" elsif (platform() = LINUX) or (platform() = FREEBSD) then plat = "exu" end if sys = system_exec(plat & " " & EVAL_PROG_NAME, 0) -- read the content of the temporary result file, -- and convert it to a number fn = open(EVAL_RES_NAME, "r") if fn = -1 then return EVAL_READ_ERR end if ret = get(fn) close(fn) -- delete temporary files -- system("DEL *.tmp", 0) -- return the number from the temporary result file if ret[1] = GET_SUCCESS then return ret[2] else return EVAL_READ_ERR end if end function -- Demo object result sequence expression expression = "3*2.5" -- expression = "power(4,2)" result = eval(expression) if atom(result) then printf(1, "%s = %g\n", {expression, result}) elsif equal(result, EVAL_WRITE_ERR) then puts(1, "Could not write eval program ... Sorry!") elsif equal(result, EVAL_READ_ERR) then puts(1, "Could not read eval result ... Sorry!") end if puts(1, "\nPress Enter to continue ...") if getc(0) then end if
If you still have questions, just let us know. Regards, Juergen -- Have you read a good program lately?