<DEFINE FOO () ...>
is equivalent to <SETG FOO <FUNCTION () ...>>
But EVAL will fall back to the LVAL if the atom doesn't have a GVAL. In other words: <A B C>
is equivalent to <APPLY <COND (<GASSIGNED? A> ,A)
(<ASSIGNED? A> .A)
(T <ERROR>)>
B
C>
https://github.com/taradinoc/mdl-docs/blob/master/docs/03-bu...Another thing I couldn't find is exactly what a trailer with an empty OBLIST means. Does it use <ROOT>? It shows up in TELL for the uses of RETURN!-, which probably are to use a non-overridden version of RETURN.
(Or any idea what SETG20 is supposed to mean? It shows up in Bureaucracy.)
I'm not sure what the purpose of things like <RETURN!-> and <ORB!-> is. It could have something to do with the way they implemented Z-machine opcodes as MDL atoms, i.e. <RETURN!-> forces it to use the MDL SUBR instead of the opcode? Maybe they moved the MDL atoms that collided with Z-machine opcodes to a separate OBLIST, and this was needed to access them from MDL code in the same file?
I never figured that part out, so when ZILF is generating code, it uses the same OBLISTs it used while interpreting and just looks things up by their PNAMEs.
SETG20 and DEFINE20 are used in "MDL-ZIL" files, where routines are defined with DEFINE instead of ROUTINE, global variables are created with SETG instead of GLOBAL, etc. Presumably that was a way to run the games in MDL during development to avoid recompiling them. SETG20 and DEFINE20 are aliases for the MDL versions of SETG and DEFINE.
A translation from MDL to Python would look like this:
(This is in contrast to a sibling comment: in MDL would evaluate to )However, there is a bit of a caveat in the translation. In MDL, atoms are self-evaluating, and it takes a call to LVAL or GVAL to obtain their stored values (as a shorthand, dot and comma prefixes give LVAL and GVAL calls, respectively). I haven't been able to find out from exactly which scope the evaluator gets the definition of a function. Which of the following two corresponds to what the evaluator actually does?