Mutt Language

HomePage | RecentChanges | EditorIndex | TextEditorFamilies | Preferences

========================================================================

The Mutt2 Programming Language Craig Durland 9/89 10/91

========================================================================

Here is the documentation for the core Mutt2 programming language. There are probably many extensions, depending on what application Mutt is embedded in. See the documentation for the application for more info.

		     Copyright 1991 Craig Durland
    Distributed under the terms of the GNU General Public License.
  Distributed "as is", without warranties of any kind, but comments,
	       suggestions and bug reports are welcome.

======================================================================

Syntax

======================================================================

symbol action

  (	evaluate expression
  )	end expression
  {	start block
  }	end block

SYNTAX

  pgm   : {exp [exp ...]}, {}
  exp   : (fcn [args]), (var [args]), var, const, ()
  const : number (123, 0xAbC?), string ("abc", 'abc'), TRUE, FALSE
  arg   : block
  block : pgm, exp or const
  fcn   : a Mutt function (such as + or while) or defined function.

======================================================================

Data Types

======================================================================

Mutt is a typed language. (data-types):

  Type		id	What it is
  
--
-- -- BOOLEAN 0x05 TRUE or FALSE. BLOB 0x06 A pointer to a block of data. NUMBER 0x03 32 bit signed integer. STRING 0x08 A bunch of characters. LIST 0x09 A list of things. VOID 0x01 A type of nothing. FCNPTR 0x07 A pointer to a function. CHARACTER 0x0A This is not a real data type. It is a helper type. REAL 0x04 Not implemented.

Id is a numeric constant that is used to identify a data type. They are

  used in Mutt programs when you need to talk about types (see
  convert-to).

List Syntax

  Sometimes I'll need to refer to the contents of a list.  To do that,
    I'll use [<first element> <next element> ...].  Everything in "[]"
    are the contents of the list.  "[]" by itself means the empty list.

======================================================================

Return Values

======================================================================

All blocks "return" a value. Pgms return the value of the last exp

  executed.  Note that a pgm can return values of different types.
The class of a return value can be one of:
  BOOLEAN, BLOB, NUMBER, STRING, LIST, VOID, FCNPTR.

======================================================================

Variables (aka vars)

====================================================================== CREATION
  Vars must be created before they can be used.
  Global vars are initialized to:
      bool			: FALSE
      int, small-int, byte	: 0
      string			: ""
      list			: empty
  Most Local vars are NOT initialized (ie they contain garbage when
    created).  Local strings and lists are initialized the same as
    globals.
EVALUATION & ASSIGNMENT
  Vars behave like fcns, ie (var) evaluates the var (returns its value)
    and (var val) passes val to the var for assignment.  (var val)
    returns val.  If you just want to evaluate a var, you can treat it
    like a const - ie "var" is equivalent to "(var)".  Note, however,
    doing this may cause logic bugs if var also happens to be the name
    of a const (since the const is locked out).  See GOTCHAS.  In some
    cases, (var) and var don't mean the same thing - see pointer.
  Cascading assignment:  you can assign multiple vars the same value.
    eg (int x y z)(x (y (z 123))) assigns 123 to x, y and z.
    eg (int x)(string s 20)(x (convert-to NUMBER (s "123"))) sets s to
      "123" and x to 123.
SCOPE
  The scope of a variable is the same as the pgm it is created in.
  A variable created outside of a fcn (defun) is global - ie anybody
    can get at it.  Global variables are local to the file (and any
    included file(s)) they are created in.
  For example:
    If foo.mut contains:
      (int foo)		; declare and create global var "foo"
      (defun "hoho" { (int bar) (bar foo) })
      (foo 123)		; assign 123 to foo
    (load "foo.mut") will create a global var foo.  (hoho)
    creates bar and sets it to 123.  hoho is done and bar is freed.
    foo is still alive and equal to 123.

======================================================================

Functions and Keywords

====================================================================== Everything in this list is a function (except those that have a return
  class of zip).

A TOKEN is a bunch of letters, eg foo.

Keyword Args [arg class(s) : return class]





-

; (semi-colon) A comment that extends to the end of the line

(== value value ...) [STRINGs, NUMBERs or BOOLEANs : BOOLEAN]

  Test 2 or more items for equality.  
  You can only compare like types - eg (== "123" 123) is illegal.
  eg (== foo 1), (== "one" "two"), (== (+ foo 3) bar 5).
(!= value value) [NUMBER NUMBER : BOOLEAN]
	Same as == but nonequality.  Only 2 items.
