1. Suggested enhancement
I had previously made a suggestion for something equivalent to
BASIC's "CHAIN" statement; several people gave some quite
useful suggestions as to how roughly equivalent functionality
could be implemented. I have been using them, with acceptable
results (though I still think a CHAIN would be marginally
better).
Today, however, inspiration walked up behind me and whacked me
upside the head with a two-by-four, which leads to an Idea
that I think, if implemented, would be quite a nifty (dare I
say "elegant") enhancement to Euphoria:
Allow a procedure/function call "execute" (or something along
those lines) which takes a sequence of characters forming
valid Euphoria statements, and returns whatever executing
those statements results in - or nothing at all, if there's no
return value in the statements. This would allow:
1. A CHAIN facility - read a Euphoria program text into the
variable foo, then "execute(foo)".
2. A macro facility for any Euphoria program - let the user
define macros using Euphoria, and any interface that
the program author feels is best for the purpose,
then "execute(macrovariable)".
3. A procedural parameter capability - you could write highly
generic routines without needing to redefine
procedures or functions for (for example)
comparisons. "function sort(fooseq, compareproc) ...
if execute(compareproc) = -1 then ..."
4. A dynamic code facility - since "includes" are idempotent,
and cannot be done except at the absolute top level
of the program, there's no simple way of defining
what gets done "on the fly" such that you can have
the Euphoria-knowledgeable user instruct you as to
how to handle unforseen situations, and be able to
implement those solutions immediately (i.e., without
shutting down and restarting the program).
"while 1 do ... userproc = ... execute(userproc) ..."
Comments? Questions? Discussion?
=========================================================================
Jeff Zeitlin jeff.zeitlin at execnet.com
---
~ OLXWin 1.00b ~ I have seen the future and it is now the past.
2. Re: Suggested enhancement
- Posted by John DeHope <jwap at SOUTHEAST.NET>
Jan 16, 1997
-
Last edited Jan 17, 1997
JEFF ZEITLIN wrote:
> Allow a procedure/function call "execute" (or something along
> those lines) which takes a sequence of characters forming
> valid Euphoria statements, and returns whatever executing
> those statements results in - or nothing at all, if there's no
> return value in the statements.
I have used a program language/environment called "MUMPS" which provided
this functionality. It allows your code to write code, a really
interesting feature, eh? I just thought I'd let everybody know that this
can be/has been done before.
3. Re: Suggested enhancement
On Thu, 16 Jan 1997, John DeHope wrote:
> I have used a program language/environment called "MUMPS" which provided
> this functionality. It allows your code to write code, a really
> interesting feature, eh? I just thought I'd let everybody know that this
> can be/has been done before.
>
That's be great! I can just let my games write new games and I can take a
vacation! When's that new version coming out? =)
Michael Packard
Lord Generic Productions
lgp at exo.com http://exo.com/~lgp
A Crash Course in Game Design and Production
http://exo.com/~lgp/euphoria
4. Re: Suggested enhancement
On Thu, 16 Jan 1997, John DeHope wrote:
> JEFF ZEITLIN wrote:
> > Allow a procedure/function call "execute" (or something along
> > those lines) which takes a sequence of characters forming
> > valid Euphoria statements, and returns whatever executing
> > those statements results in - or nothing at all, if there's no
> > return value in the statements.
>
> I have used a program language/environment called "MUMPS" which provided
> this functionality. It allows your code to write code, a really
> interesting feature, eh? I just thought I'd let everybody know that this
> can be/has been done before.
It was also done in the BBC Microcomputer's BASIC. The command EVAL() let
you enter a string comprising any mathematical function available on the
computer, (including established variables) and returned the result.
e.g.
A = 17: B = 42: C = EVAL("SQR(B - A)")
and C would be set to 5.
It looks like I'm gonna be around for a while..., :)
Carl
--
Carl R White | e-mail...: crwhite at comp.brad.ac.uk
| finger...: crwhite at dcsun1.comp.brad.ac.uk
| web......: http://www.student.comp.brad.ac.uk/~crwhite
5. Re: Suggested enhancement
> It was also done in the BBC Microcomputer's BASIC. The command EVAL() let
> you enter a string comprising any mathematical function available on the
> computer, (including established variables) and returned the result.
>
> e.g.
> A = 17: B = 42: C = EVAL("SQR(B - A)")
>
> and C would be set to 5.
<nothing-to-do-with-euphoria>
LISP does that too, lest anyone forget, as well as some variants of LPC, the
programming language that powers some kinds of MUDs and the Roxen httpd.
The Amylaar version specifically has a structure called a "closure" that
can be written up by the routine on the fly. And, in the totally obscure
category, an old COMPUTE!'s Gazette utility called "Smart VAL" lets the VAL()
function on Commodore 64 BASIC 2.0 act identically to the example above.
</nothing-to-do-with-euphoria>
Cameron Kaiser
http://www.sserv.com/
spectre at sserv.com
6. Re: Suggested enhancement
JEFF ZEITLIN suggested:
> Allow a procedure/function call "execute" (or something along
> those lines) which takes a sequence of characters forming
> valid Euphoria statements, and returns whatever executing
> those statements results in - or nothing at all, if there's no
> return value in the statements. This would allow:
>
> 1. A CHAIN facility - read a Euphoria program text into the
> variable foo, then "execute(foo)".
If the his would add powerful tools, especially for an array of
functions.
ie.
function calculate ( number1, number2, operator )
VirtualMachine = { "add", "subtract", "multiply",
"divide" }
foo = VirtualMachine[operator] & "(number1, number2)"
return execute(foo) --ie execute( "add(number1,
number2)" )
end function
>
> 2. A macro facility for any Euphoria program - let the user
> define macros using Euphoria, and any interface that
> the program author feels is best for the purpose,
> then "execute(macrovariable)".
>
> 3. A procedural parameter capability - you could write highly
> generic routines without needing to redefine
> procedures or functions for (for example)
> comparisons. "function sort(fooseq, compareproc) ...
> if execute(compareproc) = -1 then ..."
I don't understand this one.
>
> 4. A dynamic code facility - since "includes" are idempotent,
> and cannot be done except at the absolute top level
> of the program, there's no simple way of defining
> what gets done "on the fly" such that you can have
> the Euphoria-knowledgeable user instruct you as to
> how to handle unforseen situations, and be able to
> implement those solutions immediately (i.e., without
> shutting down and restarting the program).
> "while 1 do ... userproc = ... execute(userproc) ..."
This is exactly what i want.
Especially if the imported procedures could be stored in a precompiled
form, with necessary stubs to slot right in, fast...
and of course could recieve paramters and return.
And if they could call imported procedures, then you'd need some
method
to avoid infinte regression and overflowing the stack, etc.
I'd favour a system variable that let you set the size of the stack,
and
whether the overflow would exit the program or be a 'soft error' that
ended
the function, returning a NULL or somesuch.
I'd like to know more how the interpreter works, does it create
bytecode ?? Can that bytecode be loaded on the fly.
If these are too much, then can i have this...
The "switch to" statement (a specialized version of Case,
stripped for
speed)
switch to variable {
code for variable = 0; -- seperated by semi-colons
code for variable = 1;
...
code for variable = n;
}
code for else -- optional, handles variable <> 0 - n
end switch
multiple lines of code
ie.
function VirtualMachine ( OPCODE var1 )
switch to OPCODE {
Stack = {} ;
Stack = Stack & Heap[ var1 ] ;
Heap[ var1 ] = Stack[ length(Stack) ] ;
Stack = Stack[ 1 ... length(Stack) - 1 ] ;
... etc ..
}
end switch
end function
-banjo
7. Re: Suggested enhancement
David Cuny wrote (I received this via private mail - I think it
probably meant to go to the list)...
A::>Jeff Zeitlin suggested being able to pass a sequence of Euphoria code to
::>Euphoria.
A::>Sounds like a good suggestion. The biggest problem I can think of would be
::>when an error occured, how would you know *where* it occured?
Well, the ex.err dump would show that it happened on an EXECUTE
statement/function, and would dump the variables. One of the
dumped variables would be the executed code - so you would at
least be able to pin it down by that much. If it wasn't passed
as a variable, there wouldn't be a lot of code to desk check;
it's unlikely in the extreme that one would write more than
about a line of code this way - and I can't think of any real
reason why someone would want to do so, rather than just
writing it directly into the program. Wait, yes I can, but
there's still not going to be much code.
In the case where it happens in a large chunk of code in a
variable, I think it might depend on how it is actually
implemented; if I were doing this, I would most likely make it
a "back door" to the parser and interpreter routines - much
like JPSoftware did when they added the %@EXEC[] function to
4DOS. There would be a small performance hit for EXECUTEd
code, but... Anyway, I see no reason why the ex.err report
couldn't at least print the offending statement "in EXECUTE
parameter" - for example
program.ex:41
attempt to divide by 0 in "? 1/0" in EXECUTE parameter
Global & Local Variables
...etc.
A::>If Robert doesn't want to put this together, one of the list members would
::>certainly be able to write this. Obviously, there would be a performance hit
::>taken if it were coded in Euphoria, but it is doable.
Certainly it is - but you'd have to write both the parser _and_
the interpreter, and if you wanted access to Euphoria's
debugging facilities, you'd have to write the debugger and
trace facilities as well. We'd be talking _major_ performance
hit; it might be acceptable if the language you're parsing
isn't Euphoria and isn't easily translatable into Euphoria -
but I doubt that many people would find it so. One of the
major benefits of Euphoria, IMO, is that it is _fast_ and
_compact_ - enough so to impress the Borland that wrote the
original Turbo Pascal. I don't think that my EXECUTE proposal
would slow it down into the realm of most language
interpreters; one would gain the flexibility of a LISP
interpreter without having to sacrifice the simplicity or a
significant portion of the speed of Euphoria.
A::>Euphoria itself certainly has an interesting parser, and is lazy when it
::>comes to parsing lines. For example, I can have the line:
A::> puts( {}, 1 }
A::>and Euphoria parses it happily, only paying attention to the number of
::>arguments (and whether any arguments require parameters), and not attempting
::>any further validation until the line is actually run.
Interesting - I would have expected that the built-ins, at
least, would have at least as strong type-checking as the
user-written routines. OTOH, that might have made it
unacceptably difficult to permit overriding of those routines
with user code.
A::>Also, the 'end' keyword is not part of the language. For example, if you try
::>to run the following code:
A::> end
A::>you don't get an "unmatched end" error, you get an "unknown command". I get
::>the feeling that each of the structure have their own parsing routines, that
::>scan the input until they find a matching "end" clause.
Possibly - it's certainly how I would think to do it...
A::>The biggest problem in coding a Euphoria parser in Euphoria is the lack of
::>forward declarations.
I'm not sure I perceive why forward declarations would be
necessary - would you be willing to elucidate?
=========================================================================
Jeff Zeitlin jeff.zeitlin at execnet.com
---
~ OLXWin 1.00b ~ ..... Help!, The TD has fallen and it can't get up!
8. Re: Suggested enhancement
Jeff Zeitlin wrote:
> I'm not sure I perceive why forward declarations would be
> necessary - would you be willing to elucidate?
In most cases you can do the same job as a mutual recursion does if you just
rewrite the algorithm, but this can be difficult and makes the code hard to
read. The reason why this matters so much for parsers is that parser algorithms
are naturally mutually recursive, since their grammar form (EBNF, context-free
grammar or syntax diagram) is by definition mutually recursive. As regards to
efficiency, a good grammar-based parser (by this I mean the grammar is
"factored non-left-recursive") is practically as efficient as a non-mutually
recursive parser. Check any good text on compiler construction for details.
> 3. A procedural parameter capability - you could write highly
> generic routines without needing to redefine
> procedures or functions for (for example) [cut]
This is the best proposed enhancement to Euphoria I've heard till now...
Wish I had come with it ;)! I believe it's possible to embed this feature
into the language in one of two different ways, so to keep type-safety:
1. Allow fully general procedure/function parameters types, for example,
a function that sorts an arbitrary sequence of objects in some user-defined
order would have as header
function sort (sequence nonsorted, function less_eq(object a, object b))
or something similar. The trouble with this approach is that the
proc/fun parameters could have their own proc/fun parameters. This makes
for a difficult interpreter implementation, and considerable execution
overheads if used extensively. The type-checking issues are also very
difficult to deal with, unless one restricts the allowed types of the
proc/fun's arguments. All this is due to the more complex calling mechanism
and the possibility of having a proc/fun argument reference its static
context (non local variables known only to itself) when it is called
inside the routine it was passed to.
2. Allow restricted procedure/function parameter types, such that their
argument is just an "object", not another proc/fun. This would put all
the effort of type-consistency in the programmer's hands, in a way much
like the type idea of Euphoria, so it fits nicely in that scheme.
I believe 2 would be the best choice for the enhancement. I'm not sure having
dynamic run-time macro facilities would be an advisable idea. Just think
all the parsing, type-checking and precompiling that will happen with all
those macros moving around the program... Cameron Kaiser mentioned the
possibility of using closures, but the implementation of closures is very
expensive both in time and space...
Somebody suggested the idea of having proc/fun types could be useful for
having sequences of proc/funs (sorry, I can't find the exact reference between
the lots of e-mails here). This is very difficult to have in Euphoria, since
you would be able to put type incompatible functions in the same list, and
then sometime later call the functions stored in the list. This obviously
requires a lot of type information to be mantained besides those functions
in the sequence (this is called a "descriptor"). Managing all that type info
would be difficult, and there is also needed information about the static
context of all those functions. This mandatory dynamic type checking would
cause a significant overhead to the execution time, too.
In short, I believe the idea of restricted proc/fun argument types would be
a great thing to have, but it shouldn't be as general as the mentioned
features for efficiency problems would arise.
-----------------------------
Carlos Gonzalia,
Universidad Nacional del Sur
Bahia Blanca, Argentina.
gonzalia at criba.edu.ar
-----------------------------