X-Git-Url: https://jxself.org/git/?a=blobdiff_plain;ds=sidebyside;f=mim%2Fmim.txt;fp=mim%2Fmim.txt;h=553046a5ca268a72840b94bab403d657375d70c0;hb=d73ace3f3292e320b461b8fcd2e9f5dc5d9684d7;hp=0000000000000000000000000000000000000000;hpb=d530283ea60fb0ddcc28e9c5bd072456afe06e07;p=pdp10-muddle.git diff --git a/mim/mim.txt b/mim/mim.txt new file mode 100644 index 0000000..553046a --- /dev/null +++ b/mim/mim.txt @@ -0,0 +1,283 @@ +MIM-Muddle differences + +Beware: ^A is now the `control-S' character--it halts whatever you're +doing, and returns to the previous listen loop. ^S is normally just +used for flow control, as is standard on tops-20 and unix. ^G is the +interrupt character, as before. + +Changes in types + +UVECTORs must be of UTYPE FIX. In consequence, UTYPE and CHUTYPE no +longer exist. + +BYTES always have byte size 8, so the BYTES and IBYTES routines no +longer take a byte size argument. + +RSUBRs, RSUBR-ENTRYs, SUBRs, and FSUBRs are all represented by MSUBRs. +The structure of compiled routines is now: +#MSUBR [name-of-IMSUBR:ATOM + name-of-routine:ATOM + decl:LIST + offset-in-code-vector:FIX] +This corresponds to the RSUBR-ENTRY in muddle. An IMSUBR corresponds to +the RSUBR: the first element is code, and the remainder of the elements +are external references. Since the interpreter is written in muddle and +compiled, there's no need for special types for interpreter routines. + +There are two new types of primtype ATOM: +GVAL evaluates to the global value of the atom, and prints as ,atom. +LVAL evaluates to the local value of the atom (in the current +environment), and prints as .atom. The routines GVAL and LVAL still +exist as well, and are used for constructs where you're getting the +value of something that's not an atom. + +Locatives no longer exist, except (in some sense) to globals and locals. +GBIND returns the global binding of an atom: + will error if the atom is not GBOUND?; will +create the binding if necessary. +LBIND returns the local binding, and errors if the atom is not bound: + returns the current binding; returns the +binding relative to the specified frame. +GET-VALUE and PUT-VALUE will return/set the value slot of the binding. + +All activation-like objects are now of type FRAME. Something you used +to decl as is now . + +The structure of CHANNELs has changed completely. See below for +details. + +The PRIMTYPE of FIXes, FLOATs, and friends is now FIX. There is still a +type WORD. There is no type LOSE; type UNBOUND is the nearest +equivalent, but not quite the same--an atom whose LVAL is of type +UNBOUND will give an error when you LVAL it, since it has no value. + +OBLISTs are now primtype ATOM rather than UVECTOR. All atoms are stored +in ,ATOM-TABLE, which is a hashed vector of lists. To get all the atoms +in an OBLIST, you can call GET-OBLIST with the oblist name. + +TUPLEs are now PRIMTYPE VECTOR, rather than TUPLE. + + +Type declarations + +DECLs may be used as before (objects of type DECL scattered around), but +are defaultly not checked by the interpreter (the compiler still uses +them). To check old-style decls, invoke . This +gives DECL an EVALTYPE, which does more or less the right thing. + +Objects of type ADECL are recognized and checked by the interpreter +unless DECL-CHECK is false. There are two uses, which have basically +the same syntax. +In argument lists (and binding lists for PROG/REPEAT/BIND), you may +follow the atom by its decl, thus: + +The value of a function may be declared in the argument list, thus: + +The syntax is atom, followed by :, followed by the declaration. + +ADECLs may also be used anywhere in your code. Thus +<+ .X:FIX 1> declares that .X will return a FIX, regardless of what it's +decled to be elsewhere (of course, we assume that the other decl allows +FIX as a possibility). In general, anything may be followed by : and a +decl; this builds an ADECL, which is a pair consisting of the object and +its decl. When the ADECL is evaluated, the object inside is evaluated, +then the result is compared to the decl. The compiler will cheerfully +use these. + +GDECLs are as before. + +Interpreter changes + +CASE is now built-in. The syntax is +, thus: +) + (2 ) + DEFAULT + ()> +Only ==? compiles efficiently. More than one value may be associated +with a branch by using the following bizarre syntax: +) + (4 )> + +Functions may return more than one value (or no value). The syntax in +the function is: + + +If the frame argument is false, LPROG!-INTERRUPTS must be bound to a +FRAME somewhere; the easiest way to do that is by being inside a PROG or +REPEAT. + +If the calling function does nothing special, it will see only the first +thing returned (an error results in this case if the MULTI-RETURN tuple +is empty. In order to see all of the values, the function must be +called from a segment, which means you have to be doing something where +a segment is reasonable: either another function call, or a structure +builder. (MULTI-SET sort of exists, but isn't fully supported yet.) +Thus: +<+ !>, where FOO does a MULTI-RETURN, will sum all the things it +returned. This is of course indistinguishable from FOO returning a +structure, except that no structure is created. + +EXIT is like QUIT, except that it takes a status code. On UNIX, this +literally exits, with whatever status you supply (thus non-zero is bad); +on tops-20, it halts, but leaves the status code in AC2, with -1,,3 in +AC1. + +OFFSETs now have three slots, rather than two. The first two are the +same: the index, and the type of object the offset may be applied to; +the third is the type of object allowed in the slot referenced. The +third slot need not be supplied when an offset is created. Thus: +> returns something that must be +applied to an MSUBR. If it's being used for PUT, the new object must +be a list; if it's being used for NTH, the object returned will be a +list. This is useful because PUT doesn't check the type of the new +object. + +Decls may still be associated with atoms, but the syntax is different. +Before, one used . Now, one uses +. returns the decl, if it's there. +The same mechanism may be used to manipulate the decl associated with a +newtype. PUT-DECL/GET-DECL may also be applied to GBINDs, LBINDs, and +OFFSETs. + +Stack objects + +It is possible to build VECTORs, UVECTORs, STRINGs, and BYTES on the +stack (which is why TUPLEs are PRIMTYPE VECTOR). This must be done at +toplevel in an argument list, except that a CHTYPE may be wrapped around +the stack build, and it may be the result of a macro expansion. Thus: + +> KEYWORD>> + +)) ...> +is legal. The syntax is +, as: +> +> + +etc. These objects are on the stack, and vanish when the function that +built them returns. Aside from that, they are first-class objects. + + +I/O + +I/O is still done through objects called channels, and most of the +high-level routines (READ, PRINT, etc.) are roughly the same, but aside +from that everything's different. + +There are three ways to get a channel: + +OPEN takes a direction (a string), a file name (a string, possibly +empty), and optional defaults for NM1, NM2, DEV, SNM, and radix. This +differs from muddle, which didn't take a radix argument, and didn't take +a name and all four defaults at the same time. The direction may be one +of: +"READ": read-only, ascii +"READB": read-only, binary (36-bit on 20x, 32-bit on unix) +"PRINT": create a new file, read/write, ascii +"PRINTB": create a new file, read/write, binary +"PRINTO": modify an existing file (therefore, read/write), ascii +"PRINTBO": modify an existing file, binary +This returns a channel or a false, containing various error codes and +error messages. The channel is ready to be used by READ, PRINT, and +friends, and can be found on . + makes the channel ready for READ/PRINT, and adds it to +CHANLIST if it's not already there. (There are ways of making channels +that don't leave them ready for READ/PRINT, and don't put them on +CHANLIST.) + +GEN-OPEN is more general than OPEN. It takes a file name, a STRING, and +optionally: the MODE, a string, default "READ"; the byte size, default +"ASCII"; and the device type, which is defaulted depending on what the +name points to. The values of DEV, NM1, NM2, and SNM are used to +default the file name, just as they are for OPEN. +The MODE argument: +"READ": open for read only +"CREATE": make a new file (data may be read, once it's written) +"MODIFY": modify an existing file +"APPEND": append data to an existing file (write-only) +The BYTE-SIZE argument: +"ASCII": 7-bit on the 20, 8-bit on unix +"8BIT": 8-bit (uses BYTES rather than STRING) +"BINARY": full-word transfers--36-bit on the 20, 32-bit on unix + +I'll explain in a bit about the device type. The two most commonly used +are DISK and TTY; GEN-OPEN defaults depending on what the system thinks +the file name refers to. will generate a TTY-type +channel; FOO.BAR"> will generate a DISK channel. + +GEN-OPEN returns a channel or false, just like OPEN. + + +CHANNEL-OPEN is the most general (and least friendly) way of opening a +channel. It takes: +Device type, an atom +File name, a string or false +Any other arguments required for the type of channel being opened. + +Thus: +FOO.BAR" "READ" "ASCII" <> T> +opens a DISK channel to foo.bar, read-only, 7-bit, unbuffered, +without modifying the read date. + +> +is how muddle creates INCHAN and OUTCHAN (which are the same object). + +More on this later, when I explain channel types in their full glory. + + +High-level I/O + +READ: all arguments are optional. +A channel, default .INCHAN +Something to eval at end-of-file, default ' +A list of oblists, default .OBLIST +A vector, the read table. Default .READ-TABLE or ,READ-TABLE. (More on +this in a bit.) +[Modulo the difference in read tables, this is as before...] +READ from the TTY is more intelligent about unmatched parens... + +TYI, NEXTCHR, READCHR, and READB all exist, unchanged. + +READSTRING: +A string, the buffer to read into +"OPTIONAL" +A channel to read from, default .INCHAN +A fix, the number of characters to read, or a string, containing +characters to break on, default the length of the buffer +An object to evaluate at EOF, default +A fix, magic. +READSTRING differs in three ways from old muddle's version: +1) The terminal character, when the third argument is a string, is +returned in the buffer. +2) When reading from the TTY, READSTRING falls into an equivalent of the +tops-20 TEXTI call; thus, if you specify a string as the third argument, +READSTRING will return immediately on reading one of the characters. +There's no need for a muddle `wakeup' character. +3) The magic fifth argument specifies how many characters in the buffer +are good. This is most useful when you're reading from the TTY, and the +buffer fills before the desired terminal character--you can make a +bigger buffer, and call READSTRING again with a fifth argument of the +old buffer length. This is transparent to the user--it looks like one +call to READSTRING to him. + +Two other magical things have been added. +If READ-PROMPT!- has a local value, and that's a STRING, the string will +become the prompt for keyboard input. +If READ-BREAKS!- has a local value that's a STRING, the characters in +that string will act like ESCAPE in READ and READSTRING, REPLACING +ESCAPE. Because READ is fairly intelligent about handling unbalanced +parens, it is possible to make CRLF take the place of ESCAPE--typing a +multi-line form works because READ silently tries again until it has +something that's balanced. [This does have efficiency problems; the +first lines of the form will be parsed many times in the process, +possibly building a lot of garbage in the process...] + +Input from the TTY all goes through TEXTI, so ^R, ^W, ^U, ^L are all +standard. ^D is like old muddle. There is no particularly convenient +way to clear your input buffer, short of multiple ^U's or a ^A (which +loses if you aren't in a listen loop, of course...). +