A semi-statically typed, semi-poetic, semi-language made by @beaverden and @ClaudiuIoanMaftei as a final assignment for the Formal Languages, Automata and Compilers course.
It was made using LEX, YACC and works only thanks to unknown magic unicorn power.
- Working examples can be found in
programs/
- Please note that this language is our first experience in parser and interpreter design and is not intended for any practical use.
- Also consult the list of bugs (I wish there wasn't any).
- Any string inside "[ ]" is meant to be taken as a regular expression. [type] means something like int or string and [identifier] would mean "_HolyHandGrenade" or "var".
- Language lacks some important features that are not implemented now.
While having flex and bison installed, run make
This will generate a executable limbaj.out
.
Run with a file name as parameter to get the output.
./limbaj.out programs/gcd.txt
There are four primitive types, any other types are composed of them.
- Integer (whole, discrete, full)
- Boolean (doubting)
- String (saying)
- List (book)
Their default values are 0, untruth, "", book<> respectively.
Variables are only declared using enter
.
enter whole var
enter saying name
enter saying Jesus
Constant variables are denoted with fixed
keyword before type
enter fixed whole i
^ Which will be a interesting tactical move, because the constant variable has no value and it will be never assigned.
We can assign a value when declaring by using telling
enter fixed whole i telling 5
enter saying str telling "hello"
Wiil be equivallent to const int i = 5
and char* str = "hello"
There are just a few stupid multiple ways to change a variable.
let [id] ascend
i++
and for an integer typelet [id] descend
i--
let [id] be [expression]
i = expression
let there be [expression] added to [id]
i += expr
let there be [expression] conspired from [id]
i -= expr
let there be [expression] dividing [id]
i /= expr
let there be [expression] empowering to [id]
i *= expr
let there be [expression] reminding [id]
i %= expr
A expression can be:
- Function call
- Number, string, list (book<1, 2, 3>), boolean value
- Variable identifiers and chained structure addressing (
from
) - One of the predefined functions (if the return type is correct in the context of the expresssion)
- none (number 0 actually)
- one (number 1 actually)
- Expression enclosed in '< >'
Any of the above in a correct combination with operators:
adding
(+)conspiring
(-)dividing
(/)reminding
(%)empowering
(*)is
(==)is not
(!=)lower than
(<)greater than
(>)up to lower than
(<=)down to greater than
(>=)
What is a "correct combination"?:
adding
(numbers, strings, lists)conspiring
(numbers)dividing
(numbers)reminding
(numbers)empowering
(numbers, numbers+strings with give a pythonic result)- Comparison operators and only be used with numeric types
Anything else can and will (I hope so) generate a runtime error
Some examples of correct expressions:
1 adding 5 // 6
2 empowering <5 adding 1> // 12
book<1, 2, 3> // list containing 1, 2, 3
book<1, 2, 3> + book<3, 2, 1> // book<1, 2, 3, 3, 2, 1>
"hey" + ", mate" // "hey, mate"
"hey" empowering 5 // "heyheyheyheyhey"
5 empowering "hey" // "heyheyheyheyhey"
untruth is indeed // untruth
A "struct" type declaration is done using proclaim
proclaim <type_name>
<
[type] fixed? [identifier],
...,
[type] fixed? [identifier]
>
Members of a struct can be accessed with [identifier] from [var_identifier]
In this example, member a
is accessed from p
with a from p
. from
can be chained if more layers of complex types are present, like a from b from c from var
.
proclaim pair
<
whole a,
whole b
>
enter pair p
quote<a from p>
quote<b from p>
quote<[expr]>
Output an expression (quote<1 adding 2>
)
summon<[var]>
Inputs a value of the same type as var into var
verbose<[expr]>
Simmilar to str() in python
numeric<[expr]>
Simmilar to int() in python
ask whether <[expression]> then
<
...
>
otherwise
<
...
>
To exit or continue any loop use break free
and continue
since [expression]
<
...
>
for [assignment], since [expression], [assignment]
<
...
>
describe [func_id] as [type] adventure of < [type] [id], [type] [id], ... >
<
...
exeunt [expr]! // Return statement. Should be the same as function return type
>
- Adding to back:
write chapter [expression] to [id]
- Adding to position
write [expression] as chapter [expression] to [id]
- Removing from position
erase chapter [expression] of [id]
- Indexing
chapter [expression] of [id]
(chapter 5 of arr
will return the element at position 5, starting from 0)
There are no comments. Because f*ck you, that's why.
- One should be able to assign a complex variable to another complex variable
- Implement &&, ||, ! for boolean expressions
- If you can declare a fixed variable in a struct, you should be able to assign it right away
If you made it to the end, take your cookie, you glorious reader!