(< value1 value2) TRUE if value1 < value2. [NUMBER NUMBER : BOOLEAN] (<= value1 value2) TRUE if value1 <= value2. [NUMBER NUMBER : BOOLEAN] (> value1 value2) TRUE if value1 > value2. [NUMBER NUMBER : BOOLEAN] (>= value1 value2) TRUE if value1 >= value2. [NUMBER NUMBER : BOOLEAN] (+ values) [NUMBERs : NUMBER]
	Add a bunch of numbers  eg (+ 1 2 3 4) => 1+2+3+4
(- values) [NUMBERs : NUMBER]
	Subtract a bunch of numbers eg (- 1 2 3 4) => 1-2-3-4 = -8
(* values) multiply a bunch of numbers [NUMBERs : NUMBER] (/ values) divide a bunch of numbers [NUMBERs : NUMBER] (+= var values) [TOKEN NUMBERs : NUMBER]
    Add value(s) to var and assign it back to the var.  Returns the result.
    Short hand for (var (+ var values)).
    eg (+= foo 1) (+= foo fud 3) 
(-= var values) Subtract value from var. [TOKEN NUMBERs : NUMBER] (*= var values) Multiply var by value. [TOKEN NUMBERs : NUMBER] (/= var values) Divide var by value. [TOKEN NUMBERs : NUMBER]

"string"

  String constant.
  Special characters:
    \	quote the next character.  "\\" => '\'   "\^" => '^'
    ^	convert the next character to a control character (make sure that
	  the letter is UPPERCASE!).  eg "^A"
	Note: escape == ^[.
'string'
  String constant.
  No special characters except '' reduces to ' ie if you need a string
    like "don't", you can use 'don''t'.
  This form is handy for regular expressions.

(and values) [BOOLEAN [BOOLEAN ...] : BOOLEAN]

  Logically and a bunch of things
  The first FALSE value will terminate (ie the rest of the and will
	not be evaluated).
  Example:
    (and (previous-line) (foo)):  If previous-line returns TRUE, foo is
      called and that will be the result of the and.  If previous-line
      returns FALSE, the and returns FALSE and foo is not called.
  See also: or.								  
(arg n) [NUMBER : any class]
  Get the nth argument from the parameter list.
  The arguments are numbered 0,1...,(nargs)-1
  eg (fcn 1 "two" (three)) has 3 arguments:  numeric 1, string "two" and
    whatever fcn three returns.  (arg 0) returns 1, (arg 1) returns
    "two", (arg 2) returns result of (three).  (arg 3), (arg -1), etc
    error.
  Notes:
    You cannot set a arg unless it is a pointer.
    See defun for how you can name the args.
  See also: ask, defun, nargs.
(array type name dimensions) [TOKEN TOKEN NUMBERs [TOKEN NUMBERs] : zip]
  Create an array.  Types allowed: bool, int, small-int.
  (array int x 5 z 7) creates two arrays:  x with 5 ints and z with 7.
  (array int y 2 3) creates an array with 2 rows of 3 ints each.
  (x 3 123) sets the third element of x to 123.
  (x 3) returns 123.
(ask prompt(s)) [any class(s) ... : STRING]
  Get the next argument from the argument list; if the argument list is
    empty, query the user.  Aways returns a string - if the arg is not a
    string, it is converted to one.
  eg if (foo (ask "foo = ")) is in fud then (fud "hoho") will pass "hoho"
    to foo.  (fud) will cause the message "foo = " to appear and will wait
    for a response to assign to foo.
  You can force the pgm to query the user with (ask-user).  If you do
    this, you will need one per ask.  The next unmodified (ask) will
    behave as above.
  (ask) can take more than one argument.  For example, if foo is 123 then
    (ask "foo is currently " foo ".  Change it to: ") might prompt:
    "foo is currently 123.  Change it to: ".
  Notes:
    Be careful if you mix arg lists and asks.  It can be confusing (to
      the programmer) if you try to get some args via (arg n) and others
      via (ask).  In this case, you should use interactive asks to keep
      ask out of the arg list.  Use nargs and arg if you must mix (to
      implement your own ask like functionality) and will be asking for
      an arg starting after the first one.
    If not interactive, each ask will get the next arg from the arg
      list.  The first ask gets a copy of the first arg, the second ask
      gets the a copy of the second arg, etc.  until there are no more
      args.  After that, next ask will abort the program.  There is no
      way to restart ask.
    Ask doesn't change the arg list - you can ask away and still get at
      any arg with (arg).
  See also: arg, ask-user, convert-to, arg, nargs.
(ask-user) [zip : VOID]
  The next ask will query the keyboard and not the program args.
  Turned off after every ask.
  See also: ask.

(bool var [var ...]) [TOKEN [TOKEN ...] : zip]

  Create one or more boolean variables.  If in a defun, the variable is
    local to that defun, otherwise it is global.
  Evaluation: var					 [TOKEN : BOOLEAN]
  Assignment: (var value)			 [TOKEN BOOLEAN : BOOLEAN]
  Example: (bool foo)(foo TRUE)  ;; create and set "foo" TRUE
  See also: int, string, list, array.
(break) [zip : zip]
  Get out of the smallest enclosing for or while loop.  The loop then
    retuns the value of the last block executed.
  See also: continue, for, while.
(byte var [var ...]) [TOKEN [TOKEN ...] : zip]
  Evaluation: var					  [TOKEN : NUMBER]
  Assignment: (var value)			   [TOKEN NUMBER : NUMBER]
  Allocate 8 bit unsigned integers.
  The range of a byte is [0 : 255].
  Note that a NUMBER may not fit in a byte.  If not, the number will be
    truncated to fit.
  See also: int, small-int, array, bool.

(cond test body ...)

	    [[BOOLEAN, block, [BOOLEAN, block ...]] : last block executed]
  Same as  nested  if's.  If the  test is TRUE  then the next  block  is
    executed and the cond is ended.  Otherwise the next block is skipped
    and the cycle repeats.
  eg
  (string str)(str (ask "str = "))
  (cond
    (== str "one") (msg "number 1")
    (== str "foo") (msg "bar")
    TRUE (msg str " is not something I know about.")
  )
  See also: switch.
(concat parameters) [anything ... : STRING]
  Concatenate parameters.
  eg (concat "foo = " foo) returns "foo = 123" if foo is 123 or "123".
(const name value [name value ...]) [TOKEN BOOLEAN|NUMBER|STRING : zip]
  Create one or more constants.  Used like other constants (such as
    numbers, strings, etc).
  Precedence: args, local vars, global vars, pgms, consts.
  eg
    (const foo 123 bar "hoho")
    (msg foo bar)	;; this prints "123hoho")
  Notes:
    Do not use ()'s around constants - they are for functions only.
    See GOTCHAS.
