Alexey Krivonogov

The Gentee programming language

Vol 1. Programming for beginners

Basic definitions

Introduction

This manual is being written at present. I plan to publish new articles each week. Feel free to send me your comments and suggestions to info@gentee.com and write the following subject - Gentee.

The last update: 23.06.2006.
Tips for beginners
  • Practice makes perfect. Set a problem and then try to solve it.

  • Explore sources that are ready-to-use. For example, you can find them in the subdirectory Sources\Stdlib

What is a program?

Mankind speaks different languages, in the same way as we deal with computers using various programming languages. There is a huge variety of languages that includes well-known languages, such as: /++,C#,VB,Java,Pascal,PHP,Perl as well as numerous exotic languages. Furthermore, each language has its own peculiarities and it is used in the appropriate field. As a rule, if only a person has learnt one programming language, he will manage to master other languages much faster. Gentee has much in common with /++ and C#,Java, though it is not an object-oriented language, actually. Once you have studied Gentee, you will be able to learn more complicated programming languages if necessary.

Thus, a program is a set of instructions which a computer follows.Computer programming is writing a program with the help of any computer language. There is an elementary program below:

func myprog<main>
{
}

func - is a keyword that defines a function. The point is, if programs are large, they are split into several smaller parts, which are called functions, methods or operators. Each part of a program produces appropriate operations. The main attribute indicates that this is the first function which is called when running a program. A function body must be enclosed in curly brackets, actually; however, in the example given above no function body is specified inside the brackets.

In order to run the program you have to save it as the .g file (for example, myprog.g). As for Gentee Studio, press the Execute key or key combinations Ctrl-F2 in order to startup the program. If you use the explorer or any file shell, double-click the mouse or press the Enter key in order to run the program.

Unfortunately, there is no work result, because our program does not perform any operations. Data can be displayed using either @"the output line" or print("the output line").

func myprog<main>
{
   @"Hello, World!"
}

If you run this program, it will be shut at once and you can not read the text. Let us write getch() at the end of the function, it is a function call that must be followed by a keystroke.

func myprog<main>
{
   print( "Hello, World!" )
   getch()
}

Where do the print and getch functions come from? Actually, any language including Gentee has its standard library that contains a set of frequently used functions, types and objects. It makes it possible not to program the same operations again. More detailed information about available libraries can be found in the appropriate section.

Exercise 1. Display any text.

Introduction to arithmetic expressions

As you know, 2 + 2 = 4, does a computer manage to calculate it?
func sum<main>
{
   print("2 + 2 = \( 2 + 2 )\n")
   getch()
}

In the example given above the first expression '2 + 2' is a part of the string, however, '2 + 2' enclosed in parentheses is considered to be an arithmetic expression. We calculate using the calculator almost in the same way. Similarly, '-' used to subtract, '*' used to multiplicate and '/' used to divide two numbers. The '\' character used inside the string is a special character.

  • \(expression) is used to output the result of the expression.
  • \n - the line feed character.
  • \" - the quotation marks inside the string.
To calculate the expression 25*(387-113)/2, we can write down
@"Result = \(25 * (387 - 113) / 2)\n"

While calculating such expressions, you are likely to come accross the funny problem. For example

@"\( 1/2 ) \( 2 - 3 )\n"

returns the result: '0 4294967295'. This is not an error. There are different types of numbers in mathematics: natural numbers, integers, real numbers, complex numbers, etc. So in programming languages there are also some types of numbers. Let us take a look at the uint type (similar to natural numbers), furthermore, all numbers are of this type by default. A huge number can be written on paper, however, each number must be placed in its own position on a computer. For this reason there are some restrictions. An number of the uint type is varied from 0 to 4294967295; as well as that, the range is iterated. '4294967295 + 1' returns 0 again, and 0 - 1 returns 4294967295. Let us have a look at '1/2'. The arithmetic expression returns a number of the same type, in addition, as numbers of the uint type contain no fraction, it is dropped, so 0 is returned.

Source layout

Text layout is subject to rules and regulations of a programming language as well as it is a matter of personal preference. Let us take a look at a programming language's syntax. A program text consists of a sequence of tokens that can be integers, keywords, names (identifiers), operators and service characters.

  • Integer. For example: 25, 426, -1327. Numbers of the following type 0xFF31, 345L, 567D, -5.32, 89E-23 will be discussed later.

  • Keyword. The keyword that you have already known is func. It is used to define a function. Actually, there are not so many keywords in the language, you can easily remember them. For example: import, operator, method, foreach, while, define.

  • Name(identifier). You can take advantage of choosing any names you like. The clearer the names, the easier you can find errors and modify your program. Names contain letters and numbers, but a letter must be the first element. Furthermore, they are case-sensitive. You had better choose names of the same style. The most frequently used styles are: getvalue, get_value, GetValue.

  • Operations. The simplest arithmetic expressions have been described above ('+', '-', '*', '/' ). In addition, there are comparison operations ('==', '>', '<', '>=', '<='), assignment operations '=', etc.

  • Service characters. Service characters are various types of brackets, ',', ':', ';', '.'. Each symbol mentioned above is appropriately used, for example, curly brackets are not to be replaced with parentheses.

