Examples

Statements

In this example we present the different statements in CellSpeak. Most of the statments should be very familiar.























(1) This also works for more then two variables - as long as the number of expressions on the right matches the number of variables on the left. This mult-ssignment is not an expresssion, i.e. it cannot be used as a part of another expression.


















(2) Another use for a delayed assignment would be a return statement like  return p ~ p.next  where a pointer is returned and set to p.next afterwards. Normally this would require an intermediate variable.



(3) The keyword is can be used in comparisons. It is equivalent to the == operator.

























(4) This allows for concise checks at the start of piece of code, e.g.  not p ? return  or  Str is null ? return  It is actually possible to use an expression followed by a return statement:  a > 100 ? a = 0 & return  which is a concise way to check if a is larger then 100, and if so to reset it to zero and return. The statement can also be a break, leave, yield or continue statement. Note that the expression and the statement must be linked with an &. Code is often riddled with this type of checks, and this allows for a concise but still clear notation.










(5) Internally the month variable is a pointer, so any changes to the variable are immediately reflected in the array itself.































































(6) Switch statements in CellSpeak can be constructed from any countable type (byte, word, int, enum), but also from strings. In the bytecode, a switch statement is implemented as a sorted table, thus making sure that selections in the table are efficient irrespective of the size of the table. The switch statement allows to write clear and efficient, table-driven software.

04 Statements.celsrc
use Windows, Math, Strings, Editor

group Statements

design Demonstrator is

	-- In this example we put all the statements in the constructor
	constructor is
	
	-- We create the output cell
	cell Window = create MenuWindow("Statement test")
	
-. 1. Assignment .-
	
	-- Display the title for this test	
	Window <- print("\n\n*** Test1: assignment\n")	
	
	-- Declare and initialize
	float a = 4, b = 7, c = 6
	
	-- a quadratic form
	float x = 5
	var y = a*x^2 + b*x + c
	
	-- expressions can be embedded in a string
	Window <- print("\ny = a*x^2 + b*x + c 	when x = [x=3] then y = [a*x^2 + b*x + c]")
	
	-- Assignments are expressions and can be part of other expressions
	c = (a = 3.14)*( b = 73.8)
	Window <-print("\n a = [a], b = [b] , c = a * b = [c]")
	
	-- declaring and initialising a number of variables
	int r,s,t,u,v,w	
	r = s = t = u = v = w = 144	
	Window <- print("\nThe variables u,v,w and c have the same value: [r], [s], [t], [u], [v] and [w]")
	
	-- we can swap two variable without the need for a temp variable like this
	Window <- print("\na and b before swapping: a = [a], b = [b]")
(1)	a,b = b,a
	Window <- print("\na and b after swapping: a = [a], b = [b]")
	
	-- Operations and assignments can be combined
	a += 25.1		-- this is equivalent to a = a + 25.1
	b /= a + b^3	-- this is equivalent to b = b/(a + b^3)
	
	-- The result of an assignment can be used again, eg as an index
	int SmallPrimes[] = [ 2, 3, 5, 7, 11, 13, 15, 17, 19]
	int i=0
	
	Window <- print("\nThe second prime number is [SmallPrimes[ i += 1 ]]")	
	
-. 	2. Delayed assignment .-

	Window <- print("\n\n*** Test2: Delayed assignment\n")	

	-- In array selections, loops or in return statements we often want to use 
	-- the value BEFORE the assignment and do the assignment afterwards.
	-- Therefore in CellSpeak we have the delayed assignment. The delayed assignment uses the ~ symbol

	i = 7	-- normal assignment
	i ~ 8	-- delayed assignment - behaves here exactly as a normal assignment
	
	i = 19
	var j = i ~ 13  -- j is 19 and i is 13 after the assignments			
	
	-- delayed assignment is most useful in return statements, selections or loops where you want to change a variable
	-- after using it as an index or as a return value without having to add a temp variable or extra statement.	
	i = 0
