Re: Self Modifying Code
- Posted by lgregg May 27, 2019
- 1572 views
Is there a way to write self-modifying code in Euphoria? Or, perhaps, more simply, to have a Euphoria program write Euphoria code to an external file and then later "include" it in the same program?
Have you looked at the Preprocessor ?
It's not something I've used, but might work for your requirement.
Due to the parsing order (I'm guessing) Euphoria tries to read all the includes first, before running any code, so the following sort of thing will not work:
atom fn = open("time.e","w") puts(fn,sprintf("atom clock=%d",time())) close(fn) include time.e ? clock
<0052>:: can't find 'time.e' in any of ...
/home/irv
/home/irv/inc.ex
/home/irv/demos
/usr/local/include
include time.e
^
There's always the possibility of having your code write a (modified) copy of itself, then run that copy, I suppose.
It all depends upon what you are trying to do. Need more details - for example, EuGTK can certainly modify a program's appearance on the fly - button labels, colors, text, visibility of controls, etc. thru the use of simple .ini files, which can be written and loaded at any point, not just on startup.
It seems like so much of the World Wide Web is built with php, using embedded php code in html documents. For example:
<!DOCTYPE html> <html> <body> <?php $txt = "Hello world!"; $x = 5; $y = 10.5; echo $txt; echo "<br>"; echo $x; echo "<br>"; echo $y; ?> </body> </html>
BUT, why could we not do something similar using Euphoria?
<!DOCTYPE html>
<html>
<body>
<?euphoria
sequence txt = "Hello world!"
integer x = 5
atom y = 10.5
printf(1,"txt=%s\n",{txt})
printf(1,"x=%g\n",x)
printf(1,"y=%g\n",y)
?>
</body>
</html>
I wrote a preprocessor using an example from the OpenEuphoria site, to extract the Euphoria code and execute it. At this time, it does not return an html document with the embedded Euphoria code replaced with the results of running the preprocessor, although I imagine that is possible. I thought that Self Modifying code might be helpful. Here is the preprocessor:
/*
Program: process_file_eup.ex
Date: 19-JAN-2019
Purpose: To read a file and process one line at at time, pulling
out Euphoria (or other) code and writing to a file.
Blank lines are not output.
Should be able to use as a Euphoria pre-processor.
Invocation: eui process_file_eup.ex i text_file o code_file
or as a preprocessor
eui extension:process_file_eup.ex {filename.extension (as shown earlier)}
e. g.
eui html:process_file_eup.ex eup_test_2.html
*/
public include std/cmdline.e
public include std/io.e
public include std/sequence.e
public include std/text.e
constant begin_tag = lower("<?euphoria") -- change for other start tag
, begin_tag_len = length(begin_tag)
, end_tag = "?>" -- change for other stop tag
, end_tag_len = length(end_tag)
integer start = 0, stop = 0
sequence NULL = ""
-- Process each supplied line.
function process_each_line(sequence aLine, integer line_no, object data)
sequence lp=NULL
integer beginpos=0, endpos=0, done=0
-- printf(data[1],"aLine=%s, start=%g\n",{aLine}&start)
loop do
if start = 0 then
beginpos = match(begin_tag, lower(aLine))
if beginpos > 0 then
start = 1
aLine = aLine[beginpos + begin_tag_len .. $]
end if
end if
if start = 1 then
endpos = match(end_tag, aLine)
if endpos > 0 then
stop = 1
lp = aLine[endpos + end_tag_len .. $]
aLine = aLine[1 .. endpos - 1]
end if
end if
if start = 1 and length(aLine) > 0 then
printf(data[1],"%s\n",{aLine})
end if
if stop = 1 then
start = 0
stop = 0
end if
if length(lp) > 0 then
aLine = lp
lp = NULL
else
done = 1
end if
until done=1
end loop
if data[2] > 0 and line_no = data[2] then
return 1
else
return 0
end if
end function
-- Main
procedure main()
integer in1, out1
sequence cmd, extras
cmd = command_line()
if length(cmd) > 6 then
extras = cmd[7]
else extras = {}
end if
-- Get input file
if length(cmd) < 4
or compare(upper(cmd[4]),"STDIN") = 0
then in1 = STDIN
else
in1 = open(cmd[4],"r")
if in1 = -1 then
printf(1,"Could not open input file, %s, aborting\n",{cmd[4]})
abort (11)
end if
end if
-- Get output file
if length(cmd) < 6
or compare(upper(cmd[6]),"STDOUT") = 0
then out1 = STDOUT
else
out1 = open(cmd[6],"w")
if out1 = -1 then
printf(1,"Could not open ouput file, %s, aborting\n",{cmd[6]})
abort (12)
end if
end if
-- The first element of the third argument is the output file handle
process_lines(in1, routine_id("process_each_line"), {out1, 0})
close(in1)
close(out1)
end procedure
main()