(continue) [zip : zip]
  Go to the bottom of the smallest enclosing for or while loop.
    If in a for loop, this means the inc part.
  See also: break, for, while.
(convert-to type value) [NUMBER any : type]
  Convert a value of one data type to another type.
  Valid conversions:
    BLOB to:
      No valid conversions.
    BOOLEAN to:
      NUMBER:	  TRUE -> 1 and FALSE -> 0
    FCNPTR to:
      No valid conversions.
    LIST to:
      No valid conversions.
    NUMBER to:
      STRING:	 same as (concat).  eg 123 -> "123"
      CHARACTER: 0x33 -> "3"
      BOOLEAN:	 0 -> FALSE and everything else -> TRUE
    STRING to:
      NUMBER:	 "123" -> 123
      CHARACTER: "3" -> 0x33
    VOID to:
      No valid conversions.
   The numeric constants for the data types are in the data types
     section (see data-types).

  eg (foo (convert-to NUMBER (ask "A number please: ")))
  Note:
    To convert a number into a string, you can also use concat.  eg
      (string s 20)(s (concat 123)) will convert numeric 123 into a
      string and assign it to s.  This is the same as (s (convert-to
      STRING 123))
    To convert to a list, use: (insert-object L 0 val1 val2 ...).  
      If (convert-to LIST val1 val2 ...)  is ever implemented, it would
      be the same as:
        (defun convert-to-list (int type)(val1 val2) ;; ...
	  { (list L) (insert-object L 0 (push-args 1)) L })
  See also: ask.

(defun name [arglist] [modifier(s)] pgm [name ...])

			    [TOKEN [([type] TOKEN)...] [TOKENs] pgm : zip]
  Define a function.  Multiple functions can be defined.
  Comments and whitespace have no performance or size penalty, so use
    them.
  You can optionally name the arg list.  
    ([type] name [dimension(s)] [name [dimension(s)]] ...) ...
    int, small-int and byte all mean NUMBER (since all numerics are
    promoted to NUMBER when passed).  Array subscripts are used to
    determine the dimension the passed in array - the first dimension is
    a placeholder (as in C).  Arg type is optional - if not used, no
    assumptions are made about the the arg (ie it will be type checked
    at runtime if needbe).  If an arg is typed, what ever is passed in
    is assumed to be of the correct type - it is not checked.
  Modifiers are used to put conditions on a function.
    Modifier : What It Does
    
