HQ9+ with headers

From Esolang
Jump to navigation Jump to search

HQ9+ with headers is an esolang originally thought up by User:Cortex, though the only reference to ever exist was a single example, labeled 'Print "Hello, World!QHQQHQ"':

==== HEADER ====
COMMAND FLOW
    2,1,3
CHARACTER SEMANTICS
    H
        p("Hello, World!")
    Q
        p({{CODE}})
    9
        p({{99BOB}})
    +
        a++
STARTUP
    a = 0
    placeholders = ["CODE", "99BOB"]
CHECKSUM
    277
==== END HEADER ====
QHQ

This article is a full specification based off the example by User:BoundedBeans.


Syntax

A program consists of headers, followed by a program. The program should not be on the same line as a header.

Formal definition of lines

  • Take the entire code as one long string, and replace sequences of a carriage return followed by a line feed ("/r/n" in most programming languages) with just a line feed.
  • Replace each remaining carriage return with a line feed.
  • Split the string into an array of strings. A new string should begin at the first character, and at each line feed. The resulting strings should not contain any line feeds.
  • Each resulting string is a separate line

Headers

Headers begin with:

==== HEADER ====

And end with:

==== END HEADER ====

Both of these may have optional trailing spaces or tabs, but they may not have leading whitespace. They both must be on their own line.

Headers are divided into sections. Sections may also have subsections, to infinite depth. The line above the first line indented in the section is the name of the section.

Sections and subsections are indented by 4. Lines within the header markers must have exactly a multiple of 4 spaces before the first non-space character. Tabs, vertical tabs, and form feeds are considered to be part of the line.

Any line in a section may have trailing spaces, which are not considered to be part of the line. A horizontal tab, however, is considered part of the line, and also takes any preceding spaces until the previous horizontal tab or graphical character with it to be part of the line as well.

Program

The program consists of a list of commands. It must not be on the same line as a header or header marker. The program may spread across multiple lines. The commands are defined in the headers.

Standard headers

Non-standard header sections can be added as an extension, but their names must start with a double quote (").

COMMAND FLOW

This section is required.

It consists of a comma (,) separated list of base 10 numbers which is a permutation of numbers 1 to n, where n is exactly number of commands in the program. This determines the order of commands that will run in the program.

It may be broken up into multiple lines, which will be concatenated.

If the double quote (") is used as the first character of an element in this list, it indicates a non-standard control flow extension. It is not given a separate number to jump to.

If the single quote (') is used as the first character of an element in this list, it indicates special control flow. It is not given a separate number to jump to.

If the slash (/) is used as the first character of an element in this list, the element should be treated as if it weren't there, for comments about the control flow. It is not given a separate number to jump to.

Special single-quote control flow

'JZv#n where n is a number and v is a variable name, tests if the variable is equal to the number zero, and if so, jumps to instruction n. Otherwise, no jump is performed.

'J_n where n is a number, unconditionally jumps to instruction n.

'H halts the program.

'Fv#n where n is a number and v is a variable name, runs a POSIX fork, setting v to the return value of fork. If the interpreter can't fork, v should keep its current value and the program should jump to instruction n.

CHARACTER SEMANTICS

This section is required.

It consists of subsections named a single character. That character will be used in the program to refer to the command.

The section contents should be a list of semantic commands, each on their own line, to run. A command can be broken up into multiple lines by having the last non-space character be a backslash (\), which will be removed and also cause the next line to be treated as part of the same line. If you really need a backslash at the end of the line, you can do this:

(preceding commands)
The line after this is blank. \\ 

(following commands)

STARTUP

This section is required.

A sequence of semantic commands, each on their own line, to be run before the program. A command can be broken up into multiple lines by having the last non-space character be a backslash (\), which will be removed and also cause the next line to be treated as part of the same line. See the CHARACTER SEMANTICS section for more details.

CHECKSUM

This section is required.

Must contain one line containing a decimal number. The number must be a certain correct number depending on the program.

To get the number:

  • Take the text of the program (don't include the headers or line breaks), and add up the ASCII values of all the characters.
  • Modulo the result by 1024
  • Add 43 to the result

Variable names

Variable names can be any sequences of lowercase letters except for placeholders.

Semantic commands

p() No operation.

p("S") where S is any sequence of characters other than double quote (") or at signs (@), as well as sequences of the at sign followed by two uppercase hexadecimal digits representing byte escapes, will print the string S with the byte escapes turned to their corresponding bytes. It does not automatically print a newline, you must use @0A for that.

p(Vv) where v is a variable name, prints the contents of the variable.

p({{CODE}}) prints the program.

p({{99BOB}}) prints the lyrics to 99 bottles of beer. The exact format is not specified, and is implementation dependent.

v++ where v is a variable name, increments the variable.

v = n where n is a decimal number, sets v to n.

placeholders = S where S is any sequence of characters, no operation.

[ADD v u w] where v, u, and w are variable names, adds v and u and assigns the result to w.

[SUB v u w] where v, u, and w are variable names, subtracts v and u and assigns the result to w.

[MUL v u w] where v, u, and w are variable names, multiplies v and u and assigns the result to w.

[DIV v u w] where v, u, and w are variable names, divides v and u and assigns the result to w.

[~:: v u h i] where v and u are variable names and h and i are concatenated sequences of uppercase hexadecimal bytes. If v is greater than u, runs h as a semantic command, otherwise runs i as a semantic command.

[>>, v] where v is a variable name, assigns the ASCII code of a character of input to v.

[>>. v] where v is a variable name, assigns the ASCII code of a decimal number of input to v. To create the decimal number, an assumed 0 is supplied, and further digits are appended from characters of input until the first non-character, which is skipped (and can never be obtained again) and ignored, or EOF.

Examples

Infinite loop

==== HEADER ====
COMMAND FLOW
    1,'J_1
CHARACTER SEMANTICS
    N
        p()
STARTUP
    p()
CHECKSUM
    121
==== END HEADER ====
N

Truth-machine

==== HEADER ====
COMMAND FLOW
    1,'JZtruth#3,2,'J_2,3
CHARACTER SEMANTICS
    i
        [>>. truth]
    1
        p("1")
    0
        p("0")
STARTUP
    p()
CHECKSUM
    245
==== END HEADER ====
i10