diff --git a/.gitignore b/.gitignore
index db4032e0..a8e5ff00 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,6 +18,7 @@
/src/test/**/*.obj
/src/test/**/*.sym
**/*.stackdump
+/src/test/confidence/**/input
/src/test/confidence/**/result
/src/test/confidence/**/result-*
/src/test/confidence/**/*.asm
diff --git a/src/runtime/In.Mod b/src/runtime/In.Mod
index aa67e4e7..873a00d9 100644
--- a/src/runtime/In.Mod
+++ b/src/runtime/In.Mod
@@ -3,113 +3,136 @@ MODULE In;
IMPORT Platform, SYSTEM, Out;
VAR
- nextch: CHAR;
- ready: BOOLEAN;
- initialized: BOOLEAN;
+ Done-: BOOLEAN;
+ nextch: CHAR; (* Maintains 1 character read ahaead except at end of line. *)
+ readstate: INTEGER;
- Done-: BOOLEAN;
-
-PROCEDURE ReadChar;
-VAR error: Platform.ErrorCode; n: LONGINT; ch: CHAR;
-BEGIN
- error := Platform.ReadBuf(Platform.StdIn, ch, n);
- ready := (error = 0) & (n = 1);
- IF ready & (nextch = 0DX) & (ch = 0AX) THEN
- ready := (error = 0) & (n = 1)
- END;
- IF ready THEN nextch := ch ELSE nextch := 0X END
-END ReadChar;
-
-PROCEDURE Flush;
-BEGIN Out.Flush; IF ~initialized THEN ReadChar END; initialized := TRUE
-END Flush;
+CONST
+ pending = 0; (* readstate when at start of input or end of line. Implies nextch undefined. *)
+ ready = 1; (* readstate when nextch is defined and contains next character on current line. *)
+ eof = 2; (* readstate when at end of file. *)
PROCEDURE Open*;
- VAR error: Platform.ErrorCode;
+VAR error: Platform.ErrorCode;
BEGIN
- error := Platform.Seek(Platform.StdIn, 0, Platform.SeekSet); (* Rewind STDIN to beginning of file. *)
- ready := TRUE; initialized := FALSE;
+ error := Platform.Seek(Platform.StdIn, 0, Platform.SeekSet); (* Rewind STDIN to beginning of file. *)
+ readstate := pending;
+ Done := TRUE;
END Open;
-PROCEDURE Char*(VAR ch: CHAR);
-BEGIN Flush;
- Done := ready;
- IF ready THEN ch := nextch; ReadChar ELSE ch := 0X END
-END Char;
-
-PROCEDURE Skip;
+PROCEDURE ReadChar;
+VAR error: Platform.ErrorCode; n: LONGINT;
BEGIN
- WHILE ready & (nextch <= " ") DO ReadChar END; (* Skip leading blanks, CR, LF, tab etc. *)
-END Skip;
+ error := Platform.ReadBuf(Platform.StdIn, nextch, n);
+ IF (error = 0) & (n = 1) THEN readstate := ready ELSE readstate := eof END
+END ReadChar;
+
+PROCEDURE StartRead; (* Ensure either nextch is valid or we're at EOF. *)
+BEGIN Out.Flush; IF readstate = pending THEN ReadChar END;
+END StartRead;
+
+PROCEDURE StartAndSkip; (* Like StartRead, but also skip over blanks, CR, LF, tab. *)
+BEGIN StartRead;
+ WHILE (readstate = ready) & (nextch <= " ") DO ReadChar END
+END StartAndSkip;
+
+PROCEDURE Char*(VAR ch: CHAR);
+BEGIN
+ StartRead;
+ Done := readstate = ready;
+ IF Done THEN
+ ch := nextch;
+ IF ch = 0AX THEN readstate := pending ELSE ReadChar END
+ ELSE
+ ch := 0X
+ END
+END Char;
PROCEDURE HugeInt*(VAR h: HUGEINT);
VAR
- neg, hex, decdigit, hexdigit: BOOLEAN;
+ neg, hex, endofnum: BOOLEAN;
decacc, hexacc, digit: HUGEINT;
BEGIN
- Flush; Skip;
-
- neg := nextch = '-'; IF neg THEN ReadChar END;
- hex := FALSE;
- endofnum := FALSE;
- decacc := 0;
- hexacc := 0;
- Done := FALSE;
-
- WHILE ready & ~endofnum DO
- decdigit := (nextch >= "0") & (nextch <= "9");
- IF decdigit THEN digit := ORD(nextch) MOD 16 END;
-
- hexdigit := (nextch >= "f") & (nextch <= "f") OR (nextch >= "A") & (nextch <= "F");
- IF hexdigit THEN ORD(nextch) MOD 16 + 9; hex := TRUE END;
-
- IF decdigit OR hexdigit THEN
- Done := TRUE;
- decacc := decacc * 10 + digit;
- hexacc := hexacc * 16 + digit;
- ReadChar
- ELSIF nextch = "H" THEN
- hex := TRUE; endofnum := TRUE; ReadChar
+ StartAndSkip;
+ Done := FALSE;
+ IF readstate = ready THEN
+ neg := nextch = '-'; IF neg THEN ReadChar END;
+ hex := FALSE;
+ endofnum := FALSE;
+ decacc := 0;
+ hexacc := 0;
+ WHILE (readstate = ready) & ~endofnum DO
+ digit := -1;
+ IF (nextch >= "0") & (nextch <= "9") THEN
+ digit := ORD(nextch) MOD 16
+ ELSIF (nextch >= "a") & (nextch <= "f")
+ OR (nextch >= "A") & (nextch <= "F") THEN
+ digit := ORD(nextch) MOD 16 + 9; hex := TRUE
+ END;
+ IF digit >= 0 THEN
+ Done := TRUE;
+ decacc := decacc * 10 + digit;
+ hexacc := hexacc * 16 + digit;
+ ReadChar
+ ELSIF nextch = "H" THEN
+ hex := TRUE; endofnum := TRUE; ReadChar
+ ELSE
+ endofnum := TRUE
+ END
+ END;
+ IF Done THEN
+ IF hex THEN h := hexacc ELSE h := decacc END;
+ IF neg THEN h := -h END
ELSE
- endofnum := TRUE
+ h := 0
END
- END;
- IF Done THEN
- IF hex THEN h := hexacc ELSE h := decacc END;
- IF neg THEN h := -h END
- ELSE
- h := 0
END
END HugeInt;
PROCEDURE Int*(VAR i: INTEGER);
- VAR h: HUGEINT;
+VAR h: HUGEINT;
BEGIN HugeInt(h); i := SYSTEM.VAL(INTEGER, h)
END Int;
PROCEDURE LongInt*(VAR i: LONGINT);
- VAR h: HUGEINT;
+VAR h: HUGEINT;
BEGIN HugeInt(h); i := SYSTEM.VAL(LONGINT, h)
END LongInt;
PROCEDURE Real*(VAR x: REAL);
-BEGIN ASSERT(FALSE) (* Not implemented *)
+BEGIN HALT(99) (* Not implemented *)
END Real;
PROCEDURE LongReal*(VAR y: LONGREAL);
-BEGIN ASSERT(FALSE) (* Not implemented *)
+BEGIN HALT(99) (* Not implemented *)
END LongReal;
+PROCEDURE Line*(VAR line: ARRAY OF CHAR);
+VAR i: INTEGER;
+BEGIN StartRead; i := 0; Done := readstate = ready;
+ WHILE (readstate = ready) & (nextch # 0DX) & (nextch # 0AX) & (i < LEN(line)-1) DO
+ line[i] := nextch; INC(i); ReadChar
+ END;
+ line[i] := 0X;
+ IF (readstate = ready) & (nextch = 0DX) THEN ReadChar END;
+ IF (readstate = ready) & (nextch = 0AX) THEN readstate := pending END;
+END Line;
+
PROCEDURE String*(VAR str: ARRAY OF CHAR);
- VAR i: INTEGER;
-BEGIN Flush; Skip; i := 0;
- IF ready AND nextch = '"' THEN (* " *)
+VAR i: INTEGER;
+BEGIN StartAndSkip; i := 0;
+ IF (readstate = ready) & (nextch = '"') THEN (* " *)
ReadChar;
- WHILE ready & (i < LEN(str)-1) & (nextch >= " ") & (nextch # '"') DO (* " *)
- str[i] := nextch; INC(i)
+ WHILE (readstate = ready)
+ & (i < LEN(str)-1)
+ & (nextch >= " ")
+ & (nextch # '"') DO (* " *)
+ str[i] := nextch; ReadChar; INC(i)
END
END;
- Done := ready & (i < LEN(str)-1) & (nextch = '"'); (* " *)
+ Done := (readstate = ready)
+ & (i < LEN(str)-1)
+ & (nextch = '"'); (* " *)
IF Done THEN
ReadChar; str[i] := 0X
ELSE
@@ -118,11 +141,11 @@ BEGIN Flush; Skip; i := 0;
END String;
PROCEDURE Name*(VAR name: ARRAY OF CHAR); (* Read filename. Presumably using shell semantics. *)
-BEGIN ASSERT(FALSE) (* Not implemented *)
+BEGIN HALT(99) (* Not implemented *)
END Name;
BEGIN
- nextch := 0X;
- ready := FALSE;
- initialized := FALSE;
+ nextch := 0X;
+ readstate := pending;
+ Done := TRUE;
END In.
diff --git a/src/runtime/Out.Mod b/src/runtime/Out.Mod
index 52157484..c6429527 100644
--- a/src/runtime/Out.Mod
+++ b/src/runtime/Out.Mod
@@ -97,7 +97,7 @@ PROCEDURE -Entier64(x: LONGREAL): SYSTEM.INT64 "(int64)(x)";
PROCEDURE RealP(x: LONGREAL; n: INTEGER; long: BOOLEAN);
-(* LongReal(x, n) writes the long real number x to the end of the output stream using an
+(* RealP(x, n) writes the long real number x to the end of the output stream using an
exponential form. If the textual representation of x requires m characters (including a
three-digit signed exponent), x is right adjusted in a field of Max(n, m) characters padded
with blanks at the left end. A plus sign of the mantissa is not written.
diff --git a/src/test/confidence/in/expected b/src/test/confidence/in/expected
new file mode 100644
index 00000000..df0db21e
--- /dev/null
+++ b/src/test/confidence/in/expected
@@ -0,0 +1,14 @@
+--- Testing with Oberon 2 variable model ---
+chars: Splurdle
+integer: 37
+string: "Bert"
+line: rest of line
+line: another line
+
+
+--- Testing with Component Pascal variable model ---
+chars: Splurdle
+integer: 37
+string: "Bert"
+line: rest of line
+line: another line
diff --git a/src/test/confidence/in/intest.mod b/src/test/confidence/in/intest.mod
new file mode 100644
index 00000000..cb8d2963
--- /dev/null
+++ b/src/test/confidence/in/intest.mod
@@ -0,0 +1,16 @@
+MODULE intest;
+IMPORT Out, In;
+
+VAR ch: CHAR; i: INTEGER; s: ARRAY 100 OF CHAR;
+
+BEGIN
+ In.Char(ch); Out.String("chars: ");
+ WHILE In.Done & (ch # ".") DO Out.Char(ch); In.Char(ch) END;
+ Out.Ln;
+ In.Int(i); IF In.Done THEN Out.String("integer: "); Out.Int(i,1); Out.Ln END;
+ In.String(s); IF In.Done THEN Out.String('string: "'); Out.String(s); Out.String('"'); Out.Ln END;
+ In.Line(s);
+ WHILE In.Done DO
+ Out.String("line: "); Out.String(s); Out.Ln; In.Line(s)
+ END
+END intest.
diff --git a/src/test/confidence/in/test.sh b/src/test/confidence/in/test.sh
new file mode 100644
index 00000000..ee738ab4
--- /dev/null
+++ b/src/test/confidence/in/test.sh
@@ -0,0 +1,16 @@
+#!/bin/sh
+. ../testenv.sh
+rm -f intest # Remove LSW binary so it doesn't hide Cygwin binary.
+echo 'Splurdle.25H "Bert"rest of line'>input
+echo another line>>input
+$OBECOMP intest.mod -m -O2
+./intest result-O2
+$OBECOMP intest.mod -m -OC
+./intest result-OC
+echo --- Testing with Oberon 2 variable model --- >result
+cat result-O2 >>result
+echo "" >>result
+echo "" >>result
+echo --- Testing with Component Pascal variable model --- >>result
+cat result-OC >>result
+. ../testresult.sh
diff --git a/src/tools/make/oberon.mk b/src/tools/make/oberon.mk
index ffdbded1..c67dfe10 100644
--- a/src/tools/make/oberon.mk
+++ b/src/tools/make/oberon.mk
@@ -197,6 +197,7 @@ runtime:
cd $(BUILDDIR)/$(MODEL); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../../src/runtime/Modules.Mod
cd $(BUILDDIR)/$(MODEL); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../../src/runtime/Strings.Mod
cd $(BUILDDIR)/$(MODEL); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../../src/runtime/Out.Mod
+ cd $(BUILDDIR)/$(MODEL); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../../src/runtime/In.Mod
cd $(BUILDDIR)/$(MODEL); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../../src/runtime/VT100.Mod
cd $(BUILDDIR)/$(MODEL); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../../src/runtime/Files.Mod
cd $(BUILDDIR)/$(MODEL); $(ROOTDIR)/$(OBECOMP) -Ffs -O$(MODEL) ../../../src/runtime/Math.Mod
@@ -382,14 +383,15 @@ RUNTEST = COMPILER=$(COMPILER) OBECOMP="$(OBECOMP) -O$(MODEL)" FLAVOUR=$(FLAVOUR
confidence:
@printf "\n\n--- Confidence tests ---\n\n"
cd src/test/confidence/hello; $(RUNTEST)
- cd src/test/confidence/isptest; $(RUNTEST)
cd src/test/confidence/out; $(RUNTEST)
+ cd src/test/confidence/in; $(RUNTEST)
cd src/test/confidence/math; $(RUNTEST)
cd src/test/confidence/intsyntax; $(RUNTEST)
cd src/test/confidence/language; $(RUNTEST)
+ cd src/test/confidence/arrayassignment; $(RUNTEST)
cd src/test/confidence/texts; $(RUNTEST)
cd src/test/confidence/library; $(RUNTEST)
+ cd src/test/confidence/isptest; $(RUNTEST)
cd src/test/confidence/lola; $(RUNTEST)
- cd src/test/confidence/arrayassignment; $(RUNTEST)
if [ "$(PLATFORM)" != "windows" ] ; then cd src/test/confidence/signal; $(RUNTEST); fi
@printf "\n\n--- Confidence tests passed ---\n\n"