Просмотр исходного кода

stdlib: ProgramArgs + IOChan (+ SysShim/stdin primitives)

- stdlib/programargs: ArgCount (excl. program name), GetArg (1-based)
  over SysShim.argc/arg (shim m2argc/m2arg, /proc/self/cmdline).
- stdlib/iochan: opaque ChanId (C FILE*); StdIn/Out/ErrChan;
  ReadChar/WriteChar/WriteString/WriteLn/WriteInt over SysShim.
- SysShim: add argc/stdin/fgetc/fwriteint; shim.c: m2stdin.
- tests: progargs_prog (7), iochan_prog (stdout 'hello 42', reads
  'Z') -> 126/126. Fixpoint OK (2,071,330 bytes).
- docs updated.
Eric Streit 1 неделя назад
Родитель
Сommit
4afc2b25f1

+ 2 - 0
compiler/run_tests.sh

@@ -232,6 +232,7 @@ expect_run_files MathProg 12 ../stdlib/sysio.def ../stdlib/sysio.mod ../stdlib/m
 expect_run_files Utf8Prog 127 ../runtime/syslib/Utf8.def ../runtime/syslib/Utf8.mod utf8_prog.mod
 expect_run_files ConvProg 127 ../stdlib/conversions.def ../stdlib/conversions.mod conv_prog.mod
 expect_run_files TStrEq 15 t_streq.mod
