CIT 594 The "Bugs" Language
Spring 2008, David Matuszek

This is a brief introduction to the "Bugs" language. "Bugs" is a language that I invented for the purposes of this course (CIT594 in 2008), and that you will be implementing.

Bugs is a special-purpose language whose raison d'Ítre is simply to draw pretty patterns. A program in the language controls one or more "bugs" that move around the screen, optionally drawing colored lines as they go. While it is possible to use the language to do general computations, that isn't a very good idea.

Bug World

Bugs live and move about in a square. The size of the square is 100 units wide by 100 units high. Any bug whose x and y coordinates are both between 0.0 and 100.0 will be (at least partially) visible on the screen.When this square is displayed on the computer screen, the window may be any number of pixels square, but from the program's point of view, the top and left edges are always 0.0, and the bottom and right edges are both at 100.0. As usual for graphics programs, the x coordinate increases to the right, and the y coordinate increases downwards.

Bugs are not constrained to stay within this square; it's just that any bug that wanders outside it will not be visible on the screen. Hence, most programs should try to keep bugs within the square.

Basic structure

Bugs is "slightly" object-oriented. That is, there is an (optional) "Allbugs" class that contains variables and functions available to all bugs. The complete program consists of one or more "bugs" that inherit these variables and functions, and in addition can define their own variables and functions.

The Allbugs class looks like this:

Allbugs {
// zero or more variable declarations
// zero or more function definitions
}

Variables declared in the Allbugs class act like Java static variables; that is, there is only one copy of each such variable, and it is shared by all bugs.

Structure of a Bug

Each Bug has a name and up to four parts:

  1. Some number (zero or more) of variable (var) declarations.
  2. An optional initialization block.
  3. A required "main program".
  4. Some number (zero or more) of functions.

A Bug definition looks like this:

Bug sally {
// zero or more variable declarations
// an optional initialization block
// one or more commands
// zero or more function definitions
}

The above (if the comments are replaced by actual code) defines a Bug named "sally". In this language, only Allbugs defines a class, while Bug defines an object of that class, albeit one with its own unique variables and functions.

Variable declarations

A variable declaration is simply the keyword var followed by a list of variable names, for example,

var distance, goal, danger

Variable names begin with a letter and may consist of letters, digits, and underscores. All variables hold real (double) numbers, and all numbers in a Bugs program are real numbers. Numbers written as integers are still real numbers; for example 5 is the same as 5.0.

There may be multiple var declarations in a Bug. There is no difference between declaring all the variables in one var declaration or in multiple var declarations.

There are no private variables. A bug may refer to its own variables by name, and it may refer to another bug's variables with dot notation, for example, wilbur.goal.

Every bug has three predefined variables: x, y, and angle. The x and y variables specify the bug's location, while the angle variable tells, in degrees, which way it is facing. An angle of zero means the bug is facing right (due east); positive values of angle are counterclockwise, so that north is 90, west is 180, and south is 270.

The initialization block

The initialization block, if present, contains one or more commands, and looks like this:

initially {
// one or more commands }

Only Bug definitions, not the Allbugs class, can have an initialization block. However the initialization block of a Bug can use variables and functions from both the bug being defined and the Allbugs class.

Commands

Commands are described in detail below. This part of a Bug definition constitutes the "main program" part of this bug.

The command part of a Bug is not set off by any special keyword; it is simply the sequence of commands following the initialization block (if there is one) and before the first function definition (if any functions are defined).

Function definitions

Functions defined in Allbugs are available to every bug, and behave exactly as if they were defined separately in each bug. This means, in particular, that if a bug uses a function defined in Allbugs, that function can use variables and functions defined in the bug. (Any reference to a variable that has not been declared, here or elsewhere, will result in a runtime error.)

Functions defined in an individual bug are private to that bug, and cannot be called from any other bug. However, as discussed above, functions defined in Allbugs act as if they were defined in the individual bug.

A function definition looks like this:

define functionName using parameter1, ..., parameterN {
// zero or more local variable declarations
// one or more commands
}

If the function has no parameters, the keyword using should be omitted. Parameters and local variables are available only within the function, not from outside it.

Within a function, a statement of the form return expression may be used. All functions return values, and the expression part is mandatory. If the end of a function is reached without encountering a return statement, a value of 0.0 is returned.

Commands

Commands are divided into two groups, "actions" and "statements." The distinction is that an action causes the bug to do something visible on the screen, and these actions must be coordinated with the actions of other bugs. A statement, on the other hand, is a purely computational step.

Expressions

In the Bugs language, all values are kept as double values. A number may be written with our without a decimial point, but may not begin with a decimal point.

The usual four arithmetic operations--add (+), subtract (-), multiply (*), and divide (/)--are provided, with the usual precedences. Parentheses may be used. Function calls may be used in an expression, with the same syntax as in C.

There are no boolean values in the Bugs language. Numbers "close to" zero are considered to be false, and all other numbers are considered to be true. Conventionally, the number 1 is used when a true value is required. With this representation,

These all work when "true" is represented by the number 1, but may not work for other nonzero numbers.

The six standard comparison operators-- <, <=, = (not == !), !=, >, and >= --are also provided. Each returns either 0 (false) or 1 (true) as a result. Consequently, run-on comparisons such as x < y < z are legal but unlikely to give the desired result. In order to simplify "boolean conditions", = will return 1 (true) if the numbers being compared are within 0.001 of each other, and != will return 0 (false).

There are two built-in functions: direction(bugName) returns the angle from this bug (that is, the bug calling the function) to the named bug (0.0 being due east), and distance(bugName) returns the distance from this bug to the named bug. (Hence, if this bug executed the two commands angle = distance(thatBug) and move distance(thatBug), it would end up directly "on top of" that bug.)

Statements

An assignment statement consists of a single variable, followed by an equals (=) sign, followed by an expression. For example,

x = 2 * (x + 1)

There is only one kind of loop, loop {...}, which can contain any number of commands, plus zero or more exit if condition lines. For example,

loop {
move 10
exit if x > 100
turn 90
move 10
exit if y < 0
turn -90
}

A switch statement consists of the word switch and braces containing some number of case groups. For example,

switch {
case x < y
x = y
case x < z
temp = x
x = z
case 1 // 1 means "true" z = y }
The first case with a "true" (nonzero) condition is the one executed. Unlike C or Java, there is no break statement, nor is there any need for one; at most one case will be executed. (If no case condition is met, the statement has no effect.)

There is no if statement, but if c then do_x else do_y can be represented as

switch {
case c
do_x
case 1 do_y }

The do statement consists of the word do followed by a function call; the result returned from the function is discarded.

A color statement consists of the word color followed by a color name, such as red or black. This statement changes the color that this bug draws in as it moves. Color names include the fourteen defined in java.awt (but in lowercase and camelCaps), plus whatever other colors you wish to define. The word none acts as an additional color name.

As in C or Java, a function call may also be used as a statement; any result returned by the function is ignored.

The return statement was described earlier, and may only be used within a function definition.

Actions

An action is a command that results in a visible change on the computer screen.

The turn expression action causes the bug to turn expression degrees counterclockwise from its current angle.

The turnto expression action causes the bug to turn to expression degrees, measured counterclockwise from due east.

Both turn and turnto may take a value less than zero or more than 360.0, and adjust it to be within this range. Both actions will also set the bug's angle variable to a number in the range 0.0 to 360.0.

A bug's angle variable can be set directly by an assignment statement; this also will adjust the value (if necessary) to be between 0.0 and 360.0. Such an assignment does not count as an "action," and its effect will not be visible on the computer screen until the next action occurs.

The move expression action causes the bug to move forward, in the direction it is facing, expression units, where a "unit" is 1/100 of the visible window size. The bug draws a line as it goes, in the bug's current color (unless that color is none).

The moveto expression_1, expression_2 action causes the bug to move to position (x, y) = (expression_1, expression_2), drawing a line as described in move. If both expressions are in the range 0.0 to 100.0, the bug will be visible in the window. This action changes the bug's x and y variables, but does not change the angle the bug is facing.

As with angle, the bug's x and y variables can be set with assignment statements, but this will not be visible on the screen until the next action occurs.

Finally, the line x1, y1, x2, y2 action draws a line from (x1, y1) to (x2, y2) in the bug's current color. (If the color is none, nothing is drawn.) This action really doesn't fit the "bugs theme," but is provided simply as a convenience to the programmer.

Layout and comments

In the Bugs language, every statement and every variable declaration goes on a separate line. An open brace, {, always ends a line; a close brace, }, always goes on a line by itself. switch statements must be laid out as in the example. Blank lines, and lines containing only comments, are ignored.

Comments are as in Java.

Good indentation is recommended, but not required by the language.

Execution

Execution of a Bugs program proceeds as follows:

First, the initialization block of each bug is executed. Normally, this code should at least set the position and angle of the bug on the screen. If these variables (x, y, and angle are not set, they default to 0.0. Initialization blocks are executed once and once only. With multiple bugs, there is no guarantee in which order the initialization blocks will be executed.

After initialization, the program goes into an infinite loop, as follows:

The "main program" part of each bug is executed, up to and including an action command. Upon reaching an action command, the bug pauses execution until every other bug has also executed one action command. At that point, all the various actions are reflected on the screen, and there is a brief pause (a fraction of a second).

Once the new screen image has been displayed, each bug continues from where it left off, and again computation continues until all bugs have performed another action.

Although there is no guarantee that the bugs will execute in any particular order, the programmer can rely on their being executed in the same order during each execution cycle.

Thus, all bugs will appear to the user to be moving simultaneously. The programmer can keep the bugs "in sync" by careful attention to when actions are performed.