-
--
HIDDEN Only functions defined after this one can reference it. MAIN This function will be executed when it is loaded. MAIN is a special function name. It defines a function that is executed at load time (the same as a function marked MAIN) and can not be called by anyone. Use MAINs to do things that only need to be done once before anything else is done (for example, initializing some variables). Use the modifier MAIN if you also want to be able to repeat things at other times. There is no limit on the number of MAIN functions or functions marked MAIN. MAINs are called in the order that they are defined. Functions marked MAIN are called alphabetically (for the purposes of the sort, functions named MAIN are treated as if their name really was MAIN and are sorted by address (ie first defined, first called)). For example: (defun foo { (msg "this is foo") } ; (foo) prints "this is foo" bar (int x y)(string s) ; bar has 3 args: 2 numbers and a string { (msg s) ; same as (msg (arg 2)) (msg (+ x y)) ; same as (msg (+ (arg 0)(arg 1))) } fred (z) { (msg z (arg 1)) } ; print the first and second args sam MAIN { (msg "sam") } ; sam is run at load time MAIN { (msg "MAIN is run only at load time") } ) Notes: You can not assign to an arg unless it is a pointer.

  There is a special case of defun that generates code and returns a
    pointer to that code.  These "anon" defuns are for passing code
    fragments to routines without having to go to the effort of thinking
    up a name for a routine.  {{ and }} are the symbols that delimit the
    code and can be used just about anywhere but are only useful as part
    of a function call.
    For example:
      1> (defun example (pointer defun code) { (code) })
      2> (example {{ (msg "example") }})
    Line 1 defuns a routine that takes a pointer to code and runs the
    code.  Line 2 shows how to use an anon defun in a call.  When line 2
    is run, "example" is printed out.
  Anon defuns can do anything defuns can (declare variables, make calls,
    etc) except name the arg list.  This means that you have to use the
    (arg n) notation when dealing with passed in args.  Also, a anon
    defun can NOT access variables declared in the defun it is in.  It
    can access global variables.
    For example:
      (defun
        foo
	{
	  (int x)
	  {{ (msg x) }}
	})
      is an error.

  See also: arg, pointer, the example pgms.
(done) [zip : zip]
  Exit smallest enclosing pgm.
  See also: halt.

(extract-element object-name n)

						    [LIST NUMBER : object]
						  [STRING NUMBER : STRING]
  Make a copy of the nth element of a list or string.
  This is the same as (atomize (extract-elements object-name n 1))
    except there is no atomize function.  For example, extracting a
    number from a list results in a number.  If you had used
    extract-elements, it would have returned a list with number in it.
  See extract-elements for how n can modified by the function.
  In the STRING case, this function is the same as
    (extract-elements string n 1).
  Examples:
    (extract-element "123" 1) => "2"
    (extract-element ["123" 4 5] 1) => 4
    (extract-element  [] n) => []
  See also:  extract-elements, insert-object, remove-elements,
    length-of, list.
(extract-elements object-name n z)
					       [LIST NUMBER NUMBER : LIST]
					   [STRING NUMBER NUMBER : STRING]
  Starting at element n, copy of z elements of a list or string to a new
    list or string (0 == first element)
  If (z <= 0) or (n > (length-of object)) or (object == []), returns [].
  If n or z is < 0 then the length of the object is added to them.
  If n > (length-of object), it is set after the last element of the
    object.
  If ask for more elements than are available, returns as many as can.
  Examples:
    (extract-elements "123" 1 1) => "2"
    (extract-elements ["123" 4 5] 0 2) => ["123" 4]
    (extract-elements ["123" 4 5] 1 1) => [4]
    (extract-elements [] n z) => []
  extract-elements also acts like Mock Lisp's substr:
    (extract-elements "foobar" 0 3) => "foo"
    (extract-elements "foobar" -1 1) => "r"
    (extract-elements "foobar" 0 -1) => "fooba"
    (extract-elements "foobar" 3 100) => "bar"
    (extract-elements "foobar" 50 100) => ""
  See also:  extract-element, insert-object, remove-elements, length-of,
    list.

(FALSE) [zip : BOOLEAN]

  The boolean constant FALSE.

