CLCLC-INTERCAL

From Esolang
Jump to navigation Jump to search

CLCLC-INTERCAL by User:Zzo38 is a variation on CLC-INTERCAL, just like CLC-INTERCAL is variation on C-INTERCAL and INTERCAL-72. These are the differences of CLC-INTERCAL are listed here, please.

Compiler options

It uses compiler options similar to 1972 INTERCAL, with these additional options:

  • NOOPTIMISE,OPTIMISE: Selects optimiser on/off.
  • POLITE,MEAN: If MEAN, ignores how many PLEASE commands there are.
  • ASCII,BAUDOT,EBCDIC,HOLLERITH: Select character set. Everything is represented internally in EBCDIC (the CLC-INTERCAL set).
  • EARLY,NOEARLY: If EARLY then lectures are allowed to be before (1000), if NOEARLY then it is not allowed to have lectures before (1000).
  • ROMAN,WORDS: Tells if numeric input should be in Roman numerals or in the words for the digits.
  • CLOCK,NOCLOCK: Setting CLOCK causes roman number 4 to be output as IIII instead of IV, in case you don't want to offend IVPITER when you turn the printout (or computer screen) upside-down.

Threading with COME FROM, NEXT/FORGET/RESUME, computed labels (even in the "label" part of the statement!), and COME FROM/NEXT FROM gerunds are automatically supported. Wimpmode (which means input/output numbers by digits) is not supported, and bases other than base 2 are also not supported. There is no "automagical inclusion" of system libraries, you have to do it manually.

Labels and register numbers larger than 65535 are supported but you can't enter them directly, it can be used only by overloading and computed labels and other similar things. Labels and registers 0 are reserved by the interpreter and therefore cannot be used (well, you can try to use them, but you might mess up everything or make error messages occur, etc).

There is also a compatibility mode setting:

  • CLCLCINTERCAL = the default mode
  • 1972INTERCAL = compatibility with 1972 INTERCAL
  • CINTERCAL = compatibility with C-INTERCAL
  • CLCINTERCAL = compatibility with CLC-INTERCAL
  • SIDEWARDS = sidewards compatibility
  • SNIDEWARDS = snidewards compatibility

And also there is no limit to the number of NEXTing or STASHing or backtracking or anything else like that, it is limited only by the memory.

Classes and lectures

You can even IGNORE or STASH or RETRIEVE or REMEMBER a class register, which causes it to store the subjects that class teaches and the label for those lectures. Also, even classes can enrol to learn another class, so you can even make classes that are dynamically defined.

The && operator allows you to learn a subject inside of a expression. The left side is a student and the right side is any expression. First it will assign the value of the expression to the student, make the student learn subject #65535 and then when the lecture is finished the expression will return the new value of the student.

Quantum INTERCAL

Quantum registers are registers indicated by the | (spike) character. Quantum registers can be STASHed, RETRIEVEd, IGNOREd and REMEMBERed (although it will not necessarily have the effect you might want, only the register is stashed/retrieved/ignored/remembered (which is only useful if you recreate the qubit the register corresponds to), not the quantum value of the register, which is uncopyable). The quantum values stay throughout threads and backtracking points.

The commands:

DO QUANTUM expression statement
DO quantumregister <- expression
DO TRANSFORM expression

There is a new binary operator the Controlled-V operator which is _ (flatworm). It does a controlled-V with the left and right side and returns the new quantum value of the left side.

A numeric expression where a quantum expression must be used is replaced with a temporary quantum value, which may be assigned to a quantum register for non-temporary. The numeric expression is the real part interleave by imaginary part, of the probability, with #0 being zero percent and '#100$#0' being one hundred percent.

If a quantum expression is used where a numeric expression is required, it will do a measurement and return #0 if false or '#100$#0' if true (either way as a 32-bit number).

In a quantum command, the stuff it changes will be stored as a quantum change, which will only be measured when a non-quantum command is executed that depends on the result of the quantum command. A quantum command can have separate NOTs both before QUANTUM and after the quantum expression.

The TRANSFORM command does a Hadamard transform on the expression.

And if after doing a measurement on a qubit in order to figure out the result of a non-quantum command, if it generates a error it will adjust the qubit to the other value.

The following commands can be QUANTUM (i.e. have quantum probabilities associated):

ABSTAIN FROM (labels only, not statements)
Calculate
DEFINE (functional programming)
ENROL
ENSLAVE
FREE
GRADUATES
IGNORE
REINSTATE (labels only, not statements)
REMEMBER
RETRIEVE
STASH
STUDY
SWAP

