You can use this language to create simple games that run on a simple retro console simulator.
It is recommended to use .cg as the file extension.
Jump to the The Language section to learn how to code in this language.
The samples directory contains a few sample code files, please try running them to understand the working.
The core implements a RegEx-based lexical analyzer and an LR(0) parser. The grammar is defined in a form similar to BNF.
The compiler for the language is present in the language directory.
The samples directory contains some sample codes.
The simulator needs PyGame 2.0+ to run. It has been tested on Python 3.8.6.
Considering that you have the code written in the file code.cg, you can run the code by running the following command.
python3 language/runner.py code.cg
The above command will run the game on a 30×30 console at 30 frames per second. To run with a custom configuration (say 30×20 at 10 frames per second), use the following command
python3 language/runner.py code.cg 30 20 10
The code is run on a retro console simulator made with PyGame.
The console has 6 buttons - Power, Start, X, Y, A, and B.
| Button | Mapping |
|---|---|
| Power | Return |
| Start | Space |
| X | X or ← |
| Y | Y or ↑ |
| A | A or ↓ |
| B | B or → |
The Power button is used to turn on/off the console. Other buttons work as defined in the code.
The console has a display - a grid of black and white pixels. The language provides commands to display shapes on the screen.
The console is driven by a clock whose frequency is decided during compile time. At every tick, code corresponding to the current state is executed - computation, updating the display, changing the state, etc.
The games may run at different speeds at different frequencies.
The game is a state machine. We can define states and jump from one to another. The console simulator has a clock which runs at a fixed speed (defaults to 30Hz). At each tick, the operations defined within a state are executed and the state is updated as required.
The first line of the file must be the name of the initial state.
Anything followed by a // until the end of the line is considered a comment.
Comments cannot appear at the beginning of the file.
They must be present after the initial state declaration.
A shape is a 2D collection of pixel colors (black, white, or transparent). The shapes can be painted(overlaid) on a screen.
A shape can be defined as follows.
#disc {
..##..
.#++#.
#++++#
#++++#
.#++#.
..##..
}
Here, #disc is the name of the shape. # represents a black pixel, + represents a white pixel, and . represents a transparent pixel.
Shape name is a # followed by one or more alphanumeric or underscore characters.
Shapes can be defined only at the root of the document.
A state is a collection of statements. Variable assignment, button handling, state change, and display update statements can be written inside a state.
~firstState{
// Statements go here
}Here, ~firstState is the name of the state.
A state name is a ~ followed by one or more alphanumeric or underscore characters.
Variables can store integers only and are global in scope. If not defined, variables default to 0.
Here is an example of a variable assignment
$four = [2+2]Here, $four is the name of the variable.
After execution of the statement, 4 is stored in the variable $four.
A variable name is a $ followed by one or more alphanumeric or underscore characters.
There are 3 constants present in the language.
| Constant | Meaning |
|---|---|
!W |
The width of the device (default 30) |
!H |
The height of the device (default 30) |
!FPS |
The frame rate of the device (default 30) |
An expression is used to do arithmetic or logical operations on literals, variables, or constants.
The code snippet below shows the use of an expression.
$a = [1+2]
$aSquaredMod10 = [($a*$a)%10]The precedence of the operators is as follows (in descending order)
| Operator | Description |
|---|---|
(, ) |
Parentheses |
+, -, ~ |
Unary plus, minus, not |
*, /, % |
Multiplication, integer division, modulo |
+, - |
Addition, subtraction |
<=, <, >=, >, =, ~= |
Less than or equal to, less than, greater than or equal to, greater than, equal to, not equal to |
&, | |
Logical and, or |
The associativity for all operators is from left to right.
The logical operators consider zero as
falseand non-zero values astrue. The logical operators evaluate to 0 instead offalseand 1 instead oftrue.
Random numbers are an important part of games. We can generate random numbers as follows.
$randomNumberOnADice = r[1][6]
$randomNumberOnADice = r[6][1] // Same as previous statement
$anotherRandomNumber = r[0][!W-1]Random expressions are also expressions.
We can use if and if not to make selections.
Any expression can be used as a boolean expression.
Zero represents a false value and any non-zero value represents true.
if [2+2=4]{
// Statements
}
if not [$x>10]{
// Statements
}The body of an
ifstatement cannot be empty. There is noelsestatement present in the language.
The language provides while and while not for iterations.
In case of an infinite loop, the device freezes.
Here is an example
$x = [0]
while [$x<5]{
// Statements
$x = [$x+1]
}There are two commands for updating the screen - clear and display.
Clears the whole screen.
clear
It is used to overlay a shape on the screen. The top-left coordinate of the position where the shape is to be overlayed is required.
display #someShape @ ([$x], [$y])
display #anotherShape @ ([!W - $x], [!H - $y])The coordinates are two expressions.
At every tick, the code inside the current state is executed.
We can change the current state by using goto statement.
goto ~anotherStateAny code following goto is not executed.
Button handlers are defined inside the state.
There are five button handlers - @X, @Y, @A, @B, @START.
We need not define all the button handlers.
@X{
// Statements
}In case of any issues, post to the issues section of this GitHub repository. Please provide a minimum reproducible example.
We are looking forward to implementing the following features in the future.
- An optional
elsewithif
