DGOL

From Esolang
Jump to: navigation, search

DGOL (Directed Graph Oriented Language) is an imperative programming language in which all values are pointers to nodes within directed graphs.

Lexical Structure

Linear whitespace is ignored.

Identifiers consist of 1 or more alphanumeric characters, with the exception of "0".

Comments begin with "*" and extend to the end of the line, and may only appear where a newline is allowed in the grammar.

EBNF Syntax

module = { use-declaration | newline }, { subroutine-definition | newline }, ( program-definition | library-definition ), { newline } ;

use-declaration = "USE", identifier, newline ;

subroutine-definition = "SUBROUTINE", identifier, "(", [ identifier, { ",", identifier } ], ")", newline, statements, "END", identifier, newline ;

program-definition = "PROGRAM", identifier, newline, statements, "END", identifier, newline ;

library-definition = "LIBRARY", identifier, { subroutine-declaration | newline }, "END", identifier, newline ;

subroutine-declaration = "SUBROUTINE", identifier, newline ;

statements = { [ statement ], newline } ;

statement = let-statement | if-statement | do-statement | call-statement | return-statement | exit-statement ;

identifier-or-0 = identifier | "0" ;

let-statement = "LET", identifier, ( "=", identifier-or-0 | "<", identifier | ">", identifier-or-0 ) ;

if-statement = if-head, { "ELSE", if-head }, [ "ELSE", newline, statements ], "END", "IF" ;

if-head = "IF", identifier, ( "=" | ">" ), identifier, newline, statements ;

do-statement = "DO", identifier, [ "<", identifier ], newline, statements, "END", "DO" ;

call-statement = "CALL", identifier, [ ".", identifier ], "(", [ identifier-or-0, { ",", identifier-or-0 } ], ")" ;

return-statement = "RETURN" ;

exit-statement = "EXIT", identifier ;

Variables and Values

A node has an identity and a set of edges, where each edge points from itself to another node or itself. A new node has no edges.

Unreachable nodes and edges are garbage collected.

A variable holds a pointer to a node. Variables are created at first use, containing a pointer to a new node, and are scoped to the program or subroutine in which they are used. Each subroutine call creates a new scope.

Variables are passed into subroutines by reference.

Declarations and Definitions

USE declarations import library modules, which contain subroutines that can be called with the CALL statement. Duplicate USE declarations in a module are not allowed.

SUBROUTINE definitions define subroutines that can be called within the module, or can be exported from a library module for other modules to USE and CALL. The subroutine name must be unique within a module.

A PROGRAM definition defines the main entry point of a program. A program must have exactly one module with a PROGRAM definition.

A LIBRARY definition contains a list of exported subroutines from the module. A module must have one PROGRAM definition or one MODULE definition, but not both.

Statements

There are three varieties of LET statements.

The first type of LET statement, with "=", points a variable on the left hand side to the node pointed to by the variable on the right hand side, or, if the right hand side is "0", a new node.

The second type of LET statement, with ">", adds an edge from the node pointed to by the variable on the left hand side to the node pointed to by the variable on the right hand side, or, if the right hand side is "0", a new node. If the edge already exists, there is no effect.

The third type of LET statement, with "<", removes any edge from the node pointed to by the variable on the left hand side to the node pointed to by the variable on the right hand side. If there is no such node, there is no effect.

There are two varieties of IF statements.

The first type of IF statement, with "=", executes its branch if the node pointed to by the variable on the left hand side is the same as the node pointed to by the variable on the right hand side. Otherwise, the following ELSE branch, if present, is executed.

The second type of IF statement, with ">", executes its branch if there is an edge from the node pointed to by the variable on the left hand side to the node pointed to by the variable on the right hand side. Otherwise, the following ELSE branch, if present, is executed.

There are two varieties of DO statements.

The first type of DO statement, with a single identifier labeling the loop, repeatedly executes its statements unless an EXIT or RETURN statement is executed.

The second type of DO statement iterates over edges of the node pointed to by the variable on the right hand side, setting the variable on the left hand side to the node pointed to by each edge prior to executing the statements in the body. The set of edges is determined at the start, and is not affected by any changes to the nodes when executing the body. The order of iteration is unspecified.