(floc function-name) [TOKEN|STRING : BLOB] (floc function-name ()) [TOKEN|STRING : (function-name)] (floc function-name arg1) [TOKEN|STRING any : (function-name arg1)] (floc function-name arg1 arg2 ...)

		 [TOKEN|STRING any any ... : (function-name arg1 arg2 ...)]
  Return the address of or call a function.
  (floc function-name) returns the address of function-name.
  (floc function-name ()) calls function-name with no args.
  (floc function-name arg) calls function-name with one arg.
  (floc function-name arg1 ... argN) calls function-name with N args.

  A function is:
    An internal-function - one of:
      ask, concat, extract-element, extract-elements, insert-object,
      msg, remove-elements
    A program (something created with (defun)).
    The name of an external token (see the compiler "-t" option).

  The format of function-name is:
    A token (such as foobar).
    A string (such as "foobar").
    A function that returns a string (such as (foobar)).
    A string variable (such as (foostring)).

  Note that most of the keywords and functions in this list are not
    "real" functions - ie they have no address and can't be used in floc
    (the exceptions are the internal functions mentioned above).
  If using strings (variable or constant), you can only reference
    programs or tokens (ie no internal-functions).
  If given args, a function call is generated.  If you want to call a
    function that has no args, use () as the args list
    (eg "(floc "foobar" ())").
  If you want to use a string variable, the format is:
    (floc (string-var)) or (floc (string-var)([args]))
    The thing to note is that the string var has to be in parentheses
    (this is probably a bug).  At run time, the string is deferenced and
    its contents is used to identify the function.

  Example:
    (defun
      add (pointer defun plus) (x y)
	{ (msg x " + " y " = " (plus x y)) }
      add-two-numbers (int a b) { (+ a b) }
      silly-add (a b) { "three" }
    )
    (add (floc add-two-numbers) 1 2)	; 1 + 2 = 3
    (add (floc silly-add) "one" "two")	; one + two = three
  Example:
    (string name-of-two)
    (defun
      one { "two" }
      two { "this is a test" }
    )
    (msg (floc (one)()))		;; this prints: this is a test
    (name-of-two "two")
    (msg (floc (name-of-two)()))	;; this also prints: this is a test

  Notes:
    (floc foobar) returns the address of a already defined function.
      Its an error if foobar is not defined in the same file (or any
      included files) as the floc.
    The order in which the address is resolved (at compile time) is:
	Internal-functions (see above).
	An already defined program.
	An external token or a pgm defined after the floc.
	String (constant or variable).  Resolved at run time.
      Given these rules, you should be careful about name overloading.
    (floc "foobar"):  The location of foobar is resolved at runtime.
      This is slower and generates more code but always works (if foobar
      really is a function and not a typo).  Note that this method does
      not work for internal-functions or external tokens that don't also
      have a name list for the tokens.
  See also: loc, defun, pointer, qsort (in the Example Programs below)

(for init test inc body)

		[block, BOOLEAN, block, block : FALSE (unless break used)]
  A for next loop:  perform init once.  Perform body and inc while
    test is TRUE.  This is equivalent to:
	init (while test { body inc })
  break will terminate the loop and continue will jump to inc.
  For example:
    (int j)
    (for (j 1) (< j 6) (+= j 1)
    {
      (if (== j 3)(continue))	; skip 3
      (msg j)
    })
    prints out: 1 2 4 5
  See also: break, continue, while.

(goto label) [TOKEN : zip]

  Even if you dare, use this with care.
  Don't cross defun boundaries.
  See also: label.

(halt) [zip : zip]

  Halt the Mutt machine.  This stops any program that is running and
    returns control to the application.
  See also: done.

(if test true [false]) [BOOLEAN, block, block : last block executed]

  test and true must exist even if blank (ie "{}" or "()").
  eg (if (== foo bar) (msg "foo == bar") (msg "foo != bar") )
     (== foo bar)(if () (msg "foo == bar"))
  The C conditional expression "condition ? true : false" can be mimiced
    with (if condition true false).
(include filename) [TOKEN|STRING : zip]
  Compile another file.  After filename is compiled,  compiling  resumes
    at the line after the one that contained the include.
    ie  "(include foo.mut)" is the same as "(include foo ; doo daa"
(insert-object object-name n new-object ...)
					[LIST NUMBER any [any ...] : LIST]
			      [STRING NUMBER STRING [STRING ...] : STRING]
  Insert an object into another object after the nth element.
  To prepend an object, use n == -1.
  You can put the following types into a list: STRING, NUMBER, LIST.
    Mix and match as much as you like.
  Example:
    (list L)
    (insert-object L 0 "123" 5 6) => ["123" 5 6]
    (insert-object L 0 4)         => ["123" 4 5 6]
    (insert-object L 555 7)	  => ["123" 4 5 6 7]
  See also:  extract-element, remove-elements, length-of, list, string.
(int name [name ...]) [TOKEN [TOKEN ...] : zip]
  Evaluation: var					  [TOKEN : NUMBER]
  Assignment: (var value)			   [TOKEN NUMBER : NUMBER]
  Create 32 bit integer variables.
  The range of a int is [-2,147,483,648 : 2,147,483,647].
  See also: bool, byte, small-int, string, array.
(small-int name [name ...]) [TOKEN [TOKEN ...] : zip]
  Evaluation: var					  [TOKEN : NUMBER]
  Assignment: (var value)			   [TOKEN NUMBER : NUMBER]
  Create 16 bit integer variables.  The only advantage of using small-int
    instead of int is that small-ints require less memory to store (and
    it might take less time to store and retrieve them).
  The range of a small-int is [-32,768 : 32,767].
  Note that a NUMBER may not fit in a small-int.  If not, the number
    will be truncated to fit.
  See also: bool, byte, int, string, array.