(Commands that adjust program flow are not allowed to be QUANTUM. This is different than CLC-INTERCAL.) Also, expressions are still calculated at the time the quantum command is executed, the quantum probability only refers to the quantum probability of assigning a value, abstaining from a label, the student having graduated, etc.

The part about figuring out what a quantum register refers to when being used as part of a quantum probability is always classical (non-quantum), so always does measurements if necessary.

Input/output

Numeric input/output is same as 1972 INTERCAL. However if the ROMAN parameter is given, input will be in roman numerals. If using words, in addition to the standard words usable, you may also use FOWER in place of FOUR, FIFE in place of FIVE, and NINER in place of NINE, if you want to.

Binary I/O by bytes applies to 16-bit arrays. Each element of the array is one byte, using numbers #0 to #255 and #65535 for end-of-file.

Text I/O uses 32-bit arrays, output using Baudot (just normal Baudot, not the extended Baudot that it uses for reading the program codes). Each element in the array corresponds to 6 Baudot codes, low bits 0-4 are the first character, 5-9 the next, 10-14, 15-19, 20-24, 25-29, and bits 30 and 31 are not used on output. A null (code 0) is outputting no character. For input, bits 30 and 31 indicate how many characters input for each element of the array: 0=five characters, 1=no characters, 2=one character, 3=only input to replace null characters in the array.

(Note that the CLC-INTERCAL reference is wrong, L is actually 18 (decimal) and W is 19 in Baudot. CLCLC-INTERCAL uses correct Baudot, not the wrong Baudot in the CLC-INTERCAL manual. Also, figures character 20 (decimal) is # sign)

I/O using class registers indicates which I/O device or mode is being used, which one depends on where the program is being used, for example you might have two printers each in a different room, using @1 for the printer in this room and @2 for the printer in that room.

Operators/expressions

Here is the difference from CLC-INTERCAL:

  • Ownership paths use 1 instead of $ as in CLC-INTERCAL.
  • _ registers don't exist anymore (they aren't needed, compiler is only modified while the program is running, not at other times).
  • The unary operators OR,XOR,AND, and division, do not exist.
  • If using ASCII encoding, the interleave operator is $ (as in C-INTERCAL).
  • A new binary operator & which is the "cellular automata" operator. The left is the data, the right is the cellular automata specification. It is not specified as a normal cellular automaton number, please see section about it below for information about how it is specified.
  • Another new binary operator is the && operator which is not the same as & operator. See the above "classes and lectures" for information.
  • More new binary operator _ is Controlled-V operator. See information about quantum INTERCAL.

Cellular automata

Cellular automata is specified differently than normal cellular automata.

The identity function is number zero.

The bits 0 to 9 specify conditions for toggling bit at current position (0 specifies require 0, 1 specifies require 1, . specifies don't care, () specifies current position, w=wrapping, nw=non-wrapping):

  • bit0 = (.)
  • bit1 = 1(0) w
  • bit2 = 0(0) w
  • bit3 = 0(1) w
  • bit4 = 1(1) w
  • bit5 = (.)0 w
  • bit6 = (.)00 w
  • bit7 = (.)000 w
  • bit8 = 1(.) nw
  • bit9 = 0(.) nw

The bits 10 to 12 specify conditions for toggling all bits at once:

  • bit10 = (0)
  • bit11 = (1)
  • bit12 = 1(0) w

The bits 13 to 15 specify conditions for toggling other bits:

  • bit13 = (0) toggle all zero bits consecutively this one and extending to the right, non-wrapping
  • bit14 = (1) toggle all one bits consecutively this one and extending to the left, non-wrapping
  • bit15 = (1) toggle all bits to the right of this one

Examples:

  • The XOR operator is #18
  • The OR operator is #2
  • The AND operator is #8
  • The NOT operator is #1
  • The identity operator is #0

Compiler modification

Compiler modification can be done using CREATE and SWAP and CREMATE (the new name for DESTROY, just for confusion) commands like CLC-INTERCAL. However, some commands are different so it won't work exactly the same. Also the way of the compiler won't work exactly the same either.

Terminals matching text, if using number constants you must now use EBCDIC numbers instead of ASCII numbers.

If you use AS code, the code can also be a 16-bit or 32-bit array in which case it uses those as the bytes from the array as the bytecodes to generate. The array can also be used in place of a terminal to use the contents of that array as the EBCDIC codes for the text to match.

You can run multiple programs after each other by specifying multiple programs names on the command line, so you can modify syntax and use it in the next program. Each program in this line runs after the previous one stops, with all the same states and syntaxes, but with different labels.

Note that you cannot swap or convert between BODY WHILE CONDITION and CONDITION WHILE BODY. You have to use CREMATE/DESTROY and CREATE to modify the syntax in that way.

The ?TYPE flag no longer exists in CLCLC-INTERCAL, because of the way the compiler works, that flag would not do anything.

New opcodes

As well as removing some CLC-INTERCAL opcodes, CLCLC-INTERCAL also has some new opcodes. Some of the new opcodes not specified anywhere else in this text is listed here.

There is a opcode for creating new operators. The parameters to this opcode consists of:

  • The number of arguments
  • An expression indicating a label
  • Registers for each argument
  • Values for each argument

That opcode will do stash the current value of each register followed assigning to each one (if the registers are the same it will make a stack containing the values), and when FINISH LECTURE is executed it will get the new value of the first register argument for the expression's value and then retrieve the first register (it won't automatically retrieve the other registers, you have to do that during the lecture).

