Compiler “ramc-ram”
RAM has a very simple assembler-like language, consisting of direct and indirect reading/writing from/to registers or input/output tape. Also, there are three control-flow instructions.
Source code files end with .ram
extension; compiler output uses extension .bram
.
Language syntax
A program written for RAM consists of two sections, which can be intermixed and repeated in any order, but the preferred order is as follows:
INPUT section
INSTRUCTIONS section
Input section
The INPUT
section contains definitions the content of input tape - one or more lines in the form:
<input> ITEMS
where ITEMS
is a space-separated list of inputs. Each input is one word - it might be any number or string. Strings must be in quotes - single ('
) or double ("
).
For example, the input section might be:
<input> 1 2 3 'hello' 'world!'
In this case, there are five inputs: numbers 1,2,3, then word “hello” and the last one is “world!”. Note floating-point numeric values are not supported.
Instructions section
There exist many variations of RAM instructions, unfortunately, the syntax is not very unified. The reason might be that RAM is not a real machine.
Each instruction must be on a separate line, in the following form:
[LABEL:] INSTRUCTION [; optional comment]
Each instruction position can be optionally labeled with some identifier (LABEL
field), followed by a colon (:
) character. The labels can be then referred to in other instructions.
Comments can be one-line or multi-line. One-line comments begin with a semicolon (;
), hash sign (#
), double-dash (--
) or double-slash (//
). A one-line comment continues to the end of the line. Multi-line comments start with /*
characters and end with */
characters. In-between there can be multiple lines of text, all treated as comment.
An instructions consists of the operation code, optionally followed by an operand separated with at least one space (
), but not with a newline.
Operation code is expressed as an abbreviation of corresponding operation (e.g. SUB
for SUBtraction). An operand can be one of three types: constant (=i
), direct operand (i
), where i
specifies the register index on tape and indirect operand (*i
), where the address of operand specified is stored in register Ri.
The following table describes all possible instructions, usable in the RAM simulator:
Instruction | Constant (=i ) | Direct (i ) | Indirect (*i ) |
---|---|---|---|
READ | Ri ← next input | ||
WRITE | output ← i | output ← Ri | output ← M[Ri] |
LOAD | R0 ← i | R0 ← Ri | R0 ← M[Ri] |
STORE | Ri ← R0 | M[Ri] ← R0 | |
ADD | R0 ← R0 + i | R0 ← R0 + Ri | R0 ← R0 + M[Ri] |
SUB | R0 ← R0 - i | R0 ← R0 - Ri | R0 ← R0 - M[Ri] |
MUL | R0 ← R0 * i | R0 ← R0 * Ri | R0 ← R0 * M[Ri] |
DIV | R0 ← R0 / i | R0 ← R0 / Ri | R0 ← R0 / M[Ri] |
JMP | IP ← i | ||
JZ | if R0 == 0 then IP ← i | ||
JGTZ | if R0 > 0 then IP ← i | ||
HALT | halts the simulation |
The table describes also the behavior of each instruction. The compiler does not care about the behavior, but about the syntax of the instructions, which is also incorporated in the table.
Code example
For example, this is a valid program:
; Copy R(X) to R(Y)
;
; input tape:
; destination register: X
; source register: Y
;
; output:
; R(X) = R(Y)
; R(Y) = R(Y)
<input> 3 4 'hello' 'world'
; load X,Y
read 1
read 2
; load r.X, r.Y
read *1
read *2
; copy
load *2
store *1
halt