(label label-name) [TOKEN : zip]

  The target of a goto.
  eg (label foo)(goto foo) creates an infinite loop.
  See also: goto.
(length-of name) [any : NUMBER]
  Return the length of a object.
  Type		Length
  

STRING Number of characters in the string. eg "foo" => 3. LIST Number of elements in the list. eg ["one" 2 "three"] => 3. See also: list, insert-object.
(list name [name ...]) [TOKEN [TOKEN ...] : zip]
  Create one or more list variables.  If in a defun, the variable is
    local to that defun, otherwise it is global.
  Example:
    (list L) creates a list named L.
    (insert-object L 0 "123" 5 6) puts 3 elements in to L:  ["123" 5 6]
  See also:  string, extract-element, insert-object, length-of,
    remove-elements.
(loc var) [TOKEN : BLOB]
  Return the address of a variable.  In this way you can modify the
    variables you pass to functions.
  loc works on the following types:  byte, int, small-int, bool and arrays.
    Strings and lists not supported (yet).
  Example:
    (int a b c d)	; 4 ints in row.  Same order as (array int a 4)
    (defun
      MAIN
      {
	(a 123)(foo (loc a))(msg "a = " a "   b = " b)
	(bar (loc a))
      }
      foo (array int x 2)  ; first element of x maps to a
      {
	(msg "(x 0) = " (x 0))	; display the value of a
	(x 0 456)		; set a to 456
	(x 1 111)		; set b to 111
      }
      bar (pointer int x)
	{ (msg "x = " (x)) }	; display the value of a
    )
    When this is run it produces:
	(x 0) = 123
	a = 456   b = 111
	x = 456
  See also: arg, defun, floc, pointer.

(msg stuff) [any class ... : STRING]

  Prints a message.  The list is concatenation of the arg list.
  Returns the entire message.
  eg (msg "foo = " foo)
  Note: (msg) is the same as (msg "").

(nargs) [zip : NUMBER]

  Return the number of parameters passed to the function.
  eg (foo 1 "two" (three)) has 3 arguments and (nargs) returns 3.
  See also: arg.
(not value) [BOOLEAN : BOOLEAN]
  Negate value.
  For example: (not (== foo 1)) returns TRUE if foo not equal to 1.
(novalue) [zip : VOID]
  A way to make sure a function returns VOID.

(or value ...) [BOOLEAN [BOOLEAN ...] : BOOLEAN]

  Logically or a bunch of things.
  The first TRUE value will terminate (ie the rest of the or will
	not be evaluated).  eg (or (beginning-of-line) foo)
  For example:
    (or (foo) TRUE (bar)):  If (foo) returns TRUE, the or returns TRUE
    and nothing else is done.  If (foo) return FALSE, the or returns
    TRUE anyway (because of the TRUE).  In all cases, bar is never
    called.
  See also: and.

(pointer type var-names) [TOKEN TOKEN [TOKEN ...] : zip]

  Declare pointer vars.  You can create pointers to byte, small-int,
    int, bool, and defun (functions).
  Pointers to data:
    To get what a pointer points to: (pd)
    Assignment: (pd location) where location is a pointer
      arg or something returned by loc or floc.
  Pointers to functions:
    (pf) calls function pointed to by pf with no args.
    (pf arg1 ... argn) calls pf with n args.
  See also: defun, floc, loc.
(push-arg exp) [anything : anything]
  Push a arg onto the function call list.  Useful when you need to call
    a function and you don't what args you need to call it with at
    compile time.
  Example:
    (int j)
    (foo "arg 1"
      (for (j 0) (< j some-num) (+= j 1) (push-arg (peek j)))
    )
    This will call foo with one or more args:  "arg 1" and some-num of
      whatever peek returns.
  See also: push-args.
(push-args n) [NUMBER : last arg]
  Push all the args from n back on the stack.  The first arg is 0.
  For example: If max is a function that takes the maximum of all its args,
    and foobar is a function that takes a string and a list of numbers and
    you want to find the maximum of those numbers, you could:
    (defun foo (string s) { (int m) (m (max (push-args 1))) })
  Notes:
    push-args can only be used with defined functions plus concat and msg.
      For example (+ (push-args 3)) is an error, (msg (push-args 3)) is OK.
    If n is greater than the number of args, no args are pushed and no
      error is generated.
    You can treat push-args like a run-of-the-mill arg - eg (foo 123
      (push-args 2) "hoho") and (foo (push-args 4) (push-args 2)) are
      OK.
  See also: push-arg.

(remove-elements object n z) [LIST|STRING NUMBER NUMBER : VOID]

  Remove z elements of a object starting at the nth element.
  If (n >= (length object)), nothing happens.
  (remove-elements [] n z):  [].