Exporting programs

You can import and export using IMPORT and EXPORT commands. They can be in multiple programs in the program chain indicated on the command line. The exporting program must come first, and then the importing program. After EXPORT or IMPORT you give the numbers indicating what to import/export, separated by + (intersection) sign. It will check for matching import/export in a similar way to enrol for classes according to the subject it teaches. If you IMPORT, it will include the contents of the export file at the end of the file that imports it. In this way, you can create standard libraries and such things as that.

For example:

DO EXPORT #1
PLEASE DO GIVE UP
(1000) PLEASE NOTE standard library codes, etc...

Now you might import as follows:

DO .1 <- #1
DO %50 (1000) NEXT
PLEASE IMPORT .1
DO (1000) NEXT

In this example, the first line will be a error if executed because label (1000) doesn't exist yet before you imported it. The third line will work because (1000) now exists.

Assigning to expressions

You can even assign to constants, such as:

DO .4 <- #1
PLEASE DO #3 <- #4
DO .3 <- #2

and now .4 has #2 value.

You can assign to any expression in which case it will modify the operand on the left of the expression to make the expression have the correct value, if this is impossible it is a error, unless that register is ignored.

If the operator has no inverse, it will try each value starting at #0 and incrementing until it finds the correct value, without ever backtracking. It will backtrack in case of a error during the lecture, however.

Networking

You can set up a CLCLC-INTERCAL program to run on network. It uses STEAL and SMUGGLE commands same as CLC-INTERCAL, but there is no CASE command, network lookups are performed differently.

Using STEAL or SMUGGLE without ON and FROM is only useful if only a single connection is used in the networking. If multiple conections are being used you need to use ON and FROM to indicate which one.

The FIND command will find a process or address. For example:

DO FIND ,1
DO FIND ,2 FROM ,1SUB#1

This will load the list of addresses into ,1 and then load the list of processes from the first address found into ,2. It is a error if there is no address or no process. Using a normal register (not array) will tell how many there is, instead, in which case it is not an error to not have any, it will just set it to zero instead.

Functional INTERCAL

Commands for functional:

DO APPLY functional
DO SUSPEND expression
DO EVALUATE register

The functional operator is $$ which returns a functional, and can be used with APPLY command. The left half is a label (or another functional) and the right half can be any expression.

APPLY will call the label using NEXTing using number on the left of a functional expression. If the left half is a functional then it will call that functional and replace the return value with the .# returned from that functional and then do the next one. And .# register will correspond to the value on the right.

Using SUSPEND will cause the functional to return a functional corresponding to the current position in the program with the value of given expression stored in 1.# when it comes back to this point and the value on the right of the called functional to be placed in 2.# when it comes back. You will need to free .# from 1.# and 2.#, which will also free the memory. The suspending also includes the return stack, so the return stack will also be restored when the suspension stops suspending and continues.

The .# register can also be assigned to in this mode, in which case when you RESUME that part of the expression will be set to that value when doing the next functional.

The EVALUATE command takes a register storing a functional and performs an evaluation on it and stores the result in the same register.

Example ((1) implements the i combinator and (2) implements the k combinator):

(2) DO SUSPEND #0
DO FREE .# FROM 2.#
PLEASE FREE .# FROM 1.#
(1) DO RESUME #1

This example uses lazy evaluation but you can change it to eager by using EVALUATE command.

Namespaces

