<> <> <> <> <> JaM Introduction JaM is a simple stack-based interactive system with graphics utilities. JaM is intended to be a flexible system, giving the user rather direct control over the primitives. It is not intended to be a fault tolerant system for beginning users. This manual is written in the same spirit: the intent is to explain only those aspects of JaM which are not properties of programming languages in general. It gives explainations of all but the most obscure intrinsic functions and a sampling of the most useful external utilities. JaM has three major components: a virtual memory, a set of primitives which perform stack manipulations much like a very powerful, flexible Hewlett-Packard calculator, and a graphics package. All functions in JaM make use of the operand stack. This stack contains objects: integers, reals, booleans, character strings, commands, streams, dictionaries, arrays, and special stack markers. Execution proceedes by getting a token from the input stream, converting it into an object, checking whether or not it is executable and executing it. Non-executable objects are pushed onto the stack. During execution, operands may be retrieved from the stack and results are returned on the stack. This means that all input is given in postfix notation. The graphics package is a group of functions, some written in JaM, others written directly in Cedar, which must be loaded in addition to the basic JaM system. Basic Operation JaM execution proceedes simply by transforming the input stream into a series of objects and processing them sequentially. There are two types of objects: nouns which are automatically placed on the operand stack, and verbs which are immediately executed. The JaM scanner parses the input stream into a series of tokens separated by tabs, carriage returns, spaces and commas. There are three types of tokens: numbers, strings and identifiers. Numbers and strings are converted directly into the corresponding objects and placed on the operand stack. Identifiers are looked up in the current dictionary (explained later) and the resulting object is processed according to whether it is a noun or a verb. Syntactically, a string is a sequence of characters enclosed in parentheses. It may contain anything except unbalanced parentheses (even carriage returns). Any token which is neither a number nor a string is an identifier. The system has a total of three major stacks: the operand stack, the dictionary or context stack, and the execution stack. The dictionary stack is used for keeping track of identifiers during execution. This stack functions as a series of nested contexts, much like the blocks of a block structured language. A dictionary is esentially a table of fixed size for associating identifiers with their values. When the scanner comes across an identifier, it tries to look it up in the dictionary on the top of the dictionary stack. If the lookup is successful, the value found in the dictionary is the next object returned by the scanner. Otherwise, the identifier is looked up in each of the other dictionaries on the dictionary stack in sequence, until a value is found. The execution stack is used for keeping track of nested function calls. It contains the information necessary to implement recursive function invocations. It need not be the direct concern of the user since he cannot refer to it directly. How to Start Type the command jamimager'' to the CommandTool. This will create a JaM typescript for you to interact with the JaM interpreter and a JaMImager viewer for the graphics utilites. JaM gives you a prompt *'' in the typescript viewer. Initially, the operand stack is empty and the dictionary stack contains only one dictionary, the system dictionary. All the JaM intrinsic functions are defined in this dictionary. There are a number of other functions which JaM assumes exist and expects the user to define. These will be explained later when we discuss the relevent details of the system. Commands and Utilities This discussion is organized by function. All commands relating to a particular topic are given together along with an explanation of the particular aspect of the system to which they relate. The exact placement of arguments and results of each function on the stack is given by a diagram. For example: .add The symbols in angle brackets, , , , represent objects on the stack. An arrow (operand stack before the command is executed from the condition after. Only the top-most objects on the stack are shown, the others are assumed to remain unchanged. A comment may describe the command following the symbol will be used to mean the bottom of the stack. There are various error conditions which can occur when trying to execute a command. These are discussed in a separate section (see Error Handling) because there are special functions relating to this topic. Arithmetic and Bit Manipulation There are three types of numeric objects: reals, integers, and long integers. Integers and reals are 32 bits. Implicit type conversion is performed on numeric objects, but it is also possible to do these conversions explicitly (see Type Conversion). .add .sub .mul .div .idiv .neg .cos .sin .atan .exp .log .sqrt .bitor .bitxor .bitand .bitnot .bitshift < 0 then the y high order bits are set to zero and y is shifted right. If |y| Boolean and Relational Commands The following commands deal with boolean objects. They have two possible values represented here by .true'' and .false''. For integer comparisons, implicit type conversion occurs before comparison. If one argument is integer and the other is long integer or real, the integer is converted to that type. Similarly, long integers may be converted to real type. Strings may also be compared using lexicographic ordering. It is not legal to compare integers with strings. .true .false .eq .gt .lt .not .and .or .xor Stack Manipulation Commands It is often useful to manipulate the operand stack. It is probably not good practice, however, to try to use the stack for all temporary storage. Define local variables instead (see Dictionary Related Commands). Overuse of stack manipulation makes programs hard to read and difficult to debug. With this warning in mind, the following diagrams should make these commands clear. .pop .copy ... .index ... .count || ... .roll ... counting from 1, not 0, by k mod i, we really mean i when i divides k.) .dup .exch .clrstk || ... /clr || ... Defined in basic.jam. Stack Marking and Mark Manipulation Commands There is a special object called a stack mark. Its main purpose is for keeping variable numbers of arguments on the stack. The .loop and .rept commands (see below) use this concept internally to allow arbitrary execution inside the loop without losing track of the original condition of the operand stack. .mark .cnttomrk ... .clrtomrk ... Execution Control Commands JaM has much of the execution control machinery found in Algol-like languages. This includes looping'', if-else'' and select'' constructions. There is no go to'' command, however, as this would not easily fit into the stack oriented structure of JaM. The constructions just mentioned do fit in with the stack oriented structure because they can operate on executable objects in the operand stack. For example, the .if command expects a boolean object and any other object on the operand stack. If the boolean equals .true, then the other object is executed, otherwise the .if command pops the object from the stack. .exec stack, it is the result of some kind of execution. This means that x is effectively evaluated twice as with the eval'' function in Lisp. To reverse this effect, see Type Conversion .if /if .ifelse /ifelse .rept .loop .for thereafter. .exit to the marks placed upon entering the current loop. .stop to Error Handling. Dictionary Related Commands Variables are stored in special objects called dictionaries. Dictionary objects are general symbol tables useful for all kinds off storage. They have a fixed maximum size specified at the time of their creation. As mentioned earlier, there is a stack of dictionaries maintained by the system. The dictionaries in this stack are used like levels of static nesting for variable definitions in an Algol-like language. Dictionaries may be named and retrieved for later use just like other objects in JaM. There are a few things to watch out for when dealing with dictionaries. Some of the system commands and utilities assume that there is space left in the current dictionary (the one at the top of the dictionary stack) to define temporary variables. For this reason, you should be careful about creating small dictionaries. Another problem is what to do when dictionaries get filled up. There are about four choices: push another dictionary onto the dictionary stack with .begin, remove the offending dictionary with .end, delete entries to make room, or clear the dictionary. This problem is particularly severe for users who just start defining variables without ever worrying about dictionaries. The system dictionay has a capacity of 256 entries, most of which are already filled up with system command definitions. When the system dictionary gets filled up, whatever you do, don't clear it! In the following table, refer to keys or variables and refers to the corresponding values. .curdict .dict .def /def certain functions. It provides a convenient way to document programs. To access this dictionary, see Input/Output Commands. This utility resides in the file basic.jam /xdef .del .load allows its definition to be printed. (See Type Conversion and Input/Output Commands). .store definition of k exists, this functions as .def .put .get .known .where /dir /kdir ?? This usually includes most of the external utility functions whic have been loaded. .clrdict .dictforall .begin .end .end .sysdict .length .maxlength .attachdict dictionary d2. .detachdict .attachedforall .detachall Array Related Commands Array objects are linear arrays of objects indexed starting at zero. They have fixed lengths determined when they are created. There are commands for creating arrays, storing into them, retrieving objects from them, etc. Most commands either expect array objects on the operand stack or return array objects. Arrays can also be made executable. (See Type Conversion) .array [ ] ... obji ]'' forms an i-element array. .subarray range error. .aput .aget .aload .astore ... .arrayforall .abind .afind not appear on the stack. .length Input/Output Commands This catagory of commands deals primarily with string and stream objects. Files are represented in JaM as special objects called streams. Commands for reading and writing files accept string type aruments and return string results. There is always an input stream and an output stream. By default, these are both identified with the terminal. When writing strings to a file (stream), keep in mind that carriage returns can be part of strings and no implicit carriage returns are ever written to an output stream. Either the input stream or the output stream can be directed to any file. It is also possible to convert streams to strings and manipulate them that way. (see Type Conversion) .print = (Uses .cvis -- see Type Conversion). /stk == information about non-printable objects and even uses a reverse dictionary to decipher commands. /pstk dictionary look up which could cause an error. ? be one of the system commands and utility funcions or something defined using the /def utility (see Dictionary Related Commands). ?? .stream = .false for read or .true for write. Byte streams are the proper type of streams for most text files. The created stream is left on the operand stack. If access is greater than one, it becomes the current output stream. (uses .searchrules) .killstream .run definitions. A * prompt is printed each time the scanner comes to a carriage return. (uses .searchrules) .loadbcd .searchrules) .readitem bytestream or keystream and one word for a wordstream. Bytes are returned as integers, e.g. ascii codes for characters.) .writeitem .writebytes .searchrules /cr /sp /tab /lp /rp /quote Type Conversion Commands There are several different types of objects in JaM. String objects have a fixed length once they are created. It is possible to change existing strings (see Scanner and String Manipulation Commands) but their length remains constant. There are two numeric types: integer and real. When the scanner finds a string without any decimal point, it tries to make it an integer, then if it's too big, a long integer. Strings too long to be long integers are converted to reals. Strings containing decimal points naturaly become real type objects. It is not possible to enter numbers in exponential notation; however, one can type 6.7 10 -11 .exp .mul to get 6.7 Type conversion commands allow the user to determine the types of objects and convert from one object type to another. Type mismatches cause run-time errors. These errors cause special error routines to be executed, which are user definable. .type bits), .real (32 bits), .atom, .rope, .stream, .cmd, .op, .array, .dict, .mark, .other. .length .cvs .cvis result. If the string s is too short, JaM calls the function .sizechk to handle the error. You must define this yourself. .cvrs .cvos .cvirs .cvi .cvr .cvx string or array on the operand stack as is required by the execution control commands. .cvlit .commandname The most important type conversion is the conversion to executable. This is necessary every time a function is defined. There are two main executable forms in JaM: strings and arrays. Strings are a lot easier to use, but arrays are a lot faster. When a string is expected, the scanner must extract the objects from the string and each identifier must be looked up in the dictionary stack. When arrays are executed, they are already sequences of objects. In addition, all the identifiers have been looked up ahead of time. Executable strings are simpler to use because it is easier to change the definitions of the functions they call and they are easier to read and print. The use of the functions .cvx, .load, and .exec when defining executable arrays can be very confusing. Recursive functions are also more difficult with arrays. The following examples illustrate the difference in format: (average) (.add 2 .div) .cvx .def (average) [ (.add) .load 2 (.div) .load ] .cvx .def When using executable arrays, it is necessary to .load each function to get its definition (see Dictionary Related Commands). There is a utility called /compile to make this a little easier. Use ? (explained under Input/Output Commands) to find out about this. String Manipulation Commands This section had the JaM scanner commands and they are now obsolete. .length .substring .search and after the first occurrence of s, and <.false> if no substring of t matches s. .asearch Graphics Commands The graphics commands are not part of the basic JaM system. The basic graphics commands are enabled by loading JamGraphics.bcd. There are useful extensions to these basic graphics commands in various files of utilities. The basic primitives are implemented in Cedar and provide for a display context stack. This is maintained so that transformations and other state information can easily be saved and restored. The .pushdc, .popds and .initdc commands control this stack. State information concerning the graphics device is held in an entity called the display context. Most transformation, clipping, and painting commands alter this state. Most drawing commands both use this state and alter it. One of the more important components of the state is the current definition of the coordinate system. Points in the graphics display are refered to by pairs of real numbers. JaM maintains a transformation matrix for converting these numbers to the coordinates used by the display divice. The translation matrix affects only the placement of new objects on the display. Changing the transformation matrix with a transformation command affects the placement of already existing objects. The state information also contains the position of a special point called the current draw position. The line drawing commands use the draw position to define one endpoint of the line. The draw position is also used to control the placement of text within the display. The file Graphics.jam contains definitions useful to the beginning user. There are also other definitions which are intended more for demonstration purposes. A sampling of functions from Graphics.jam will be included in the following table along with the basic commands from JamGraphics.bcd in terms of which they are defined. The commands whose names start with a period come from JamGraphics.bcd and the other commands come from Graphics.jam. It is possible to look at the definitions of the commands from Graphics.jam using .load == (see Dictionary Related Commands and Input/Output Commands). This allows you to see exactly what these commands do and examine how the more basic graphics commands are used. There are several concepts common to many graphics commands. First of all, parametric cubic splines are used to specify curves. Cubic splines in turn are specified either in terms of the x and y coordinates of points, or by the coefficients of the actual parametric equations. Usually, the coordinates come from the mouse. A cubic spline segment may be specified by four points called its B ezier points. They have a specific mathematical relationship to the spline; informally, the spline passes through the first and fourth point, goes near the other two, and is always contained within the convex quadrilateral defined by the four points. Many commands facilitate the building of paths made up of curves and straight lines. The path does not actually show up on the screen until a command is given to fill in the area enclosed by the path. There are commands which control how the area is filed in. In particular, some commands set up a clipping box which is intersected with the region to be filled in. There is also a painting function which controls the texture (halftone, etc.) of the shaded region. .initdc .pushdc .popdc .translate .scale is enlarged and lines are thickened. (Lines are normally about one unit wide). .rotate < .sixpoint are mapped into the the last three. .concat .drawto .rdrawto moves the draw position as well. .moveto .getpos .rmoveto .drawboxarea position is left at the lower left corner. .drawcubic parametric equation. .beziertocubic control points are converted to the parametric form of a cubic. .cubictobezier form of a cubic is converted to its four B ezier control points. .startpath interior of the path is determined by a winding number technique. .starteopath interior. There is a difference only in paths which cross themselves. .enterpoint Successive .enterpoint's create polygonal paths. path .enterpoint''. .enterrect current path. rect rect .entercubic entered in the current path. .enterspline ... current path. This curve is a natural spline consisting of n cubics. .entercspline ... spline the .touch function (see below). cspline .newboundary the same path, it designates a hole in the center exactly when it winds in the opposite direction. .drawarea .drawscreenarea .erase .erase .cliparea .clippedcliparea .clippedcliparea comprising the current path clip clipping region (from graphics.jam). cclip graphics.jam). clips rectangle is defined by two .touch's: one at its lower left corner and the other at its upper right. blob (from graphics.jam). cblob (from graphics.jam). poly .dot dot area .texture when filling in areas. By default, n=1 is used. This causes areas to be filled in solid black. .paint integer n is in the range 0...3, but is more convenient to use the identifiers defined in the file graphics.jam. Pixels for which the texture bit is 1 are: set to 1 (black) if n=0 (paint), inverted if n=1 (invert), set to 1 and all other pixels are set to 0 if n=2 (replace), and set to 0 (white) if n=3 (erase). The default is paint. .touch waiting for the user to push the button. .mouse buttons need be pushed. .redup happens, execution is interrupted and the coordinates of the mouse are put on top of the stack. Then the function executed. All of these default to .pop .pop so they originally function as no-ops. .reddown .yellowup .yellowdown .blueup .bluedown .setfont font, so this command is required before any characters can be drawn. .drawchar character. .erasechar character. .drawstring string. .getstringbox .getcharbox text separated by carriage returns and are spaced dy below each other with a left margin at x (from graphics.jam). .displayoff .displayon Error Handling Run time error handling routines in JaM are user definable. When such an error is detected, the appropriate function (identifier, whose value is to be executed) is called. The default definitions of these functions are found in the file errordefs.jam. Not having these defaults loaded will cause an infinite string of errors when JaM tries to call the error handling routines. These defaults may be changed, but typically they stop execution and print the stack after displaying a short message regarding the type of error. When writing new error handling routines one must keep in mind that the operand stack and execution stack must remain intact when the error handling routine is called. One version of these routines prints the stack using /stk (see Input/Output Commands) and puts the user in a loop which reads lines from .mystream (the input stream) and executes them. This terminates when an empty line is found. Hitting carriage return causes JaM to attempt to continue execution. At various stages in this routine it is possible to get an additional (nested) error. This could be a little awkward. In this case it is a good idea to use the .stop command. The error handling routines are: .stkundflow .undefkey .longname .badname .typecheck stack along with its other arguments. .dictfull tried to define its own temporary varible into a full user dictionary. .syntaxerr .overflow .stkovrflow .rangechk .sizechk in some versions of the file errordefs.jam. The Edit Package This package can help reduce some of the inconvenience of continually having to change a bravo file when one is debugging programs in JaM. It is possible to make minor changes in function definitions without having to exit JaM and .run an external file again. This helps prevent the virtual memory from being filled up with garbage and it can save a lot of time. The editor is necessarily rather primitive, however, and it is desirable for safety to have programs saved on external files. For these reasons, this package should not be overused. To use this package, run edit.jam (see .run under Input/Output Commands). The commands are: /edit format of /p (see below). Subsequent calls to /p and /r refer to k. /p /r found, a message is printed and the definition is unchanged. To see the effect of your change, use /p. Programming and Use of JaM Because JaM is quite different from other programming languages, it is appropriate to give hints on how to program and put JaM to good use. The JaM input language has very little syntax. This attribute is both good and bad. The lack of syntax is good because a uniform representation is attained. The lack of syntax is bad because the code is hopelessly unreadable. In JaM it is almost true that any line of code can do anything (given the appropriate redefinitions of identifiers). Because of this property of JaM code, it is desirable to do several things when programming. First, document each funtion as it is written (use /def and /xdef under Dictionary Related Commands). Second, use naming conventions for functions that all belong to a given class (for example, intrinsic commands are started with .''). The latter convention will allow a person reading the code to tell what catagory a function is in by its name and may help him avoid accidentally redefining intrinsic functions. Since JaM is a stack orientated machine, the user must mentally keep track of the contents of the stack. It is easier to program JaM if each routine performs only one function and is very short. Normally a JaM routine should be at most one or two lines long. For example, suppose we wish to use the absolute value of a given number. Then, rather than introduce the code in line, it is desirable to write an "abs" function and then use that function e.g. (abs)(.dup 0 .lt (.neg) .cvx .if) .cvx .def Also if complex paramerters are being passed to JaM control statements, it is better to name the parameters rather than have lines and lines full of parentheses.