Browse Source

v3 step 5.3 — Math, WholeIO, input (93/93 tests green)

Eric Streit 2 tuần trước cách đây
mục cha
commit
c9ace4c564

+ 20 - 1
compiler/run_tests.sh

@@ -170,7 +170,7 @@ build_session() {
   [ -f "gen_ssa/$prog.ssa" ] || { echo "no image"; return 1; }
   qbe -o "gen_ssa/$prog.s" "gen_ssa/$prog.ssa" 2> "gen_ssa/$prog.qbeerr" \
     || { echo "qbe"; cat "gen_ssa/$prog.qbeerr"; return 1; }
-  cc "gen_ssa/$prog.s" "$SHIM" -o "gen_ssa/$prog" 2> "gen_ssa/$prog.ccerr" \
+  cc "gen_ssa/$prog.s" "$SHIM" -o "gen_ssa/$prog" -lm 2> "gen_ssa/$prog.ccerr" \
     || { echo "cc"; cat "gen_ssa/$prog.ccerr"; return 1; }
   return 0
 }
@@ -209,6 +209,25 @@ expect_run_files DTypesProg 36 d_types.def d_types.mod d_types_prog.mod
 expect_run_files DOpaqueProg 55 d_opaque.def d_opaque.mod d_opaque_prog.mod
 expect_run_files_out Hello 0 "Hello, Modula-2!" ../stdlib/sysio.def ../stdlib/sysio.mod hello.mod
 expect_run_files_out StringsProg 0 "Hello World" ../stdlib/sysio.def ../stdlib/sysio.mod ../stdlib/strings.def ../stdlib/strings.mod strings_prog.mod
