RosettaCodeData/Task/Range-expansion/Oberon/range-expansion.oberon
2023-07-01 13:44:08 -04:00

235 lines
4.7 KiB
Text

MODULE LIVector;
IMPORT SYSTEM;
TYPE
LIPool = POINTER TO ARRAY OF LONGINT;
LIVector*= POINTER TO LIVectorDesc;
LIVectorDesc = RECORD
cap-: INTEGER;
len-: INTEGER;
LIPool: LIPool;
END;
PROCEDURE (v: LIVector) Init*(cap: INTEGER);
BEGIN
v.cap := cap;
v.len := 0;
NEW(v.LIPool,cap);
END Init;
PROCEDURE (v: LIVector) Add*(x: LONGINT);
VAR
newLIPool: LIPool;
BEGIN
IF v.len = LEN(v.LIPool^) THEN
(* run out of space *)
v.cap := v.cap + (v.cap DIV 2);
NEW(newLIPool,v.cap);
SYSTEM.MOVE(SYSTEM.ADR(v.LIPool^),SYSTEM.ADR(newLIPool^),v.cap * SIZE(LONGINT));
v.LIPool := newLIPool
END;
v.LIPool[v.len] := x;
INC(v.len)
END Add;
PROCEDURE (v: LIVector) At*(idx: INTEGER): LONGINT;
BEGIN
RETURN v.LIPool[idx];
END At;
END LIVector.
MODULE LIRange;
IMPORT Out, LIV := LIVector;
TYPE
Range* = POINTER TO RangeDesc;
RangeDesc = RECORD
l,r: POINTER TO ARRAY 1 OF LONGINT;
END;
PROCEDURE (r: Range) Init*();
BEGIN
r.l := NIL;
r.r := NIL;
END Init;
PROCEDURE (r: Range) IsEmpty*(): BOOLEAN;
BEGIN
RETURN (r.l = NIL) & (r.l = NIL);
END IsEmpty;
PROCEDURE (r: Range) SetLeft*(v: LONGINT);
BEGIN
IF r.l = NIL THEN NEW(r.l) END;
r.l[0] := v;
END SetLeft;
PROCEDURE (r: Range) SetRight*(v : LONGINT);
BEGIN
IF r.r = NIL THEN NEW(r.r) END;
r.r[0] := v;
END SetRight;
PROCEDURE (r: Range) LeftPart*(): BOOLEAN;
BEGIN
RETURN r.l # NIL;
END LeftPart;
PROCEDURE (r: Range) GetLeft(): LONGINT;
BEGIN
RETURN r.l[0];
END GetLeft;
PROCEDURE (r: Range) RightPart*(): BOOLEAN;
BEGIN
RETURN r.l # NIL;
END RightPart;
PROCEDURE (r: Range) GetRight*(): LONGINT;
BEGIN
RETURN r.r[0];
END GetRight;
PROCEDURE (r: Range) Show*();
BEGIN
Out.Char('(');
IF r.l # NIL THEN Out.LongInt(r.l[0],10) END;
Out.String(" - ");
IF r.r # NIL THEN Out.LongInt(r.r[0],10); END;
Out.Char(')');Out.Ln
END Show;
PROCEDURE (r: Range) Expand*(VAR liv: LIV.LIVector);
VAR
from, to : LONGINT;
BEGIN
IF r.l # NIL THEN from := r.l[0] ELSE from := 0 END;
IF r.r # NIL THEN to := r.r[0] ELSE to := from END;
WHILE (from <= to) DO
liv.Add(from);INC(from)
END
END Expand;
END LIRange.
MODULE Splitter;
TYPE
Splitter* = POINTER TO SplitterDesc;
SplitterDesc = RECORD
from: INTEGER;
c: CHAR;
s: POINTER TO ARRAY OF CHAR;
END;
PROCEDURE (s: Splitter) Init*;
BEGIN
s.c := ',';
s.from := 0;
s.s := NIL;
END Init;
PROCEDURE (s: Splitter) On*(str: ARRAY OF CHAR);
BEGIN
s.from := 0;
NEW(s.s,LEN(str));
COPY(str,s.s^)
END On;
PROCEDURE (s: Splitter) OnWithChar*(str: ARRAY OF CHAR;c: CHAR);
BEGIN
s.from := 0;
s.c := c;
NEW(s.s,LEN(str));
COPY(str,s.s^)
END OnWithChar;
PROCEDURE (s: Splitter) Next*(VAR str: ARRAY OF CHAR);
VAR
k : INTEGER;
BEGIN
k := 0;
IF (s.from < LEN(s.s^) - 1) & (s.s[s.from] = 0X) THEN str[0] := 0X END;
WHILE (k < LEN(str) - 1) & (s.from < LEN(s.s^) - 1) & (s.s[s.from] # s.c) DO
str[k] := s.s[s.from];
INC(k);INC(s.from)
END;
IF k < LEN(str) - 1 THEN str[k] := 0X ELSE str[LEN(str) - 1] := 0X END;
WHILE (s.from < LEN(s.s^) - 1) & (s.s[s.from] # s.c) DO INC(s.from) END;
INC(s.from)
END Next;
END Splitter.
MODULE ExpandRange;
IMPORT Out, LIV := LIVector, LIR := LIRange, S := Splitter;
PROCEDURE GetNumberFrom(s: ARRAY OF CHAR; VAR from: INTEGER; VAR done: BOOLEAN): LONGINT;
VAR
d,i: INTEGER;
num,sign: LONGINT;
BEGIN
i := from; num := 0;sign := 1;
CASE s[i] OF
'-': sign := -1;INC(i)
|'+': INC(i);
ELSE
END;
WHILE (i < LEN(s) - 1) & (s[i] >= '0') & (s[i] <= '9') DO
d := ORD(s[i]) - ORD('0');
num := d + num * 10;
INC(i);
END;
IF i = from THEN done := FALSE ELSE done := TRUE; from := i END;
RETURN sign * num
END GetNumberFrom;
PROCEDURE GetRange(s: ARRAY OF CHAR): LIR.Range;
VAR
r: LIR.Range;
i: INTEGER;
num: LONGINT;
done: BOOLEAN;
BEGIN
i := 0;NEW(r);r.Init();
WHILE (i < LEN(s) - 1) & (s[i] = 20X) DO INC(i) END;
(* Left value *)
done := FALSE;
num := GetNumberFrom(s,i,done);
IF ~done THEN RETURN r END;
r.SetLeft(num);
WHILE (i < LEN(s) - 1) & (s[i] = 20X) DO INC(i) END;
CASE s[i] OF
'-' : INC(i);
| 0X : RETURN r;
ELSE
END;
WHILE (i < LEN(s) - 1) & (s[i] = 20X) DO INC(i) END;
(* Right Value *)
done := FALSE;
num := GetNumberFrom(s,i,done);
IF ~done THEN RETURN r END;
r.SetRight(num);
RETURN r;
END GetRange;
VAR
i: INTEGER;
r: LIR.Range;
sp: S.Splitter;
p : ARRAY 128 OF CHAR;
liv: LIV.LIVector;
BEGIN
NEW(sp);sp.Init();
NEW(liv);liv.Init(128);
sp.On("-6,-3--1,3-5,7-11,14,15,17-20");
sp.Next(p);
WHILE (p[0] # 0X) DO
r := GetRange(p);
r.Expand(liv);
sp.Next(p);
END;
FOR i := 0 TO liv.len - 2 DO
Out.LongInt(liv.At(i),3);Out.Char(',');
END;
Out.LongInt(liv.At(liv.len - 1),3);Out.Ln;
END ExpandRange.