Subversion Repositories Kolibri OS

Rev

Rev 8859 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
7983 leency 1
(*
7597 akron1 2
    BSD 2-Clause License
3
 
9893 akron1 4
    Copyright (c) 2018-2022, Anton Krotov
7597 akron1 5
    All rights reserved.
6
*)
7
 
8
MODULE ARITH;
9
 
8859 leency 10
IMPORT STRINGS, UTILS, LISTS;
7597 akron1 11
 
12
 
13
CONST
14
 
15
    tINTEGER* = 1;  tREAL* = 2;  tSET*    = 3;
16
    tBOOLEAN* = 4;  tCHAR* = 5;  tWCHAR*  = 6;
17
    tSTRING*  = 7;
18
 
8097 maxcodehac 19
    opEQ* = 0; opNE* = 1; opLT* = 2; opLE* = 3; opGT* = 4; opGE* = 5;
20
    opIN* = 6; opIS* = 7;
7597 akron1 21
 
8097 maxcodehac 22
 
7597 akron1 23
TYPE
24
 
25
    VALUE* = RECORD
26
 
27
        typ*:      INTEGER;
28
 
29
        int:       INTEGER;
30
        float:     REAL;
31
        set:       SET;
32
        bool:      BOOLEAN;
33
 
8859 leency 34
        string*:   LISTS.ITEM
7597 akron1 35
 
36
    END;
37
 
38
 
39
VAR
40
 
41
    digit: ARRAY 256 OF INTEGER;
42
 
43
 
44
PROCEDURE Int* (v: VALUE): INTEGER;
45
VAR
46
    res: INTEGER;
47
 
48
BEGIN
49
 
7696 akron1 50
    CASE v.typ OF
51
    |tINTEGER, tCHAR, tWCHAR:
7597 akron1 52
        res := v.int
7696 akron1 53
    |tSET:
7693 akron1 54
        res := UTILS.Long(ORD(v.set))
7696 akron1 55
    |tBOOLEAN:
7597 akron1 56
        res := ORD(v.bool)
57
    END
58
 
59
    RETURN res
60
END Int;
61
 
62
 
63
PROCEDURE getBool* (v: VALUE): BOOLEAN;
64
BEGIN
65
    ASSERT(v.typ = tBOOLEAN);
66
 
67
    RETURN v.bool
68
END getBool;
69
 
70
 
71
PROCEDURE Float* (v: VALUE): REAL;
72
BEGIN
73
    ASSERT(v.typ = tREAL);
74
 
75
    RETURN v.float
76
END Float;
77
 
78
 
7983 leency 79
PROCEDURE range* (i: VALUE; a, b: INTEGER): BOOLEAN;
80
    RETURN (a <= i.int) & (i.int <= b)
81
END range;
82
 
83
 
7597 akron1 84
PROCEDURE check* (v: VALUE): BOOLEAN;
85
VAR
7696 akron1 86
    res: BOOLEAN;
7597 akron1 87
 
88
BEGIN
7696 akron1 89
    CASE v.typ OF
7983 leency 90
    |tINTEGER: res := range(v, UTILS.target.minInt, UTILS.target.maxInt)
91
    |tCHAR:    res := range(v, 0, 255)
92
    |tWCHAR:   res := range(v, 0, 65535)
7696 akron1 93
    |tREAL:    res := (-UTILS.target.maxReal <= v.float) & (v.float <= UTILS.target.maxReal)
7597 akron1 94
    END
95
 
7696 akron1 96
    RETURN res
7597 akron1 97
END check;
98
 
99
 
100
PROCEDURE isZero* (v: VALUE): BOOLEAN;
101
VAR
102
    res: BOOLEAN;
7696 akron1 103
 
7597 akron1 104
BEGIN
7696 akron1 105
    CASE v.typ OF
106
    |tINTEGER: res := v.int = 0
107
    |tREAL:    res := v.float = 0.0
7597 akron1 108
    END
109
 
110
    RETURN res
111
END isZero;
112
 
113
 
114
PROCEDURE iconv* (s: ARRAY OF CHAR; VAR v: VALUE; VAR error: INTEGER);
115
VAR
116
    value: INTEGER;
117
    i:     INTEGER;
118
    d:     INTEGER;
119
 
120
BEGIN
121
    error := 0;
122
    value := 0;
123
 
124
    i := 0;
125
    WHILE STRINGS.digit(s[i]) & (error = 0) DO
