User:Zzo38/FurryScript
(PLEASE DO NOT MOVE THIS DOCUMENT TO MAIN NAMESPACE. IT DOES NOT BELONG THERE. KEEP IT UNDER MY USER NAMESPACE.) (However, note that it is being discussed this notice might be wrong (in which case this note should be removed, and the page should probably moved anyways); it is currently unsure, though, so please discuss it first.)
At request of IRC, I made this file for documenting FurryScript.
FurryScript is a domain specific programming language (mostly for random text generator), also usable (but not very well) for other programming (as esolangs often are), with some strange features compared with ordinary programming languages (see also Prehistory of esoteric programming languages):
- The only arithmetic operation is subtraction.
- Negative numbers cannot be entered directly and can only be achieved by subtraction or type casting.
- Strings may contain subroutine calls, but these calls are probabilistic and delayed.
- There are no scalar variables (actually there is one (the input), but it only stores text strings).
- There are only some kinds of loops, and not most of the common kinds found in other programming languages (although it does have some of them).
- List variables and subroutine variables can be anonymous, even though they are not first-class objects.
- There are no conditional blocks.
- Subroutines may exit "OK", "bad", or "very bad", with different effects depending on circumstances.
(Other programming languages for random text generation (mentioned in the Wikipedia article for esoteric programming) are Dada Engine and rmutt (from the Wayback Machine; retrieved on 18 February 2014). FurryScript was not influenced by these programs; it was written independently.)
Comments
Comments start with {{ and end with }}
Subroutines
To make a subroutine, put the name with [ suffix (no space in between) and end with ] (there must be a space after [ and before and after ] however). You can nest subroutine definitions. Code are not executed until calling the subroutine.
To call a subroutine, use its name with # suffix.
Lists
To make a list, put the name with ( suffix (no space in between) and end with ) (there must be a space after ( and before and after ) however). Codes in list are executed right away, and whatever is placed on the stack will be put into a list instead.
To dump a list to the stack, use its name with @ suffix.
Strings
A string is typed with < and > around it. You can have < and > inside the string if nested properly, but they mean special codes, not the actual less than and greater than signs.
It is also possible to make a story text by {|| and ||} around it. A story text can contain multiple lines and all characters are treated literally (including matched or unmatched < and >). The comment sequences {{ and }} can be included without being interpreted as comments.
Numbers
You can type a zero or positive integer in decimal notation.
Generation
Generation is an important function of this program. It automatically does generation when necessary, although you can activate it explicitly by using the GEN command. Everything left on the stack at the end of the file is also used as templates for doing generation immediately and that is what is resulting in the output of the program. See information about templates which can be used for controlling generation.
There is a string on the stack, and this string can contain instructions. If it contains a subroutine call, that subroutine is called and a random string is selected in its place; that string may in turn include additional instructions, and these subroutines may additionally include backtracking with BAD, HOR, and RES commands.
Concatenation
Prefixing any command with + means that string resulting from that command is concatenated to end of the string on the stack from before.
Subroutine operations
- name# ( ? -- ? ) Execute subroutine
- name## ( ? -- ? ) Execute subroutine and propagate result of success level (tail recursive)
- name^ - Call with current continuation
- OK ( -- ) Normal exit from subroutine (implied)
- BAD ( -- ) Bad exit from subroutine (meaning of bad and very bad exits is described later)
- HOR ( -- ) Very bad exit from subroutine
- RES ( cont -- ? ) Restore the continuation
List operations
- name@ ( -- ? ) Dump a list to stack
- name* - Skip next command unless the list contains duplicate entries
- name| - Run next command for each entry of list (data is pushed to stack). Stop if BAD or HOR results, and the result is propagated
- name|| - Run next command for each pair of entries of list (data is pushed to stack). BAD means stop and propagate the bad result, OK means stop normally, HOR means continue with the next pair.
- RSC ( list -- v ) Select a random entry from the list made up so far
- ALL ( list -- name ) Save the list made up so far into a new anonymous list
- SHF ( list -- list ) Shuffle the list made up so far
- LUT ( value table -- out ) Lookup table
- SCA ( list total -- list ) List made up so far, of numbers, are scaled so that they add up as close as possible to specified total without exceeding it
String operations
- LT ( -- string ) String with less than sign
- GT ( -- string ) String with greater than sign
- BR ( -- string ) String with line break
- BS ( -- string ) String with backspace
- CO ( x y -- result ) Concatenation strings
- CAP ( in -- out ) Make first character uppercase. If it cannot do so, it adds a mark that causes it to become uppercase when the letter is put there
- GEN ( in -- out ) Perform generation using templates explicitly
Stack operation
- DUP ( x -- x x ) Duplicate
- DR ( x -- ) Drop
- EX+ ( x -- ) Move from main stack to auxiliary stack (note: auxiliary stack is not part of continuation data)
- EX- ( -- x ) Move from auxiliary stack to main stack
- SW ( x y -- y x ) Swap
- TIM ( value number -- ? ) Make the number of copies (used in subroutines and list to make an event more probable)
- CHA ( value number -- ? ) (number-1) in (number) chance to drop value from stack, 1 in (number) chance to retain (used in subroutines (but not in lists) to make an event less probable)
- MA ( value x y -- ? ) Retain value if x matches y
- NMA ( value x y -- ? ) Retain value if x not matches y
Flow control
- REP ( times -- ) Repeat next command a number of times
- RRE ( times -- ) Repeat next command a random number of times (at least once)
- MA? ( x y -- ) Skip next command unless match
- NMA? ( x y -- ) Skip next command unless not match
- ET? ( x y -- ) Skip next command unless x ends with y
- NET? ( x y -- ) Skip next command unless x not ends with y
- BT? ( x y -- ) Skip next command unless x begins with y
- NBT? ( x y -- ) Skip next command unless x not begins with y
- ?? - Execute next command with an implicit BAD afterward; if it is OK, then this becomes very bad
- ARG - Execute next command for each argument of the current template (list 0 is assumed to store the number of arguments), pushing that argument to the stack when calling
- AGA - Start over active block
- MC ( ? next -- ? ) If previous states is matching (use ` at end of a name for wildcards), then escape current subroutine block and use the next string generator and use as next state name and subroutine name
Parameters
- PAR ( -- par ) Load parameter into stack
- PAS ( par -- ) Save value from stack into parameter
- PA ( value flag -- ? ) Discard the value if flag text is not in parameter, keep value if it is
- PA+ ( value flag -- ? ) Discard the value if flag text is not in parameter, otherwise the value is treated as the name of a subroutine to execute
Templates
Inside of a string, you can have a name of a subroutine or list with < and > around it. These templates can also take parameters separated by | symbol. If there is a subroutine, it execute the subroutine and make a list of the things it placed on the stack, and selects one entry at random (using equal probabilities each). If it is not a subroutine, it just uses the existing list. The result is substituted into its place. You can use BAD and HOR commands for backtracking, in case one result is no good please try something else.
Namespaces
Any file in "furinc" directory, can be loaded with a word having / suffix. And then the codes in that file are belonging to their own namespace where you put the name before / and the other name after /.
Dynamic name select
If you include ~ in a command (other than string) it will use the string as the name to put (it can be used with suffixes); if it is inside of special codes it will strip them
Translations
- TR ( z y x -- z' ) If z is equal to y, then replace it with x instead
- TR- ( z y x -- z' ) If z is equal to y, then replace it with x and exit the subroutine
- TRB ( z y x -- z' ) If z is equal to y then replace by x, if it was x then replace by y, otherwise stay as it is
- TRB- ( z y x -- z' ) As above but also exit the subroutine if a replacement has occurred
- REX ( in match repl -- out ) Perform regular expression match and replace
- REX- ( in match repl -- out ) Perform regular expression match and replace, and exit the subroutine if resulted in a change
- REX+ ( in match repl -- out ) Perform regular expression match and replace, and exit the subroutine if not resulted in a change
Miscellaneous commands
- NOP ( -- ) No operation
- SU ( y x -- result ) Subtract x from y
- DEB - Display stack and categories (debug purpose)
- DBG - Display stack and level (debug purpose)
- RNG ( low high -- out ) Random number generator
- LAH ( subr regex -- out ) Make a code to match a regular expression and call subroutine during a generation function
- IMC ( ? count -- ) Initialize Markov chain
- DIC ( dice -- out ) Dice roll
- SKI ( table points -- ? ) Skill generator
Dice
Roll dice specification can have dice with + and - in between, they can be constant numbers and can be dice with glitch and with keep/drop lowest/highest.
The format is:
- count (number, if omitted use 1)
- dice (d and number of sides, if omitted use constant; d without a number assumes six sides)
- glitch (g and glitch value, used if half or more of dice is 1)
- drop/keep lowest/highest (d or k, followed by l or h, followed optionally by how many to keep/drop)
- multiplier (x followed by a number to multiply this term by)
For example, <4d6dl> DIC is the standard way to generate ability scores at random in Dungeons & Dragons.
Anywhere a number is expected, you can also use a single dice notation in parentheses. Nesting is allowed, but the full format otherwise is not possible; you are limited to one or two terms, where the first term is dice and the second term is a constant, and where glitches and multipliers are not allowed.
Skill generator
The skill generator makes a random skill set from a skill table and the number of skill points to use. It is given as pairs of the skill name (which can include templates) and the option string.
It result in list of pairs of skill names and ranks of that skill.
Options:
- C (1): Cost to increase this skill by one rank
- I (0): Amount to increase the cost after a rank is added
- M: Maximum value of this skill
- c (1): Add skill multiple times in order to multiply chance to select it
- d (1): Number of sides of dice
- r: If specified, 1 in this number is chance to remove from list of available skills to advance after selected; if c is also specified, it only remove one at a time
- v (0): Initial value of skill; provide ranks for free (do not use for template skills)
Examples
PAR
Truth-machine (won't actually work because it has no interactive I/O):
1[ <1> 1# ] PAR DUP ~#
<Hello, world!>
Beer:
0( 99 ) X[ DUP +< bottles of beer on the wall.> SW DUP +< bottles of beer,> SW <Take one down and pass it around,> SW 1 SU DUP +< bottles of beer.> +BR SW ] 99 ARG X#
Six-sided dice:
1 6 RNG +<>
NEXT[ DUP PAS SW 0 SW SU SU PAR SW ] 0 1 PAR REP NEXT# +<>
Skill generator:
SKILLS( ( <Attack> <> <Defense> <> <Special> <> ) 5 SKI ) SKILL[ <: > +SW CO EX+ OUT( OUT@ EX- ) HOR ] OUT( ) SKILLS|| SKILL## OUT@
ENIUQ[ DUP LT +SW +GT +< ENIUQ#> ] <ENIUQ[ DUP LT +SW +GT +< ENIUQ#> ]> ENIUQ#
Goldilock's Method:
MAKE[ <1d8+> PAR <^(.).*$> <\1> +REX DIC PAR <^.> <> REX PAS ] PERCENT( 6 REP MAKE# 100 SCA ) TABLE( 0 5 1 6 2 8 3 9 4 10 10 11 14 12 19 13 25 14 30 15 35 16 48 17 65 18 77 19 ) CALC[ +<: > SW `TABLE LUT CO EX+ ] PERCENT@ <Charisma> CALC# <Wisdom> CALC# <Intelligence> CALC# <Constitution> CALC# <Dexterity> CALC# <Strength> CALC# 6 REP EX-
See external resources for more examples.