HOME Try Sather download Post Messages

15. Interface with other languages such as C and Fortran

1. Introduction

I am going to explain about the interface with other languages such as C and Fortran. Sometimes using Fortran or C is better because the performance may improve and because you can use convenient libraries. The interface implies that Sather has been developed for writing practical applications (as well as academic study).

2. Interface with Fortran

I will show two examples: one is factorial and the other is product of matrices

2.1. Factorial

Codes ffact.f ([code 1a]) and ffact.sa ([code 1b]) show Fortran and Sather parts of factorial calculation.

Function factorial(n) in ffact.f returns factorial of n. The function is called from the sather part of the program (ffact.sa)

[code 1a]: ffact.f

01:           integer function factorial(n)
02:           integer n
03:           factorial = 1
04:           do i=1,n
05:              factorial = factorial * i
06:           enddo
07:           return
08:           end
[code 1b]: ffact.sa
01:     -- interface with fortran
02:     -- to compile:
03:     -- sacomp ffact.sa -external FACT ffact.f  -o ffact
06:     external FORTRAN class FACT is          -- declare an external class written in Fortran
07:        factorial(i:F_INTEGER):F_INTEGER;    -- function defined in FACT
08:     end;
10:     class MAIN is
11:        main(av:ARRAY{STR}) is
12:           i:F_INTEGER := #(av[1].cursor.get_int);  -- integer of Fortran is F_INTEGER in Sather
13:           a:F_INTEGER := FACT::factorial(i);       -- an instance of F_INTEGER is created by #(INT)
14:           #OUT + av[1] + "! = " + a.str + "\n";    -- convert to string by str method
15:        end;
16:     end;

You have to tell the compiler that FACT is defined in ffact.f using the -external flag.

$ sacomp ffact.sa -external FACT ffact.f -o ffact
$ ./ffact 10
10! = 3628800
Several Fortran data types such as F_INTEGER and F_REAL are available. You can create a instance of these data types by the create method with giving a corresponding Sather data type as an argument. See Sather — A Language Tutorial: Chapter 13 Interfacing with Fortran for detailed information.

2.2. Product of matrices

The F_ARRAY2{F_data_type} class represents two dimensional arrays. An instance of F_ARRAY2{F_data_type} can be created from that of ARRAY2{T}.

Codes mat.f ([code 2a]) and mat.sa ([code 2b]) show Fortran and Sather part of matrices product calculation. Be aware that the order of line index and column index is different in Fortran (column, line) and (line, column) in Sather.

[code 2a]: mat.f

