LICE

From Esolang
Jump to navigation Jump to search

Name

LICE stands for the LISP INTERCAL C Esoteric language.

Syntax

 prog  --> exp1 exp2             ` exp1: command line, exp2: exit code `

  exp  --> (exp1 exp2 exp3)        ` assignment `
       --> .num                    ` integer variable `
       --> ,num                    ` array of integer variables `
       --> ;num                    ` floating-point variable `
       --> :num                    ` macro `
       --> #num                    ` numeric constant `
       --> $num                    ` I/O handle `
       --> binop exp1 exp2         ` arithmetic etc. on expressions `
       --> unop exp                ` arithmetic etc. on expressions `
       --> [exp-list] exp1 exp2    ` arithmetic if-then-else `
       --> {exp-list}              ` array constant `
       --> 'char                   ` character constant `
       --> "char-list"             ` array of character constant `

binop  --> +        ` addition `
       --> -        ` subtraction `
       --> *        ` multiplication `
       --> /        ` division `
       --> %        ` remainder `
       --> &        ` bitwise AND `
       --> |        ` bitwise OR `
       --> ^        ` bitwise XOR `
       --> <        ` less-than `
       --> =        ` equals `
       --> >        ` greater-than `
       --> @        ` array concatenation and INTERCAL mingle `
       --> !        ` array indexing and INTERCAL select `

 unop  --> ~        ` bitwise NOT `
       --> ?        ` random number `
       --> \        ` converts nonzero to #1 `

 char  --> character      ` Unicode codepoint of character (not \) `
       --> \character     ` escaped character (like in C) `

  num               ` a decimal integer `

Description

Whitespace is ignored (except in special syntax: ', " and `). The backquote ` is used to open and close comments. There has to be a space either side of each ` - this allows for extension to the language.

The most important construct is the assignment (exp1 exp2 exp3). This evaluates exp2 and assigns exp1 (an lvalue) to it. The whole assignment-expression then evaluates to exp3.

All variables are global. Each variable has a number, and a symbol in front for its type: . integer, , array of integers, ; floating-point and $ for I/O handles (see below).

Type coercion is done automatically between integers and floating-point numbers, in the C way, but arrays cannot be coerced into scalars, nor vice-versa (use indexing and array constants).

Integer constants are like integer variables, but with # in front. Array constants are written within braces { }; the entries are just a list of expressions (no separators). For text, a shorthand can be used: ' in front of a character other than \ is that character's Unicode codepoint, and '\ can be used for C-style escapes. Array constants of characters can be written in double-quotes ". If a constant is used as an lvalue in an expression, any alteration will be ignored.

Macros are defined by using a :num as the lvalue of an assignment. Basically the code in the rvalue of the assignment is saved, and every time :num is used in an expression, the saved code is substituted. Recursion is fully supported (since this is the ONLY method of flow control).

Expressions are generally operation-operand-operand or operation-operand. + - * / % are the basic mathematical binary operators. & | ^ ~ are the bitwise operators. < = > are the comparison operators. @ is concatenation (on arrays) and INTERCAL mingle (on numbers). ! is indexing (on arrays - zero-based) and INTERCAL select (on numbers). ? generates a random floating-point number between zero and it's operand. \ converts all nonzero expressions to #1.

[exp-list] exp1 exp2 is the arithmetic if-then-else. It sequentially evaluates each exp in the list (no separators), until one of them evaluates to zero, or it runs out of expressions. This is then used to decide which of the exps after it to evaluate. If all exps in the brackets are nonzero, then exp1 is evaluated, otherwise exp2 is evaluated. (Note that it uses lazy evaluation both inside and after the brackets.)

The whole program is a special type of assignment, but with only two expressions. The first is assigned to the command-line arguments, and the result of evaluating the second is returned to the system as the status/exit code.

I/O is done with variables starting with $. I don't want to bother defining exactly how it all works, but basically, every odd-valued handle allows access to the I/O data, and the even-valued handle after it allows the changing of its I/O mode. By default, if an integer or floating-point number is assigned to $1, it is printed as a number; if an array is assigned to $1, it's elements are printed as a string; and similarly for assigning $1 to something else.

Examples

Hello world

#0($1"Hello, world!\n"#0)

Fibonacci sequence

Infinite:

#0(:1(.3+.1.2($1.3(.2.1(.3.2:1))))(.1#1(.2#1:1)))

Prints a certain number of numbers (given in the command-line). Has an exit code of 0 if inputted number was positive; otherwise exits with 1 (and doesn't print anything):

.4(:1(.3+.1.2($1.3(.2.1(.3.2(.4-.4#1[.4]:1#0)))))(.1#1(.2#1[>.4#0]:1#1)))