+expect_run_files ProgArgsProg 7 ../runtime/syslib/SysShim.def ../runtime/syslib/SysShim.mod ../stdlib/programargs.def ../stdlib/programargs.mod progargs_prog.mod
 expect_run_files_out UTextProg 42 "héllo" ../runtime/syslib/Utf8.def ../runtime/syslib/Utf8.mod ../stdlib/textio.def ../stdlib/textio.mod utext_prog.mod
 
 expect_run_files_in() {
@@ -252,6 +253,7 @@ expect_run_files_in() {
 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_run_files_in RealProg 42 "3.500000E+00" "1.25" ../stdlib/realio.def ../stdlib/realio.mod ../stdlib/sysio.def ../stdlib/sysio.mod realio_prog.mod
+expect_run_files_in IOChanProg 0 "hello 42" "Z" ../runtime/syslib/SysShim.def ../runtime/syslib/SysShim.mod ../stdlib/iochan.def ../stdlib/iochan.mod iochan_prog.mod
 expect_run_files FilesProg 42 ../stdlib/files.def ../stdlib/files.mod files_prog.mod
 expect_run_files TBadFile 42 ../stdlib/files.def ../stdlib/files.mod t_badfile.mod
 rm -f gen_ssa/_files_tmp.txt

+ 18 - 0
compiler/tests/iochan_prog.mod

@@ -0,0 +1,18 @@
+MODULE IOChanProg;
+(* IOChan: standard channels, string/int output, char input. *)
+IMPORT IOChan;
+VAR ExitCode : INTEGER;
+VAR out, inp : IOChan.ChanId;
+VAR c : CHAR;
+BEGIN
+  out := IOChan.StdOutChan();
+  inp := IOChan.StdInChan();
+  IOChan.WriteString(out, "hello ");
+  IOChan.WriteInt(out, 42);
+  IOChan.WriteLn(out);
+  c := IOChan.ReadChar(inp);
+  IOChan.WriteString(out, "got ");
+  IOChan.WriteChar(out, c);
+  IOChan.WriteLn(out);
+  ExitCode := 0
+END IOChanProg.

+ 16 - 0
compiler/tests/progargs_prog.mod

@@ -0,0 +1,16 @@
+MODULE ProgArgsProg;
+(* ProgramArgs with no arguments: count 0, GetArg fails.  Exit 7. *)
+IMPORT ProgramArgs;
+VAR ExitCode : INTEGER;
+VAR s : ARRAY [0 .. 63] OF CHAR;
+BEGIN
+  IF ProgramArgs.ArgCount() = 0 THEN
+    ExitCode := ExitCode + 1
+  ELSE ExitCode := 100 END;
+  IF NOT ProgramArgs.GetArg(1, s) THEN
+    ExitCode := ExitCode + 2
+  ELSE ExitCode := 100 END;
+  IF NOT ProgramArgs.GetArg(999, s) THEN
+    ExitCode := ExitCode + 4
+  ELSE ExitCode := 100 END
+END ProgArgsProg.

+ 8 - 7
docs/features.md

@@ -1,4 +1,4 @@
-# m2compiler-V3 — feature status (at `v3-lang-polish`, 124/124 green)
+# m2compiler-V3 — feature status (at `v3-programargs-iochan`, 126/126 green)
 
 Pipeline: Coco/R `M2.atg` (1748 lines, 73 productions) → `gm2`-built
 `M2` → QBE `.ssa` → `qbe` → `cc` → run. `SymTab.mod` 1623 lines,
@@ -83,19 +83,20 @@ Legend: ✅ done · 🔄 partial · ⏸ not started / deferred.
 - ✅ `runtime/syslib`: `SysShim`, `FileIO`, `Utf8` (UTF-8 codec).
 - ✅ `stdlib`: `SysIO`, `TextIO` (+ UTF-8 `U*`), `WholeIO`, `Math`,
   `Strings`, `CharClass`, `Files`, `Conversions`, `RealIO`,
-  `Storage`.
+  `ProgramArgs`, `IOChan`, `Storage`.
 
 ## Not started
 - ⏸ Clarion `CLASS` lowering (declared + checked only); Unicode
   `UString` whole-string assignment; strict `231` def/impl signature
-  checks; string `+`; `ProgramArgs` / `IOChan`. (ISO `ConvResults`
-  enumerations are now expressible.) The TopSpeed legacy grammar
-  (`TopSpeed-V3-M2.atg`) is a separate sidecar, not merged.
+  checks; string `+`; `IOChan` beyond the standard streams. (ISO
+  `ConvResults` enumerations are now expressible.) The TopSpeed
+  legacy grammar (`TopSpeed-V3-M2.atg`) is a separate sidecar, not
+  merged.
 
 (Self-hosting is reached: `bootstrap/fixpoint.sh` builds a
 byte-identical compiler image; `stdlib/` + `runtime/syslib` are in
 use. See `docs/summary_selfhosting.md`.)
 
-Next: `ProgramArgs` / `IOChan`, string concatenation, strict `231`
-def/impl signature checks. Roadmap: `docs/plan.md`,
+Next: string concatenation, strict `231` def/impl signature checks,
+`IOChan` over files. Roadmap: `docs/plan.md`,
 `docs/blaise-phases-map.md`.

+ 2 - 1
docs/plan.md

@@ -38,7 +38,8 @@ m2compiler-V3/
   runtime/syslib/    SYSTEM, Storage, SysIO, SysClock, Trap, Utf8
                      always-linked, self-hostable, NO gm2-only imports
   stdlib/            Strings, TextIO (+U*), WholeIO, Math, Files,
-                     Conversions, RealIO, CharClass
+                     Conversions, RealIO, CharClass, ProgramArgs,
+                     IOChan
                      opt-in via IMPORT, classic DEFINITION+OPAQUE,
                      Benjamin-R10 semantics, classic syntax only
   tools/redux-check/ modern-syntax enforcement helper

+ 50 - 0
docs/summary_programargs-iochan.md

@@ -0,0 +1,50 @@
+# Step: ProgramArgs + IOChan
+
+Tag `v3-programargs-iochan`. Suite **126/126**; fixpoint **OK**
+(`bootstrap/fixpoint.sh`, image **2,071,330 bytes**).
+
+## `ProgramArgs`
+
+- `ArgCount() : CARDINAL` — the number of arguments *after* the
+  program name.
+- `GetArg(n : CARDINAL; VAR s : ARRAY OF CHAR) : BOOLEAN` —
+  1-based (`1` = first argument); `FALSE` when absent.
+- Over `SysShim.argc`/`SysShim.arg` → shim `m2argc`/`m2arg`, which
+  read `/proc/self/cmdline` (Linux).
+
+## `IOChan`
+
+- `TYPE ChanId;` — opaque; completed as `ADDRESS` (a C `FILE *`).
+- `StdInChan`/`StdOutChan`/`StdErrChan`.
+- `ReadChar`, `WriteChar`, `WriteString`, `WriteLn`, `WriteInt`.
+- All operations go through `SysShim` (`stdin`/`stdout`/`stderr`,
+  `fgetc`/`fputc`/`fputs`/`fwriteln`/`fwriteint`); a `NIL` handle
+  degrades to a safe no-op / `0C`, as in `Files`.
+
+## Bridge additions
+
+- `runtime/syslib/SysShim.def`/`.mod`: `argc`, `stdin`, `fgetc`,
+  `fwriteint`.
+- `runtime/syslib/shim.c`: `m2stdin`.
+
+## Tests
+
+- `progargs_prog.mod` (exit 7, run with no arguments): `ArgCount = 0`,
+  `GetArg(1)` and `GetArg(999)` return `FALSE`.
+- `iochan_prog.mod`: writes `hello 42` on `StdOutChan`, reads one
+  character from `StdInChan`, echoes `got Z`; first stdout line
+  `hello 42`, exit 0.
+
+## Scope notes
+
+- `ProgramArgs.ArgCount` excludes `argv[0]`; `GetArg` is 1-based.
+- `IOChan` is a pragmatic subset: `ReadString`, `ReadResult`,
+  seek/position and channels over files are not included; `ChanId`
+  wraps only the standard streams for now.
+
+## Files
+
+`stdlib/programargs.def`/`.mod`, `stdlib/iochan.def`/`.mod`,
+`runtime/syslib/SysShim.def`/`.mod`, `runtime/syslib/shim.c`,
+`compiler/tests/{progargs_prog,iochan_prog}.mod`,
+`compiler/run_tests.sh`, `docs/{features,plan}.md`.

+ 9 - 0
runtime/syslib/SysShim.def

@@ -21,9 +21,18 @@ PROCEDURE fputs (h : ADDRESS; VAR s : ARRAY OF CHAR);
 PROCEDURE fwriteln (h : ADDRESS);
 PROCEDURE fwriteintw (h : ADDRESS; v : INTEGER; wid : CARDINAL);
 
+PROCEDURE stdin () : ADDRESS;
 PROCEDURE stdout () : ADDRESS;
 PROCEDURE stderr () : ADDRESS;
 
+PROCEDURE fgetc (h : ADDRESS) : CHAR;
+(* Reads one byte from h; 0C at end of file. *)
+PROCEDURE fwriteint (h : ADDRESS; v : INTEGER);
+(* Writes v in decimal to h (no field width). *)
+
+PROCEDURE argc () : CARDINAL;
+(* Number of command-line words, including the program name. *)
+
 PROCEDURE arg (i : CARDINAL; VAR s : ARRAY OF CHAR;
                cap : CARDINAL) : BOOLEAN;
 (* Copies command-line argument i into s (capacity cap); FALSE when

+ 28 - 0
runtime/syslib/SysShim.mod

@@ -24,6 +24,14 @@ PROCEDURE m2stdout () : ADDRESS;
   EXTERNAL;
 PROCEDURE m2stderr () : ADDRESS;
   EXTERNAL;
+PROCEDURE m2stdin () : ADDRESS;
+  EXTERNAL;
+PROCEDURE m2fgetc (h : ADDRESS) : CHAR;
+  EXTERNAL;
+PROCEDURE m2fwriteint (h : ADDRESS; v : INTEGER);
+  EXTERNAL;
+PROCEDURE m2argc () : CARDINAL;
+  EXTERNAL;
 PROCEDURE m2arg (i : CARDINAL; VAR s : ARRAY OF CHAR;
                  cap : CARDINAL) : BOOLEAN;
   EXTERNAL;
@@ -79,6 +87,26 @@ BEGIN
   RETURN m2stderr()
 END stderr;
 
+PROCEDURE stdin () : ADDRESS;
+BEGIN
+  RETURN m2stdin()
+END stdin;
+
+PROCEDURE fgetc (h : ADDRESS) : CHAR;
+BEGIN
+  RETURN m2fgetc(h)
+END fgetc;
+
+PROCEDURE fwriteint (h : ADDRESS; v : INTEGER);
+BEGIN
+  m2fwriteint(h, v)
+END fwriteint;
+
+PROCEDURE argc () : CARDINAL;
+BEGIN
+  RETURN m2argc()
+END argc;
+
 PROCEDURE arg (i : CARDINAL; VAR s : ARRAY OF CHAR;
                cap : CARDINAL) : BOOLEAN;
 BEGIN

+ 1 - 0
runtime/syslib/shim.c

@@ -180,6 +180,7 @@ long m2fwriteintw(long h, long v, long wid)
 /* Standard streams as file handles. */
 long m2stdout(void) { return (long)stdout; }
 long m2stderr(void) { return (long)stderr; }
+long m2stdin(void) { return (long)stdin; }
 
 /* Command-line arguments, read from /proc/self/cmdline (Linux). */
 static char *m2_args[1024];

+ 18 - 0
stdlib/iochan.def

@@ -0,0 +1,18 @@
+DEFINITION MODULE IOChan;
+(* A minimal channel abstraction over the runtime streams (an
+   ISO-style ChanId).  ChanId is opaque; the standard channels are
+   the standard input/output/error streams. *)
+
+TYPE ChanId;
+
+PROCEDURE StdInChan() : ChanId;
+PROCEDURE StdOutChan() : ChanId;
+PROCEDURE StdErrChan() : ChanId;
+
+PROCEDURE ReadChar(cid : ChanId) : CHAR;
+PROCEDURE WriteChar(cid : ChanId; c : CHAR);
+PROCEDURE WriteString(cid : ChanId; VAR s : ARRAY OF CHAR);
+PROCEDURE WriteLn(cid : ChanId);
+PROCEDURE WriteInt(cid : ChanId; n : INTEGER);
+
+END IOChan.

+ 49 - 0
stdlib/iochan.mod

@@ -0,0 +1,49 @@
+IMPLEMENTATION MODULE IOChan;
+(* A ChanId is a C FILE* handle; all operations go through SysShim
+   (which degrades a NIL handle to a safe no-op / 0C). *)
+
+IMPORT SysShim;
+
+TYPE ChanId = ADDRESS;
+
+PROCEDURE StdInChan() : ChanId;
+BEGIN
+  RETURN SysShim.stdin()
+END StdInChan;
+
+PROCEDURE StdOutChan() : ChanId;
+BEGIN
+  RETURN SysShim.stdout()
+END StdOutChan;
+
+PROCEDURE StdErrChan() : ChanId;
+BEGIN
+  RETURN SysShim.stderr()
+END StdErrChan;
+
+PROCEDURE ReadChar(cid : ChanId) : CHAR;
+BEGIN
+  RETURN SysShim.fgetc(cid)
+END ReadChar;
+
+PROCEDURE WriteChar(cid : ChanId; c : CHAR);
+BEGIN
+  SysShim.fputc(cid, c)
+END WriteChar;
+
+PROCEDURE WriteString(cid : ChanId; VAR s : ARRAY OF CHAR);
+BEGIN
+  SysShim.fputs(cid, s)
+END WriteString;
+
+PROCEDURE WriteLn(cid : ChanId);
+BEGIN
+  SysShim.fwriteln(cid)
+END WriteLn;
+
+PROCEDURE WriteInt(cid : ChanId; n : INTEGER);
+BEGIN
+  SysShim.fwriteint(cid, n)
+END WriteInt;
+
+END IOChan.

+ 9 - 0
stdlib/programargs.def

@@ -0,0 +1,9 @@
+DEFINITION MODULE ProgramArgs;
+(* Command-line arguments.  ArgCount is the number of arguments
+   *after* the program name; GetArg is 1-based (1 = first argument).
+   GetArg returns FALSE when there is no such argument. *)
+
+PROCEDURE ArgCount() : CARDINAL;
+PROCEDURE GetArg(n : CARDINAL; VAR s : ARRAY OF CHAR) : BOOLEAN;
+
+END ProgramArgs.

+ 22 - 0
stdlib/programargs.mod

@@ -0,0 +1,22 @@
+IMPLEMENTATION MODULE ProgramArgs;
+(* Over the SysShim bridge (which reads /proc/self/cmdline). *)
+
+IMPORT SysShim;
+
+PROCEDURE ArgCount() : CARDINAL;
+  VAR n : CARDINAL;
+BEGIN
+  n := SysShim.argc();
+  IF n = 0 THEN
+    RETURN 0
+  ELSE
+    RETURN n - 1
+  END
+END ArgCount;
+
+PROCEDURE GetArg(n : CARDINAL; VAR s : ARRAY OF CHAR) : BOOLEAN;
+BEGIN
+  RETURN SysShim.arg(n, s, HIGH(s) + 1)
+END GetArg;
+
+END ProgramArgs.