!vim: set sw=4 sts=4 ! help.h - help for ZedFunge [ HelpScreen char helpmode; @erase_window -1; @split_window 1; @set_window 1; style reverse; HLine(0, scr_xmax, 0, ' '); AtScreen(0, 0, "Help - "); AtScreen(scr_xmax + 1 - 112, 0, "F1 Basic F2 Advanced F3 Keys F4 Misc F5 Conc F6 Files F7 Blocks F8 SysInfo F9 Non-compliance F10 History"); !Change the number there to the number of characters style roman; @buffer_mode 1; @set_window 0; if (char == 'z' or '}' or '{' or 'y' or 'o' or 'i' or 't' or 'r' or 'n' or 's' or ''' or ';' or 'j' or 'p' or 'g' or 'w' or ']' or '[') helpmode=2; else if (char == ' ') helpmode=4; else helpmode=1; do { @erase_window 0; switch (helpmode) { 1: !Basic commands if (char >='0' && char <='9') char = '0'; if (char >='a' && char <='f') char = 'a'; if (char == '>' or '^' or '<' or 'v') char = '>'; if (char == 'l' or 'h') char = 'l'; if (char == '*' or '+') char = '+'; if (char == '-' or '/') char = '-'; HelpLine(char, '0', "Push the digit onto the stack."); HelpLine(char, 'a', "Push the hexadecimal onto the stack (10-15)."); HelpLine(char, '>', "Change the IP direction to go the way pointed."); HelpLine(char, 'l', "Change the IP direction to go low (in to screen)/high (out)."); HelpLine(char, '+', "Add/Multiply the top two elements of the stack."); HelpLine(char, '-', "Subtract/Divide the top stack element from/into the second element."); HelpLine(char, '%', "Divide the top stack element into the second, push the remainder."); HelpLine(char, '\', "Swap the top two elements of the stack."); HelpLine(char, '.', "Output top stack element as an integer."); HelpLine(char, ',', "Output top stack element as an character."); HelpLine(char, '"', "Enter or exit string mode."); HelpLine(char, ':', "Duplicate the top stack element."); HelpLine(char, '|',"Vertical if. Pop from stack; head down if 0, up otherwise."); HelpLine(char, '_',"Horizontal if. Pop from stack; head right if 0, left otherwise."); HelpLine(char, 'm',"Layer if. Pop from stack; head low if 0, high otherwise."); HelpLine(char, '!', "If top element is 0, make it 1, otherwise make it 0."); HelpLine(char, '`', "If second element is greater than top, push 1, otherwise push 0."); HelpLine(char, '#', "Jump over the next instruction."); HelpLine(char, '$', "Discard the top stack element."); HelpLine(char, '?', "Randomly change direction - equal chance of each cardinal direction."); HelpLine(char, '&', "Input integer from keyboard."); HelpLine(char, '~', "Input character from keyboard."); HelpLine(char, ASCII_AT, "Terminate IP execution."); 2: !Advanced commands HelpLine(char, '[', "Rotate ccw about z-axis"); HelpLine(char, ']', "Rotate cw about z-axis"); HelpLine(char, 'w', "Pop two cells, rotate ccw if first greater, cw if second"); HelpLine(char, 'g', "Get the value from Funge space, given a vector as argument"); HelpLine(char, 'p', "Put. Opposite to get; vector of location then element to store"); HelpLine(char, 'j', "Pops a number, jumps that many spaces (so 1j acts like #)"); HelpLine(char, ';', "Ignores all instructions until the next ;"); HelpLine(char, ''', "Pushes the next character and jumps over it (like #)"); HelpLine(char, 's', "Pops a character, stores it in the next space and jumps over it"); HelpLine(char, 'n', "Clears all elements in the stack"); HelpLine(char, 'r', "Reflects IP away"); HelpLine(char, 'k', "Pops a number n (may be 0), executes next instruction n times in place"); HelpLine(char, 't', "Split - See F5"); HelpLine(char, 'i', "File in - See F6"); HelpLine(char, 'o', "File out - See F6"); HelpLine(char, '{', "Begin Block - See F7"); HelpLine(char, '}', "End Block - See F7"); HelpLine(char, 'u', "Stack Under Stack - See F7"); HelpLine(char, 'y', "System Information - See F8"); HelpLine(char, 'z', "Explicit No-Operation (takes one tick)"); 3: !Keys print "Advanced keys^ The actions of function keys F1 to F10 are shown at the top of each screen. If you can't type them on your keyboard, they can be escaped by typing F followed by the number (0 for F10). ^^ Move around in two dimensions with the cursor keys. In Trefunge mode, F12 and F11 go low and high respectively - Fl and Fh are the appropriate escapes. Type to enter text, use backspace, tab, return as normal. Note that input keeps flowing in the same direction until you press a direction key - this can get confusing with high and low until you're used to it, but makes sense when you are.^^ Other main mode commands - ^F11/F12 or Fh/Fl: Go low/high (moving in the third dimension) ^Fy/Fd/Fp or Fc/Fx/Fv: yank/kill/put, AKA copy/cut/paste ^Fb: Insert breakpoint ^Ff: Load a file as an overlay ^Fo: Return to origin ^Debug mode commands - ^d: twin-toggle debugging info modes ^i: switch currently tracked IP "; 4: !Miscellaneous info print "ZedFunge98ish, aka ZedFunge (see F9 for an explanation of the ~ish~), interprets a version of the multidimensional programming language known as Funge 98. ZedFunge is currently running in a ", dimensions, "D space of ", line_width, " by ", page_height, " by ", space_thickness, " memory cells. Each cell contains an integer. These are displayed on screen as their ASCII character where possible.^^ The Instruction Pointer (IP) starts in the high top left cell moving towards the right. It interprets each character as an instruction. These are listed in the first two help screens (F1, F2). All characters not in the list are treated as no-operations.^^ The processor has a stack which contains a list of numbers. Most operations are performed using the stack. So, to add two numbers, you first push them both on the stack, and then use the add (+) command. This will pop the top two numbers of the stack, add them together, and push the result back on.^^ Some instructions expect a ~vector~ as an argument, or pop one. This is just a position in the space, normally relative to (0, 0, 0), and is of the form zyx with z nearest the top of the stack - so to input the vector (1, 2, 3) you want to push 123 in that order (e.g. >123g pushes the cell at position (1, 2, 3) onto the stack). In dimensions lower than 3, only the appropriate number of cells make up a vector.^^ There is a special mode called string mode, where instead of interpreting the characters as instructions, the IP simply pushes them as characters onto the stack. The IP will continue in the same direction doing this until it leaves string mode. The ~ instruction enters and exits string mode.^^ In debug mode (F5), the buffer is shown at the bottom of the screen. Press 'd' to flip between showing cells in the ASCII range as numbers or characters.^^ You can yank/copy, kill/cut and put/paste - use Fy/Fc, Fd/Fx, Fp/Fv respectively (whichever keyset and terminology you're more comfortable with (sorry emacs types) - I'll use the first convention here). You yank/kill by specifying a left, upper, high point and then a right, lower, low point. The block between (cube, square or line depending on the dimension) is read into memory, and, for a kill, wiped over with spaces. Putting will then put that block down starting from the current position. Spaces in the kill buffer won't write over characters already in the space - the put overlays what was there before rather than replacing it.^^ Changing the dimensions of the board - ZedFunge starts in 3-dimensional mode (trefunge) with dimensions ", MAX_LINE_WIDTH, "x", MAX_PAGE_HEIGHT, "x", MAX_SPACE_THICKNESS, ". When you clear, with F7, you are given the opportunity to change these dimensions. In lower dimensions, instructions (like h or |) which don't make sense act like r; ? randomly selects a cardinal direction from those available, and when an instruction pops or pushes a vector it is of the appropriate length. The memory of the Z-Machine is sadly very limited, so your space can't be very big. Sorry about that. The dimensions are saved when you save a file with F3 and automatically loaded when you load the file, unless you load it as an overlay (Ff). That works like putting, and will fail if the file is of too great a dimension.^^ Thanks to Chris Hall (c@@64pobox.co.uk) for most of the signed 4-byte integer arithmetic routines and for alpha testing of ZBefunge.^^ For further information about Funge, see the vaguely functioning^ http://www.catseye.mb.ca/esoteric/befunge/index.html^^ or the aptly named (and recommended)^ http://www.quote-egnufeb-quote-greaterthan-colon-hash-comma-underscore-at.info/befunge/^^ or just do a search.^^ Francis Irving wrote ZBefunge, of which this is an extension/desecration, perpetrated by Martin Bays. If you have any suggestions, bug reports or comments about ZedFunge then please email me at mbays@@64freeshell.org. Francis can be contacted at francis@@64flourish.org. Or see either Francis' page at^ http://www.flourish.org/zbefunge.html^^ or mine at^ mbays.freeshell.org/zedfunge.html^^ - you should be able to get some example Funge93 programmes (which are compatible if you change to two dimensions, 80x25, before loading) from the former, and maybe eventually some Funge98 ones from the latter.^^ This programme is distributed under the GNU general public license, version 2 or later (at your option). See the file copying.txt for full information.^^"; 5: !Concurrency print "Concurrency - ^ ZedFunge provides support for multithreading. What this means is this - you can have multiple IPs going at once, all interpreting instructions and reading and writing to/from the board, the user and files, their activities interleaving in a remarkably funky way. All you have to do to set it going is use the t instruction, which splits off a new IP from the one which executes it. The new IP is born with the same stack, offset and so on as its parent, but with an opposite direction.^^ Execution proceeds in ~ticks~, with each IP getting the opportunity to execute one instruction. One tick goes past with each STEP (F10 or space) in Debug mode. White space takes no ticks to process, nor does jumping with #, j, ; and so on. A child IP take its turn before its aging parent.^^ In debug mode, you can switch which IP you're tracking (showing details at the bottom, following it high and low, and highlighting it if you have colours enabled) by pressing the 'i' key.^^ An @@64 terminates the IP which reaches it - the programme ends when all IPs have terminated. Alternatively, the q instruction quits as soon as any IP executes it.^^ There is a limit of ", NUM_IPS, " IPs which can be running at any one time. After that, t instructions will be ignored until some IPs get terminated.^^ As for what use multiple IPs are - I'll let you figure that one out yourself."; 6: !File handling print "ZedFunge programmes can input and output files from/to disc or memory. This works just like F2 and F3 and like yanking and putting respectively. In particular - ^^ The i instruction first pops a null terminated reverse string - that is, like what is read in by an IP reading 0~gnirts~ from left to right - then a flags cell, then a vector. It then tries to load in the file whose filename is given by the string, and then put it starting from the position given by the vector, overlaying for spaces, just like overlaying with Ff does.^^ The way the Z-Machine is set up, the user gets a chance to stop the file loading, or to give it the wrong file. Nothing can be done about that. Also, if the filename doesn't include a period, interpreters seems to assume a .AUX extension. If for any reason no file was loaded (the user rejected the request, or there was no file of that name) the i acts like an r, reversing the direction of the IP. Otherwise, it pushes two vectors Va then Vb giving the size and least point of the file loaded in, suitable for inputting to o.^^ o, then. The o instruction first pops a null-terminated 0~gnirts~ string for the file-name, then a flags cell, then a ~least point~ vector Vb giving the start co-ordinates and then a size vector Va. It then reads the cube/square/line from Vb to Vb+Va inclusive, just like a yank with Fy/Fc, and tries to output it to the file. The same as for i goes for this file operation. And again, if it fails o acts like r. If given a size vector with negative components, o will fail.^^ Those flags cells - Only the last two bits have any significance. If the last is high (1 or 3), the file is read as linear text rather than a Funge file (not yet implemented). If the penultimate bit is high (2 or 3), and if no filename is given (just the 0 terminator), the operation is made to/from memory rather than a file. This is exactly like yanking and putting in edit mode. Note that loading something into memory and then loading a file will wipe over what was loaded into memory. Note also that this is not a part of the official Funge98 spec, so don't use it if compatibility concerns you. But given the difficulties involved with handling files in the Z-Machine, it seemed worth including.^^ By the way, file input and output are best combined with blocks - see F7."; 7: !Blocks print "There are a couple of complications to what I've explained so far, but they're handy complications so do keep reading.^^ Firstly, those position vectors used by g, p, i and o - I talked about them as being relative to the origin ((0,0,0)), but they don't have to be. Each IP has an offset, a vector which is added to all vectors pushed and popped by instructions it executes. The exception is the size vector accepted by o and output by i - this is relative only to the other least point vector. Offsets are copied to the child when splitting with t.^^ Secondly, there isn't just a stack for each IP - there's a stack of stacks. Here's how it works. A block is opened by the { instruction. This pops a cell we'll call n, then it pushes a new stack on the stack stack, then it transfers n cells, preserving order, from the previous stack to the new top one. Then it sets the offset vector for the IP to the (absolute) position of the next instruction it's going to run. It also pushes the old offset vector onto the old (now second to top) stack.^^ Basically, you should think of this as a function call with n arguments. The code executed within the newly opened block is isolated from what came before - a stack is started afresh with just those n cells, and p, g, i, o instructions are considered relative to the inner block.^^ The block is closed with }. This pops a cell we'll call n, then it pops that vector the { stored on the penultimate stack and assigns the offset to it, then it pushes n cells from the top stack to the second-top stack, then it pops off and throws away the top stack.^^ In other words, it returns out of the block with n cells as the code's return values, and resets the offset to what it was before entering the block, and ends up back on the old stack, having undone everything { did.^^ So overall, a {} block takes some cells off the stack, does some stuff with those cells, then puts some new cells back on the stack. And while the IP is in the code block, the offset is the position of the first instruction of the block.^^ Blocks can be nested, which does just what you'd expect (and what the ~stack stack~ terminology is intended to make sense of). The maximum nesting depth is ", MAX_BLOCKS, " - after that { acts like r. Also, attempting to end a block without having started one makes } act like r.^^ Hope that all made sense... one thing that confused me at first - remember that { always opens and } always closes, even if the IP is travelling right to left.^^ In debug mode, the stack list uses a '.' to mark where the top stack ends and the stack underneath begins. Also, you can toggle between showing the delta (direction) and the offset of the IP by pressing 'd' a couple of times (it also toggles ASCII mode for the buffer)^^ I've skipped over the technicalities of what happens if there aren't enough cells to pop - basically what you'd expect, but see the official spec (which should have come with this programme) for details.^^ The encapsulation provided by the {...} construct can be overriden with the ~stack under stack~ instruction, u. u pops a cell n, then pops n cells from the under-stack and pushes them onto the top stack in a pop-push loop (such that order is reversed). The first few cells popped will of course be the offset vector { stored. If you give u a negative argument, it works the other way round - popping cells from the top stack and pushing them onto the one underneath. "; 8: ! System Information print "OK, this is really just for completeness. The y instruction is meant to give all sorts of information about the interpreter and the current programme state. Much of this either makes no sense for the Z-Machine, or is otherwise unimplemented, but some is. It pops a cell, and pushes cells according to what it was - ^^ 1: pushes a 7. That's telling you that t, i and o are implemented, in case you care.^ 2: pushes 4, the number of bytes per cell^ 7: starting to get more useful - pushes the number of dimensions the programme is running in^ 8: pushes a numeric identifier for the current IP (see F5)^ 10: pushes the position of the IP as a vector^ 11: pushes the delta (direction) of the IP as a vector^ 12: pushes the offset of the IP as a vector^ 17: pushes the depth of block nesting of the IP^ anything else: reflects the IP, like r^^ Note that when vectors are pushed, they are absolute - relative to the origin rather than the IPs current offset."; 9: !Non-compliance print "I've done my best to make this comply with the Funge98 specification, but I've run up against the twin limitations of the Z-Machine and of my own programming skills. Here, then, is a quick list of what doesn't work, with brief explanations/excuses. A copy of the official spec should have been packaged with this programme.^^ Firstly, main thing - the space. The Funge98 space is meant to be a Lahey space 2", "@@94", "64x2", "@@94", "64x2", "@@94", "64 in dimension. The cunning dynamic memory allocation this would involve is beyond me, at least for now. I also can't see a nice way of presenting such a space in the editor/debugger. And so I settled on this b93-like space, a legacy from the original ZBefunge, with toroidal wrapping. If you think you can do better, please do.^^ Also, each cell in the space is only 8 bits long, rather than 32. However, a programme can write and read 32-bit signed integers at up to ", LONG_BOARD_CELLS, " cells (a compile-time limit), so you can have a little workspace. The buffer cells are always 32-bit, signed.^^ x, the fly instruction allowing you to set any vector as delta, isn't properly implemented. If you try to use it to set the delta to anything unusual, it'll just reflect. Anything else wouldn't make much sense in this compromise space. y doesn't do the silly hackish thing it's meant to do if you give it a large argument. Linear file-handling (a high least significant bit in the flag cell) isn't done. Didn't really seem much point, given that it'll wrap back up on itself for anything other than a very short file.^^ No fingerprints. I don't much like the idea. Seems like cheating. If you want to do something, you'll have to write it in funge.^^ Maybe some other stuff I forgot.^^ If anyone feels like picking up where I've left off, then please feel absolutely, totally, completely free. This is GPLed, so just go for it. I'd appreciate it if you told me, though.^^ Note that this is all one-way non-compliance - real Funge98 code might not run on ZedFunge98ish, but ZedFunge98ish code should run on a real Funge98 interpreter. The exception to this one-way compliance is the buffer flag for i and o - see F6 - though porting should be a simple matter of introducing a temporary file.^^ By the way, the handprint is ~ZFGE~ in hexadecimal i.e. 0x5A464745. "; 10: !History print " Version history - ^ 0.7.1b - first proper release, based on ZBefunge 0.7b ^ 0.7.2b - bug-fix release: stupid display problem with third dimension, t was broken in two quite catastrophic ways, miscellaneous other things. ^ 0.7.3b - changed name from ZFunge to ZedFunge, after discovering the former was already taken as the name of a (much better) interpreter by Zinx Verituse (http://staff.xmms.org/zinx/misc/). How embarrassing is that? Various bugfixes etc, too, largely thanks to Jeffrey Lee's fungus "; } switch (ReadKey()) { FUNCTION_1: helpmode = 1; FUNCTION_2: helpmode = 2; FUNCTION_3: helpmode = 3; FUNCTION_4: helpmode = 4; FUNCTION_5: helpmode = 5; FUNCTION_6: helpmode = 6; FUNCTION_7: helpmode = 7; FUNCTION_8: helpmode = 8; FUNCTION_9: helpmode = 9; FUNCTION_10: helpmode = 10; default: helpmode = 0; } } until (helpmode==0); @buffer_mode 0; @set_window 1; DrawAll(); ]; [ HelpLine userchar thischar text; if (userchar == thischar) style reverse; if (thischar == '0') print "0-9 ", (string)text; else if (thischar == 'a') print "a-f ", (string)text; else if (thischar=='l') print "lh ", (string)text; else if (thischar=='>') print "@@94>v< ", (string)text; else if (thischar == '+') print "+* ", (string)text; else if (thischar == '-') print "-/ ", (string)text; else print (char) thischar, " ", (string)text; print "^"; style roman; ];