You can even have namespaces in INTERCAL. You assign namespaces using the NAMESPACE command, example:

PLEASE DO NAMESPACE #33 AS ,TIMER,

You may also import/export namespaces, for example:

DO NAMESPACE #14~'.4$.5' IMPORT #1
DO EXPORT NAMESPACE #100 AS ,FAKENAMESPACE,

And then any time a namespace may be accessed using the NAME operator, representing a register or label in a different namespace.

To call a subroutine in namespace #33 with a parameter in register .1 in namespace #33, you could do:

DO #33 NAME .1 <- .1$.1
DO #33 NAME #4 NEXT

And you can even have things like:

(#33 NAME #5) PLEASE COME FROM #34 NAME '#0 NAME ,1 SUB #1'

Because the NAME operator can really mean two things, a number which might represent a label (or subject) in another namespace or naming a register in another namespace, the naming a register is assumed if possible, otherwise the naming a label is assumed. Namespace #0 always represents the current namespace.

Backtracking

You can do backtracking just like backtracking INTERCAL, using MAYBE and GO BACK and GO AHEAD commands. Even modified syntax and events is stored in backtracking points. But abstaining and importing and quantum values is not stored in backtrack points (although quantum registers are, just not quantum values).

There is one register in which itself, the stashing stacks for it, ignore state, ownership paths, etc is not stored in backtracking states and is global in all backtracking points, it is the CHOICE register. It represents the choicepoint/backtracking-point on the top of the backtracking stack (not counting quantum values, but quantum registers are still stored). The stashing stack for this register represents the rest of the backtracking stack.

There is also another normal (not global to all backtracking points) register called () which can be dimensioned as a array, and used as a array of choicepoints.

Also, the CHOICE register may be used as a namespace identifier, so that you may deal with registers in other choicepoints by doing things such as:

DO CHOICE NAME .1 <- .1
PLEASE '() SUB #3' NAME .3 <- '() SUB #1' NAME .3

And you can also use CHOICE and elements of () as labels to NEXT or COME FROM, in which the label will be the statement immediately after the MAYBE statement. (But it is not valid in the label part of a statement.) For example, you can do something like this:

MAYBE DO NOT COME FROM CHOICE

Front-tracking

Vector INTERCAL

You can do vectoring in CLCLC-INTERCAL, using the binary VECTOR operator. Each side must be an array of equal dimension, but do not have to have the same data type, and each side must point to a different array. If used in an expression on the left side of a WHILE statement, it will execute the WHILE statement for each pair of one element from the left array and one element from the right array. It will do the same in any other statement, just executing the statement multiple times. The operator returns something that is not an error, but if used with anything that actually cares about its value, it is an error.

Example ways of using:

(1) DO ,1 VECTOR ,2 WHILE (45) NEXT
(2) DO ,1 VECTOR ,2 NEXT
(3) DO QUANTUM |5 ,3 VECTOR ,1 <- #0
(4) DO QUANTUM |5 .1 <- ,3 VECTOR ,1

Line (1) calls (45) as many times as necessary for each pair. Line (2) is always an error. Line (3) is an error as soon as |5 is measured (which includes any time ,3 is used, unless it is redimensioned before it is used), because ,3 VECTOR ,1 is always an error no matter what value ,3 has and therefore it cannot possibly make ,3 VECTOR ,1 have the value #0 therefore it generates an error. Line (4) is an error as soon as it is executed because the right side of the assignment is calculated as soon as possible (the exception is if ,3 or ,1 depend in quantumness).

During the command executed while vectoring, either array may use SUB#0 in which case it uses the current index which is the one being used. You may also use the special .# register, which is an error if the indices for each array is different, or the current index if both are the same.

Dynamically writing the source-codes

In addition to changing syntax while keeping the source-code same, you can dynamically modify source-codes at run time. The new commands to do this are:

DO APPEND array
DO BECOME array
DO REPLACE array WITH array
DO REPLACE class WITH array
DO label REPLACING array WITH array
DO label REPLACING class WITH array

The arrays are 16bit arrays or 32bit arrays, containing EBCDIC numbers for the characters in the source code. APPEND appends something to the end, BECOME replaces the entire source-code and restarts from the beginning, and REPLACE causes part of the source-code matching something to be replaced with something else. This is a case-sensitive global replace.

The class is a syntactic class, and causes it to replace anything that matches that syntactic class in the current syntax. If the label REPLACING form is used, then for each instance of that in the source-code it will set the array to the current text there, do that label NEXT, and then replace with the new values of that array.

Executing bytecodes

There is a command to execute bytecodes that you put a array of bytecodes and it will execute that one until that byte codes gives up. Modifying compiler/source-codes will modify these codes but won't affect the bytecodes. Also the bytecodes have their own labels and stuff like that too, but it can still access other namespaces. The command can be in the format:

DO EXECUTE array

Example (which doesn't seem to do anything useful):

DO ,1 <- #2
DO ,1 SUB #1 <- #15
PLEASE DO ,1 SUB #2 <- #42
DO EXECUTE ,1

Slavery

There is more commands for dealing with slavery in CLCLC-INTERCAL, such as:

DO FREE ALL FROM register
DO register SLAVES LEARNS subject
DO ENROL register SLAVES TO LEARN subjects
DO register SLAVES GRADUATES
DO register SLAVES <- expression
DO STASH register SLAVES
DO RETRIEVE register SLAVES
DO IGNORE register SLAVES
DO REMEMBER register SLAVES
DO FREE register FROM ALL
DO register OWNERS LEARNS subject
DO ENROL register OWNERS TO LEARN subjects
DO register OWNERS GRADUATES
DO register OWNERS <- expression
DO STASH register OWNERS
DO RETRIEVE register OWNERS
DO IGNORE register OWNERS
DO REMEMBER register OWNERS

These commands are used to deal with all slaves or owners of a register all at once.

UTF-INT

UTF-INT is a unicode encoding for using with INTERCAL EBCDIC encoding. The 1x represents the least significant nybble of a character and goes first, 2x is in middle, 3x is the last byte of a unicode character and is the most significant nybble.

INTERCAL EBCDIC characters are not treated equivalent to their corresponding unicode characters, so even though 11 34 and C1 both represent uppercase "A", they are treated as two different characters by INTERCAL. When creating a syntax you have to indicate each byte of the unicode character separately.

Examples

One example of how to dynamically define a class:

DO STUDY #1 AT (1000) IN CLASS @1
PLEASE DO ENROL @2 TO LEARN #1
DO .3 <- #42
DO ENSLAVE @2 TO .3
PLEASE @2 LEARNS #1
DO @2 GRADUATES
DO FREE @2 FROM .3
DO GIVE UP
(1000) DO STUDY '11@1'$#1 AT (4000) IN CLASS 1@1
DO STUDY '11@1'$#2 AT (4003) IN CLASS 1@1
DO STUDY '11@1'$#3 AT (4010) IN CLASS 1@1
PLEASE FINISH LECTURE

Example of creating a new syntax:

DO CREATE ?VERB ,INCREMENT, ?EXPRESSION AS ENS + WHP + #99 + ?EXPRESSION #1 + NXT + #99

Hello world program (output only):

PLEASE ;1 <- #2
DO ;1 SUB #1 <- #17947$#20775
DO ;1 SUB #2 <- #5204$#21386
DO READ OUT ;1
PLEASE GIVE UP

Here is a program which outputs all numbers 1 to 2000 in order:

DO STUDY #65535 AT (1000) IN CLASS @1
DO ENROL .1 TO LEARN #65535
DO .1&&.1 <- #2000
PLEASE DO GIVE UP
(1000) DON'T READ OUT .1
DO REINSTATE (1000)
PLEASE FINISH LECTURE

Because of the way error-checking works with quantum probabilities, the following program will output III, unless line (95) is abstained from (or omitted) in which case it will output II instead:

DO |1 <- #0
DO ,1 <- #3
PLEASE DO .1 <- #0
DO QUANTUM |1 .1 <- #1
(95) DO ,1 SUB #3 <- ,1 SUB .1
DO .1 <- #1$.1
PLEASE READ OUT .1

Some program which might implement the Deutsch algorithm or maybe it doesn't, I wouldn't understand completely what it does:

DO |1 <- #0
DO |2 <- #100$#0
DO TRANSFORM |1
DO TRANSFORM |2
DO (13000) NEXT
DO TRANSFORM |1
DO TRANSFORM |2
DO .1 <- #0
DO QUANTUM |1 .1 <- #1
DO READ OUT .1

See if you can figure out this example, please:

(1) PLEASE STASH ,1
DO ,1 <- .1
DO .1 <- #1
PLEASE REINSTATE (2)
MAYBE NOT .1 <- #0
DO ,1 SUB .2 WHILE ABSTAIN FROM (2)
(2) PLEASE GO BACK
PLEASE DO RETRIEVE ,1
DO GO AHEAD
DO RESUME #1