Breeze XSBL

eXtensible Stack Based Language

 

Version 0.1.1

 

 

USER MANUAL

 

 

 

 

 

This is alpha software, which means it is usable and the feature list is almost complete but not totally implemented.

 

Disclaimer
The information provided in this document is provided "AS IS" without warranty of any kind, either express or implied, including, but not limited to, the warranty of non-infringement and the implied warranties of merchantability and fitness for a particular purpose.
Verbatim, copying and redistribution are permitted in all media for any purpose, provided all copyright notices are preserved along with related original URLs.

Copyright © 2015 Mauro DiNuzzo

 

 

 

 

 


 

 

 

Contents

 

 

 

 

 

 

 

Contents. 3

1 Getting Started. 5

1.1 Introduction.. 5

1.2 Download and installation.. 5

1.3 Compiling the source. 5

1.4 Limitations. 6

2 The language. 7

2.1 Features. 7

2.2 Top-level interpreter 8

2.2.1 The basics: numbers and lists. 8

2.2.2 The special application #.. 10

2.2.3 Including external files. 11

2.2.4 The stacks. 11

2.2.5 Control flow.. 12

2.2.6 Lambda programming. 13

3 Applications. 14

3.1 System stacks. 14

3.1.1 Named stacks manipulation. 14

3.1.2 Interpreter and meta-programming. 15

3.1.3 Standard stack manipulation. 17

3.1.4 List manipulation. 20

3.1.5 Control flow.. 25

3.1.6 Exception handling. 28

3.1.7 Debugging and profiling. 29

3.2 Libraries. 30

3.2.1 Mathematics. 30

3.2.2 Standard Input/Output 36

3.2.3 Operating System Interactions. 39

Index. 42

 


 

1 Getting Started

 

 

 

 

 

 

1.1 Introduction