+expect_run_files MathProg 12 ../stdlib/sysio.def ../stdlib/sysio.mod ../stdlib/math.def ../stdlib/math.mod math_prog.mod
+
+expect_run_files_in() {
+  # $1 prog, $2 exit code, $3 expected first line, $4 stdin, then files
+  prog="$1"; want="$2"; wantline="$3"; input="$4"; shift 4
+  if ! build_session "$prog" "$@"; then
+    fail=$((fail+1)); echo "FAIL(session-in): $prog build failed"; return
+  fi
+  out=$(printf '%s\n' "$input" | timeout 10 "gen_ssa/$prog" 2>/dev/null); got=$?
+  first=$(printf '%s\n' "$out" | head -n 1)
+  if [ "$got" = "$want" ] && [ "$first" = "$wantline" ]; then
+    pass=$((pass+1)); echo "PASS(session-in): $prog -> $got [$first]"
+  else
+    fail=$((fail+1)); echo "FAIL(session-in): $prog rc=$got line=[$first] want=[$wantline]"
+  fi
+}
+
+expect_run_files_in ReadProg 0 "42" "20 22" ../stdlib/sysio.def ../stdlib/sysio.mod read_prog.mod
+expect_run_files_in WholeIOProg 0 "42" "6 7" ../stdlib/sysio.def ../stdlib/sysio.mod ../stdlib/wholeio.def ../stdlib/wholeio.mod wholeio_prog.mod
 
 expect_fail_files() {
   # $1 = listing basename, $2 = message (may be empty), then files

+ 9 - 0
compiler/tests/math_prog.mod

@@ -0,0 +1,9 @@
+MODULE MathProg;
+(* Math library: sqrt + sin via libm. Exit 12. *)
+FROM Math IMPORT sqrt, sin;
+VAR ExitCode : INTEGER;
+VAR r : REAL;
+BEGIN
+  r := sqrt(144.0) + sin(0.0);
+  IF r > 11.9 THEN ExitCode := 12 ELSE ExitCode := 0 END
+END MathProg.

+ 11 - 0
compiler/tests/read_prog.mod

@@ -0,0 +1,11 @@
+MODULE ReadProg;
+(* Reads two integers from stdin, prints their sum. *)
+FROM SysIO IMPORT ReadInt, WriteInt, WriteLn;
+VAR a, b, s : INTEGER;
+BEGIN
+  a := ReadInt();
+  b := ReadInt();
+  s := a + b;
+  WriteInt(s);
+  WriteLn
+END ReadProg.

+ 12 - 0
compiler/tests/wholeio_prog.mod

@@ -0,0 +1,12 @@
+MODULE WholeIOProg;
+(* WholeIO: VAR-parameter reads, integer output. *)
+FROM WholeIO IMPORT ReadInt, WriteInt;
+FROM SysIO IMPORT WriteLn;
+VAR a, b, p : INTEGER;
+BEGIN
+  ReadInt(a);
+  ReadInt(b);
+  p := a * b;
+  WriteInt(p);
+  WriteLn
+END WholeIOProg.

+ 43 - 0
docs/summary_step5.3.md

@@ -0,0 +1,43 @@
+# V3 step 5.3 — Math, WholeIO, input (done 2026-09-22)
+
+Third stdlib landing. Suite 93/93 (50 run — incl. 4 trap-aborts,
+4 sessions, 2 session-output, 2 session-input, 1 unit — + 43 reject).
+LL(1)-clean, zero gm2 warnings.
+
+## Math (`stdlib/math`)
+
+Direct libm bindings via `EXTERNAL` (the routine names are valid
+Modula-2 identifiers and match the C symbols): `sqrt`, `exp`, `ln`,
+`sin`, `cos`, `arctan`, plus `fabs` exposed as `abs`, and the
+constants `Pi` / `E`. REAL parameters/returns lower as QBE `d`.
+Harness now links `-lm`.
+
+`MathProg` → 12 (`sqrt(144.0) + sin(0.0)`).
+
+## Input (`runtime/syslib/shim.c` + `SysIO`)
+
+Shim additions `m2readchar` (fgetc), `m2readint` (whitespace-skipping
+signed decimal). `SysIO` gains `ReadChar` / `ReadInt`; the harness
+gains `expect_run_files_in` (pipes stdin). `ReadProg` reads two
+integers and prints the sum → `42`.
+
+## WholeIO (`stdlib/wholeio`)
+
+Classic `WriteInt` / `WriteCard` / `ReadInt(VAR)` / `ReadCard(VAR)`
+over the shim integer routines. `WholeIOProg` reads two ints and
+prints their product → `42`.
+
+## Notes
+
+- External functions returning `CHAR`/`INTEGER` bind directly
+  (`m2readchar() : CHAR`, `m2readint() : INTEGER`); a zero-parameter
+  external call is `name()`.
+- `math.def` REAL constants are emitted as globals flushed at
+  `main` startup (existing REAL-const path), so `Math.Pi` loads
+  correctly in clients.
+
+## Deferred to 5.4+
+
+`Files`, `Storage` / `SYSTEM` (`ALLOCATE`/`DEALLOCATE`, `ADDRESS`,
+generic pointers — needs SYSTEM types), explicit external link
+names, string escapes, `ReadString`. Traps still `$abort`.

+ 26 - 0
runtime/syslib/shim.c

@@ -10,6 +10,7 @@
 
 #include <unistd.h>
 #include <stdlib.h>
+#include <stdio.h>
 
 /* Write the contents of a string descriptor to fd 1. Returns the
    number of bytes written. */
@@ -28,6 +29,31 @@ long m2writeln(void)
     return 0;
 }
 
