Next: Running the Compiler Up: Compiling for Computational Origami Previous: The Compiler

The Input Language

The language understood by the compiler is a high level, procedural language. It supports a single data type, an array of bits with a predetermined size. Variable names consist of an arbitrary sequence of the characters A-Z, 0-9, and _. The first character must be a non-digit. Variables are used in the form var<expr>. When declaring a variable, expr is an integer defining the number of bits in the array. These bits are numbered starting with zero. Thus a declaration for a<5> would create the variable a with bits numbered 0, 1, 2, 3, and 4. When referencing a variable, expr can be a more complex expression indicating the particular bits that are to be referenced. A single integer (representing a particular bit), a range of integers (denoted num:num), or a sequence of these separated by commas are valid bit specifiers. For example, the reference b<2,5:7,10:8> would refer (in order) to the bits 2, 5, 6, 7, 10, 9, and 8 of the variable b. In addition, a variable with no <expr> present can be used as shorthand for all bits in the array, starting with bit 0.

Variables are dynamically scoped, and all functions are call-by-value (it is impossible for a function to mutate one of its parameters).

A program consists of a set of (optional) function declarations followed by the main body of the program. A function declaration is specified as:

function(var<num>, var<num>, ...)
{

}

where function is the name of the function and var<num> ... is a set of formal arguments.

A statement can be a declaration or an assignment. Each statement must end with a semicolon (``;''). The following statements are supported:

DECL var<num> ...

DECL declares one or more variables so that they can be used later in the program. If more than one variable is declared, they are separated by commas. A DECL statement can occur anywhere in the program, but must preceed the first usage of the declared variable(s). Variables declared with DECL have no initial value, and an error will be generated if a variable is referenced before a value is assigned to it.

Example: DECL sum<8>, opcode<2>;

INPUT var<num>@bitpos ...

INPUT declares one or more variables that will be used as inputs to the origami array. These variables can be used in exactly the same manner as variables declared with DECL, but they are guaranteed to have an initial value. bitpos is either a single integer denoting the input position to be assigned to bit zero of this variable (with subsequent input positions being assigned to subsequent bits), or a list of comma separated integers enclosed in square brackets (``['' and ``]'') denoting explicit input positions for each bit. If the second form is used, the number of integers between the brackets must equal the number of bits in the bit array. INPUT statements may only appear in the main body of the program; they may not appear in function declarations.

Example: INPUT value1<16>@10, value2<6>@[40,42,44,46,48,50];

OUTPUT var<num>@bitpos ...

OUTPUT declares one or more variables that will be used as outputs from the origami array. These variables may only be assigned to, and may only be assigned to once. bitpos is declared in exactly the same manner as in INPUT above. OUTPUT statements may only appear in the main body of the program; they may not appear in function declarations.

Example: OUTPUT result<16>@10, overflow<2>@[5,9];

varref ... = expr

Assignment statements compute arbitrary expressions and assign the results to one or more variables. A varref is a set of comma separated variable references as described above. For example, a<2> and b<1:3>, c<5>, d are valid variable reference lists for the left hand side of an assignment statement. The expr can be a variable reference (not a variable reference list) or a function call. The number of bits in the result of the right hand side expression must agree with the number of bits in the left hand side variable reference list.

Function calls are specified as name(arg, arg ) where each arg is a variable reference or function call. The arguments do not have to match up variable for variable with the variables declared in the function header. However, the number of bits must agree. The bits are assigned, in order, starting from the first bit of the first arg and proceeding to the last bit of the last arg. Thus, if function B takes the parameters a<2>, b<2>, and is called with B(f<1>, g<0:1>, h<5>), bit 1 of f will be assigned to a<0>, bit 0 of g will be assigned to a<1>, bit 1 of g will be assigned to b<0>, and bit 5 of h will be assigned to b<1>.

Calls may also be made to routines defined in libraries. A library consists of a set of precomputed or hand-compiled origami arrays with fixed input and output positions. They are useful because in many cases prepackaged routines can be smaller and more efficient than routines generated by the compiler. In addition, since there are no intrinsic functions, library routines are the only way to perform any computation.

Example: sum<1>, carry = ADD(a<0>, b<0>, carry);

RETURN varref ...

RETURN is used to return a set of bits from a function to the calling routine. It takes a list of variable references (as described under the assignment statement above) and returns the bits in the order specified.

Example: RETURN sum<0:7>, carry;

Following is a short program that, given the basic logic operations ADD (half adder) and OR from a library, will add two 4-bit numbers together.


FULLADDER(a<1>, b<1>, c<1>)
{
    DECL sum<1>, carry<1>, sum2<1>, carry2<1>, carryout<1>;

    sum, carry = ADD(a, b);
    sum2, carry2 = ADD(sum, c);
    carryout = OR(carry, carry2);

    RETURN sum2, carryout;
}

INPUT a<8>@6, b<8>@14;
DECL sum<9>, carry<1>;
OUTPUT result<9>@10;

sum<0>, carry = ADD(a<0>, b<0>);
sum<1>, carry = FULLADDER(a<1>, b<1>, carry);
sum<2>, carry = FULLADDER(a<2>, b<2>, carry);
sum<3>, carry = FULLADDER(a<3>, b<3>, carry);
sum<4>, carry = FULLADDER(a<4>, b<4>, carry);
sum<5>, carry = FULLADDER(a<5>, b<5>, carry);
sum<6>, carry = FULLADDER(a<6>, b<6>, carry);
sum<7>, sum<8> = FULLADDER(a<7>, b<7>, carry);

result = sum;



Next: Running the Compiler Up: Compiling for Computational Origami Previous: The Compiler


Robert French