01:     c
02:     c     calculating the product of matrices c = a * b
03:     c
04:           subroutine mattimes(l,m,n,a,b,c)
05:           integer l,m,n,i,j,k
06:           real a(n,l), b(m,n), c(m,l), tmp
07:           do i=1,l
08:              do j=1,m
09:                 tmp=0.0
10:                 do k=1,n
11:                    tmp=tmp+a(k,i)*b(j,k)
12:                 enddo
13:                 c(j,i)=tmp
14:              enddo
15:           enddo
16:           return
17:           end
[code 2b]: mat.sa
01:     -- Matrix test
02:     --  sacomp mat.sa -chk -external FMAT mat.f -o mat
04:     external FORTRAN class FMAT is
05:        mattimes(l,m,n:F_INTEGER, a,b,c:F_ARRAY2{F_REAL}); 
06:     end;
08:     class MAT is
09:        include ARRAY2{FLT};               -- MAT class inherits ARRAY2{FLT} 
11:        times(b:SAME):SAME                 -- define product
12:           pre self.nc = b.nr  -- check if the column number of the left side and line number of right side is same.
13:        is
14:           c:SAME:=#(self.nr, b.nc);  -- declare a result storing matrix
15:           FMAT::mattimes(#(self.nr), #(b.nc), #(self.nc), #(self), #(b), #(c)); -- calling mattimes from the Fortran module.
16:           return c;  -- values in F_ARRAY2{REAL} and ARRAY2{FLT} change simultaneously
17:        end;
18:     end;
20:     class MAIN is
21:        main is
22:           i:INT;
23:           a,b,c:MAT;
24:           a:=#(||1.0, 1.0, 2.0|, |2.0, 2.0, 3.0||);
25:           b:=#(||1.0, 1.0|, |1.0, 2.0|, |1.0, 3.0||);
26:           c:=a*b;         -- matrices product calculation gets simple
28:           loop                          -- showing the answer
29:     	 i:=1.up!;
30:     	 #OUT + c.elt!;
31:     	 if i%c.nc=0 then #OUT+"\n";
32:     	 else #OUT+" ";
33:     	 end;
34:           end;
35:        end;
36:     end;
The mat calculates

as a test.
$ sacomp mat.sa -chk  -external FMAT mat.f -o mat
$ ./mat
4 9
7 15

3. Interface with the C language

The interface with C is similar to that with Fortran.

3.1. Factorial

Codes cfact.c ([code 3a]) and cfact.sa ([code 3b]) shows factorial calculation program written in C and Sather.

[code 3a]: cfact.c

01:     unsigned long factorial(unsigned long i){
02:         unsigned long j, n;
03:         for(n=1,j=1;j<=i;++j) n*=j;
04:         return n;
05:     }
[code 3b] cfact.sa
01:     -- interfacing with C
02:     -- to compile:
03:     -- sacomp cfact.sa -external FACT cfact.c  -o cfact
04:     --
06:     external C class FACT is
07:        factorial(i:C_UNSIGNED_LONG):C_UNSIGNED_LONG;
08:     end;
10:     class MAIN is
11:        main(av:ARRAY{STR}) is
12:           i:C_UNSIGNED_LONG := #(av[1].cursor.get_int);
13:           a:C_UNSIGNED_LONG := FACT::factorial(i);
14:           #OUT + av[1] + "! = " + a.str + "\n";
15:        end;
16:     end;
The C language data types are named 'C_' + (data type in C (capital)) like C_CHAR and C_FLOAT. Instances of these data types are created by the create method with an argument of corresponding Sather data type. See Sather — A Language Tutorial: Chapter 14 Interfacing with ANSI C for detail.

You can compile and execute the program in a similar way to that of Fortran (ffact).

$ sacomp cfact.sa -external FACT cfact.c -o cfact
$ ./cfact 10
10! = 3628800

3.2. Converting array and pointer

I am going to explain how to use pointers in the C language from a Sather code. The ARRAY{T} classes in Sather are converted to pointers by the array_ptr method.

I will show a pointer version of the encryption program (crypt.sa). As you cannot operate the XOR of the Sather CHAR type, you should convert the string data into array of INT. This part get efficient by using the C language, in which XOR of char is defined.

Following codes (encrypt.c ([code 4a]) and encrypt.sa ([code 4b])) show the improved version.

[code 4a]: encrypt.c

01:     void encrypt(char* key, char* plain, char* cipher){
02:         char *key1, *plain1, *cipher1;
03:         for(key1=key, plain1=plain, cipher1=cipher; *plain1 != 0; key1++, plain1++, cipher1++){  // the function expects that the string end with null
04:     	if(*key1==0) key1=key;    // reuse the key
05:     	*cipher1 = *key1 ^ *plain1;  // XOR of each bit
06:         }
07:         *cipher1=0;  // add null at the end
08:     } 
[code 4b] crypt.sa (partial)
01:     external C class ENCRYPT is                     -- declare external class ENCRYPT 
02:        encrypt(key,plain,cipher:C_CHAR_PTR);
03:     end;
05:     class ARCHAR is  -- ARRAY{CHAR} + methods to convert from/to STR
06:        include ARRAY{CHAR};  
08:        create(s:STR):SAME is  -- create from  STR 
09:           res:SAME:=#(s.size);
10:           loop
11:     	 res.set!(s.elt!);
12:           end;
13:           return res;
14:        end;
16:        to_str:STR is         -- convert to STR
17:           fs:FSTR:=#(self.size);
18:           loop
19:     	 fs:=fs+self.elt!;
20:           end;
21:           return fs.str;
22:        end;
23:     end;  -- ARCHAR
25:     class XOR < $CRYPT is
27:        private attr akey:ARCHAR;
29:        create(key0:STR):SAME is
30:           return new.init(key0);
31:        end;
33:        private init(key0:STR):SAME is
34:           akey:=#(key0);
35:           return self;
36:        end;
38:        encrypt(s:STR):STR is
39:           pl:ARCHAR:=#(s);
40:           ci:ARCHAR:=#(s.size);
41:           ENCRYPT::encrypt(#(akey.array_ptr), #(pl.array_ptr), #(ci.array_ptr));  -- calling the C function
42:           return ci.to_str;
43:        end;
45:        decrypt(s:STR):STR is   -- decrypt is same as the encrypt
46:           return encrypt(s);
47:        end;
48:     end; -- end of XOR
Functions written in the C language that expect strings end with the null character work properly. Maybe it adds the null character at the end when it converts ARRAY{CHAR} into C_CHAR_PTR

Compile and run the program then you will get following output.

$ sacomp crypt.sa -external ENCRYPT encrypt.c -o crypt
$ ./crypt 'hello world! beautiful beautiful!'
Cipher Test using "hello world! beautiful beautiful!"

Plain send: hello world! beautiful beautiful!
Plain receive: hello world! beautiful beautiful!

XOR send: (non graphical string)
XOR receive: hello world! beautiful beautiful!

4. Summary

As you can combine Sather with Fortran or the C language easily, you can use fast functions written in Fortran or C at the bottle neck (the most time consuming part), which makes whole program efficient. First you should write your program in Sather, because it is more efficient in writing. If your program is not fast enough, try to find the bottle neck using a profiler (you can use a profiler for the C language such as gprof, because the Sather code is converted into C) to rewrite the bottle neck in Fortran or C.

Download and play with the code in this chapter.

HOME Try Sather download Post Messages