Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

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