On this page:
Poetic is an esoteric programming language (or esolang) based on one of the most classic esolangs, brainf***. The main form of data storage in Poetic is the unsigned byte, which can be used to store a number in the range 0–255, an ASCII character, or whatever else you can conceive of using it for. Poetic has a "tape" of 30,000 of these values, and a memory pointer to keep track of which one of those values is currently being accessed.
The beauty of Poetic, and what sets it apart from most other programming languages, is that there are multiple ways to write a program. Poetic programs can be written in natural language, as a way to either self-describe them, obfuscate them, or to simply have fun with their design. The goal of the Poetic programming language is that someone could walk into a slam poetry session, recite a Poetic program, and have nobody know the difference.
Source Code
Source code for Poetic is entered in the form of words, in any natural language. There are exactly 10 instructions in Poetic, each represented by a numeric digit, and each word is converted to instructions as follows:
- Words are considered to consist of any number of alphabetic characters (with or without accents) and apostrophes.
- Any character that is not an alphabetic character or apostrophe is ignored, and treated as whitespace.
- Each word of n letters represents:
- The digit n if n < 10
- The digit 0 if n = 10
- Two consecutive digits if n > 10 (for example, 12-letter words represent the digits 1, 2)
While it is possible to program using words that aren't "real", but are considered words by this system, this is not recommended. It misses the whole point of the language in the first place. (If you are able to use this device to great poetic effect, however, feel free!)
Here are some special cases that arise as a consequence of these rules:
| Word | Instructions |
|---|---|
| easy | 4 |
| shouldn't | 8 |
| vocabulary | 0 |
| unintelligible | 1, 4 |
| word-for-word | 4, 3, 4 |
| 4th place | 2, 5 |
| good4you | 4, 3 |
| fun & games | 3, 5 |
Instruction Set
Poetic has 10 instructions, each represented by a numeric digit. They are as follows:
| Value | Opcode | Description |
|---|---|---|
| 1 | IF | If the current byte is equal to 0, jump execution to after the matching EIF. |
| 2 | EIF | If the current byte is not equal to 0, jump execution to before the matching IF. |
| 3 | INC | Increment the value of the current byte by next_digit. If next_digit is 0, the value used instead is 10. |
| 4 | DEC | Decrement the value of the current byte by next_digit. If next_digit is 0, the value used instead is 10. |
| 5 | FWD | Increment the memory pointer by next_digit. If next_digit is 0, the value used instead is 10. |
| 6 | BAK | Decrement the memory pointer by next_digit. If next_digit is 0, the value used instead is 10. |
| 7 | OUT | Output the value of the current byte as an ASCII character. |
| 8 | IN | Read a character from the input stream, and write its ASCII value to the current byte. |
| 9 | RND | Set the current byte to a random value from 0 to 255. |
| 0 | END | End program execution here. This does not end program execution if it is used as an argument for INC, DEC, FWD, or BAK. |
Note that the words for the opcodes are not the instructions themselves, but they are handy ways to refer to the instructions in Poetic pseudocode. Writing BAK 4 in your source code will not result in a BAK 4 being executed; writing Poetic code (for example) would have this effect.
Clarifications
These definitions still leave a bit of room for interpretation for many situations that could arise. Here is my attempt at clarifying the correct behavior in these situations.
- The Poetic interpreter is smart. It can tell the difference between digits being used as instructions, and digits being used as data. For example, a fool I am would be interpreted as IF DEC 1 EIF, and it would decrement the current byte by 1 until it is 0.
- IF/EIF pairs can be nested. This means that, if the current byte is 0 and a statement like IF...IF...EIF...EIF is executed, the program would jump to the second EIF, not the first.
- Each of the bytes on the "tape" wrap: 255 + 1 = 0, and 0 − 1 = 255. If one wishes to express numbers that are outside of the unsigned byte range, one needs to program very creatively.
- Not only do the values of bytes wrap, but the memory pointer also wraps. Incrementing the memory pointer at the end of the tape wraps around to the beginning, and decrementing the memory pointer at the beginning of the tape wraps around to the end.
- Once the end of input is reached, the IN command ceases to update the current byte. (This applies to both file input and STDIN input, even though STDIN doesn't technically have an "end".)