A CALL statement calls a subroutine defined in the module or, if qualified with a module name plus ".", in another module. If there are fewer arguments provided than parameters in the subroutine definition, the additional parameters are set to new nodes. Any arguments in excess of the parameters in the subroutine definition are ignored.

A RETURN statement returns the execution to the caller. RETURN statements are not allowed in a PROGRAM definition. Reaching the end of the statements in a subroutine body is an implicit return.

An EXIT statement causes execution to continue with the statement following the containing DO statement with the matching label.

Standard Library

The IO library is defined as

 * THE IO LIBRARY DEFINES 2 SUBROUTINES
 
 * IO.READBYTE READS A BYTE
 * IF EOF IS ENCOUNTERED, AN EDGE IS ADDED FROM BYTE TO EOF,
 * OTHERWISE ANY EDGE FROM BYTE TO EOF IS REMOVED.
 * IF THE 1 BIT IS 1, AN EDGE IS ADDED FROM BYTE TO 1,
 * OTHERWISE ANY EDGE FROM BYTE TO 1 IS REMOVED.
 * IF THE 2 BIT IS 1, AN EDGE IS ADDED FROM BYTE TO 2,
 * OTHERWISE ANY EDGE FROM BYTE TO 2 IS REMOVED.
 * IF THE 4 BIT IS 1, AN EDGE IS ADDED FROM BYTE TO 4,
 * OTHERWISE ANY EDGE FROM BYTE TO 4 IS REMOVED.
 * IF THE 8 BIT IS 1, AN EDGE IS ADDED FROM BYTE TO 8,
 * OTHERWISE ANY EDGE FROM BYTE TO 8 IS REMOVED.
 * IF THE 16 BIT IS 1, AN EDGE IS ADDED FROM BYTE TO 10,
 * OTHERWISE ANY EDGE FROM BYTE TO 10 IS REMOVED.
 * IF THE 32 BIT IS 1, AN EDGE IS ADDED FROM BYTE TO 20,
 * OTHERWISE ANY EDGE FROM BYTE TO 20 IS REMOVED.
 * IF THE 64 BIT IS 1, AN EDGE IS ADDED FROM BYTE TO 40,
 * OTHERWISE ANY EDGE FROM BYTE TO 40 IS REMOVED.
 * IF THE 128 BIT IS 1, AN EDGE IS ADDED FROM BYTE TO 80,
 * OTHERWISE ANY EDGE FROM BYTE TO 80 IS REMOVED.
 * IF ANY ARGUMENT REFERS TO THE SAME NODE AS ANOTHER ARGUMENT, THE
 * RESULT IS UNDEFINED.
 SUBROUTINE READBYTE(BYTE, EOF, 1, 2, 4, 8, 10, 20, 40, 80)
   * IMPLEMENTATION UNSPECIFIED
 END READBYTE
 
 * IO.WRITEBYTE WRITES A BYTE
 * IF THERE IS AN EDGE FROM BYTE TO 1, THE 1 BIT IS 1, OTHERWISE IT IS 0.
 * IF THERE IS AN EDGE FROM BYTE TO 2, THE 2 BIT IS 1, OTHERWISE IT IS 0.
 * IF THERE IS AN EDGE FROM BYTE TO 4, THE 4 BIT IS 1, OTHERWISE IT IS 0.
 * IF THERE IS AN EDGE FROM BYTE TO 8, THE 8 BIT IS 1, OTHERWISE IT IS 0.
 * IF THERE IS AN EDGE FROM BYTE TO 10, THE 16 BIT IS 1, OTHERWISE IT IS 0.
 * IF THERE IS AN EDGE FROM BYTE TO 20, THE 32 BIT IS 1, OTHERWISE IT IS 0.
 * IF THERE IS AN EDGE FROM BYTE TO 40, THE 64 BIT IS 1, OTHERWISE IT IS 0.
 * IF THERE IS AN EDGE FROM BYTE TO 80, THE 128 BIT IS 1, OTHERWISE IT IS 0.
 SUBROUTINE WRITEBYTE(BYTE, 1, 2, 4, 8, 10, 20, 40, 80)
   * IMPLEMENTATION UNSPECIFIED
 END WRITEBYTE
 
 LIBRARY IO
   SUBROUTINE READBYTE
   SUBROUTINE WRITEBYTE
 END IO

References