I consider that there is no need to discuss a programming language's syntax in greater detail now. If you omit a bracket or use a comma incorrectly, the compiler will warn you about the mistake.

A style for formatting sources plays a large role in writing a program. The example below shows the sum of even numbers in the array that are calculated with the help of two functions. These functions both operate and are used for the same purpose. Let us compare two variants.

func uint evensum( arr array )
{
   uint i result

   fornum i, *array
   {
      if !( array[i] & 1 ) 
      {
         result += array[i]
      }    
   }
   return result   
}
func uint f1( arr a )
{uint I l;fornum I, *a{if !(a[I]&1){l += 
a[I]}}return l}

Even though the variant on the right is shorter, it is hard to comprehend. There are special programs (so called obfuscators) that make sources unreadable, nevertheless, they execute in exactly the same way.

Curly brackets are used quite often. Using curly brackets we can write the fragment from the previous example, as follows

if !( array[i] & 1 ) { result += array[i] }

we can also use ':', with help of which the whole text is enclosed in curly brackets.

if !( array[i] & 1 ) : result += array[i]

You should use comments in addition to clear names and format text properly. Take advantage of comments in order to recall the information mentioned in previous sections. Comments are considered to be main assistants of your program documentation. There are two types of comments:

  • Nested or multiline comments. Begin with an opening delimiter '/*', and run to a closing delimiter '*/'.

  • Line comments. Begin with two forward slashes '//' and run to the end of the line

/*--------------- 
   The example 
   illustrates 
   a multiline comment
---------------*/
   i = i + 20  // Single-line comment  

Function

A function is a main "building" unit of a program. Every function peforms the same appropriate operations. A function can return a value as well as receive incoming parameters, that are responsible for a result. Let us have a look at function description:

func myfunc
func uint my( uint i j k ) // Three parameters i j k are of the uint type
func sum( uint left, int right ) 

Any function contains a block code enclosed in curly brackets. A block code describes its behaviour. That is a sequence of expressions, conditional statements, loops. Furthermore, a block code describes local variables. Local variables are cells or objects that keep results temporarily. Local variables are components of any function and can be defined in any place.

If either variables or parameters are of the same type, they are separated by space characters. Otherwise, parameters are separated by commas and variables start with a new line.

The example below shows a function that is applied for sum, difference, product and real quotient. A local variable is used for keeping the product of two numbers, as the simplest example.

func myout( int i j )
{
   int multi

   multi = i * j

   @"\(i) + \(j) = \( i + j )
\(i) - \(j) = \( i - j )
\(i) * \(j) = \( multi )
\(i) / \(j) = \( i / j )\n"
}

func main<main>
{
   myout( 20, 10 )
   myout( 567, 35 )
   myout( 16, 4 )
}

Results returned by the myout function are subject to values of the i and j parameters. In the example given below there is one assignment operator '='. It assignes new values to variables. When calling a function, local variables have zero values; however, values can be assigned to local variables after they have been defined.

uint i = 10
i = i * 5 + 2
After this fragment has been executed, the i value will equal 52.

Method

A method differs from a function by its description and its peculiar way of calling. When a method is used, it makes it clear that we perform some operations on the specified object.

// Description
method [return_type] variable_type.method_name( parameters )
// Use
variable.method_name( parameters ) 
Let us have a try to make the print function be a method.
method str.myprint : print( this )

func main<main>
{
   str  hello = "Hello!"
 
   hello.myprint()
   getch()  
}

this is a variable which method is called. In this case, there is no need for additional variable hello. A string enclosed in double quotes is an ordinary variable of the str type, but it has no name. You will not able to use it then.

"Hello!".myprint()

In object-oriented languages methods belong to the specific type, in order to add some new methods, you need to define a new type based on the present type. Gentee allows you to assign new methods to the present types in any position at any time.

The Gentee compiler checks that variable and parameter types are used properly. On the one hand, it causes some inconvenience; however, on the other hand, it makes it possible to make no mistakes and to define functions and methods that have the same names and different parameters. The compiler is able to define whether it is the required function or method at the time of calling it. Let us use one more myprint method, that will output the string the specified number of times.

method str.myprint : print( this )

method str.myprint( uint count )
{
   str  s = this + "\n"  
   print( s.repeat( count ))
}

