by drummyfish, released under CC0 1.0, public domain
This is an article on comun following the progopedia (http://progopedia.com) style. The aim is to provide another learning resource about comun in a well designed format which is already known to a number of people. Once comun gets to progopedia (possibly by just copying this article), this document will become obsolete. The article follows.
Data:
Comun is an imperative stack-based programming language focused on keeping relative implementation simplicity while remaining practically usable.
It was made in 2022 by Miloslav Číž (known as drummyfish) with the goal of creating a language suitable for very simple computers.
The language has a very short, completely public domain specification. In nature it is very similar to Forth, by which it was largely influenced, but additionally includes features such as basic data types (so called "type environments" allowing the use of different size integers) and pointers. The syntax is notable for using no English keywords but rather utilizing short, mostly one or two character symbols.
Comun is currently largely work in progress. There exists a working C implementation which utilizes bytecode and makes it simple to transpile comun to other languages. A self-hosted implementation is being worked on.
feature | value |
---|---|
inline comments | # |
non-nestable comments | # ... # |
case-sensitivity | yes |
variable identifier regexp | [_a-zA-Z][_a-zA-Z0-9]* |
function identifier regexp | [_a-zA-Z][_a-zA-Z0-9]* |
variable assignment | <value> $:<varname> |
variable declaration | ~<varname> |
comparison | < > <= >= << >> <<= >>= |
function definition | <funname>: <commands> . |
function call | <funname> |
function call with no parameters | <funname> |
if - then | <cond> ? <commands> . |
if - then - else | <cond> ? <commands> ; <commands> . |
loop forever | @@ <commands> . |
while condition do | @ <commands> . |
physical (shallow) equality | = |
physical (shallow) inequality | != |
This example keeps note of the previously computed two Fibonacci numbers, being both time and memory efficient.
numPrint:
0 ><
@@
$0 10 % "0" + >< 10 /
$0 0 = ?
!@
.
.
^
-->
.
1 1 # initial values, can be changed
$1 numPrint ", " -> ->
$0 numPrint ", " -> ->
14 @'
$2 $2 +
$0 numPrint
><
", " -> ->
-- # decrease counter
.
"..." -> -> ->
This is a straightforward implementation which pushes values 0 (string terminator), 10 (ASCII code for newline) and a string that is subsequently printed with the built-in -->
command.
0 10 "Hello, World!" -->
This example uses recursive factorial definition as possibly the more elegant option, though an iterative version can be written in similarly simple way. Also note that this version uses 64 bit type environment to be able to print the very high values, however 64 bit environment is at the moment not supported by the current implementation; to make this version work with current implementation just strip the ~64
and ~0
directives.
~64
numPrint:
0 ><
@'
$0 10 % "0" + ><
10 /
.
^
-->
.
factorial:
?'
$0 -- factorial *
;
^ 1
.
.
0 @@
$0 16 > ?
!@
.
$0 numPrint
0 "! = " -->
$0 factorial numPrint 10 ->
++
.
~0
TODO
This example showcases the use of variables and pointers. It reads the input and processes it at the same time, making use of the lowerCase
variable to hold the state, storing the result string on the stack. After this stack position is restored from the stackTopBackup
pointer and the result is printed out.
isLetter: $0 "A" >= $1 "Z" <= & >< $0 "a" >= >< "z" <= & | .
toUpper: $0 $0 "a" >= >< "z" <= & ? "a" - "A" + . .
toLower: $0 $0 "A" >= >< "Z" <= & ? "A" - "a" + . .
~lowerCase # holds case state
~stackTopBackup:0 # remembers previous stack top
" "
$0>stackTopBackup
@@ # read and process the input at the same time
<-
$0 isLetter ?
$lowerCase ?
toLower
;
toUpper
.
1 $:lowerCase
;
0 $:lowerCase
$0 10 <= ? # end of input?
^ !@
.
^ # non-letter, remove
.
.
0 # terminate with zero
$stackTopBackup>0 $>0
@' # print until reaching the end zero
->'
$>0
.