+/* Read one character from stdin (0 at EOF). */
+long m2readchar(void)
+{
+    int c = getchar();
+    return (c == EOF) ? 0 : c;
+}
+
+/* Read a signed decimal integer from stdin, skipping leading
+   whitespace. The first non-digit after the number is consumed. */
+long m2readint(void)
+{
+    long v = 0;
+    int c;
+    int neg = 0;
+
+    do { c = getchar(); } while (c == ' ' || c == '\t' ||
+                                 c == '\n' || c == '\r');
+    if (c == '-') { neg = 1; c = getchar(); }
+    while (c >= '0' && c <= '9') {
+        v = v * 10 + (c - '0');
+        c = getchar();
+    }
+    return neg ? -v : v;
+}
+
 /* Set a string descriptor's logical length (header). */
 long m2setlen(long *desc, long n)
 {

+ 15 - 0
stdlib/math.def

@@ -0,0 +1,15 @@
+DEFINITION MODULE Math;
+(* Real math, bound to libm. *)
+
+CONST Pi = 3.14159265358979;
+CONST E = 2.71828182845905;
+
+PROCEDURE sqrt(x : REAL) : REAL;
+PROCEDURE exp(x : REAL) : REAL;
+PROCEDURE ln(x : REAL) : REAL;
+PROCEDURE sin(x : REAL) : REAL;
+PROCEDURE cos(x : REAL) : REAL;
+PROCEDURE arctan(x : REAL) : REAL;
+PROCEDURE abs(x : REAL) : REAL;
+
+END Math.

+ 31 - 0
stdlib/math.mod

@@ -0,0 +1,31 @@
+IMPLEMENTATION MODULE Math;
+(* Direct libm bindings (names are valid Modula-2 identifiers and
+   match the C symbols). `fabs` is exposed as `abs`. *)
+
+PROCEDURE sqrt(x : REAL) : REAL;
+  EXTERNAL;
+
+PROCEDURE exp(x : REAL) : REAL;
+  EXTERNAL;
+
+PROCEDURE ln(x : REAL) : REAL;
+  EXTERNAL;
+
+PROCEDURE sin(x : REAL) : REAL;
+  EXTERNAL;
+
+PROCEDURE cos(x : REAL) : REAL;
+  EXTERNAL;
+
+PROCEDURE arctan(x : REAL) : REAL;
+  EXTERNAL;
+
+PROCEDURE fabs(x : REAL) : REAL;
+  EXTERNAL;
+
+PROCEDURE abs(x : REAL) : REAL;
+BEGIN
+  RETURN fabs(x)
+END abs;
+
+END Math.

+ 6 - 0
stdlib/sysio.def

@@ -13,4 +13,10 @@ PROCEDURE WriteInt(n : INTEGER);
 PROCEDURE WriteChar(c : CHAR);
 (* Writes a single character to standard output. *)
 
+PROCEDURE ReadChar() : CHAR;
+(* Reads one character from standard input (0C at end of file). *)
+
+PROCEDURE ReadInt() : INTEGER;
+(* Reads a signed decimal integer, skipping leading whitespace. *)
+
 END SysIO.

+ 16 - 0
stdlib/sysio.mod

@@ -13,6 +13,12 @@ PROCEDURE m2writeint(n : INTEGER);
 PROCEDURE m2writechar(c : CHAR);
   EXTERNAL;
 
+PROCEDURE m2readchar() : CHAR;
+  EXTERNAL;
+
+PROCEDURE m2readint() : INTEGER;
+  EXTERNAL;
+
 PROCEDURE Write(VAR s : ARRAY OF CHAR);
 BEGIN
   m2write(s)
@@ -33,4 +39,14 @@ BEGIN
   m2writechar(c)
 END WriteChar;
 
+PROCEDURE ReadChar() : CHAR;
+BEGIN
+  RETURN m2readchar()
+END ReadChar;
+
+PROCEDURE ReadInt() : INTEGER;
+BEGIN
+  RETURN m2readint()
+END ReadInt;
+
 END SysIO.

+ 9 - 0
stdlib/wholeio.def

@@ -0,0 +1,9 @@
+DEFINITION MODULE WholeIO;
+(* Integer input/output (ISO-style names). *)
+
+PROCEDURE WriteInt(n : INTEGER);
+PROCEDURE WriteCard(n : CARDINAL);
+PROCEDURE ReadInt(VAR n : INTEGER);
+PROCEDURE ReadCard(VAR n : CARDINAL);
+
+END WholeIO.

+ 30 - 0
stdlib/wholeio.mod

@@ -0,0 +1,30 @@
+IMPLEMENTATION MODULE WholeIO;
+(* Binds the shim integer routines directly. *)
+
+PROCEDURE m2writeint(n : INTEGER);
+  EXTERNAL;
+
+PROCEDURE m2readint() : INTEGER;
+  EXTERNAL;
+
+PROCEDURE WriteInt(n : INTEGER);
+BEGIN
+  m2writeint(n)
+END WriteInt;
+
+PROCEDURE WriteCard(n : CARDINAL);
+BEGIN
+  m2writeint(n)
+END WriteCard;
+
+PROCEDURE ReadInt(VAR n : INTEGER);
+BEGIN
+  n := m2readint()
+END ReadInt;
+
+PROCEDURE ReadCard(VAR n : CARDINAL);
+BEGIN
+  n := m2readint()
+END ReadCard;
+
+END WholeIO.