func main<main>
{
   "Hello!".myprint()
   "-----".myprint( 5 )
   getch()  
}

Console Input And Output

As you noticed, all examples given above showed that a text was displayed in a separate window. First-generation computers displayed only symbols. During the periods of rapid growth in the computer industry, grafic was displayed and a window interface that is now a usual tool for us was supplied. Nevertheless, a window interface is not required for some programs, which need only text input or output. Such programs are called console programs. This manual gives examples using console operations; in other words, the program samples perform a text input or output. First, to know the things mentioned above are well enough to learn how to program. Second, another manual will deal with window interface programming. As a rule to create a console application requires a few expenditures.

As I used to output data with the help of the print function and the @"output string" operation, let us proceed to data input.

To begin with, I would like to give a piece of advice for those users who fail to output national character set to a console. If a text in Russian is ouputted to a Windows console

print("!")

you will see strange characters on the screen. There is no error, it happens because Windows inherited some peculiarities from the MS-DOS operating system. Each operating system supports several specific character sets. Windows console applications use a character set supported by MS-DOS, and you type a text using the Windows character set. In case of coinciding the Latin character sets supported by MS-DOS and Windows, the Russian character set supported by MS-DOS will differ from the Windows character set. For obvious reason, the text in English is displayed properly, and the text in Russian is unreadable. Have a look at the example:

print("ਢ!")

Surprisingly, the required information will be displayed if the example above is executed. You can solve this problem using the following methods: oem2char and char2oem. A string converts from DOS to Windows with the help of the first method, and vise versa using the second method.

print( "!".char2oem())

Let us define a function used for text output. I use a temporary variable of this function in order not to spoil the string.

func myprint( str out )
{
   str  dos = out
   print( dos.char2oem())
}

One function used for data input has been known to you so far. This is getch used for indicating a character of the key that has been pressed. You can use the congetstr( str outtext intext ) function in order to get a whole string. The outputted text can be specified in the first parameter, the second parameter is a result string. The text input ends after you have pressed Enter.

str in
congetstr( "Enter your name: ", in )
print("Your name: \(in)\n")

Conditional Statement

The conditional statement alters the sequence of program operations depending on the value of a expression. This expression is called a conditional expression, and its value can be either true or false (zero). Actually, a conditional statement is used in any programming language; furthermore, it is considered to be one of the most fundamental concepts in computing. In Gentee the conditional statement looks like this:

if conditional_statement1
{ 
   // executes if conditional_statement1 is nonzero 
}
elif conditional_statement2
{
   // executes if conditional_statement2 is nonzero
}
else
{
   // executes if the previous conditions are false.
}

The following additional statements elif and else are optional. Several elif statements can be specified. These statements are checked if the previous conditions are false.

A conditional expression is an expression that returns a number. If the value equals zero, the expression is FALSE, otherwise, it is TRUE. In the simple example a variable can be used as a conditional expression.

uint i

if i { ... }
There are the following comparison operators.

a < b returns 1 if a is less than b; otherwise, this value is equal to zero.
a > b returns 1 if a is greater than b; otherwise, this value is equal to zero.
a <= b returns 1 if a is less than or equal to b; otherwise, this value is equal to zero.
a >= b returns 1 if a is greater than or equal to b; otherwise, this value is equal to zero.
a == b returns 1 if a is equal to b; otherwise, this value equals zero.
a != b returns 1 if a is not equal to b; otherwise, this value is equal to zero.<

Please note that unlike the assignment operation, the double equal sign '=' is used to obtain equality. In the example below the body of the conditional statement executes in any case, because the assignment operator assigns 1 to the i variable and then returns this value.

if i = 1 {...}
The correct expression looks like this
if i == 1 {...}
Now we can write a function that determines a low number from two numbers.
func int mymin( int left right )
{
   if left < right : return left
   return right
}

else was not specified, because if left is less than right, we exit the function.

Except the comparison operations, there are three logical operations:

a && b returns 1 if a and b are nonzero. Otherwise, the expression returns zero.
a || b returns 1 if a and b are nonzero. It returns zero, if a and b equal zero.
!a returns 1 if a equals zero, and it returns zero if a is nonzero.

Let us make the previous example more difficult: we write the function that returns the sum of two low numbers from three numbers that must be the parameters. Let us have a look at the following three alternative solutions.

// Example 1
func int mymin( int left right ) : return ?( left < right, left, right )
func int mymin( int x y z ) : return mymin( x + y, mymin( x + z, y + z ))

This path to the solution is rather short. We deal with any three sums in order to choose the low number between them. As you have probably noticed, the functions have the same names. The example shows how a function and a method with the same name are defined.

The operator
 
?( conditional expression, expression1, expression2 )