126
        d := digit[ORD(s[i])];
127
        IF value <= (UTILS.maxint - d) DIV 10 THEN
128
            value := value * 10 + d;
129
            INC(i)
130
        ELSE
131
            error := 1
132
        END
133
    END;
134
 
135
    IF error = 0 THEN
136
        v.int := value;
137
        v.typ := tINTEGER;
138
        IF ~check(v) THEN
139
            error := 1
140
        END
141
    END
142
 
143
END iconv;
144
 
145
 
146
PROCEDURE hconv* (s: ARRAY OF CHAR; VAR v: VALUE; VAR error: INTEGER);
147
VAR
148
    value: INTEGER;
149
    i:     INTEGER;
150
    n:     INTEGER;
151
    d:     INTEGER;
152
 
153
BEGIN
154
    ASSERT(STRINGS.digit(s[0]));
155
 
156
    error := 0;
157
    value := 0;
158
 
159
    n := -1;
160
    i := 0;
8859 leency 161
    WHILE (s[i] # "H") & (s[i] # "X") & (s[i] # "h") & (s[i] # "x") & (error = 0) DO
7597 akron1 162
 
163
        d := digit[ORD(s[i])];
164
        IF (n = -1) & (d # 0) THEN
165
            n := i
166
        END;
167
 
7693 akron1 168
        IF (n # -1) & (i - n + 1 > UTILS.target.maxHex) THEN
7597 akron1 169
            error := 2
170
        ELSE
171
            value := value * 16 + d;
172
            INC(i)
173
        END
174
 
175
    END;
176
 
7693 akron1 177
    value := UTILS.Long(value);
7597 akron1 178
 
8859 leency 179
    IF ((s[i] = "X") OR (s[i] = "x")) & (n # -1) & (i - n > 4) THEN
7597 akron1 180
        error := 3
181
    END;
182
 
183
    IF error = 0 THEN
184
        v.int := value;
8859 leency 185
        IF (s[i] = "X") OR (s[i] = "x") THEN
7597 akron1 186
            v.typ := tCHAR;
187
            IF ~check(v) THEN
188
                v.typ := tWCHAR;
189
                IF ~check(v) THEN
190
                    error := 3
191
                END
192
            END
193
        ELSE
194
            v.typ := tINTEGER;
195
            IF ~check(v) THEN
196
                error := 2
197
            END
198
        END
199
    END
200
 
201
END hconv;
202
 
203
 
204
PROCEDURE opFloat2 (VAR a: REAL; b: REAL; op: CHAR): BOOLEAN;
205
BEGIN
206
    CASE op OF
7983 leency 207
    |"+": a := a + b
208
    |"-": a := a - b
209
    |"*": a := a * b
210
    |"/": a := a / b
7597 akron1 211
    END
212
 
7983 leency 213
    RETURN (-UTILS.maxreal <= a) & (a <= UTILS.maxreal) (* +inf > UTILS.maxreal *)
7597 akron1 214
END opFloat2;
215
 
216
 
217
PROCEDURE fconv* (s: ARRAY OF CHAR; VAR v: VALUE; VAR error: INTEGER);
218
VAR
219
    value:    REAL;
220
    exp10:    REAL;
221
    i, n, d:  INTEGER;
222
    minus:    BOOLEAN;
223
 
224
BEGIN
225
    error := 0;
226
    value := 0.0;
227
    minus := FALSE;
228
    n := 0;
229
 
9893 akron1 230
    exp10 := 0.0;
231
    WHILE (error = 0) & (STRINGS.digit(s[i]) OR (s[i] = ".")) DO
232
        IF s[i] = "." THEN
233
            exp10 := 1.0;
7597 akron1 234
            INC(i)
235
        ELSE
9893 akron1 236
            IF opFloat2(value, 10.0, "*") & opFloat2(value, FLT(digit[ORD(s[i])]), "+") & opFloat2(exp10, 10.0, "*") THEN
237
                INC(i)
238
            ELSE
239
                error := 4
240
            END
7597 akron1 241
        END
242
    END;
243
 
9893 akron1 244
    IF ~opFloat2(value, exp10, "/") THEN
8859 leency 245
        error := 4
246
    END;
247
 
248
    IF (s[i] = "E") OR (s[i] = "e") THEN
7597 akron1 249
        INC(i)
250
    END;
251
 
252
    IF (s[i] = "-") OR (s[i] = "+") THEN
253
        minus := s[i] = "-";
254
        INC(i)
255
    END;
256
 
257
    WHILE (error = 0) & STRINGS.digit(s[i]) DO
258
        d := digit[ORD(s[i])];
259
        IF n <= (UTILS.maxint - d) DIV 10 THEN
260
            n := n * 10 + d;
261
            INC(i)
262
        ELSE
263
            error := 5
264
        END
265
    END;
266
 
267
    exp10 := 1.0;
268
    WHILE (error = 0) & (n > 0) DO
269
        IF opFloat2(exp10, 10.0, "*") THEN
270
            DEC(n)
271
        ELSE
272
            error := 4
273
        END
274
    END;
275
 
276
    IF error = 0 THEN
277
        IF minus THEN
278
            IF ~opFloat2(value, exp10, "/") THEN
279
                error := 4
280
            END
281
        ELSE
282
            IF ~opFloat2(value, exp10, "*") THEN
283
                error := 4
284
            END
285
        END
286
    END;
287
 
288
    IF error = 0 THEN
289
        v.float := value;
290
        v.typ := tREAL;
291
        IF ~check(v) THEN
292
            error := 4
293
        END
294
    END
295
 
296
END fconv;
297
 
298
 
299
PROCEDURE setChar* (VAR v: VALUE; ord: INTEGER);
300
BEGIN
301
    v.typ := tCHAR;
302
    v.int := ord
303
END setChar;
304
 
305
 
306
PROCEDURE setWChar* (VAR v: VALUE; ord: INTEGER);
307
BEGIN
308
    v.typ := tWCHAR;
309
    v.int := ord
310
END setWChar;
311
 
312
 
313
PROCEDURE addInt (VAR a: INTEGER; b: INTEGER): BOOLEAN;
314
VAR
315
    error: BOOLEAN;
316
 
317
BEGIN
318
    IF (a > 0) & (b > 0) THEN
319
        error := a > UTILS.maxint - b
320
    ELSIF (a < 0) & (b < 0) THEN
321
        error := a < UTILS.minint - b
322
    ELSE
323
        error := FALSE
324
    END;
325
 
326
    IF ~error THEN
327
        a := a + b
328
    ELSE
329
        a := 0
330
    END
331
 
332
    RETURN ~error
333
END addInt;
334
 
335
 
336
PROCEDURE subInt (VAR a: INTEGER; b: INTEGER): BOOLEAN;
337
VAR
338
    error: BOOLEAN;
339
 
340
BEGIN
341
    IF (a > 0) & (b < 0) THEN
342
        error := a > UTILS.maxint + b
343
    ELSIF (a < 0) & (b > 0) THEN
344
        error := a < UTILS.minint + b
345
    ELSIF (a = 0) & (b < 0) THEN
346
        error := b = UTILS.minint
347
    ELSE
348
        error := FALSE
349
    END;
350
 
351
    IF ~error THEN
352
        a := a - b
353
    ELSE
354
        a := 0
355
    END
356
 
357
    RETURN ~error
358
END subInt;
359
 
360
 
361
PROCEDURE lg2 (x: INTEGER): INTEGER;
362
VAR
363
    n: INTEGER;
364
 
365
BEGIN
366
    ASSERT(x > 0);
367
 
7983 leency 368
    n := UTILS.Log2(x);
369
    IF n = -1 THEN
7597 akron1 370
        n := 255
371
    END
372
 
373
    RETURN n
374
END lg2;
375
 
376
 
377
PROCEDURE mulInt* (VAR a: INTEGER; b: INTEGER): BOOLEAN;
378
VAR
379
    error:    BOOLEAN;
380
    min, max: INTEGER;
381
 
382
BEGIN
383
    min := UTILS.minint;
384
    max := UTILS.maxint;
385
 
386
    IF ((a > 1) & (b > 1)) OR ((a < 0) & (b < 0)) THEN
387
        error := (a = min) OR (b = min) OR (ABS(a) > max DIV ABS(b))
388
 
389
    ELSIF ((a > 1) & (b < 0)) OR ((a < 0) & (b > 1)) THEN
390
        error := (a = min) OR (b = min);
391
        IF ~error THEN
392
            IF lg2(ABS(a)) + lg2(ABS(b)) >= UTILS.bit_depth THEN
393
                error := ABS(a) > max DIV ABS(b)
394
            END
395
        END
396
 
397
    ELSE
398
        error := FALSE
399
    END;
400
 
401
    IF ~error THEN
402
        a := a * b
403
    ELSE
404
        a := 0
405
    END
406
 
407
    RETURN ~error
408
END mulInt;
409
 
410
 
411
PROCEDURE _ASR (x, n: INTEGER): INTEGER;
7693 akron1 412
    RETURN ASR(UTILS.Long(x), n)
7597 akron1 413
END _ASR;
414
 
415
 
416
PROCEDURE _LSR (x, n: INTEGER): INTEGER;
7693 akron1 417
    RETURN UTILS.Long(LSR(UTILS.Short(x), n))
7597 akron1 418
END _LSR;
419
 
420
 
421
PROCEDURE _LSL (x, n: INTEGER): INTEGER;
7693 akron1 422
    RETURN UTILS.Long(LSL(x, n))
7597 akron1 423
END _LSL;
424
 
425
 
426
PROCEDURE _ROR1_32 (x: INTEGER): INTEGER;
427
BEGIN
7693 akron1 428
    x := UTILS.Short(x);
7597 akron1 429
    x := ORD(BITS(LSR(x, 1)) + BITS(LSL(x, 31)))
7693 akron1 430
    RETURN UTILS.Long(x)
7597 akron1 431
END _ROR1_32;
432
 
433
 
7693 akron1 434
PROCEDURE _ROR1_16 (x: INTEGER): INTEGER;
435
BEGIN
436
    x := x MOD 65536;
437
    x := ORD(BITS(LSR(x, 1)) + BITS(LSL(x, 15)))
438
    RETURN UTILS.Long(x)
439
END _ROR1_16;
440
 
441
 
7597 akron1 442
PROCEDURE _ROR (x, n: INTEGER): INTEGER;
443
BEGIN
7693 akron1 444
 
445
    CASE UTILS.bit_diff OF
446
    |0: x := ROR(x, n)
447
    |16, 48:
448
        n := n MOD 16;
449
        WHILE n > 0 DO
450
            x := _ROR1_16(x);
451
            DEC(n)
452
        END
453
    |32:
7597 akron1 454
        n := n MOD 32;
455
        WHILE n > 0 DO
456
            x := _ROR1_32(x);
457
            DEC(n)
458
        END
459
    END
460
 
461
    RETURN x
462
END _ROR;
463
 
464
 
465
PROCEDURE opInt* (VAR a: VALUE; b: VALUE; op: CHAR): BOOLEAN;
466
VAR
467
    success: BOOLEAN;
468
 
469
BEGIN
470
    success := TRUE;
471
 
472
    CASE op OF
473
    |"+": success := addInt(a.int, b.int)
474
    |"-": success := subInt(a.int, b.int)
475
    |"*": success := mulInt(a.int, b.int)
476
    |"/": success := FALSE
7983 leency 477
    |"D": a.int := a.int DIV b.int
7597 akron1 478
    |"M": a.int := a.int MOD b.int
479
    |"L": a.int := _LSL(a.int, b.int)
480
    |"A": a.int := _ASR(a.int, b.int)
481
    |"O": a.int := _ROR(a.int, b.int)
482
    |"R": a.int := _LSR(a.int, b.int)
483
    |"m": a.int := MIN(a.int, b.int)
484
    |"x": a.int := MAX(a.int, b.int)
485
    END;
486
    a.typ := tINTEGER
487
 
488
    RETURN success & check(a)
489
END opInt;
490
 
491
 
492
PROCEDURE charToStr* (c: VALUE; VAR s: ARRAY OF CHAR);
493
BEGIN
494
    s[0] := CHR(c.int);
495
    s[1] := 0X
496
END charToStr;
497
 
498
 
499
PROCEDURE opSet* (VAR a: VALUE; b: VALUE; op: CHAR);
500
BEGIN
501
    CASE op OF
502
    |"+": a.set := a.set + b.set
503
    |"-": a.set := a.set - b.set
504
    |"*": a.set := a.set * b.set
505
    |"/": a.set := a.set / b.set
506
    END;
507
    a.typ := tSET
508
END opSet;
509
 
510
 
511
PROCEDURE opFloat* (VAR a: VALUE; b: VALUE; op: CHAR): BOOLEAN;
512
BEGIN
513
    a.typ := tREAL
514
    RETURN opFloat2(a.float, b.float, op) & check(a)
515
END opFloat;
516
 
517
 
518
PROCEDURE ord* (VAR v: VALUE);
519
BEGIN
520
    CASE v.typ OF
521
    |tCHAR, tWCHAR:
522
    |tBOOLEAN: v.int := ORD(v.bool)
7693 akron1 523
    |tSET:     v.int := UTILS.Long(ORD(v.set))
7597 akron1 524
    END;
525
    v.typ := tINTEGER
526
END ord;
527
 
528
 
529
PROCEDURE odd* (VAR v: VALUE);
530
BEGIN
531
    v.typ := tBOOLEAN;
532
    v.bool := ODD(v.int)
533
END odd;
534
 
535
 
536
PROCEDURE bits* (VAR v: VALUE);
537
BEGIN
538
    v.typ := tSET;
539
    v.set := BITS(v.int)
540
END bits;
541
 
542
 
543
PROCEDURE abs* (VAR v: VALUE): BOOLEAN;
544
VAR
545
    res: BOOLEAN;
546
 
547
BEGIN
7693 akron1 548
    res := FALSE;
7597 akron1 549
 
550
    CASE v.typ OF
551
    |tREAL:
552
        v.float := ABS(v.float);
553
        res := TRUE
554
    |tINTEGER:
555
        IF v.int # UTILS.minint THEN
556
            v.int := ABS(v.int);
557
            res := TRUE
558
        END
7693 akron1 559
    END
560
 
7597 akron1 561
    RETURN res
562
END abs;
563
 
564
 
565
PROCEDURE floor* (VAR v: VALUE): BOOLEAN;
566
VAR
567
    res: BOOLEAN;
568
 
569
BEGIN
570
    v.typ := tINTEGER;
571
    res := (FLT(UTILS.minint) <= v.float) & (v.float <= FLT(UTILS.maxint));
572
    IF res THEN
573
        v.int := FLOOR(v.float)
574
    END
575
 
576
    RETURN res
577
END floor;
578
 
579
 
580
PROCEDURE flt* (VAR v: VALUE);
581
BEGIN
582
    v.typ := tREAL;
583
    v.float := FLT(v.int)
584
END flt;
585
 
586
 
587
PROCEDURE neg* (VAR v: VALUE): BOOLEAN;
588
VAR
589
    z: VALUE;
590
    res: BOOLEAN;
591
 
592
BEGIN
593
    res := TRUE;
594
 
595
    z.typ := tINTEGER;
596
    z.int := 0;
597
 
598
    CASE v.typ OF
599
    |tREAL:     v.float := -v.float
600
    |tSET:      v.set := -v.set
601
    |tINTEGER:  res := opInt(z, v, "-"); v := z
602
    |tBOOLEAN:  v.bool := ~v.bool
603
    END
604
 
605
    RETURN res
606
END neg;
607
 
608
 
609
PROCEDURE setbool* (VAR v: VALUE; b: BOOLEAN);
610
BEGIN
611
    v.bool := b;
612
    v.typ := tBOOLEAN
613
END setbool;
614
 
615
 
616
PROCEDURE opBoolean* (VAR a: VALUE; b: VALUE; op: CHAR);
617
BEGIN
618
    CASE op OF
619
    |"&": a.bool := a.bool & b.bool
620
    |"|": a.bool := a.bool OR b.bool
621
    END;
622
    a.typ := tBOOLEAN
623
END opBoolean;
624
 
625
 
626
PROCEDURE less (v, v2: VALUE; VAR error: INTEGER): BOOLEAN;
627
VAR
628
    res: BOOLEAN;
629
 
630
BEGIN
631
    res := FALSE;
632
 
633
    IF (v.typ = v2.typ) OR (v.typ IN {tCHAR, tWCHAR}) & (v2.typ IN {tCHAR, tWCHAR}) THEN
634
        CASE v.typ OF
635
        |tINTEGER,
636
         tWCHAR,
637
         tCHAR:     res := v.int < v2.int
638
        |tREAL:     res := v.float < v2.float
639
        |tBOOLEAN,
640
         tSET:      error := 1
641
        END
642
    ELSE
643
        error := 1
644
    END
645
 
646
    RETURN res
647
END less;
648
 
649
 
650
PROCEDURE equal (v, v2: VALUE; VAR error: INTEGER): BOOLEAN;
651
VAR
652
    res: BOOLEAN;
653
 
654
BEGIN
655
    res := FALSE;
656
 
657
    IF (v.typ = v2.typ) OR (v.typ IN {tCHAR, tWCHAR}) & (v2.typ IN {tCHAR, tWCHAR}) THEN
658
        CASE v.typ OF
659
        |tINTEGER,
660
         tWCHAR,
661
         tCHAR:     res := v.int = v2.int
662
        |tREAL:     res := v.float = v2.float
663
        |tBOOLEAN:  res := v.bool = v2.bool
664
        |tSET:      res := v.set = v2.set
665
        END
666
    ELSE
667
        error := 1
668
    END
669
 
670
    RETURN res
671
END equal;
672
 
673
 
8097 maxcodehac 674
PROCEDURE relation* (VAR v: VALUE; v2: VALUE; op: INTEGER; VAR error: INTEGER);
7597 akron1 675
VAR
676
    res: BOOLEAN;
677
 
678
BEGIN
679
    error := 0;
680
 
681
    res := FALSE;
682
 
8097 maxcodehac 683
    CASE op OF
7597 akron1 684
 
8097 maxcodehac 685
    |opEQ:
7597 akron1 686
        res := equal(v, v2, error)
687
 
8097 maxcodehac 688
    |opNE:
7597 akron1 689
        res := ~equal(v, v2, error)
690
 
8097 maxcodehac 691
    |opLT:
692
        res := less(v, v2, error)
7597 akron1 693
 
8097 maxcodehac 694
    |opLE:
695
        res := less(v, v2, error);
696
        IF error = 0 THEN
697
            res := equal(v, v2, error) OR res
7597 akron1 698
        END
699
 
8097 maxcodehac 700
    |opGE:
701
        res := ~less(v, v2, error)
702
 
703
    |opGT:
704
        res := less(v, v2, error);
705
        IF error = 0 THEN
706
            res := equal(v, v2, error) OR res
707
        END;
708
        res := ~res
709
 
710
    |opIN:
7597 akron1 711
        IF (v.typ = tINTEGER) & (v2.typ = tSET) THEN
7693 akron1 712
            IF range(v, 0, UTILS.target.maxSet) THEN
7597 akron1 713
                res := v.int IN v2.set
714
            ELSE
715
                error := 2
716
            END
717
        ELSE
718
            error := 1
719
        END
720
 
721
    END;
722
 
723
    IF error = 0 THEN
724
        v.bool := res;
725
        v.typ  := tBOOLEAN
726
    END
727
 
728
END relation;
729
 
730
 
731
PROCEDURE emptySet* (VAR v: VALUE);
732
BEGIN
733
    v.typ := tSET;
734
    v.set := {}
735
END emptySet;
736
 
737
 
738
PROCEDURE constrSet* (VAR v: VALUE; a, b: VALUE);
739
BEGIN
740
    v.typ := tSET;
741
    v.set := {a.int .. b.int}
742
END constrSet;
743
 
744
 
745
PROCEDURE getInt* (v: VALUE): INTEGER;
746
BEGIN
747
    ASSERT(check(v))
748
 
749
    RETURN v.int
750
END getInt;
751
 
752
 
753
PROCEDURE setInt* (VAR v: VALUE; i: INTEGER): BOOLEAN;
754
BEGIN
755
    v.int := i;
756
    v.typ := tINTEGER
757
 
758
    RETURN check(v)
759
END setInt;
760
 
761
 
8097 maxcodehac 762
PROCEDURE concat* (VAR s: ARRAY OF CHAR; s1: ARRAY OF CHAR): BOOLEAN;
763
VAR
764
    res: BOOLEAN;
765
 
766
BEGIN
767
    res := LENGTH(s) + LENGTH(s1) < LEN(s);
768
    IF res THEN
769
        STRINGS.append(s, s1)
770
    END
771
 
772
    RETURN res
773
END concat;
774
 
775
 
7597 akron1 776
PROCEDURE init;
777
VAR
778
    i: INTEGER;
779
 
780
BEGIN
781
    FOR i := 0 TO LEN(digit) - 1 DO
782
        digit[i] := -1
783
    END;
784
 
785
    FOR i := ORD("0") TO ORD("9") DO
786
        digit[i] := i - ORD("0")
787
    END;
788
 
789
    FOR i := ORD("A") TO ORD("F") DO
790
        digit[i] := i - ORD("A") + 10
791
    END
792
END init;
793
 
794
 
795
BEGIN
796
    init
7983 leency 797
END ARITH.