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] ascendi++and for an integer typelet [id] descendi--let [id] be [expression]i = expressionlet there be [expression] added to [id]i += exprlet there be [expression] conspired from [id]i -= exprlet there be [expression] dividing [id]i /= exprlet there be [expression] empowering to [id]i *= exprlet 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 arrwill 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!