.Open The SMALL Programming Language . Note An ASCII text version of this document can be found at .See http://www/dick/samples/small.txt using the $XBNF notation developed by Dr. R J Botting. . Goals The SMALL language is a simple scripting language used to learn about programming language concepts. It is easy to implement. It can be used for doing simple algorithms and calculations. Many things are missing from it. There are many ways to extend SMALL ($TBD) This specification is also (by design) incomplete and ambiguous. Removing errers($TBD), resolving ambiguitites($TBD), filling holes($TBD), and extending the language($TBD) makes an interesting project. . Running SMALL Programs Like all scripting languages (awk, PERL, JavaScript, TCL, etc) SMALL is interpreted. The interpreter can run interactively reading statements from the user. The SMALL interpretter can also read and interpret a file with extension or suffix ".sma". A SMALL program called `p` is always stored in a file `p`.sma. SMALL interpreters recognise the names of programs inside programs. When the name of a program is met they start to interpret the program's file. This is named a "call". The program name "calls" the program file. The call is in the "calling" program's file. When a called file is finished the interpreter returns to the calling program at the next statement after the call. One program can have any number of calls of any number of files. The name of the interpreter should be "small". A command "small p" should interpret file "p.sma". The command "small" with no argument executes the interpreter in interactive mode. In a graphic environment it should be possible to drag and drop a "p.sma" file into the icon for small interpreter to get the same effect as "small p.sma". A double-click on a "p.sma" file would also run the interpreter. . Programs A SMALL program is a sequence of statements, commands, comments, and separators. program::=#($statement | $comment | $command | $separator). See $Examples below. Each $statement and $command in a program is interpreted in the order that they occur. Comments and separators are ignored. A program or part of a program can either terminate or not terminate. If it terminates it either succeeds or fails: outcome::= $termination | nontermination. termination::=success | failure. Statements and commands can either succeed, fail, or not terminate. A program succeeds if all the statements and commands executed in the program succeed. A program fails if any statement or command fails. A program terminates when all executed statements and commands in the program have terminated. A program will not terminate if any executed statement or command in it does not terminate. comment::= "//" #($char~$end_of_line). .As_is // This is a comment Comments separate statements and commmands. They are ignored by the interpreter. separator::= end_of_line $whitespace. A separator comes between statements and commands in a program and has no effect on the interpretter. whitespace::= #($end_of_line | $ws) ws::= #( $horizontal_tab | $space). Whitespace should be used to expose the structure of a script. It has no effect on the meaning of a program - except inside a $string. . Commands command::="edit" program_name | "exit". .As_is edit example .As_is exit Commands communicate with the operating system in which the SMALL interpreter is embedded. An "exit" terminates the interpreter. An "edit p" command saves the current version of the program in the program file and invokes the users favorite editor -- stored in the environment variable EDIT -- to edit the file. SMALL takes over control when the editor exits. In essence SMALL calls the editor as a subprogram. . Statements Statements do things they are either structured or an expression followed by other things: statement::= $structured_statement | $expression_statement. Structured statement .As_is [ a < 0? -a -> b || a -> b ] Expresion statement .As_is -a -> b Structured statements allow a program to select alternatives and to repeat pieces of code. Expression statements allow the computation and disposition of values. An expression statement combines testing, assignment and output into one simple construct. expression_statement::= $expression $O($assignment) $O($disposition ). assignment::= $arrow $variable. disposition::= $ignored | $output | $returned | $tested. Examples .List Increment i .As_is i+1 -> i; Evaluate a relation and test .As_is i > 0? Decrement and test .As_is i - 1 -> i ? Concatenate string and value and output .As_is "i =" i ! Divide h by 2 and print .As_is h/2.0 -> h ! Add reciprocal of i to s .As_is 1/i+s ->s Return the square of x as value of subprogram .As_is x*x^ .Close.List The $expression is evaluated to give a value. The value can be saved in a variable. It is then disposed of in one of four ways: .Box It is ignored(default). ignored::=O(";"). It is output to the user. output::="!". It is returned to the invoking program. returned::="^". Control is returned along with the value. It is tested. tested::="?". If the value tested is 0 or it is a call that fails then the alternative or program in which the test occurs fails. Otherwise the alternative continues. .Close.Box arrow::="->". expression::= $O($prefix) $ws $simple_expression $ws #($operator $ws $O($prefix) $ws $simple_expression $ws). .As_is 2*3 .As_is 1*3+3 .As_is 3+3*1 .As_is 1+2*2 .As_is 1+2+3 The interpretter evaluates expressions to give a value. Whitespace ($ws) has no effect on the computation. Values can be strings, integers, or floating point numbers. Expressions are evaluated strictly from left to right. All the above examples give the value 6. Here is a more precise definition of the semantics of an expression using two functions $E and $V. E::$expression->$constant, E(`e`) is the value of $expression `e`. V::$simple_expression->$constant, V(`s`) is the value of a $simple_expression `s` and is defined later (see $Values below). For example E( 1+2*3 ) = E(1+2)*V(3)=E(1+2)+3=(V(1)+V(2))*3=9. E(-1+2) = E(-1) + V(2) = -V(1) + V(2) = -1. .Net For c:$constant, p:$prefix, i:$infix, e:$expression, v:$variable, s:$simple_expression. E(e i s)= E(e) i V(s). E(e i p s)= E(e) i V(p s). E(s) = V(s). .Close.Net prefix::= "+" | "-" | "~". Plus converts a string to a number. Minus negates a number (and also converts a string to a number). The tilde is a boolean negation changing 0 to 1 and all other values to 0 (like the ! in C/C++/Java). operator::= $arithmetic | $relational | $boolean | $string_op. arithmetic::="+" | "-" | "*" | "/" | "%". The operators +, -, *, /, and % have the same meaning as in C or C++ as arithmetic operators. They also convert strings into numbers. relational::= "<" | "<=" | "<>" | "=" | ">=" | ">". "<", "<=", ">" and ">=" are relation operators as in C/C++/Ada/Java. Equals is represented by "=" and is true when the two values are equal. Inequality is shown as "<>" (as in Pascal and BASIC). String comparisons are done character by character by character and numerical comparisons numerically. When a number is compared to a string, the string is converted into a number. boolean::="&" | "|". "&" and "|" are boolean conjunction and disjunction(inclusive) respectively. string_op ::= ":" | $default. The colon(":") is used for comparing strings following the rules for `regular expressions` as defined in the ANSI standard C library. For example .As_is "abbbc" : "ab*c" is true(non-zero) but .As_is "axbc" : "ab*c" is false (0). The $default operator indicates string concatenation: default::="", -- string concatentation: .As_is "Time = " h ":" m "."! Numbers are converted to decimal strings before taking part in string operations. Strings are converted to numbers before taking part in numerical operations. simple_expression::= $constant | $variable | $input | $program_call. .As_is 123 .As_is a .As_is $ .As_is abc input::="$". .As_is $->a; Read next line into variable a as a string. .As_is $+$! Read two lines, convert to number, add them and print the result. .As_is "Answer Y or N"! $="Y"? Prompt for a Yes or No response and test it. .As_is "Answer y or n:"! $:"[yY].*"? A less stringent test for words like "yes", "Yes", "Yo", "Ya", "y", ... .As_is "n=?"! $->n Prompt for a value for n. program_call::= name_of_program. .As_is abs .As_is sqrt .As_is quadratic A program call `p` fails if the file `p.sma` can not be found, or if the program inside the file fails. As an aid to debugging a program call outputs a warning: "p.sma not found" if the the file does not exist. A call can fail, succeed, or not terminate according to what its program does. A program call that succeeds returns a value. The file should contain an expression whose value is disposed of by returning it ("^"). This command also returns control. For example a program $sqx might consist of a single statement. (sqx): .As_is x*x^ . Values The value, V(s), of simple expression `s` is defined as folows: .Net For c:$constant, p:$program_name, v:$variable. V(c) = c. V(v) = `the value saved in the variable (if any) else ""`. V($) = `the next line of input`. V(p) = `the value returned by executing a '^' in program p`. V(+ s)= `if V(s) is a number n then n else convert string to number`. V(- s)= - V(s). V(~ s)= if V(s) = 0 then 1 else 0. .Close.Net The set of variables are part of the interpreter not a particular program. They are can be used and changed by any program that is executed. A called program gets its variables from the calling program. Any variables that are changed by the called program are also changed in the calling program. For example suppose we wish to read a number and output its square. We can use $sqx above: .As_is $->x; sqx! Or, perhaps, if we have a program sqxy (in file sqxy.sma) (sqxy): .As_is x*x -> y. then .As_is $->x; sqxy; y! variable::=letter. .As-is a .As_is A Capital and lower case letters are different variables. There are therefore 52 variables. constant::=$string | $integer | $float. string::= $double_quotes #(char ~ $double_quotes) $double_quotes. double_quotes::= "\"". .As_is "This is a string" .As_is "A" .As_is "123" integer::= $decimal_digit #($decimal_digit). decimal_digit::= "0".."9". .As_is 123 float::= $integer "." $integer. .As_is 123.0 Note that 12. is not a valid float. . Control Structures structured_statement::=$iteration | $selection. iteration::= "{" $alternatives "}". selection::= "[" $alternatives "]". alternatives::= alternative #( $or_else alternative) . or_else::= "||". alternative::= $program, -- as defined above. Examples of iterations and alternatives: (Log): .As_is 0->l; {a>1.0? 1+l->l; a/2.0->a;} (max): .As_is [ a>b? a! || a<=b? b! ] (not): .As_is [ p? 0^ || 1^] (iff): .As_is [ p? q? 1^ || ~p? ~q? 1^ || 0^] (and): .As_is [ p? [ q? 1^ || ~q? 0^] || 0^] (enigma): .As_is {i>1? [ i%2=0? i/2->i; || 3*i+1->i; ] } (newt): .As_is {h+l->x; x/2->x; sqx->y; y-0.5l; || y+0.5>t? x->h; } These structures have a syntax like guarded commands. The semantics are simpler. Each alternative is tried, in turn, until one succeds or all have failed. The first alternative is tried first. If it completes without failing then the set of alternatives also complete successfully and the later one ones are ignored. If an alternative fails then control is passed to the start of next alternative. If all fail then the set of alternatives as a whole has failed. If any succeeds (even after several failures) the whole succeeds and the later ones are ignored. At the failure or success of a set of alternatives, control passes to the end of the structure. If the structure is an iteration and if the alternativess succeeded then the whole structure is repeated. When all alternatives in an iteration fail then the iteration terminates successfully. Notice that an iteration can not fail. However an iteration can avoid terminating for ever. In a selection, the structure fails if all the alternatives fail and succeeds if any alternative succeeds. . Semantics The object-oriented operational semantics expressed using the UML is $TBD. .Open Examples . abs .As_is // This would be put in a file abs.sma .As_is // It is given a number in variable e .As_is // It returns the absolute value of e .As_is [ e < 0 ? -e^ .As_is || e^ .As_is ] . sqrt .As_is // This would be put in file sqrt.sma .As_is // Given a positive number in d .As_is // sqrt leaves an approximation to its sqrt in the same variable .As_is // Uses variables x,y, e, and f .As_is // calls abs above .As_is d/2 -> x .As_is { x*x-d -> e; abs>0.00001? .As_is 2*d ->f; x/2.0 ->y; d/f+y ->x; .As_is vv } .As_is x ->d . quadratic .As_is //This would be in a file quadratic.sma .As_is //'small quadratic' then reads three lines containing a number each .As_is //and solves a quadratic equation ax*x+bx+c=0 .As_is // Uses variables a,b,c,d,e,f,s,t,x,y .As_is // Calls sqrt and indirectly abs .As_is .As_is //read a,b, and c .As_is $->a; $->b; $->c; .As_is // calculate the denominator t .As_is 2*a->t .As_is [ t=0? "This is a linear equation"! .As_is || t<>0?// a<>0. .As_is // find the discriminant d .As_is 2*t*c->s; b*b-s->d; .As_is // select the correct case depending on the discriminant d .As_is [ d>0? sqrt; "Real roots: " -b+d/t " and " -b-d/t ! .As_is ||d=0? "Equal roots: " -b/t! .As_is ||d<0? -d ->d; sqrt; "Complex roots: " -b/t "+/- i*" d/t! .As_is ] .As_is ] .Close Examples . Notations O::=optional. char::=`any $ASCII character`. end_of_line::= $ASCII.CR | $ASCII.LF. horizontal_tab::=$ASCII.HT. space::=$ASCII.SP. ASCII::=http://www/dick/samples/comp.text.ASCII.html. TBD::="To Be Done". XBNF::="Extreme" $BNF. BNF::="Backus Naur Form", a popular formal syntactic meta-language. .Close Small