The present project aims at providing a pure-homoiconic, pure-postfix stack-based programming language. At this stage, it is only a proof-of-concept, whose details might change substantially in future releases. For the sake of these preliminary testing procedures, the language is being developed on top of the SWI Prolog (http://www.swi-prolog.org/) environment. Purity and minimalism, not computational speed, have been the driving forces of the software. Nonetheless, possible success of this stage could stimulate developing the language in C/C++. User should use this software ONLY for learning/testing purposes.

At the moment, the only supported operating system is Windows. There are no plans to compile the software under other platforms/operating systems. Users interested in running the software on Linux or MacOS should contact the author directly via email at info@prologwebservices.com.

What follows is a brief tutorial on how to download, install and use the Breeze programming language. For more details about concatenative languages, see http://concatenative.org/.

1.2 Download and installation

The archive containing the software and documentation is available through SourceForge at http://sourceforge.net/projects/breeze-language/. To install the software, simply run the self-installer executable. At startup, the interpreter loads the init.brz initialization file, which is expected to be in the main program directory. Normally, this file is used to include standard libraries, but can be edited to incorporate user-specific operations.

1.3 Compiling the source

SWI Prolog (http://www.swi-prolog.org/Download.html) is required in order to compile the sources. To this end, consult the make.pl Prolog script located in the src directory. The Breeze.exe executable will be automatically created in the bin directory. The executable file does not yet support command arguments. Version 0.1.1 is compiled using SWI Prolog 6.6 (32 bit).

1.4 Limitations

Presently, the language inherits the limit stack size from the hosting programming language, which is of 128MB for the x86/win32 version of SWI Prolog.

Please also note that the description of the language given in the following chapters is far from exhaustive. In particular, many features of the language are not discussed throughout the manual. Nonetheless, chapter 3 contains the list of all applications (even those poorly or not documented).

The language is being enriched with libraries (e.g., regular expressions, ODBC support, HTTP client/server) that will be included in the distribution as they become usable (i.e. at least with a minimum of useful functionality).

Testing procedure are currently not operational and there is not yet a testing suite available for the language.

 

 


 

2 The language

 

 

 

 

 

 

2.1 Features

Breeze is a general-purpose programming language. The list of basic features can be summarized as follows. The language is:

The Breeze language shares many similarities with other popular stack-oriented programming languages. The main influences can be found in Chuck Moore’s Forth (http://www.forth.org/), Kevin Albrecht’s Joy (http://www.kevinalbrecht.com/code/joy-mirror/), Christopher Diggins’s Cat (http://www.cat-language.com/) and Slava Pestov’s Factor (http://www.factorcode.org/). The notion of a purely postfix-notation language also comes from Riad S. Wahby's Lviv (http://github.com/kwantam/lviv). It should be realized, however, that the sparse ideas taken from these languages have been “filtered” towards simplicity. The most striking difference from the above-mentioned concatenative languages, which is also the main feature of the language, is that the concepts of stack and dictionary are no longer distinct. In fact, dictionary words are replaced by named stacks. The process of defining a word is replaced by “pushing” onto a named stack, and that of executing a word is replaced by “popping” from a named stack. A named stack is called an application (strictly speaking, the application is represented by the code/data within the top element of the relevant named stack). The pushing and popping operations share an anonymous stack, where the actual applications work by default. Specifically, data and code can be moved between applications by using operations (i.e. other applications) that make use of a default stack as an intermediate. This approach is described in some details throughout the present manual.

In principle, the language recognizes only numbers (integers and floats, no core support for rational or complex numbers). Numbers can be organized into lists, which are enclosed in round parenthesis and can be arbitrarily complex structures containing zero or more elements (numbers or lists). Lists are the only form of aggregation of data/code. A distinguishing feature of the language is that a list might or might not be interpreted, and interpretation of a list must be explicitly required. Notably, no control is performed on list content. Indeed, the system cannot know whether a list is supposed to contain data or code. This feature gives the user the complete control on the program. The same representation for code and data (i.e. homoiconicity) identifies the powerful meta-programming capability of the language. From the above arguments, it follows that a program is actually a list containing numbers as well as lists of numbers. The latter feature makes the language purely untyped and also entails that run-time interpretation is the only possible execution mode.

In the practice, any sequence of characters that is not evaluable as a number or as a list is interpreted as a short-hand for a set of operations that could however be achieved by using only numbers and the special application # (see below). Note that the following characters are reserved:

·         (whitespace, used to separate elements);

·         (  ) (open/closed parenthesis, used to aggregate data/code);

·         ; (semicolon, used for inline comments);

The escape sequences \s and, for example, \50, \51 and \73 (i.e. octal character representation) can be used to represent whitespace, round parentheses and semicolon, respectively. Note that the number of spaces is never preserved, which means that spaces must be provided as escape sequence when they are needed (e.g., to print out things on the screen).

2.2 Top-level interpreter

Breeze is a run-time interpreted language. Presently, compilation is not implemented and the only interface to the language is a window containing a prompt waiting for user input.

This section briefly illustrates the main features of the language by giving some simple examples. Hereafter, the red color is used to identify code/data segments typed by the user, green color is used for comments and gray color is used for system responses. Stack names (i.e. applications) will be always introduced in the upper-case mode. However, the language is not case-sensitive. Unless otherwise specified, the default stack is referred to simply as the stack.

2.2.1 The basics: numbers and lists

Since Breeze is a stack-based programming language, data follow the last-in first-out (LIFO) mechanism. Data received on the input stream (initially the standard input) are pushed on the default stack. For example, pushing the integer 100 and the floats 2.0 and 3.0 on the stack can be done as follows:

100 2.0 3.0                  

In this case the numbers are separated by one or more space characters. Space is the standard “operator” used as separator.

In order to see the content of the stack the application PS can be used, as in:

ps                                ; Breeze is not case-sensitive, thus “ps” behaves like “PS”

100 2.0 3.0

DROP PS                       ; DROP removes the last element on top of the stack                                              

100 2.0

Applications can be used to perform operations on data. For example, the sum of two numbers on top of the stack can be accomplished by +:

100 2.0

+ PS                            

102.0

The two inputs have been “popped” (i.e. removed) from the stack, then the operation has been performed and finally the result of the computation has been “pushed” (i.e. added) onto the stack. Note that the result is float because one of the two numbers of the sum is float. The + application (i.e. the code contained in the + named stack) expects to find two numbers on top of the default stack. If this is not the case, an evaluation error (terms are not numbers) or a stack underflow error (stack does not contain enough terms) will be raised (see the THROW application in Section 3).

Let’s now assume that one wants to implement the “successor” operation in the SUCC stack. This can be done as follows:

(1 +)

(SUCC) PUSH

In the example, PUSH pushes the list (1 +) onto the SUCC application (note that the SUCC stack is created on the fly if it does not exist yet). The parentheses define a list, which is not interpreted but is simply pushed on the default stack.

Now it is possible to use the SUCC application to perform the successor operation, that is:

102.0

SUCC

PS

103.0

( ) CLR                           ; ( ) identify the default stack

The application CLR used above, clears (i.e. remove all elements from) an entire stack, in this case the default stack (identified by the empty list preceding CLR). Using the SUCC application by typing the name directly is equivalent to the following sequence of operations:

102.0

(SUCC) TOP PS                          ; 1. TOP puts the top element in SUCC onto the default stack

(1 +)

APPLY                                       ; 2. APPLY puts the list into use

PS ( ) CLR

103.0

The APPLY application “unwrap” the list on top of the stack, which is equivalent to execute the data/code contained in the list. An important feature of the language is that, by definition, it is straightforward to override an application (without losing anything previously pushed on the named stack itself), as in:

(2 +) (SUCC) PUSH

(SUCC) TOP PS DROP                 ; just to see what is on top of the SUCC stack now

(2 +)

10 SUCC PS DROP                    ; this applies the new definition

12

 

The operation SEE can be used to see the entire content of a stack, that is:

(SUCC) SEE PS DROP

((1 +) (2 +))

Elements contained in a stack can be removed using POP or CLR. For example, the second definition of SUCC given above can be removed by:

(SUCC) POP DROP

10 SUCC PS DROP                    ; using the old definition, as it is now on top

11

 

2.2.2 The special application #

Importantly, as stated before the code in the named stack identified by SUCC that is interpreted by just typing the corresponding name, is a short-hand for a set of operations that can be obtained using the following code:

100 (83 85 67 67) # (80 83) #

101

The special application # is the sole mandatory symbolic element known by the system (i.e. to avoid any circular definition). The rationale underlying the use of # is simple: it accepts a list of numbers identifying the Latin-1 (ISO 8859-1 encoding) character codes of a name. This list might be also well interpreted simply as an arbitrary code identifying that name. Anyway, in the above example 83 85 67 67 is the Latin-1 code for SUCC and 80 83 is the Latin-1 code for PS. Note that the Latin-1 code is unique and it refers to the upper-case mode of a name.

Oddly, writing programs this way would be very inefficient. Nonetheless, the # stack serves to illustrate the point that numbers and names can be considered analogous entities. For practical purposes, the # application is not a primitive, but it is defined as the sequence (CHR APPLY). The CHR operation converts a list of Latin-1-encoded characters into its representation, while APPLY puts into use the content of the list on top of the default stack.

The use of APPLY can be also illustrated by the following example:

(1 2.0 +) PS

(1 2.0 +)

APPLY PS

3.0

Note that initially the stack contains one element: the whole list, which in turn contains three elements. The APPLY application is equivalent to interpret the content of the list. The inverse operation of APPLY is performed by POP, as in the following example:

3.0

( ) POP PS DROP                      

(3.0)

The POP operation performed on the default stack is thus useful as list constructor, as it “wraps” the last element on top of the stack.

2.2.3 Including external files

The following example uses the INCLUDE application to switch the current input to a physical file:

(examples/fact.brz) INCLUDE  

5 FACT1 PS                               ; “FACT1” is defined in “examples/fact.brz”

120

Note that a file might in turn include other files. To avoid multiple inclusion, the INCLUDED operation can be used to check whether a file has already been loaded, which is what the ?INCLUDE application actually does.

2.2.4 The stacks

This section describes how to add and remove terms to/from named stacks. When the software starts, only primitives are defined. One of the design feature of the language is to keep the number of these primitives as low as possible. Thus, normally at startup several files are included that contain a number of definitions.

The standard actions to manage a named stack are achieved by means of the primitives PUSH, POP and TOP. A simple example is the storage of a constant numeric value:

(include/math.brz) ?INCLUDE

(pi) (x) PUSH                             ; note that “pi” is defined in “include/math.brz”

x 2 * PS DROP

6.2831852

(x) POP

x

Uncaught Exception -- STDIN:5: Stack Error (UNDERFLOW X)

The POP application removes the top element of a named stack and puts it on the default stack. It is possible to override even primitives by pushing arbitrary data/code onto them. The system stores the original definition in reserved stacks (see Section 3). Addition/removal of data or code to/from reserved stacks is not allowed.

2.2.5 Control flow

The standard control mechanism of the language is the simple If-Then-Else construct, which is identified by the primitive IFTE. It can be shown that this mechanism plus recursion is sufficient to achieve all control flow statements such as while/repeat loops, switch/case structures, and so on. As anything in Breeze, the If-Then-Else construct is implemented in a purely postfix notation, as in:

1 2.0 (DUP 0 <) (-) (+)

1 2.0 (DUP 0 <) (-) (+)

IFTE PS

3.0

The IFTE operation expect to find three lists on the top of the default stack (the choice of the lists order is motivated by program legibility). In particular, the user writes before the If condition, and subsequently the Then and Else parts. Within the If part, the above example makes use of the DUP operation, which duplicates the top element of the stack. After this, 0 is pushed and < (less-than) comparison is made, which removes two numbers from the stack and pushes the Boolean result (in this case 0, i.e. false). A Boolean value is what the operation IFTE expect to be contained in the If list. The other two lists are self-explaining: when the Boolean values is true the True part is applied and the Else part is “dropped”, and vice versa when the Boolean values is false. Note that numbers greater than zero are interpreted as Boolean true, whilst numbers less than or equal to zero are interpreted as Boolean false.

The If-Then-Else construct is the only primitive for control flow. As an illustration, user can examine the While-Loop implementation using IFTE and LAMBDA recursion described in Chapter 3. As an example of recursion, the following code implements the factorial:

                        (                                   ; n

(DUP 0 =)                      ; n n 0 =

(DROP 1)                       ; 1

(                                   ; n

DUP 1 -                        ; n n-1

FACT                             ; recursion

*                                  ; n n-1 n-2 ... 1 * * * … * (n-1 times)

)                      

IFTE

)

(FACT)  

PUSH    ; FACT will compute the factorial of the number on top of the stack

5 FACT PS

120

The above is the standard definition of the factorial using recursion. Another (computationally slower) version using only list manipulation can be found in the examples directory.

2.2.6 Lambda programming

A very simple version of Lambda calculus is implemented using local definitions (for the definition of LAMBDA see Chapter 3). For example, consider the simple successor operation of a number as defined above. It is possible to obtain the same result without explicitly defining a new stack using LAMBDA:

2.0 (1 +) LAMBDA PS

3.0

This behavior might appear to be identical to that obtained using the APPLY operation, and this is indeed the case in the above example. However, LAMBDA comes to be very useful when recursion is required as in the factorial example:

5

((DUP 0 =) (DROP 1) (DUP 1 - REC *) IFTE)                      ; same body of FACT1 (see above)

LAMBDA PS

120

Recursion is achieved using the REC operation, which is defined only within a LAMBDA operation. Please note that LAMBDA and REC are not part of the core primitives. Note also that LAMBDA can be nested, as subsequent definitions are pushed in the REC stack. Lambda programming is often used when an operation is expected to return more than one result and/or to perform many sub-computations to store temporal results without defining new stacks (see the SEL and INS operations described in Chapter 3).


 

3 Applications

 

 

 

 

 

 

In this chapter, the built-in named stacks implemented in the language are described in some details. Stacks corresponding to core operations are marked as “primitive”, whereas the other applications are defined in terms of these primitives.

3.1 System stacks

This section briefly describes the stacks that exist at startup without loading any external library (note that the default init.brz startup file include several files). The description is accompanied by the effect of the operation on the default stack. Specifically, the local stack prior to the call is shown on the left, while the local stack after the call is shown on the right (separated by a rightward arrow).

3.1.1 Named stacks manipulation

The stacks are accessed and manipulated using the primitives PUSH, POP, TOP, DEPTH, SEE and CLR.

PUSH

PRIMITIVE

( A1…An ) ( B )

Push A1…An in the stack referenced by B (i.e. the stack name representation).

POP

PRIMITIVE

( B ) ( A1…An )

Remove the top element of the stack B and move it to the default stack.

TOP

PRIMITIVE

( B ) ( A1…An )

Returns the top element of the stack B (without removing it) and push it to the default stack.

DEPTH

PRIMITIVE

( B ) C

Returns the number of elements in the stack B.

SEE

PRIMITIVE

( B ) ( ( A1…An ) … ( Z1…Zn ) )

Push the entire content of stack B on top of the default stack (as a single list) non-destructively (i.e. without removing anything).

CLR

PRIMITIVE

( B )

Remove all elements from the stack B.

3.1.2 Interpreter and meta-programming

System primitives include the EXIT, ABORT, INCLUDE and INCLUDED operation. Meta-programming is realized through the primitive APPLY and the non-primitive LAMBDA and REC operations. The non-primitive NOP operation is also described here.

EXIT

PRIMITIVE

Exit (halt system)

ABORT

PRIMITIVE

Abort execution. This is equivalent to press CTRL+C. Execution is also aborted after uncaught exceptions.

INCLUDE

PRIMITIVE

( A )

Tells the interpreter to receive input from an external resource A (presently, only source files are accepted).

INCLUDED

PRIMITIVE

( A ) 0 | 1

Return a Boolean value according to whether the resource A has been already loaded.

?INCLUDE

 

( A )

Include the external resource A only if it has not been already loaded. This operation is defined as:

((DUP INCLUDED) (DROP) (INCLUDE) IFTE)

(?INCLUDE) PUSH

APPLY

PRIMITIVE

( An…A0 ) An…A0

Put the list An…A0 into use.

#

 

( A1…An )

Interpret the content of the stack identified by its ISO Latin-1 code, as returned by the list of numbers A1…An. This operation is defined as:

(CHR APPLY)

(#) PUSH

LAMBDA / REC 

 

 ( A1…An )

Locally apply the program A1…An, and define the helper operation REC that can be used to achieve recursion. Note that on error REC will still be defined and its removal, if needed, must eventually be done using CATCH. This operation is not a primitive and it is defined as:

((REC) DEF REC (REC) POP DROP)

(LAMBDA) PUSH

NOP

 

No operation. NOP can be used to explicitly state that no action is required. This operation is defined as:

( )

(NOP) PUSH

3.1.3 Standard stack manipulation

Default stack manipulation is accomplished by the primitives DROP, PICK, and ROLL. By using these primitives it is possible to perform complex operation on the elements of the stack, as will be described in the following.

DROP

 

PRIMITIVE

A

Remove the top element from the stack.

PICK

PRIMITIVE

A0…An n A0…An A0

Duplicate nth stack element on top of the stack, where the top of the stack position is identified by index 0.

ROLL

PRIMITIVE

A0…An n A1…An A0

Move nth element of the stack on top of the stack, where the last element pushed on top of the stack is identified by index 0.

DUP

 

X X X

Duplicate the top element of the stack. This operation is defined as:

(0 PICK)

(DUP) PUSH

?DUP 

 

X 0 | X X

Duplicate the top of the stack if it is non-zero. This operation is defined as:

((DUP 0 =) (NOP) (DUP) IFTE)

(?DUP) PUSH

OVER 

 

X Y X Y X

Duplicate the second to last element of the stack. This operation is defined as:

(1 PICK)

(OVER) PUSH

SWAP 

 

X Y Y X

Exchange the last two elements on the stack. This operation is defined as:

(1 ROLL)

(SWAP) PUSH

ROT 

 

X Y Z Y Z X

Move the third to last element of the stack on top. This operation is defined as:

(2 ROLL)

(ROT) PUSH

-ROT 

 

X Y Z Z X Y

Move the last element of the stack as third to last (inverse of ROT). This operation is defined as:

(ROT ROT)

(-ROT) PUSH

NIP 

 

X Y Y

Remove the second to last element of the stack. This operation is defined as:

(SWAP DROP)

(NIP) PUSH

TUCK 

 

X Y Y X Y

Duplicate the top element of the stack as third to last. This operation is defined as:

(SWAP OVER)

(TUCK) PUSH

2DUP 

 

X1 X2 X1 X2 X1 X2

Duplicate pair. This operation is defined as:

(OVER OVER)

(2DUP) PUSH

2DROP

 

X1 X2

Remove pair. This operation is defined as:

(DROP DROP)

(2DROP) PUSH

2SWAP 

 

X1 X2 Y1 Y2 Y1 Y2 X1 X2

Swap pair. This operation is defined as:

(3 ROLL 3 ROLL)

(2SWAP) PUSH

2OVER 

 

X1 X2 Y1 Y2 X1 X2 Y1 Y2 X1 X2

Duplicate second to last pair. This operation is defined as:

(3 PICK 3 PICK)

(2OVER) PUSH

2NIP 

 

X1 X2 Y1 Y2 Y1 Y2

Remove the second to last pair. This operation is defined as:

(2SWAP 2DROP)

(2NIP) PUSH

2TUCK 

 

X1 X2 Y1 Y2 Y1 Y2 X1 X2 Y1 Y2

Tuck pair in third to last. This operation is defined as:

(2SWAP 2OVER)

(2TUCK) PUSH

2ROT 

 

X1 X2 Y1 Y2 Z1 Z2 Y1 Y2 Z1 Z2 X1 X2

Move third to last pair on top. This operation is defined as:

(5 ROLL 5 ROLL)

(2ROT) PUSH

-2ROT 

 

X1 X2 Y1 Y2 Z1 Z2 Z1 Z2 X1 X2 Y1 Y2

Inverse of 2ROT. This operation is defined as:

(2ROT 2ROT)

(-2ROT) PUSH

3.1.4 List manipulation

The following four primitives allows for creation and handling of lists. In particular, there are the constructors CONSL and CONSR, and the destructors UNCONSL and UNCONSR.

CONSR

PRIMITIVE

( An…A1 ) ( A0 ) ( An…A0 )

List constructor. Insert unit A0 on the right of the list An…A1.

CONSL

PRIMITIVE

( A1…An ) ( A0 ) ( A0…An )

List constructor. Insert unit A0 on the left of the list A1…An.

UNCONSR

PRIMITIVE

( An…A0 ) ( An…A1 ) ( A0 )

List destructor. Remove unit A0 from the right of the list An…A0.

UNCONSL

PRIMITIVE

( A0…An ) ( A1…An ) ( A0 )

List destructor. Remove unit A0 from the left of the list A0..An.

FOLDR 

 

 ( An…A1 ) B ( C1…Cm ) D

Right fold the list A1…An starting from seed B using the operations contained in the list C1…Cm, and push the result D on the stack. This operation is defined as:

(

DUP 2SWAP SWAP

(DUP NULL =)

(2NIP DROP)

(UNCONSR APPLY 2SWAP -ROT APPLY ROT FOLDR)

IFTE

)

(FOLDR) PUSH   

FOLDL 

 

 ( A1…An ) B ( C1…Cm) D

Left fold the list A1…An starting from seed B using the operations contained in the list C1…Cm, and push the result D on the stack. This operation is defined as:

(

DUP 2SWAP SWAP

(DUP NULL =)

(2NIP DROP)

(UNCONSL APPLY 2SWAP -ROT APPLY ROT FOLDL)

IFTE

)

(FOLDL) PUSH

UNFOLDR 

 

 ( An…A1 ) B ( C1…Cm) D ( E1…El )

Right unfold the list A1…An starting from seed B using the operations contained in the list C1…Cm until condition D is satisfied, and push the result list E1…El on the stack. This operation is defined as:

(

2SWAP 2OVER DROP

(2NIP DROP)

(2OVER NIP APPLY TUCK UNIT CONSR SWAP 2SWAP UNFOLDR)

IFTE

)

(UNFOLDR) PUSH

UNFOLDL 

 

 ( An…A1 ) B ( C1…Cm) D ( E1…El )

Left unfold the list A1…An starting from seed B using the operations contained in the list C1…Cm until condition D is satisfied, and push the result list E1…El on the stack. This operation is defined as:

(

2SWAP 2OVER DROP

(2NIP DROP)

(2OVER NIP APPLY TUCK UNIT CONSL SWAP 2SWAP UNFOLDL)

IFTE

)

(UNFOLDL) PUSH 

APPEND 

 

 ( A1…An ) ( B1…Bm ) ( A1…An B1…Bm )

Append two list (right insert). This operation is defined as:

(

(DUP NULL =)

(DROP)

(UNCONSL ROT SWAP CONSR SWAP APPEND)

IFTE

)

(APPEND) PUSH

PREPEND 

 

 ( A1…An ) ( B1…Bm ) (B1…Bm A1…An )

Prepend two list (left insert). This operation is defined as:

(SWAP APPEND)

(PREPEND) PUSH

NULL 

 

( )

List constructor (empty list). This operation is defined as:

(( ))

(NULL) PUSH

LEN 

 

 ( A1…An ) n 

Return the length of the list A1…An. This operation is defined as:

((( ) POP) MAP 0 (DROP 1 +) FOLDL)

(LEN) PUSH

NTH 

 

 ( A1…An ) n ( An )

Return the Nth element of the list (starting from 1 on the left). This operation is defined as:

(

(DUP 1 =)

(DROP UNCONSL NIP)

(1 - SWAP UNCONSL DROP SWAP NTH)

IFTE

)

(NTH) PUSH

SEL 

 

 ( A1…An…Am ) n ( A1…An-1 An+1…Am ) ( An ) 

Extract the Nth element from a list. Return the element as well as the remainder of the list. This operation is defined as:

(

NULL -ROT

((DUP 1 =) (DROP UNCONSL) (1 - SWAP UNCONSL -ROT SWAP REC) IFTE)

LAMBDA

((-ROT SWAP DUP NULL =) (DROP SWAP) (CONSL SWAP REC) IFTE)

LAMBDA

)

(SEL) PUSH

 

INS 

 

 ( A1…An-1 An+1…Am ) ( An ) n ( A1…An…Am )   

Insert An in the Nth position of a list. This operation is defined as:

(

SWAP NULL SWAP 2SWAP

((DUP 1 =) (DROP)

(1 - SWAP UNCONSL -ROT SWAP 2SWAP SWAP 2SWAP REC) IFTE)

LAMBDA

((SWAP DUP NULL =) (DROP) (CONSL REC) IFTE)

LAMBDA

)

(INS) PUSH

 

MAP 

 

 ( A1…An ) ( B ) ( C1…Cn )  

Map the stack B on every element of the list A1…An to obtain another list C1…Cn. This operation is defined as:

(

SWAP NULL -ROT

((DUP NULL =) (2DROP) (UNCONSL ROT TUCK APPLY -ROT SWAP REC) IFTE) LAMBDA

((SWAP DUP NULL =) (DROP) (CONSL REC) IFTE) LAMBDA

)

(MAP) PUSH

FOREACH 

 

 ( A1…An ) ( B )   

Apply the stack B on each element of a list. This operation is defined as:

(

(SWAP DUP NULL =)

(2DROP)

(UNCONSL ROT TUCK APPLY FOREACH) IFTE

)

(FOREACH) PUSH

3.1.5 Control flow

Conditional execution is controlled by the primitive IFTE plus other six conditional primitives.

IFTE

PRIMITIVE

( A1…An ) ( B1…Bm ) ( C1…Cl ) B1…Bm | C1…Cl 

If-Then-Else control operation. Apply B1…Bm if A1…An return Boolean true, otherwise apply C1…Cl.

IFT

 

( A1…An ) ( C1…Cl ) B1…Bm | NOP 

Shorthand for the IFTE operation without the Else branch. This operation is defined as:

((NOP) IFTE)

(IFT) PUSH

=

PRIMITIVE

A B 0 | 1

Conditional EQ. This operation can be applied to numeric as well as non-numeric elements.

\=

PRIMITIVE

A B 0 | 1

Conditional NEQ. This operation can be applied to numeric as well as non-numeric elements.

>

PRIMITIVE

A B 0 | 1

Conditional GT (only numeric values).

>=

PRIMITIVE

A B 0 | 1

Conditional GE (only numeric values).

<

PRIMITIVE

A B 0 | 1

Conditional LT (only numeric values).

<=

PRIMITIVE

A B 0 | 1

Conditional LE (only numeric values).

AND

 

X Y X&Y

Boolean AND. This operation is defined as:

((0 > SWAP 0 > *) (1) (0) IFTE)

(AND) PUSH

OR

 

X Y X|Y

Boolean OR. This operation is defined as:

((0 > SWAP 0 > +) (1) (0) IFTE)

(OR) PUSH

NOT

 

X ~X

Boolean NOT. This operation is defined as:

((0 >) (0) (1) IFTE)

(NOT) PUSH

LOOP 

 

 (A1…An) (B1…Bm)

While-loop control. The actions contained in B1…Bm are repeated while the condition identified by A1…An holds true. Like many other, this operation uses LAMBDA recursion and it is defined as:

(                                              

(REC) CONSR UNIT SWAP UNIT CONSL   (IFT) CONSR                             

LAMBDA

)

(LOOP) PUSH 

TRUE 

 

1

Boolean true. This operation is defined as:

(1)

(TRUE) PUSH

FALSE 

 

0

Boolean false. This operation is defined as:

(0)

(FALSE) PUSH

BOOL 

 

A 0 | 1

Convert top of the stack to Boolean. Note that the language interprets zero as false and anything else as true. This operation is defined as:

((0 >) (1) (0) IFTE)

(BOOL) PUSH

? 

 

X

Print out “yes” or “No” if the top of the stack corresponds to Boolean true or false, respectively. This operation is defined as:

((0 >) ((yes \n) WRITE) ((No \n) WRITE) IFTE)

(?) PUSH

3.1.6 Exception handling

Control over program exceptions is accomplished by the three primitives CATCH, THROW and EXCEPTION.

CATCH

PRIMITIVE

( A1…An ) ( B1…Bm )

Catch any exception during execution of A1…An. The list B1…Bm is applied just after exception occurs (i.e. on top of the stack it is the exception term as described below). Any further exception occurring during execution of B1…Bm is discarded. If no exception occurs during execution of A1…An then B1…Bm is dropped out.

THROW

PRIMITIVE

( A1…An ) ( B )

Throw exception B with the extra information A1…An. The extra information can contain arbitrary terms, normally informing about the reason of the error. THROW pushes an exception term on top of the stack, which if uncaught is raised immediately. Known exception terms (self-explanatory names) include EXISTENCE-ERROR, PERMISSION-ERROR, EVALUATION-ERROR, STACK-ERROR, IO-ERROR and SYSTEM-ERROR.

EXCEPTION

PRIMITIVE

( A B C D ( E1…En ) )

Identify an exception term. When interpreted (e.g., using APPLY) it prints out the error message, which is the normal behavior when the exception is uncaught. Otherwise the term is left on the stack and it will be care of the catcher (see CATCH). In details, A identify the current input source, B the corresponding source line, C the calling context, D the name of the exception and E1…En is a list of extra information about the error.

3.1.7 Debugging and profiling

The primitives DEBUG, NODEBUG, DEBUGGING, TRACE, NOTRACE, TRACING, PROFILE, NOPROFILE, PROFILING, SHOWPROFILE, and RESETPROFILE plus the helper CONTEXT operation identify the (simple) debugging and profiling capabilities of the language. Given the bottom-up approach of defining new stacks, reading the full debug output will become soon unfeasible. Therefore, the user has the opportunity of ignoring a number of specified operations (via TRACE), whose computation is supposed to give the correct result. Please note that many programming mistakes can be easily figured out using SEE and/or PS in specific points throughout the code in order to examine the current stack content. The CONTEXT operation can be used concurrently to examine the current calling context.

DEBUG

PRIMITIVE

Enter debug mode.

NODEBUG

PRIMITIVE

Exit debug mode.

DEBUGGING

PRIMITIVE

0 | 1

Return a Boolean value according to the current debug mode.

TRACE

PRIMITIVE

( B )

Start tracing the stack B during debugging. This is the default for all named stacks.

NOTRACE

PRIMITIVE

( B )

Stop tracing the stack B during debugging.

TRACING

PRIMITIVE

( B ) 0 | 1

Return a Boolean value according to the tracing status of the stack B.

CONTEXT 

PRIMITIVE

( A1…An )

Push the full trace of the current calling context on top of the stack.

PROFILE

PRIMITIVE

Start or continue collecting data for the profiler.

NOPROFILE

PRIMITIVE

Stop or pause collecting data for the profiler.

PROFILING

PRIMITIVE

0 | 1

Return a Boolean value according to the current state of the profiler.

SHOWPROFILE

PRIMITIVE

Print out the data collected so far by the profiler.

RESETPROFILE

PRIMITIVE

Reset the profiler (i.e. remove all data collected so far). Note that the state of the profiler (whether it is collecting data or not) is not changed by this operation.

 

3.2 Libraries

This section covers stacks belonging to libraries useful for various tasks. At this stage these libraries are directly dependent on the libraries of the hosting programming language (please see http://www.swi-prolog.org/pldoc/index.html). The implementation of library applications is a “work-in-progress” process, which means that some operations might be incomplete. Moreover, the applications are not fully tested for bugs.

3.2.1 Mathematics

MSB

PRIMITIVE

Most significant 1 bit.

LSB

PRIMITIVE

Least significant 1 bit.

\/

PRIMITIVE

 Bitwise OR.

/\

PRIMITIVE

Bitwise AND.

XOR

PRIMITIVE

Bitwise Exclusive OR.

<<

PRIMITIVE

Bitwise shift to the left.

>>

PRIMITIVE

Bitwise shift to the right.

CEIL

PRIMITIVE

Smallest larger or equal integer.

FLOOR

PRIMITIVE

Largest larger or equal integer.

TRUNC

PRIMITIVE

Truncate to an integer towards zero.

ROUND

PRIMITIVE

Round to the nearest integer.

RANDOM

PRIMITIVE

Generate a random float in the open domain (0.0, 1.0).

SIGN

PRIMITIVE

Sign (integer -1 or +1).

ABS

PRIMITIVE

Absolute value.

GCD

PRIMITIVE

Greatest common divisor.

DIV

PRIMITIVE

Integer division towards -infinity.

REM

PRIMITIVE

Remainder of integer division.

MOD

PRIMITIVE

Modulo.

^

PRIMITIVE

Power.

+

PRIMITIVE

Addition.

-

PRIMITIVE

Subtraction.

*

PRIMITIVE

Multiplication.

/

PRIMITIVE

Division.

//

PRIMITIVE

Integer division towards zero.

MAX

PRIMITIVE

Signed maximum.

MIN

PRIMITIVE

Signed minimum.

SQRT

PRIMITIVE

Square root.

SIN

PRIMITIVE

Sine.

COS

PRIMITIVE

Cosine.

TAN

PRIMITIVE

Tangent.

ASIN

PRIMITIVE

Inverse sine.

ACOS

PRIMITIVE

Inverse cosine.

ATAN

PRIMITIVE

Inverse tangent.

SINH

PRIMITIVE

Hyperbolic sine.

COSH

PRIMITIVE

Hyperbolic cosine.

TANH

PRIMITIVE

Hyperbolic tangent.

ASINH

PRIMITIVE

Inverse hyperbolic sine.

ACOSH

PRIMITIVE

Inverse hyperbolic cosine.

ATANH

PRIMITIVE

Inverse hyperbolic tangent.

LOG

PRIMITIVE

Natural logarithm.

EXP

PRIMITIVE

Exponential.

LGAMMA

PRIMITIVE

Natural logarithm of the absolute value of the Gamma function.

ERF

PRIMITIVE

Error function.

ERFC

PRIMITIVE

Complementary error function.

LOG10

 

Base-10 logarithm. This operation is defined as:

(LOG 10 LOG /)

(LOG10) PUSH

LOG2

 

Base-2 logarithm. This operation is defined as:

(LOG 2 LOG /)

(LOG2) PUSH

PI

 

Mathematical constant π. This operation is defined as:

(0.0 ACOS 2 *)

(PI) PUSH

E

 

Mathematical constant e. This operation is defined as:

(1.0 EXP)

(E) PUSH

UMAX

 

Unsigned maximum. This operation is defined as:

(ABS SWAP ABS MAX)

(UMAX) PUSH

UMIN

 

Unsigned minimum. This operation is defined as:

(ABS SWAP ABS MIN)

(UMIN) PUSH

FLOAT

 

Conversion to float (conversion to integer can be accomplished by several operations such as TRUNC, ROUND, CEIL, FLOOR). This operation is defined as:

(1.0 *)

(FLOAT) PUSH

3.2.2 Standard Input/Output

The system provides standard input/output features. A stream is represented by a numeric unique identifier.

STDIN

PRIMITIVE

Standard input stream.

STDOUT

PRIMITIVE

Standard output stream.

STDERR

PRIMITIVE

Standard error stream.

INPUT

PRIMITIVE

Current input stream.

OUTPUT

PRIMITIVE

Current output stream.

OPEN

PRIMITIVE

( A ) ( B ) C

Open the file A with the list of options B and return the stream identifier C. Currently defined options are:

·         READ (default), WRITE, APPEND

·         TEXT (default), BINARY

·         FULL-BUFFERING (default), LINE-BUFFERING, UNBUFFERED

·         CLOSE-ON-ABORT (default), NOP-ON-ABORT

·         NOP-ON-EOF (default), ERROR-ON-EOF, RESET-ON-EOF

·         LOCK-NONE (default), LOCK-READ, LOCK-WRITE

Note that the filename must be provided in the OS path name convention.

CLOSE

PRIMITIVE

C

Close the stream identified by C.

STREAM

PRIMITIVE

C 0 | 1

Test if C is a valid stream handle.

FLUSH

PRIMITIVE

C

Flush output on stream C.

GET

PRIMITIVE

C X

Read the next character code X from stream C. Return -1 on EOF (if the stream has been opened with the NOP-ON-EOF option).

PEEK

PRIMITIVE

C X

Read the next character code X from stream C without removing it (i.e. without modifying stream position). Return -1 on EOF (if the stream has been opened with the NOP-ON-EOF option). The latter behavior can be used to test whether the current location is at the end of a stream.

SKIP

PRIMITIVE

X C

Skip input until the next character code X (or EOF) is encountered on stream C.

PUT

PRIMITIVE

X C

Write the character X on output stream C.

BOF

PRIMITIVE

C M

Reposition the stream C to the beginning of file, returning the new location M.

EOF

PRIMITIVE

C M

Reposition the stream C to the end of file, returning the new location M.

SEEK

PRIMITIVE

N C M

Reposition the stream C by moving of N units (a unit is always 1 byte except for 2-bytes Unicode encoding) relative to the current position (note that N can be negative), returning the new location M.

GETS

 

N C (A1…An)

Read the next N character codes from stream C.

PUTS

 

(A1…An) C N

Write the character codes (A1…An) to stream C.

EMIT

PRIMITIVE

A

Print on standard output the last element on top of the stack.

3.2.3 Operating System Interactions

This section describe the primitives used to interact with the Windows OS as well as with the filesystem.

GETENV

PRIMITIVE

(A) B

Get the content of the environment variable A and push it to the default stack as B.

SETENV

PRIMITIVE

B (A)

Set the content of the environment variable A to B.

FOLDERID

PRIMITIVE

(A) B

Get the value of the standard folder registered with the system (Vista or later) as A and push it to the default stack as B. The names of the known folders are defined by the KNOWNFOLDERID constant (see “Shell Reference” on msdn.microsoft.com).

EXEC

PRIMITIVE

(A)

Execute command A by spawning a Windows task (without waiting for its completion).

SHELL

PRIMITIVE

(A)

Open file or folder A using Windows shell rules.

GETREGKEY

PRIMITIVE

(A) B

Get the value of the registry key A push it to the default stack as B.

SETREGKEY

PRIMITIVE

B (A)

Set the value of the registry key A to B.

DELREGKEY

PRIMITIVE

(A)

Delete the specified registry key A.

GETCWD

PRIMITIVE

A

Get the current working directory and push it into the default stack as A.

SETCWD

PRIMITIVE

A

Set the current working directory to A.

DIR

PRIMITIVE

A (B1…Bn)

Get the current working directory content (B1…Bn) after expanding wildcard A.  

MKDIR

PRIMITIVE

A

Create the new directory A on the filesystem.

RMDIR

PRIMITIVE

A

Delete the directory A from the filesystem.

DELETE

PRIMITIVE

A

Remove file A from the filesystem.

RENAME

PRIMITIVE

A B

Rename file A as B.

ACCESS

PRIMITIVE

A (B1…Bn)

Get the list of access modes B1…Bn of file/folder A. Currently defined modes are: READ, WRITE, APPEND, EXECUTE and EXIST.

SIZE

PRIMITIVE

(A) B

Get the size of file/folder A (in bytes) and push it to the default stack as B.

TIME

PRIMITIVE

(A) B

Get the time of last modification of file/folder A (as POSIX time, i.e. seconds elapsed since 00:00:00 UTC of Jan 1, 1970) and push it to the default stack as B.

NOW

PRIMITIVE

B

Get the current time and push it to the default stack as B.

CTIME

PRIMITIVE

B (C1…C6)

Convert the POSIX time B to a list containing year, month, day, hour, minute, second using the UTC time-zone (provisional).

 

 


 

Index

 

 

 

 


-, 32

#, 16

*, 33

/, 31, 33

/\, 31

//, 33

?, 28

?DUP, 17

?INCLUDE, 16

^, 32

+, 32

<, 26

<<, 31

<=, 26

=, 25, 26

>, 26

>=, 26

>>, 31

2DROP, 19

2DUP, 19

2NIP, 20

2OVER, 19

2ROT, 20

-2ROT, 20

2SWAP, 19

2TUCK, 20

ABORT, 15

ABS, 32

ACCESS, 41

ACOS, 34

ACOSH, 34

AND, 26

APPEND, 22

APPLY, 16

ASIN, 33

ASINH, 34

ATAN, 34

ATANH, 34

BOF, 38

BOOL, 27

CATCH, 28

CEIL, 31

CLOSE, 37

CLR, 15

CONSL, 21

CONSR, 20

CONTEXT, 30

COS, 33

COSH, 34

CTIME, 41

DEBUG, 29

DEBUGGING, 29

DELETE, 41

DELREGKEY, 40

DEPTH, 15

DIR, 40

DIV, 32

DROP, 17

DUP, 17

E, 35

EMIT, 39

EOF, 38

ERF, 35

ERFC, 35

EXCEPTION, 28

EXEC, 39

EXIT, 15

EXP, 34

FALSE, 27

FLOAT, 36

FLOOR, 31

FLUSH, 37

FOLDERID, 39

FOLDL, 21

FOLDR, 21

FOREACH, 25

GCD, 32

GET, 37

GETCWD, 40

GETENV, 39

GETREGKEY, 40

GETS, 38

IFT, 25

IFTE, 25

INCLUDE, 15

INCLUDED, 16

INPUT, 36

INS, 24

LAMBDA, 16

LEN, 23

LGAMMA, 35

LOG, 34

LOG10, 35

LOG2, 35

LOOP, 27

LSB, 31

MAP, 24

MAX, 33

MIN, 33

MKDIR, 40

MOD, 32

MSB, 30

NIP, 18

NODEBUG, 29

NOP, 16

NOPROFILE, 30

NOT, 27

NOTRACE, 29

NOW, 41

NTH, 23

NULL, 23

OPEN, 37

OR, 26

OUTPUT, 37

OVER, 18

PEEK, 38

PI, 35

PICK, 17

POP, 14

PREPEND, 23

PROFILE, 30

PROFILING, 30

PUSH, 14

PUT, 38

PUTS, 39

RANDOM, 32

REC, 16

REM, 32

RENAME, 41

RESETPROFILE, 30

RMDIR, 40

ROLL, 17

ROT, 18

-ROT, 18

ROUND, 31

SEE, 15

SEEK, 38

SEL, 24

SETCWD, 40

SETENV, 39

SETREGKEY, 40

SHELL, 39

SHOWPROFILE, 30

SIGN, 32

SIN, 33

SINH, 34

SIZE, 41

SKIP, 38

SQRT, 33

STDERR, 36

STDIN, 36

STDOUT, 36

STREAM, 37

SWAP, 18

TAN, 33

TANH, 34

THROW, 28

TIME, 41

TOP, 15

TRACE, 29

TRACING, 29

TRUE, 27

TRUNC, 31

TUCK, 19

UMAX, 36

UMIN, 36

UNCONSL, 21

UNCONSR, 21

UNFOLDL, 22

UNFOLDR, 22

XOR, 31


 


 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Last modified on Tuesday, March 3, 2015 by Mauro DiNuzzo