(2)	Window <- print("\nThe first prime number is [SmallPrimes[ i +~ 1 ]], 
											and the second is [SmallPrimes[ i +~ 1 ]]")	
	
-.	3. if then else .-

	Window <- print("\n\n*** Test3: if - then - else\n")	

	-- basic form	
	int Players
	utf8 Game = "tennis"
(3)	if  Game is "tennis" then 
		Players = 2
	else 
		Players = 0
	end
	
	-- else is optional
	if Game is "handball" then
		Players = 2*7
	end
	
	-- Multiple 'else if' are more readible using elif (and avoids all the terminating 'end')
	Game = "soccer"
	if Game is "tennis"  then
		Players = 2
	elif Game is "basket" then
		Players = 2*5
	elif Game is "soccer" then
		Players = 2*11
	elif Game is "handball" then
		Players = 2*7
	end
	Window <- print("\nIn [Game] there are [Players] players on the field")
	
-.	4. Conditional expression .-
	
	Window <- print("\n\n*** Test4: expr ? true : false\n")	
	
	-- In some cases it can be clearer to use a more concise form of if then else:
	-- expresssion ? expr if true : expr if false
	Game is "tennis" ? Players = 2 : Players = 3
	Window <- print("\nThe result of 'Game is \"tennis\" ? Players = 2 : Players = 3'  with  Game = [Game] is  Players = [Players]")
	
	-- The construct can be used as a conditional expression, and thus the above can be rewritten as	
	Players = Game is "tennis" ? 4 : 5
	Window <- print("\nThe result of 'Players = Game is \"tennis\" ? 4 : 5'  with  Game = [Game] is  Players = [Players]")
	
(4)	-- The true and/or false part of the comparison can also be a return, a continue or a leave statement.
	-- This is particularly handy when checking pointers or conditions where pocessing should stop / not start.
	-- If the 'true' action is not an expression, then the 'false' action can be omitted.
	
-. 	5 For Loops .-

	Window <- print("\n\n*** Test5: for loops\n")	
	
	-- Print the title for the firts test
	Window <- print("\nThe months of the year: ")
	
	ansi months[] = ["january","february","march", "april", "may", "june", "july", "august", "september", "october", "november", "december"]
	
	-- The traditional way to define a loop - specify the indices
	for i = 0 to 11 do
		Window <- print("[months[i]] ")
	end
	
	-- Easier and safer : use foe each, the runtime knows the size of the array	
	for each month in months do
		Window <- print("[month] ")
	end	
	
	-- The loop variable 'month' does not need to be declared explicitely.
(5)	-- The loop variable is not an intermediate variable, but it stands for the array element.
	-- Changes to the loop variable affect the array element :

	Window <- print("\nThe elements of the array have changed: ")	
	for each month in months do
		Window <- print("[month.upper()] ")
	end

	-- You can also apply 'for each' to an ad hoc assembled list of elements of the same type
	Window <- print("\nThe square of some small primes: ")
	for each Prime in [2,3,5,7,11] do
		Window <- print(" [Prime]^2 = [Prime^2]")
	end
	
	-- Sometimes we need the index to manipulate array elements.
	-- We can use the following 'for loop' format where the loop
	-- variable is put between [] to show we mean the index.
	
	Window <- print("\nThe numbered months ")		
	for each [i] in months do 
		Window <- print("[i+1]:[months[i]],")
	end
	
	-- This works also for multiple indices - this avoids having to write multiple loops.
	-- We can use this for example to transpose a matrix
	
	int A[4, 4] = [ 1,2,3,4,
					5,6,7,8,
					9,10,11,12,
					13,14,15,16 ]
					
	Window <- print("\n\nTranspose a square matrix - before:
						[A[0,0]] [A[0,1]] [A[0,2]] [A[0,3]]
						[A[1,0]] [A[1,1]] [A[1,2]] [A[1,3]]
						[A[2,0]] [A[2,1]] [A[2,2]] [A[2,3]]
						[A[3,0]] [A[3,1]] [A[3,2]] [A[3,3]] 	")
						
	for each [i,j] in A do 
		if j > i then 
			A[i,j],A[j,i] = A[j,i],A[i,j]
		end
	end
	
	-- ..but we can write this shorter:
	for each [i,j] in A => j > i ? A[i,j],A[j,i] = A[j,i],A[i,j]
	
	Window <- print("\n\nTranspose a square matrix - after:
						[A[0,0]] [A[0,1]] [A[0,2]] [A[0,3]]
						[A[1,0]] [A[1,1]] [A[1,2]] [A[1,3]]
						[A[2,0]] [A[2,1]] [A[2,2]] [A[2,3]]
						[A[3,0]] [A[3,1]] [A[3,2]] [A[3,3]] 	")
								
	-- Nested loops : sometimes we need to loop over several indices.
	-- In CellSpeak this can be written in a single loop statement:	
	var Sum = 0, Count = 0
	for i = 0 to 3, j = 0 to 5, k = 0 to 7 do
		Sum += i + j + k
		Count += 1
	end
	Window <- print("\nThe sum after [Count] iterations is [Sum]")
	
	-- In some case you will still want to be able to write a general loop	
	Window <- print("\n\nGeneral for-loop. Distances are: ")
	float Distance
	for ( Distance = 0.25 , Distance < 12.50, Distance *= 1.5 ) do 
		Window <- print(" [Distance]")
	end
	
-.	6. while loop and repeat until .-

	Window <- print("\n\n*** Test6: while-do and repeat-until \n")	
	
	float RandomSum = 0
	var Iterations = 0
	while RandomSum < 2.0 do
		RandomSum += randf()
		RandomSum -= randf()
		Iterations += 1
	end
	Window <- print("\nWhile-do loop. Random sum = [RandomSum] after [Iterations] Iterations")
	
	-- or it can be written as a repeat statement (note that the condition changes in this case)	
	RandomSum = Iterations = 0
	repeat
		RandomSum += randf()
		RandomSum -= randf()
		Iterations += 1
	until RandomSum >= 2.0
	Window <- print("\nrepeat-until loop. Random sum = [RandomSum] after [Iterations] Iterations")
	
-.	7. switch statement .-
	
	Window <- print("\n\n*** Test7: switch statement \n")	
	
	-- A simple switch statement
	i=405
	ansi Selection
(6)	switch i
	
		case 17: 	Selection = "seventeen"
		case 21: 	Selection = "twenty one"
		case 13: 	Selection = "thirteen"
		case 405: 	Selection = "four hundred and five"
		case 55: 	Selection = "fifty five"
		default :	Selection = "the default selection"	
	
	end
	Window <- print("\nThe selected element [i] is [Selection]")
	
	-- There is no fall through and therefore there is no break required at the end of a case
	-- we can also use zero terminated strings in a switch statement
	ansi month = "august"
	var Days = 0
	ansi Quotation = null
	switch month
	
		case "january":		Days = 31
		case "february":	Days = 28
							Quotation = "
										Why, what's the matter, 
										That you have such a February face, 
										So full of frost, of storm and cloudiness? 
										-- William Shakespeare 'Much Ado About Nothing'"
		case "march":		Days = 31
							Quotation = "
										Our life is March weather, savage and serene in one hour. 
										-- Ralph Waldo Emerson"
		case "april":		Days = 30 
		case "may":			Days = 31 
		case "june":		Days = 30 
		case "july":		Days = 31 
		case "august":		Days = 31
							Quotation = "
										August rain: the best of the summer gone, 
										and the new fall not yet born. The odd uneven time. 
										-- Sylvia Plath, 'The Unabridged Journals of Sylvia Plath'"
		case "september":	Days = 30 
		case "october":		Days = 31 
		case "november":	Days = 30 
		case "december":	Days = 31 
		default :			Days = 0		
	end
	
	-- print the nr of days in the month
	Window <- print("\nThe month of [month] has [Days] days")
	
	-- if there is a quotation, print it
	Quotation ? Window <- print("[Quotation]")
	
-.	8. Leave and continue .-

	Window <- print("\n\n*** Test8: Leave and continue \n")	

	-- Statements can get a label with a 'Task' statement. That label can then be used in leave an continue statements.
	-- 'leave' without a label will jump out of the closest loop, while leave with a label will 
	-- jump out of the statement with the label
	-- 'continue' without a label will start the next iteration in the closest loop, 
	-- while continue wih a label will restart the loop statement with that label
	-- Multiple statements can be grouped into a compound statement, that can also have a label
	-- Even when not strictly necessary it can be helpful to use task labels just for clarity 
	
	const n = 100
	int Primes[n]
	int NrOfPrimes = 1
	int SquareRoot
	
	-- The first prime is 2
	Primes[0] = 2	
	
	-- The 'for statement' gets a label
	task FindPrimes
	
	-- Start at the next prime candidate, 3
	for (i=3,true,i+=1) do
	
		-- Calculate the integer square root of i
		SquareRoot = sqrt( i )
	
		-- Check with the primes already found
		task TestPrimes
		for j=0 to NrOfPrimes-1 do

			-- Check if the prime divides i
			i % Primes[j] is 0 ? continue FindPrimes 
			
			-- We can stop if the prime is bigger then sqrt(i)
			Primes[j] > SquareRoot ? leave TestPrimes
		end
		
		-- found another prime, add it	
		Primes[ NrOfPrimes +~ 1 ] = i
		
		-- If we found enough, we stop
		NrOfPrimes is n ? leave FindPrimes
	end

	-- Now we print the primes we found
	Window <- print("\nFound [NrOfPrimes] primes:")
	for each [i] in Primes do 
		
		-- Start a new line every 20 primes
		i % 20 is 0 ? Window <- print("\n")
		Window <- print("\t[Primes[i]]")
	end
		
	end -- of constructor		
	
end -- of design