performs the same operations as the conditional statement when it is used inside the expressions. Either expression1 or expression2 will be calculated and returned, it depends on the result of condition.

Have a look at the example 2
// Example 2
func int mymin( int x y z )
{ 
   if x < z 
   {
      if y < z : return x + y
      return x + z
   }
   if x < y : return x + z 
   return y + z
}

So, if x is less than z, we suppose that one low number has been already got. Then we must compare y and z and return the appropriate sum. If x is not less than z, we must compare x and y and return the sum of the low number as well as z.

In the example 3 we are going to obtain the maximum number and return the sum of the other two numbers.

// Example 3
func int mymin( int x y z )
{ 
   if x > y && x > z : return y + z
   if y > z : return x + z
   return x + y
}

As we dealt with the first conditional statement, we realized that x is not a maximum number. For this reason, either x + y or x + z will be returned. We need to choose a low number between y and z.

You can test the mymin function by changing its arguments and using the main function.

func main<main>
{
   print("MIN( x, y, z ) = \( mymin( 12, 45, 34 ))")
   getch()
}

Loops

Some sequence of operations is repeated iteratively a specified number of times with the help of loops. There are several types of loops in Gentee, but I am going to describe only three of them. Let us add up numbers in the range from 1 to 100. We had better use the fornum loop in order to solve this problem.

fornum counter_variable [ = initial_value ], final_value 
{
   // loop body
}

The value of the counter variable is incremented by one after each loop iteration is complete. It is not so important to assign the initial value to the variable. Please note, that the final value must be greater than the required value by one. Have a look at the solution of the problem:

func main<main>
{
   uint i sum

   fornum i, 101 : sum += i
   @"SUM (1 - 100) = \(sum)"
   getch() 
}

I suppose that you bear in mind all variables are equal to zero at the beginning, thus they are used without initializing them. The a += b operation is equal to the a = a + boperation. There are similar operations for subtration, multiplication and division: -=, *=, /= . For example, as a result of the i *= 3 operation, the value of the i variable will have been incremented by three.

The while statement is the second simple loop, with the help of which the execution of the loop body is repeated until the value of the expression is nonzero.

while conditional_expression  
{
   // loop body
}

Do the previous task using while instead of fornum. Please keep in mind that you are to change the value of the i variable. The example below illustrates how while helps to display the character that has typed.

func main<main>
{
   uint ch

   while (ch = getch()) != 'q'
   {
      print( "Key: ".appendch( ch ) += "\n" )
   }
}

The loop executes until the 'q' key is pressed. The appendch method is used to append a character to the string.

If you write in this way
print( "Key: \( ch ) \n" )
numeric values of the keys will be displayed.

The do while loop executes in a similar way as the while loop. However, unlike while loop, the condition of executing the do while loop is checked after its iteration is completed. The loop executes at least once.

do  
{
   // loop body
} while conditional_expression

Unlike the while loop, the do while loop executes once in the example below.

i = 10
while i < 10 : @"While: \( i )"

do
{
   @"Do While: \( i )"
} while i < 10 

Type Definition

Actually we can qualify everything as well as divide them into various groups. All species of animals and plants are divided into several kinds and classes. Let us examine different types of construction. There are office buildings, shops, apartment buildings, cottages, etc. If a type of construction belongs to some group, it means that it has the same characteristics. In computer programming we can say the same about types. You have already read about the uint type that is a natural number and the str - strings. We have also used the int type that is an integer in the range from -2147483648 to +2147483647. The float type and the double type are used to represent real numbers. long and ulong represent massive numbers. It is important that you are able to define your types and deal with them. Below there is an example of the type (structure) defined.

type person
{
   str  firstname
   str  lastname
   str  email
   uint age          // age
}

There are four fields of the person type for storing a name, an e-mail address and age. While you define a structure, a field's type and name are required. It is advisory for you to specify field names that either conform to field contents or have the appropriate comments. Below you can see the example of defining methods in order to set field values and display them.

method person person.set( str fname lname email, uint age )
{
   this.firstname = fname 
   this.lastname = lname
   this.email = email
   this.age = age
   return this
}

method person.print
{
   print( "Name: \(this.firstname) \(this.lastname)
Email: \(this.email)
Age: \(this.age)\n" )
}

As you see, '.' is used to access a field value in the same way as the method call. It is pretty easy, furthermore, the only thing is to write the main function. The example is simple, however, we will get to know other necessary types and deal with them in the future.

func main<main>
{
   person myf

   myf.set( "Alexey", "Krivonogov", "info@gentee.com", 34 ).print()
   getch()
}

The set method returns an object of the person type; therefore, we can use the print method at once. This is a successive methods call that makes the program shorter, nevertheless, it remains understandable and clear for programmers.