Badly Developed SADOL Machine 2

Version 2.0, 21 Dec 2005

Contents

Introduction

SADOL

SADOL is a functional, esoteric programming language invented by Martin "nooga" Gasperowicz in summer 2005. It is similar to LISP a bit. Specification of the language could be find in these addresses (it seems that they change fast so they can be inactive now):

But this document also contains full specification of the language mixed with detailed behavior of the BDSM2 interpreter, so you needn't original specification to learn it.

Main assumptions of SADOL are:

Nooga reached something really amazing - he designed language that is obfuscated and crazy as esoteric, but at the same time powerful and convenient to write even nontrivial programs.

BDSM

BDSM means Badly Developed SADOL Machine. It is an interpreter of SADOL language. Main features:

BDSM in version 2 is now fully compatible with official nooga's language specification. It has been completely rewritten and contains new optimizations, especially copy-on-write on strings and lists.

Hello World!

Traditionally, first sample program prints out a string Hello world! on the output.

!",212Hello World!

It consists of one expression that prints out a value on the console (!). This value is a string ("). This string has length that is described by an integer number (,). This number is two decimal digit length (2). These digits are 12. Then we have to write a 12 character length string. It is Hello World!.

General

Whitespaces

All whitespace characters (' ', '\r', '\n', '\t', '\v') are ignored. It means that you can format your code the way you want to make it more clear - or delete all whitespaces to make your program totally obfuscated. Exception is where verbatim characters are expected (in ' and ") - whitespaces are read as normal characters there.

Comments

Comments are all the characters inside curly brackets { }. Comment cannot contain } inside.

{ My first program in SADOL }
! " , 2 12Hello World!

Processing files

BDSM2 is executed from command line with one argument - name of a file with source code in SADOL (I suggest extension .sad for that files). Executed program gets input characters from the system console and puts output characters on that console.

You can change this behavior and make BDSM2 processing input and output files by using redirection on console input and output of the program to files. This can be done by < and/or > system shell operators - on both Windows and Linux. For example:

BDSM2.exe Source.sad < InputData.txt > OutputData.txt

End of line issue

There is a problem with end-of-line character on different platforms. Under Linux, end of line character in text files is a single '\n' character (decimal ASCII code 10). Under Windows, it is represented by the sequence of two characters: "\r\n" (13 and 10). So if you want to write a function that prints end of line at the output under Windows, you should print two characters:

~ E 0 !"2

{ program end here }

There is also a problem that end of line characters can be handled in different way when using < and > operators (redirecting console input/output to files).

End of file issue

Programs in SADOL cannot detect end-of-file state. So if you want your program to process some amount of information (eg. sort a list of numbers), you have to write the amount of data (eg. number count) at the beginning, before this data.

Values

A value is a single data element that exists in the computer memory during execution of program. It can be passed somewhere (eg. to a function), returned from somewhere (eg. by an expression) or stored somewhere (eg. in a variable or as an element of other value).

Values are created and deleted automatically. There are no pointers or references, no memory leaks and no garbage collector. You also don't have to worry about passing, returning, storing and copying data by value, even if they are quite big (eg. long list, list of lists etc.). BDSM2 have copy-on-write optimization.

Data types

Data types in SADOL are dynamic. You don't have to declare that a function parameter or variable have particular type. There are four main types:

Integer number
32-bit signed integer number. Range: -2,147,483,648 .. +2,147,483,647.
,3 666
Double (real) number
64-bit floating point number. Range: 2.2250738585072014*10^-308 .. +1.7976931348623158*10^+308. Precision: 15-16 decimal digits.
.1 5
String
Any sequence of ASCII characters. Can be any length and can contain any characters, including end-of-line.
"3XXX
List
A sequence of values implemented as dynamic vector. Can be efficiently indexed. Elements can be pushed to and popped from the back. Can be any length and can contain any values, even different types. There can be also list of lists, list of lists of lists and so on. Lists are printed on the output as in the example: (elem1,elem2,elem3).
! $3 1 1 "1A

Boolean values

There is no separate boolean data type. Several operators require as arguments or return logical values. In general, you should think of boolean values as integer number that is true when greater or equal than 1.

Character values

There is not separate data type for a single ASCII character. Use one character length strings instead.

Conversions

When instruction defines argument as converted into particular data type, it uses table below to obtain proper value. Conversions are done automatically.

  from integer from double from string from list
to integer (none) number is rounded length of string (number of characters) length of list (number of elements)
to double numeric conversion (none) length of string (number of characters) length of list (number of elements)
to string conversion from integer to string conversion from double to string (none) String containing (element1,element2,...)
to list one-element list one-element list one-element list (none)
to boolean true if >= 1 true if >= 1.0 true if not empty true if not empty

Constant evaluation

Some instructions require arguments to have value already known at compilation time. You can pass single values as these arguments, but you can also use instructions that can be optimized at compilation time (evaluated to single constants). Consider example:

!"+93Hello World!

Variables and functions

SADOL as most of programming languages gives you ability to assign and read variables, as well as define and call functions. Variable and function names are case sensitive and can be identified by any single letter (a symbol) - upper case A..Z for global and lower case a..z for local symbols.

Global symbols are common for entire program. Wherever you use them, you refer to the same variable values or function code. Local symbols exist in context of particular scope. There is a main scope of the program (top level) and every function defined its own nested scope. Local symbols a..z can be also used in the main scope of the program, not only in functions' body.

There are no predefined variables or functions in SADOL. All possible variable/function names are at your command.

Variable basics

Variable is a place in memory for storing a value outside the main control flow (where values are passed as arguments for instructions or function calls and returned by them). You can assign its value and you can use this value in expressions. You can obtain a value of a variable that hasn't been assigned before - its default value is integer 0.

: A 3     { A := 3 }
: B + A 2 { B := A + 2 }
! B       { output: 5 }

Function basics

Function is a piece of code stored under particular name, that may be called, can take some arguments and can return value. You can define function by giving its name, number of arguments and expression to evaluate when executed (code of function body). You can then call this function with passing required number of arguments and you can use returned value. You cannot call function that hasn't been defined before.

~ F 1   { F is a function that takes 1 argument }
  ! #_0 { and prints its first argument on the output }
F 6     { Call this function with argument 6 }

Local variables

Local variable exists only in the scope where it is assigned (from the first assignment to the end of this scope) and all the scopes called from it.

: a 1
: B 2
! a      { output: 1 }
! B      { output: 2 }
~ F 0 (6
  ! a    { output: 1 }
  ! B    { output: 2 }
  : a 7
  : B 8
  ! a    { output: 7 }
  ! B    { output: 8 }
F
! a      { output: 1 }
! B      { output: 8 }

Local functions

Local function exists only in the scope where it is defined (from the definition to the end of the scope) and all nested scopes.

~ f 0
  ! "2f1
~ F 0
  ! "2F1
f        { output: f1 }
F        { output: F1 }
~ G 0 (5
  f      { output: f1 }
  F      { output: F1 }
  ~ f 0
    ! "2f2
{ cannot redefine global function!
  ~ F 0
    ! "2F2
}
  f      { output: f2 }
  F      { output: F1 }
G
f        { output: f1 }
F        { output: F1 }

Advanced details

To fully understand different shades of scopes, global and local variables and functions, variable assignments and function definitions, consider following examples:

! a      { output: 0 }
: a 2    { assign local variable in main scope }
! a      { output: 2 }
~ F 0 (3 { define a function }
  ! a    { output: 2 }
  : a 3  { assign local variable in function scope }
  ! a    { output: 3 }
F        { call this function }
! a      { output: 2 }

Example of global function defined inside local function:

{ cannot call undefined function!
G
}
! X      { output: 0 }
~ f 0 (2
  ~ G 0
    !"1G
  : X 7
G        { output: G }
! X      { output: 0 }
f
G        { output: G }
! X      { output: 7 }

Example showing difference between behavior of local variables and local functions:

~ g 0
  ! "2g1
: a 5
~ f 0 (2
  g
  ! a
~ h 0 (3
  ~ g 0
    ! "2g2
  : a 6
  f
f { output: g1 5 }
h { output: g1 6 }

Variable parameter count

You can define a function with argument count equal to -1. It means that it has variable argument count. When called, there must be a number of arguments given every time and it must be known in compilation time. Inside the function, there is argument list _ available as in every function, except you don't know the size of this list.

~ F -01 (2
  : i 0
  @ < i #_-01 (5
    ! i
    ! "3 = 
    ! #_i
    ! "2
    : i +i1
F4
  1
  .12
  "5three
  $4 "1f "1o "1u "1r

{ output:
0 = 1
1 = 0.2
2 = three
3 = (f,o,u,r)
}

Rules

There are several additional rules that you should be aware:

Instructions

Constants

0..9

Parameters

(none)

Return value

Integer

Remarks

Use to express one-digit integer number constant.

Can be l-value

No

Can be evaluated in compilation time

Always

Example

!1 !2 !3
, n d1..dn

Parameters

n
Converted to integer, must be known at compilation time
Digit count
d1..dn
Converted to integer, must be known at compilation time
Digit values

Return value

Integer

Remarks

Use to express integer number constant.

Can be l-value

No

Can be evaluated in compilation time

Always

Example

: x ,3 666
. n d1..dn

Parameters

n
Converted to integer, must be known at compilation time
Digit count
d1..dn
Converted to integer, must be known at compilation time
Digit values

Return value

Double

Remarks

Use to express fractional part of real number constant. Returned value is sum of given digits, each multiplied by 10-n.

Can be l-value

No

Can be evaluated in compilation time

Always

Example

! + ,210 .15 { output: 10.5 }
" n c1..cn

Parameters

n
Converted to integer, must be known at compilation time
Character count
c1..cn
Verbatim characters

Return value

String

Remarks

Use to express string constant.

Can be l-value

No

Can be evaluated in compilation time

Always

Example

! "3Hi! { output: Hi! }
' o c

Parameters

o
Converted to integer, must be known at compilation time
One of these values: 0, 1, 2
c
o = 0
Verbatim character
o = 1
Converted to string
Mustn't be empty.
o = 2
Converted to integer
Must be in range 0..255.

Return value

o = 0
Integer
o = 1
Integer
o = 2
One-character string

Remarks

o = 0
Return ASCII code of given verbatim character.
o = 1
Return ASCII code of first string's character.
o = 2
Return character of given ASCII code.

Can be l-value

No

Can be evaluated in compilation time

o = 0
Always
o = 1
Yes
o = 2
Yes

Example

! '0A { output: 65 }

Control flow

( n e1..en

Parameters

n
Converted to integer, must be known at compilation time
Number of expressions
e1..en
Any expressions

Return value

Value of the last expression. If n = 0, returned value is integer 0.

Remarks

Use to successively execute several commands. This is main control flow instruction. It is needed because SADOL is functional language. In imperative programming languages, you can express it by just typing commands.

Can be l-value

Yes

Can be evaluated in compilation time

Yes

Example

~ F 1 (2
  ! #_0
  ! "1;
? c a b

Parameters

c
Converted to boolean
Condition
a, b
Any expressions

Return value

If condition's value is true, returns value of a. Else returns value of b.

Remarks

Conditional expression.

Can be l-value

Yes

Can be evaluated in compilation time

Yes

Example

~ F 1
  ! ? > #_0 ,210 "3>10 "4<=10
F,211
F5
@ c e

Parameters

c
Converted to boolean
Condition
e
Any expression

Return value

Value of last e execution. If there were no e executions it returns integer 0.

Remarks

Loop instruction that executes e while c is true. Condition c is checked before executing e, so it can execute zero times.

Can be l-value

Yes

Can be evaluated in compilation time

Yes

Example

: C 0
@ < C 5 (2
  ! C
  : C + C 1
{ output: 01234 }
` s

Parameters

s
Must be string

Return value

Value returned by executed expression.

Remarks

Executes given string as SADOL code and returns it's result (the result of last term). s can contain sequence of expressions (as entire program source), don't have to be single expression. Executed code doesn't create new scope.

Can be l-value

No

Can be evaluated in compilation time

No

Example

! ` ; 3

Dealing with values

: l x

Parameters

l
L-value
x
Any expression

Return value

Assigned value - equal to x.

Remarks

Assigns value x to l. l can be any l-value, especially variable, list's element or string's character. x is evaluated first.

Can be l-value

No

Can be evaluated in compilation time

No

Example

: S "3abc
: #S1 "1X
! S { output: aXc }
+ a b

Parameters

a, b
Any values
If they have different types, one is converted to other type.

Return value

Sum of given values. For returned value type, see remarks.

Remarks

Returns sum of given values. Here is a table of operations done and types of value returned according to types of given parameters:

  Integer Double String List
Integer Integer
Addition of integer numbers
Double
Addition of double numbers
String
String concatenation
List
Merging lists
Double Double
Addition of double numbers
Double
Addition of double numbers
String
String concatenation
List
Merging lists
String String
String concatenation
String
String concatenation
String
String concatenation
List
Merging lists
List List
Merging lists
List
Merging lists
List
Merging lists
List
Merging lists

Can be l-value

No

Can be evaluated in compilation time

Yes

Example

~ E 0 ! "2
!+ ,210 ,210  E
!+ ,210 .225  E
!+ ,210 "2ab  E
!+ ,210 $212  E
!+ .225 ,210  E
!+ .225 .225  E
!+ .225 "2ab  E
!+ .225 $212  E
!+ "2ab ,210  E
!+ "2ab .225  E
!+ "2ab "2ab  E
!+ "2ab $212  E
!+ $212 ,210  E
!+ $212 .225  E
!+ $212 "2ab  E
!+ $212 $212  E
- a b
* a b
% a b

Parameters

a, b
Integer or double
If %, b cannot be 0.

Return value

Integer or double
Result of the computation.

Remarks

-
Subtraction
*
Multiplication
%
Reminder

Here is a table types of returned value according to types of given parameters:

  Integer Double String List
Integer Integer Double (ERROR) (ERROR)
Double Double Double (ERROR) (ERROR)
String (ERROR) (ERROR) (ERROR) (ERROR)
List (ERROR) (ERROR) (ERROR) (ERROR)

Can be l-value

No

Can be evaluated in compilation time

Yes

Example

! * - 2 % + 2 3 2 3 { output: 3 }
/ a b
^ a b
\ a

Parameters

a, b
Converted to double
If /, b cannot be 0.

Return value

Double

Remarks

/
Division
^
Power
\
Floor

Can be l-value

No

Can be evaluated in compilation time

Yes

Example

: X / 9 2
! X   { output: 4.5 }
! \ X { output: 4 }

Lists

$ n e1..en

Parameters

n
Converted to integer, must be known at compilation time
Element count
e1..en
Any expressions
List elements

Return value

List

Remarks

Use to create list of given elements.

Can be l-value

No

Can be evaluated in compilation time

Yes

Example

: A $2 1 2
: B $1 3
: C $0
! ++ABC    { output: (1,2,3) }
# l n

Parameters

l
String or list
n
Converted to integer
Must be in range from 0 to string length (element count) - 1. If not used as l-value, can be also -1 (see remarks).

Return value

n is proper index
l is string
One-character string
l is list
List element
n is -1
Integer
l is string
String length (number or characters)
l is list
List length (number of elements)

Remarks

Indexing operator for extracting (or referencing) single elements of lists and single characters of strings. n is evaluated first.

Can be l-value

Yes

Can be evaluated in compilation time

Yes

Example

: L $3 1 2 3
: C 0
! "1[
@ < C #L-01 (3
  ? > C 0
    ! "2, 
    0
  ! # L C
  : C + C 1
! "1]
{ output: [1, 2, 3] }
] l x

Parameters

l
L-value, string or list
x
l is string
One character string
l is list
Any value

Return value

Equal to l.

Remarks

Pushes value x at the end of string or list l. Original value l is modified in place, not only new value is returned.

Can be l-value

Yes

Can be evaluated in compilation time

No

Example

: L $0
! ]]] L 123 { output: (1,2,3) }
! L         { output: (1,2,3) }
[ l

Parameters

l
L-value, string or list

Return value

l is string
One character string
Last character of given string.
l is list
Last element of given list.

Remarks

Pops last element (character) from given list (string). This element is deleted from original value l (modified in place) and returned by this instruction.

Can be l-value

No

Can be evaluated in compilation time

Yes

Example

: A $3 1 2 3
@ A
  ! [ A
{ output: 321 }

Functions

~ c n e

Parameters

c
Verbatim character
Function name
n
Converted to integer, must be known at compilation time
Argument count. -1 means variable argument count.
e
Any expression
Code as function body. Not executed directly at this place.

Return value

Integer
Equal to 1.

Remarks

Function definition.

Can be l-value

No

Can be evaluated in compilation time

No

Example

~ F 1
  (2
    ! ",211Argument = 
    ! #_0
F ,210  { output: Argument = 10 }
F "3abc { output: Argument = abc }
_

Parameters

(none)

Return value

List
List of current function's arguments.

Remarks

When used in global scope, returns empty list.

Can be l-value

Yes

Can be evaluated in compilation time

No

Example

~ F -01
  !_
F1 1     { output: (1) }
F2 1 2   { output: (1,2) }
F3 1 2 3 { output: (1,2,3) }

Logic

= a b
< a b
> a b

Parameters

a, b
Any values
If they have different types, one is converted to other type.

Return value

Boolean
Result of comparison

Remarks

Compares whether first value is equal / less / greater than the second. Here is a table of operations done according to types of given parameters:

  Integer Double String List
Integer Integer number comparison Double number comparison Lexigraphic string comparison Lexigraphic list comparison
Double Double number comparison Double number comparison Lexigraphic string comparison Lexigraphic list comparison
String Lexigraphic string comparison Lexigraphic string comparison Lexigraphic string comparison Lexigraphic list comparison
List Lexigraphic list comparison Lexigraphic list comparison Lexigraphic list comparison Lexigraphic list comparison

Can be l-value

No

Can be evaluated in compilation time

Yes

Example

: A 1
? > A 0
  ! "2>0
  0
? < A 0
  ! "2<0
  0
? = A 0
  ! "2=0
  0
& a b
| a b

Parameters

a, b
Converted to boolean

Return value

Boolean

Remarks

Logical AND / OR operation on given boolean values. Expression a is evaluated first. If its result determines result of entire instruction, expression b is not evaluated.

Can be l-value

No

Can be evaluated in compilation time

Yes

Example

: A 1
: B 2
? & >A0 >B0
  !",211A and B > 0
  0

Input/output

! x

Parameters

x
Any value

Return value

Equal to x.

Remarks

Prints value of x on the console output.

Can be l-value

No

Can be evaluated in compilation time

No

Example

! "6Value=
! 7
; t

Parameters

t
Converted to integer, must be known at compilation time
t = 0
Read one character
t = 1
Read line as integer number
t = 2
Read line as double number
t = 3
Read line as string

Return value

Value read from console input.

t = 0
One character string
t = 1
Integer
t = 2
Double
t = 3
String

Remarks

Read character(s) from console input, converts it to needed data type and returns its value. It always waits for pressing Enter on keyboard, even if only one character is needed.

Can be l-value

No

Can be evaluated in compilation time

No

Example

! ",235Do you really want to quit? (Y/n): 
: A ;0
? | =A"1Y =A"1y
  :B1
  :B0
!B

What's new?

In general, BDSM2 i brand-new, rewritten from scratch and incompatible with BDSM1. It is now compatible with official nooga's specification of SADOL language. Many optimizations were also made.

Simple programs in SADOL written for BDSM1 should also work in BDSM2. Main change that you should make is replacing every ;0 to ;1, ;2 or ;3 - according to desired data type.

Author

Adam Sawicki

Contact:
mailto:regedit_DEL_@risp.pl (delete _DEL_)
http://www.regedit.risp.pl/

At the end, I want to apologize for my poor English. It is not my native language and I have been writing this document fast so please forgive me my mistakes :)