!!!??? other magic done to n and z?
  Examples:
    (remove-elements [1 2 3] 0 1)     => [2 3]
    (remove-elements [1 2 3] 1 100)   => [1]
    (remove-elements [1 2 3] 100 100) => [1 2 3]
  Notes:
    This doesn't work on string constants (doesn't make sense either).
      ie (remove-elements "123" 1 1) doesn't work.
      (text "123")(remove-elements text 1 1) does.

(string name ...) [TOKEN [TOKEN ...] : zip]

  Evaluation: var					  [TOKEN : STRING]
  Assignment: (var value)			   [TOKEN STRING : STRING]
  Create some strings.  String length is variable ie the string will
    resize it self to hold whatever you want to put in it.
  Example:
    (string foo)
    (foo "this is a test")
    (msg foo)		;; this will print "this is a test"
  See also:  list, extract-elements, insert-object, length-of,
    remove-elements.
(switch value value block [value block ...] [default block]) [NUMBER|STRING|BOOLEAN, same, block, same, block ... : last block executed]
  Get a value.  Scan down the list until a matching value is found and then
    execute the next block and exit the switch.
  If no match is found, the default block is executed (if it exists).
  All values must have the same class.
  eg
    (switch (extract-elements (ask "Is the moon made of green cheese? ") 0 1)
      "y" (msg "Not according to current scientific thought.")
      "n" (msg "Probably the case.")
      default (msg "Burp.")
    )
  See also: cond

(TRUE) [zip : BOOLEAN]

  The boolean constant TRUE.
  Use this for the default case in cond.

(while test body) [BOOLEAN, block : FALSE (unless break used)]

  Perform body while test is TRUE.
  For example: (int j) (j 0) (while (< j 5) { (msg j) (+= j 1) } )
    will print out: 0 1 2 3 4.
  A do..while loop can be constructed like so:
	(while {body test} ())
  You can use break to get out of the loop or continue to move back to
    test.
  See also: break, continue, for.

====================================================================

			 How args are passed
==================================================================== All args are evaluated before being passed. bytes, small-ints and ints
  are converted to NUMBER.
Args are passed by value and reference. Value means a copy of the arg
  is pushed on the stack and changes to it will not be reflected  in the
  original.  When  something  is passed by  reference,  a pointer to the
  original is pushed on the stack and changes will be to the original.
- bools, numbers, voids: value. - arrays, blobs, strings, lists: reference.

====================================================================

			   Example Programs
====================================================================
	; Factorial the recursive way
(const NUMBER 0x03) (defun
  fact	;; the recursive part.  input: x  output: x!
  {
    (if (== (arg 0) 0) 1		; 0! = 1
      (* (arg 0) (fact (- (arg 0) 1))))	; x! = x * (x-1)!
  }
  fact1 (int x)		;; same as fact but with named args
  {
    (if (== x 0) 1		; 0! = 1
      (* x (fact (- x 1))))	; x! = x * (x-1)!
  }
  !	;; the main routine
  {
    (int x)
    (x (convert-to NUMBER (ask "Take factorial of: ")))
    (msg x "! = " (fact x))
  }
  MAIN { (!) }		;; (! 5) produces "5! = 120" 
)

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ (const NUMBER 0x03) (defun square MAIN ; print a table of squares {

  (int foo max)
  (max (convert-to NUMBER (ask "Max = ")))
  (foo 1)
  (while (<= foo max) { (msg foo "\^2 = " (* foo foo)) (+= foo 1) })
}) ; (square 3) produces ; 1^2 = 1 ; 2^2 = 4 ; 3^2 = 9 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ; Good ol towers of hanoi
Usage
(hanoi <n>) where n is the number of discs
(const NUMBER 0x03) (defun
  print-move (from to) { (msg "Move Disk From " from " To " to) }
  transfer (from to via)(int n)
  {
    (if (== n 1)(print-move from to)
    {
      (transfer from via to (- n 1))
      (print-move from to)
      (transfer via to from (- n 1))
    })
  }
  hanoi MAIN
    { (transfer "A" "B" "C" (convert-to NUMBER  (ask "n = ")))(msg "done.") }
) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
tobase(n,base)
convert n (base 10) to base. eg (tobase 10 16) => "A"
; C Durland

