File: programming.md

package info (click to toggle)
iraf 2.18.1-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 86,000 kB
  • sloc: ansic: 115,890; fortran: 74,576; lisp: 18,888; yacc: 5,642; sh: 961; lex: 596; makefile: 509; asm: 159; csh: 54; xml: 33; sed: 4
file content (390 lines) | stat: -rw-r--r-- 8,293 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
# Writing own procedures

## SPP tasks

This example is taken from a the [slides of a talk by Rob
Seaman](https://iraf-community.github.io/doc/spp_intro.pdf).

Take a simple program from the test directory:

File: `hello.x`
```
# HELLO -- Sample program introducing SPP.
task hello = t_hello_world
procedure t_hello_world ()
begin
    call printf ("Hello,world!\n")
end
```

Compile it, declare and run as an IRAF task

```
cl> softools
cl> xc hello.x
cl> task $hello = hello.e
cl> hello
Hello, world!
```

## SPP debugging info

This is a test for [#98](https://iraf-community.github.io/iraf-v216/issues/98).

XC is able to keep the line number of the main file, for
debugging. This is done with the `-x` flag:

```
cl> softools
cl> xc -x -f hello.x
cl> system
cl> tail hello.f nlines=22 | head nlines=11
      subroutine thelld ()
      integer*2 st0001(14)
      save
      integer iyy
      data (st0001(iyy),iyy= 1, 8) / 72,101,108,108,111, 44,119,111/
      data (st0001(iyy),iyy= 9,14) /114,108,100, 33, 10, 0/
#line 5 "hello.x"
         call xprinf(st0001)
100      call zzepro
         return
      end
```

## Machine dependent limits

This is a test for [#106](https://iraf-community.github.io/iraf-v216/issues/106).

Some limits are defined by the `R1MACH` and `D1MACH` functions. We
just test some very basic properties of these numbers:

File: `machtest.x`
```
task machtest = t_machtest
procedure t_machtest ()
real r1mach()
double d1mach()
int i
int failures
begin

# Check that all values are positive numbers

    failures = 0
    do i=1, 5 {
        if (! (r1mach(i) == r1mach(i))) {
            call printf("R1MACH(%d) is not a number\n")
	         call pargi(i)
            failures = failures + 1
        } else if (r1mach(i) <= 0) {
            call printf("R1MACH(%d) is not positive\n")
	         call pargi(i)
            failures = failures + 1
	}
    }
    call printf("\n")
    do i=1, 5 {
        if (! (d1mach(i) == d1mach(i))) {
            call printf("D1MACH(%d) is not a number\n")
	         call pargi(i)
            failures = failures + 1
        } else if (d1mach(i) <= 0) {
            call printf("D1MACH(%d) is not positive\n")
	         call pargi(i)
            failures = failures + 1
	}
    }
    if (failures == 0) {
        call printf("Simple consistency check passed.\n")
    } else {
        call printf("Simple consistency check has %d failures\n")
        call pargi(failures)
    }
end
```
Running this should give:

```
cl> softools
cl> xc machtest.x
cl> task $machtest = machtest.e
cl> machtest

Simple consistency check passed.
```

## ILP64 memory model

This is a test for [#107](https://iraf-community.github.io/iraf-v216/issues/107).

On 64-bit machines, IRAF uses the ILP64 model that makes normal SPP
`integer` 8 byte wide. `real` values however remain at 4 byte. This
should be recognized by the Fortran compiler when doing
`equivalence`.

File: `test_equiv.x`
```
task test_equiv = t_equiv
procedure t_equiv ()
real	fval, gval
int	ival
%	equivalence (fval, ival)
begin
    ival = 0
    gval = 1.2345e06
    call printf("Should be zero: %d\n")
    call pargi(ival)

    gval = 0.
    ival = 998765123423
    call printf("Should be zero: %g\n")
    call pargr(gval)
end
```

In that example, setting `ival` should not affect the independently
defined variable `gval` and vice versa:

```
cl> softools
cl> xc test_equiv.x
cl> task $test_equiv = test_equiv.e
cl> test_equiv
Should be zero: 0
Should be zero: 0.
```

## Plain FORTRAN files

The xc compiler should be able to compile plain FORTRAN files (with
FORTRAN I/O) as well. The f2c compiler used in 2.17, 2.17.1, 2.18
cannot compile this. See [discussion
#369](https://github.com/orgs/iraf-community/discussions/369).

File: `test_io.f`
```
      PROGRAM TESTIO
      OPEN (11, FILE='testio.dat')
      WRITE (11, *) 'Hello world'
      CLOSE (11)
      END
```

```
cl> softools
cl> xc -h test_io.f
cl> !./test_io.e
cl> type testio.dat
Hello world
```

## Loop optimization

This is a test for [#60](https://iraf-community.github.io/iraf-v216/issues/60).

With the original 2.16.1 release, there is a problem with loop
optimization on "newer" platforms. A simple example task is here:

File: `otest.x`
```
task otest = t_otest
procedure t_otest ()
int i
pointer p, sp
begin
    call smark(sp)
    call salloc(p, 4, TY_DOUBLE)
    do i = 1, 4
        memd[p+i-1] = i

    do i = 1, 4 {
        call printf("%d == %g\n")
	    call pargi(i)
        call pargd(memd[p+i-1])
    }

    call sfree(sp)
end
```

All this code does is to allocate a temporary array with four
integers, fill each position with its index, and then print out the
integers. Compile it, declare the task in (e)cl and run it:

```
cl> softools
cl> xc otest.x
cl> task $otest = otest.e
cl> otest
1 == 1.
2 == 2.
3 == 3.
4 == 4.
```

See issue #73 for the bug report.

## The `generic` preprocessor

The `generic` preprocessor is used to translate generic source code (code
written to work for any datatype) into type dependent source code,
suitable for compilation and insertion into a library.  The generic source
is translated for each datatype, producing a type dependent copy of the
source code for each datatype.

One way to operate `generic` is to embed `$for` and `$endfor`
directives into the source file. The example is taken from the
`sys/vops` subdir:

File: `aabs.gx`
```
$for (dr)
procedure aabs$t (a, b, npix)
PIXEL	a[ARB], b[ARB]
int	npix, i
begin
	do i = 1, npix
	    b[i] = abs(a[i])
end
$endfor
```

which produces the following single output file:

```
cl> softools
cl> generic aabs.gx -o aabs.x
cl> dir aabs*
aabs.gx aabs.x 
cl> type aabs.x

procedure aabsd (a, b, npix)
double	a[ARB], b[ARB]
int	npix, i
begin
	do i = 1, npix
	    b[i] = abs(a[i])
end

procedure aabsr (a, b, npix)
real	a[ARB], b[ARB]
int	npix, i
begin
	do i = 1, npix
	    b[i] = abs(a[i])
end

```

One may also specify the types on the command line of `generic`, like
for this input file:

File: `alim.gx`
```
procedure alim$t (a, npix, minval, maxval)
PIXEL   a[ARB], minval, maxval, value
int     npix, i
begin
        minval = a[1]
        maxval = a[1]
        do i = 1, npix {
            value = a[i]
            $if (datatype == x)
                if (abs(value) < abs(minval))
                    minval = value
                else if (abs(value) > abs(maxval))
                    maxval = value
            $else
                if (value < minval)
                    minval = value
                else if (value > maxval)
                    maxval = value
            $endif
        }
end
```

It produces one output file per type:

```
cl> softools
cl> generic -t  silrdx alim.gx
cl> dir alim*
alim.gx   alimd.x   alimi.x   aliml.x   alimr.x   alims.x   alimx.x   
cl> type alimi.x
procedure alimi (a, npix, minval, maxval)
int   a[ARB], minval, maxval, value
int     npix, i
begin
        minval = a[1]
        maxval = a[1]
        do i = 1, npix {
            value = a[i]
            if (value < minval)
                minval = value
            else if (value > maxval)
                maxval = value
        }
end
cl> type alimr.x
procedure alimr (a, npix, minval, maxval)
real   a[ARB], minval, maxval, value
int     npix, i
begin
        minval = a[1]
        maxval = a[1]
        do i = 1, npix {
            value = a[i]
                if (value < minval)
            minval = value
                else if (value > maxval)
            maxval = value
        }
end
```

The `generic` has a specific handling for `INDEF`: `INDEF` and
`IS_INDEF` are replaced with the ones specific for the processed data
type, while `INDEFR` etc. are kept as they are. Also, `$if` can limit
the preprocessing.

For example,

File: `geofxy.gx`
```
$for (rd)
procedure geo_fxy$t(fit, sf1)
pointer fit, sf1
begin
$if (datatype == r)
        if (IS_INDEFD(GM_XO(fit)))
            call gsset (sf1, GSXREF, INDEF)
$else
        call gsset (sf1, GSXREF, INDEF)
$endif
end
$endfor
```

which produces:

```
cl> softools
cl> generic geofxy.gx -o geofxy.x
cl> type geofxy.x

procedure geo_fxyr(fit, sf1)
pointer fit, sf1
begin
        if (IS_INDEFD(GM_XO(fit)))
            call gsset (sf1, GSXREF, INDEFR)
end

procedure geo_fxyd(fit, sf1)
pointer fit, sf1
begin
        call gsset (sf1, GSXREF, INDEFD)
end

```