This is the documentation for the clc compiler, which takes a sort of high level language and converts it into the assembly language understood by the cas assembler. An example usage is
./clc Examples/minsky.cl
./cas Examples/minsky.s
and Examples/minsky.cl
is an example program written in the high-level
language.
This document covers the clc compiler as it existed on October 26, 2017.
First and foremost, you need to realise that clc is not a well-written robust compiler, so the input that it can recognise is very particular.
clc parses one line at a time: there is no tokenisation. Whitespace is generally ignored, and the compiler supports C-style // comment lines.
In the following, italics represent an abstraction which you need to replace with something concrete.
Variables in the language are 8-bit and signed. To declare a variable, use the syntax:
var name;
Technically, name can be any non-whitespace characters, but I would stick with the C-style variable naming conventions. Example:
var x;
var y;
var i;
var tmp;
The language only supports one operator on the right-hand side of an assignment operation. Here is the available syntax:
name= name2;
name= constant;
name= constant op constant;
name= name2 op constant;
name= constant op name2;
name= name2 op name3;
where the names are variables names and the constants are decimal constants;
The available operators are +
, -
, &
, |
and ^
and are the same as the C operators. There are no multiply or divide operators.
Because I needed a 4-bit right shift and this is easy to do on a 4-bit CPU, there is this syntax:
name= name2 >> 4;
This syntax is supported:
name++;
If you want your program to stop in the csim simulator, or go into an infinite loop on the real hardware, use this line:
exit;
which inserts an infinite loop into the output.
The language supports if statements that are on one line:
if (name1 op name2) {
where the names are variables or numeric constants and the operations
include ==
, !=
, <
, >
, <=
and >=
.
This has the syntax:
} else {
and obviously must come after an if statement.
There is a while loop with the syntax:
while (name1 op name2) {
where the names are variables or numeric constants and the operations
include ==
, !=
, <
, >
, <=
and >=
.
There is a second syntax for an infinite loop:
while (1) {
A closed curly bracket on a line by itself ends the most recent if statement or while loop:
}
The compiler keeps a stack of if statements and while loops, so that you can nest them.
To break out of a loop, use the syntax:
break;
just like the C command.
The putchar() syntax allows you to print out an ASCII character:
putchar(69);
putchar(name);
putchar('x');
putchar('\n');
where name is a variable and x is a single character. Example:
var x;
x= 65;
putchar(x);
will print out an uppercase 'A'.
The prhex() and prhexn() syntax allows you to print out a variable as two hex digits:
prhex(name); // Two hex digits, nothing else
prhexn(name); // Two hex digits and a newline character
Note that prhex() takes nine instructions and prhexn() takes eleven instructions, so use these operations sparingly!
A function is declared with the syntax:
function name(param) {
where the name is compulsory, but the single parameter is optional.
A function is ended with a closed curly bracket on a line by itself:
}
There is no recursion in the language: you can only call a function once at a time. There must be a function called main in your program, as the compiler insert a jump to main as the first instruction in the assembly output. Due to the CPU's architecture, there can no more than sixteen different calls to one function.
The parameter named in the function declaration is visible as a local variable with that name in the function.
Returning from a function is done with one of these two lines:
return;
return(name);
where name is a variable defined in the function.
Here is a full example function:
function increment(x) {
x= x + 1;
return(x);
}
A function call can be done with an optional argument which is copied into the function parameter, and optionally with an assignment statement to save the return value. Thus, there are four possible syntax variants:
function();
function(arg);
name= function();
name= function(arg);
and arg has to be a variable not a constant.
Finally, the compiler is very stupid one-pass compiler. It doesn't do any optimisations, so there will be some space inefficiency in the code that it produces.