(defun

  mod (int n base)	; n mod base = n - (n/base)*base
	{ (- n (* (/ n base) base)) }
  tobase (int n base)
  {
    (if (< n base) (extract-elements "0123456789ABCDEF" n 1)
      (concat
        (tobase (/ n base) base)	; tobase n/base base
	(tobase (mod n base) base)	; tobase (n mod base) base
      )
    )
  }
) (const NUMBER 0x03) (defun
  MAIN
  {
    (msg (tobase
	(convert-to NUMBER (ask "n = "))
	(convert-to NUMBER (ask "base = "))))
  })
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ (defun
  sort (array int list-to-sort 1)(int n)    ; shell sort an array of n ints
  {
    (int gap i j t k)

    (gap (/ n 2))
    (while (> gap 0)
    {
      (i gap)
      (while (< i n)
      {
	(j (- i gap))
	(while (and (>= j 0) (> (list-to-sort j)(list-to-sort (+ j gap))))
	{
	  (k (+ j gap))(t (list-to-sort j))
	  (list-to-sort j (list-to-sort k))(list-to-sort k t)
	  (-= j gap)
	})
        (+= i 1)
      })
      (/= gap 2)
    })
  }
) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	; Quick sort.  From Horowitz & Sahni pg 347
	; Sort list[m..n] into ascending order

	; swap is a routine that interchanges list[a] with list[b]
	; cmp compares list[a] with list[b] and returns:
	;    negative if list[a] < list[b]
	;    positive if list[a] > list[b]
	;    zero     if list[a] = list[b]
(defun
  Qsort (list-to-sort)(int m n)(pointer defun swap cmp)
  {
    (int i j)

    (if (>= m n) (done))	;; end the recursion
    (i m) (j (+ n 1))
    (while TRUE
    {
      (while { (+= i 1)(and (<= i n) (< (cmp list-to-sort i m) 0)) } ())
      (while { (-= j 1)(> (cmp list-to-sort j m) 0) } ())
      (if (< i j) (swap list-to-sort i j) (break))
    })
    (swap list-to-sort m j)
    (Qsort list-to-sort m (- j 1) swap cmp)
    (Qsort list-to-sort (+ j 1) n swap cmp)
  }
)

	; swap and cmp routines for arrays of ints
(defun
  swap (array int list-to-sort 1)(int a b)	; swap 2 elements
  {
    (int tmp)
    (tmp (list-to-sort a)) (list-to-sort a (list-to-sort b))
    (list-to-sort b tmp)
  }
  cmp (array int list-to-sort 1)(int a b)	; compare 2 elements
    { (- (list-to-sort a) (list-to-sort b)) }
)

; (array int list-to-sort 100) ; (Qsort list-to-sort 0 n (floc swap) (floc cmp))

======================================================================

			   Notes and Tricks
======================================================================
  leading zero if it is less than 10.
    (int n)(string s 20)
    (n (convert-to NUMBER (ask "n = ")))
    (s (concat (if (< n 10) ("0")("")) n))
  This trick also works in msgs, etc.
  So, (foo { (msg "set foo to 123") 123 }) is the same as
    (msg "set foo to 123") (foo 123).

======================================================================

			  The Mutt Compiler
======================================================================
   Since Mutt is a compiled language, you'll need to compile the
programs you've written before you can run them. To do this use MC2, the Mutt2 Compiler. Type "mc2 filename". filename is assumed to have a .MUT extension (ie you don't have to type it). The compiler produces an output file in the current directory with the name name.MCO (where name is the same base name as filename).
  MC2 options:
    -I directory-name
       An alternate directory for include files.  For example, if
	 foo.mut is in directory fred and contains (include sam.mut) and
	 sam.mut is in directory /bar then you need mc -I/bar foo.
    -l
       Produce a list file showing the compiler output (name.LST).
    -t tname
       Use external token file tname.TOK.  This a code crunching
	 option.  Useful when Mutt is used as an embedded language.
	 Normally, when MC can't resolve a function call (to an external
	 function), the name is looked up at runtime.  This has two
	 disadvantages - the name takes up space and it takes time to
	 look up the name.  The token file tells MC where the external
	 functions are located and avoids these problems.  It is only
	 used at compile time.
    -v
       Display the version of the compiler.

   You can run your compiled program in one of two ways:  If Mutt is
embedded in another program, read the documentation on that program to find out how to load and run Mutt programs. If you are using Mutt standalone (using just the functions contained in this documentation) then use MM2 (the Mutt2 Machine). Type "mm2 fname" where fname is the name of the file you compiled.

For example, to compile and run the factorial program listed above:

  mc2 fact			; type this to compile the fact program
  Mutt2 compiler 10/16/91
  Errors: 0  Warnings: 0. Code size = 99 bytes.

  mm2 fact			; type this to run the fact program
  Take factorial of: 5		; user is prompted for a value and types 5
  5! = 120			; the answer is printed out

======================================================================

			       Gotchas
======================================================================
  but may not do what you think.
     (const foo 123)
     (defun foo
     {
       (int foo)
       (foo foo)	; what does this line really do???
     })

====================================================================== ======================================================================


HomePage | RecentChanges | EditorIndex | TextEditorFamilies | Preferences
Edit text of this page | View other revisions
Last edited February 29, 2016 8:07 am (diff)
Search: