https://paste.ubuntu.com/25458063/
https://github.com/mgius/zork/blob/master/rooms.c
Here is the full fortran code: http://gunkies.org/wiki/Zork#Source_code
https://paste.ubuntu.com/25458063/
https://github.com/mgius/zork/blob/master/rooms.c
Here is the full fortran code: http://gunkies.org/wiki/Zork#Source_code
neat: https://github.com/itafroma/zork-mdl/blob/master/rooms.mud#L...
- It's doing very complicated operations that operate on mutable global data, and structuring it as huge and deeply nested functions rather than splitting the operations up to smaller chunks with meaningful names. But you'd see exactly the same kind of thing in non-Lisp source code of that era; it's just different sensibilities.
- The code is incredibly heavy on conditionals. Which makes sense given the problem domain: parsing a pseudo-natural language. But MDL is a language where the conditionals kind of suck. COND is basically unreadable in any Lisp, you'd very rarely see people use it today. In CL you'd have more readable options like IF, WHEN and UNLESS. In MDL the only option is misusing short-circuiting AND/OR as a poor man's IF. Which they do in places, which doesn't help readability either.
- The use of angle brackets makes everything look like a sea of less-/greater -than comparisons. At least I just can't help it. It's especially bad when combined with the array indexing syntax.
I wouldn't say "very rarely"; COND is still used for multi-way conditionals. Virtually everyone I know would write:
(cond ((minusp x) 'negative)
((plusp x) 'positive)
(t 'zero))
Rather than: (if (minusp x)
'negative
(if (plusp x)
'positive
'zero))
IF, WHEN, and UNLESS are generally preferred where they fit nowadays, but I wouldn't call writing them with COND "basically unreadable", either, ie: (cond (pred then)
(t else))
(cond (pred then))
(cond ((not pred) then))
Compared to: (if pred then else)
(when pred then)
(unless pred then)Beyond that, I'd have to read the language manual to make sense of notations like ,foo and .bar.
The code makes a lot of references to non-local names. Someone reading the code would benefit from being familiar with the semantics of what those denote.
What's going on in those functions isn't "rocket science" though.
<DEFINE WAIT ("OPTIONAL" (NUM 3))
#DECL ((NUM) FIX)
<TELL "Time passes...">
<REPEAT ((N .NUM))
#DECL ((N) FIX)
<COND (<OR <L? <SET N <- .N 1>> 0>
<CLOCK-DEMON ,CLOCKER>
<FIGHTING ,FIGHT-DEMON>>
<RETURN>)>>>
(defun wait (&optional (num 3)) ; same arglist
(declare (fixnum num)) ; similar declaration
(tell "Time passes...") ; some call
(repeat ((n num)) ; some loop macro, see below
(declare (fixnum n)) ; declaration
(cond ((or (< (setq n (- n 1)) 0) ; old-style COND, OR, <, SETQ, -
(clock-demon clocker) ; some call
(fighting fight-demon)) ; some call
(return))))) ; return from loop
Where REPEAT would be implemented as: (defmacro repeat (vars decl &body body)
`(let ,vars
,decl
(loop (progn ,@body))))
Common Lisp basically got type declarations, rich argument lists, ... from MDL. DEMUDDLE> (parse 'expr *lispm-expr*)
(DEFINE 'WAIT ("OPTIONAL" (NUM 3)) (TYPED DECL ((NUM) FIX))
(TELL "Time passes...")
(REPEAT ((N (LVAR NUM))) (TYPED DECL ((N) FIX))
(COND
((OR (L? (SET 'N (- (LVAR N) 1)) 0) (CLOCK-DEMON (GVAR CLOCKER))
(FIGHTING (GVAR FIGHT-DEMON)))
(RETURN)))))
Someone more determined could write a small MDL->CL translator and produce a CL port of Zork (chock full of special declarations, since MDL uses dyamic scoping).I also found the following interesting remark in the primer: "One of the implementors of Zork has been heard to say that Zork is a huge conditional".
[0] http://publications.csail.mit.edu/lcs/pubs/pdf/MIT-LCS-TR-29...
While I was still working there we accumulated enough major change requests to the application that finally got the go ahead to throw the original code base out and start from scratch.