080773ed0a
Signed-off-by: Stefano Lattarini <stefano.lattarini@gmail.com> |
||
---|---|---|
examples | ||
.gitignore | ||
bison2.patch | ||
LICENSE.txt | ||
main.cpp | ||
Makefile | ||
Monicelli.lpp | ||
Monicelli.ypp | ||
Nodes.cpp | ||
Nodes.hpp | ||
README.md | ||
Scanner.hpp | ||
Specification.txt |
Monicelli
Monicelli is an esoterical programming language based on the so-called "supercazzole" from the movie Amici Miei, a masterpiece of the Italian comedy.
There is no way to translate a "supercazzola" to English, so if you don't speak Italian, I'm afraid you won't understand. I'm really sorry for you :)
Compilation
You will need bison
version >= 3.0, flex
>= 2.5 and any C++11 compiler.
A makefile is provided and will compile the mcc
executable. Compiling the
executable is a matter of:
make
A patch is provided for compatibility with Bison 2.5. If you can't really upgrade to Bison 3.0, and I strongly recommend that, you can always compile with:
make bison2
However, note that this is not supported and might be removed in a future release.
There are some other targets, which are of interest only for developers.
Usage
mcc
is a source to source compiler, which reads Monicelli and outputs a
subset of C++. For those of you who want to get to the code ASAP, the examples/
folder contains a set of programs covering most of the features of the language.
A good way to learn on the field is comparing the resulting C++ with the
input. Well, mostly with the beautified version of the input, *.beauty.mc
.
The compiler reads from standard input and print result to standard output.
$ ./mcc < examples/primes.mc > primes.cpp
$ c++ primes.cpp -o primes
$ ./primes
Language overview
The original specification can be found in Specification.txt
, and was
initially conceived by my colleagues and dear friends Alessandro Barenghi,
Michele Tartara and Nicola Vitucci, to whom goes my gratitude.
Unfortunately, their proposal was meant to be a joke and is not complete. This project is an ongoing effort to produce a rigorous specification for the language and implement a compiler, which implies filling gaps and ambiguities with sensible choices.
Statements have no terminator, i.e. no semicolon ;
or the like. A single
statement can be split across multiple lines and multiple statements can be
grouped on the same line. However, keywords consisting of multiple space-separed
words cannot be split on multiple lines.
A comma might be inserted after each statement, if it fits the sentence ;)
Accented letters can be replaced by the non-accented letter followed by a
backtick `
, although the use of the correct Italian spelling is strongly
encouraged for maximizing the antani effect.
Main
The entry point of the program (the "main") is identified by the phrase:
Lei ha clacsonato
which marks the beginning of the supercazzola (i.e. of the program).
A value can be returned by using the the following statement:
vaffanzum <expression>!
optionally, no value might be returned with:
vaffanzum!
Expressions
The usual operators are given, but spelled as words to best fit in sentences. They are directly mapped on usual operators as follows:
Form | Maps to |
---|---|
più | + |
meno | - |
per | * |
diviso | / |
maggiore di | > |
minore di | < |
maggiore uguale a/di | >= |
minore uguale a/di | <= |
So 2 più 4
means 2 + 4
.
###Binary shift
Binary shift operators have a slighly different syntax:
<what> con scappellamento a <direction> per <bits>
which is equivalent to what >> bits
or what << bits
, depending on the
direction, which is specified as follows:
Phrase | Direction |
---|---|
destra | right |
sinistra | left |
as you might have noticed, those are simply the translation in Italian of "left" and "right". For instance:
antani con scappellamento a sinistra per 2
maps to antani << 2
.
It goes without saying, other expression can be used instead of numbers. Also, the usual precedence rules apply.
Braces are not implemented.
Variables
A variable name can contain numbers, upper and lower case character and must not start with a number (the usual rules, that's it).
A variable might be prefixed with an article to fit a sentence. The
compiler does not check concordance with the following name, but accepts any
article of the Italian language: il
, lo
, la
, i
, gli
, le
, un
, una
dei
, delle
, l'
, un'
. For instance, cappello
and il cappello
refer
to the same variable.
Consequently, the articles above cannot be used as variable names.
###Assignment
A value can be assigned to a variable with the following statement:
<varname> come fosse <expression>
the alternate spelling come se fosse
can be used as well.
###Declaration
Variables can be declared in any scope. There are 5 variable types, which are directly mapped on C++/C99 types as follows:
Type name | Mapped C type |
---|---|
Necchi | int |
Mascetti | char |
Perozzi | float |
Melandri | bool |
Sassaroli | double |
A variable is declared with the following statement:
voglio <varname>, <type>
an initialization value can be provided:
voglio <varname>, <type> come se fosse <expression>
for instance:
voglio antani, Necchi come se fosse 4
declares a variables called antani
of type Necchi
(int
) and initializes
it to 4.
Input/Output
Variables and expressions can be printed with the statement:
<expression> a posterdati
Conversely, a variable might be read from input using:
mi porga <varname>
Loop
There is only one loop construct, equivalent to a C do {} while();
, which is
defined as follows:
stuzzica
<statements>
e brematura anche, se <condition>
For example:
voglio antani, Necchi come se fosse 10
stuzzica
antani come fosse antani meno 1
e brematura anche, se antani maggiore di 0
maps to:
int antani = 10;
do {
antani = antani - 1;
} while (antani > 0);
brematura
might be replaced by its alternate form prematura
Branch
The branch construct encompasses both the features of an if
and a switch
.
The best way to explain it is by comparing its various forms to the corresponding
C translation.
This is the general form:
che cos'è <variable>?
<condition>:
<statements>
o magari <condition>:
<statements>
o tarapia tapioco:
<statement>
e velocità di esecuzione
where <condition>
might be either a value or a semi-expression, that is an
operator followed by any expression. For instance:
che cos'è il genio?
intuizione:
genio come se fosse genio meno 1
o magari intuizione diviso 2:
genio come se fosse genio più 1
o magari maggiore di mobiletto per due:
genio come se fosse genio per 2
o tarapia tapioco:
genio come se fosse 2
e velocità di esecuzione
maps to:
if (genio == intuizione) {
genio = genio - 1;
} else if (genio == (intuizione / 2)) {
genio = genio + 1;
} else if (genio > (mobiletto * 2)) {
genio = genio * 2;
} else {
genio = 2;
}
The statement can emulate an if () {} else {}
:
che cos'è il genio?
maggiore di mobiletto:
genio come se fosse 2
o tarapia tapioco:
genio come se fosse 0
e velocità di esecuzione
Placing multiple o <condition>:
block is similar to a chain of else if
in C.
The o tarapia tapioco
block can be omitted:
che cos'è il genio?
maggiore di mobiletto:
genio come se fosse 2
e velocità di esecuzione
Finally, here is the equivalent of a switch () {}
:
che cos'è il genio?
1:
genio come se fosse 2
o magari 2:
genio come se fosse 7
o tarapia tapioco:
genio come se fosse 9
e velocità di esecuzione
where the o tarapia tapioco
part is like the default
block.
Functions
Note: the alternate spelling supercazzora
might be used in place
of supercazzola
wherever the latter appears.
###Declaration
A function is declared with the blinda la supercazzola
statement:
blinda la supercazzola [<type>] <name> [con <param> <type>[, <param> <type>...]] o scherziamo?
<statements>
Where <type>
can be omitted for a void function. For instance:
blinda la supercazzola Necchi antanizzata con alfio Mascetti o scherziamo?
vaffanzum alfio meno 2!
is a function of type Necchi
, taking one argument of type Mascetti
.
Multiple arguments must be comma-separed, like in:
blinda la supercazzola Necchi antanizzata con alfio Mascetti, barilotto Necchi o scherziamo?
vaffanzum alfio meno 2!
which is a function of type Necchi
, taking two arguments of type Mascetti
and Necchi
. It maps to:
int antanizzata(char alfio, int barilotto) {
return alfio - 2;
}
Finally, this:
blinda la supercazzola antanizzata o scherziamo?
vaffanzum!
is a void
function taking no arguments and becomes:
void antanizzata() {
return;
}
Functions cannot be nested and can be declared before or after the main in any
order. mcc
will not check that a return statement is always reachable inside
a non-void function. Failing to return a value leads to undefined behaviour.
###Invocation
A function is called with the brematurata la supercazzola
statement:
brematurata la supercazzola <name> [con <expression>[, <expression>...] o scherziamo?
Functions might be called inside expressions. For instance, this:
antani come se fosse brematurata la supercazzola alfio con barilotto diviso 3 o scherziamo? per 2
maps to:
antani = alfio(barilotto / 3) * 2;
Exceptions
The program might be aborted immediately with the statement:
avvertite don ulrico
there are no arguments.
Assertions
An assertion block will evaluate its expression and trigger an error message if it is found to be 0 (logical false). An assertion is stated as:
ho visto <expression>!
Comments
Any character after bituma
is ignored until a line break is encountered. For
instance, in:
antani come se fosse 4 bituma, scusi, noi siamo in quattro
, scusi, noi siamo in quattro
is ignored.
Comments are useful to fill the "supercazzola" and make it more readable, since any word (including reserved words) can be inserted into it.
###Meta comments
In addition to line comments, there are meta comments. A meta comment starts
with an hash sign #
and continues until a line break is encountered, as an
ordinary comment.
They have a different graphical symbol, which can be immediately spotted inside a long "supercazzola". Also, ordinary comments can and should be used in an improper way to fill the sentence, meta comments provide a mechanism for distiguishing "real" comments.
In addition to that, meta comments are printed to stderr
during compilation.