← 都来码 / Dolaima← 例程索引fortran/demo/demo_std.f90原文

fortran/demo/demo_std.f90 · 9680 字节 · 下载原文

! demo_std.f90 —— Fortran 第一层:**标准输入输出**(std)

! demo_std.f90 -- Fortran layer one: **standard output** (std)

!

! 这一层只用 Fortran 自己的 `print`,不碰 Crt / 图形 / 宿主 `ui_*` ——

! This layer uses only Fortran's own `print`, touching neither Crt / graphics / the host `ui_*` --

! 所以它在任何后端上都是同一份行为,也是四份 demo 里唯一有"逐字节确定性输出"

! so its behavior is identical on every backend, and it is the only one of the four demos with a

! 判据的一份(另外几份只能验"编得过、跑得完、不挂死")。

! "byte-for-byte deterministic output" criterion (the others can only verify "it compiles, it finishes, it does not hang").

!

! 跑法(桌面 vmlcli):

! How to run (desktop vmlcli):

!   dotnet scripts/vmlcli/bin/Release/net10.0/vmlcli.dll Examples/fortran/demo_std.f90

!

! 期望输出(逐字节):

! Expected output (byte-for-byte; each line below is printed in Chinese and the line under it is its translation):

!   === Fortran 标准输出 demo ===

!   === Fortran std output demo ===

!   字符串: 你好,世界

!   String: hello, world

!   整数: 42

!   Integer: 42

!   计算: 7 * 6 = 42

!   Computed: 7 * 6 = 42

!   整除: 17 / 5 = 3

!   Integer division: 17 / 5 = 3

!   取余: mod(17,5) = 2

!   Remainder: mod(17,5) = 2

!   循环求和: 1..10 = 55

!   Loop sum: 1..10 = 55

!   阶乘: 10! = 3628800

!   Factorial: 10! = 3628800

!   实数: 2.5 * 4.0 = 10

!   Real: 2.5 * 4.0 = 10

!   === done ===

!

! ◆ 一条**已修**的缺陷,留在这儿备查(本文件现在敢直接打浮点了,就是因为它修好了)

! ◆ One **already fixed** defect, kept here for reference (this file now dares to print floats directly because it was fixed)

!   (2026-10-04 复验仍成立:`print *, 2.5` ⇒ `2.5`、`print *, 2.5 * 4.0` ⇒ `10`。)

!   (Re-verified 2026-10-04, still holds: `print *, 2.5` => `2.5`, `print *, 2.5 * 4.0` => `10`.)

!

!     以前:`print *, 2.5` ⇒ `1075838976`、`print *, x * 4.0` ⇒ `1092616192`

!     Before: `print *, 2.5` => `1075838976`, `print *, x * 4.0` => `1092616192`

!     (1075838976 = 0x40200000 = 2.5f 的位模式、1092616192 = 0x41200000 = 10.0f 的)

!     (1075838976 = 0x40200000 = the bit pattern of 2.5f, 1092616192 = 0x41200000 = that of 10.0f)

!     —— 值算对了,只是 `print` 一律走**整数格式**那条路。

!     -- the value was computed correctly, but `print` always took the **integer format** path.

!

!     真身:`CompilerBase/CodeGeneratorBase.EmitPrintArgs` 只把 `isArgString` 转给

!     Root cause: `CompilerBase/CodeGeneratorBase.EmitPrintArgs` passed only `isArgString` on to

!     `EmitPrintArg`,**`isFloat` 走的是默认值 `false`** ⇒ 每个实参都 `CALL print_int`。

!     `EmitPrintArg`, and **`isFloat` took its default value `false`** => every argument did `CALL print_int`.

!     修法:给 `EmitPrintArgs` 追加了一个可选参数 `isArgFloat`(追加在末尾,

!     Fix: an optional parameter `isArgFloat` was appended to `EmitPrintArgs` (appended at the end,

!     老调用点的位置参数一个都不用动),Fortran 的 `GeneratePrint` 用现成的

!     so no positional argument at the old call sites has to change), and Fortran's `GeneratePrint` passes it in

!     `GetExprType(...) == F32/F64` 传进去。判据:`print *, 2.5` ⇒ `2.5`、

!     using the ready-made `GetExprType(...) == F32/F64`. Criterion: `print *, 2.5` => `2.5`,

!     `print *, x * 4.0`(`x=2.5`)⇒ `10`。

!

! ◆ ~~⚠ **仍未修**:`double precision` 的 **`d0` 后缀字面量恒为 0**~~

! ◆ ~~⚠ **Still not fixed**: for `double precision`, a **literal with the `d0` suffix is always 0**~~

!   ✅ **已修好(2026-10-04 复验)**:`double precision :: d` 下

!   ✅ **Fixed (re-verified 2026-10-04)**: with `double precision :: d`,

!     `print *, 1.25d0` ⇒ **1.25**(旧记 0)、`d = 9.5d0` / `print *, d` ⇒ **9.5**(旧记 0)。

!     `print *, 1.25d0` => **1.25** (previously 0), `d = 9.5d0` / `print *, d` => **9.5** (previously 0).

!     (而 `d = 1.25` 不带后缀 ⇒ 1.25 —— 这条路一直是对的。)

!     (and `d = 1.25` with no suffix => 1.25 — that route was always fine.)

!

!   ⇒ 本文件仍照旧**一个 `d0` 字面量都没有**,但那只是写法,不再是必需 ——

!   => This file still contains **not a single `d0` literal**, but that is now just a style choice, not a requirement —

!     新写的代码直接用 `1.25d0` 即可(不带后缀的十进制字面量当然还是好的)。

!     new code can simply write `1.25d0` (a suffix-less decimal literal still works too).

!

! ◆ 三条本前端的写法要求(都是实测出来的,不是风格偏好)

! ◆ Three style requirements of this frontend (all measured, not style preferences)

!

!   ① **每条语句顶格写不受限,但 `print` 的输出格式是"列表式"** —— 每个实参之间

!   ① **Statements may start at column one without restriction, but `print`'s output format is "list-directed"** -- between each argument

!      由运行时自己补分隔(本平台是空格),所以 `print *, 'a', 'b'` 打出 `a b`。

!      the runtime inserts its own separator (a space on this platform), so `print *, 'a', 'b'` prints `a b`.

!      要紧凑就**拼进同一个字符串字面量**。

!      For a compact result, **put it all into one string literal**.

!

!   ② **整数 `/` 是整除**(Fortran 的语义本来就如此):`17 / 5` = 3。

!   ② **Integer `/` is integer division** (that is Fortran's semantics anyway): `17 / 5` = 3.

!      取余用内建的 `mod(a, b)` —— 前端把它编成 VML 的原生 `MOD` 指令,

!      Use the built-in `mod(a, b)` for the remainder -- the frontend compiles it to VML's native `MOD` instruction

!      不走库调用(否则会去链一个不存在的 `func_mod`,实测炸过)。

!      instead of a library call (otherwise it links a nonexistent `func_mod`, which crashed in testing).

!

!   ③ `call xxx(...)` 与 `k = xxx(...)` **不是同一件事**:

!   ③ `call xxx(...)` and `k = xxx(...)` **are not the same thing**:

!      · `call putchar(27)` 编成 `CALL putchar`(裸名,找得到库里的实现)

!      · `call putchar(27)` compiles to `CALL putchar` (the bare name, which finds the library implementation)

!      · 但 `call ui_2d_rect(...)` 会编成 `CALL sub_ui_rect`,而**链接器只剥

!      · but `call ui_2d_rect(...)` compiles to `CALL sub_ui_rect`, and **the linker strips only

!        `func_`/`word_`/`method_`/`var_` 四种前缀,不含 `sub_`** ⇒ 碰不到 UI 库。

!        the four prefixes `func_`/`word_`/`method_`/`var_`, not `sub_`** => it never reaches the UI library.

!      所以调库函数一律写成**函数调用表达式**:`k = ui_2d_rect(...)`(编成 `func_ui_rect`)。

!      So library functions are always written as a **function-call expression**: `k = ui_2d_rect(...)` (compiles to `func_ui_rect`).

!      本文件不涉及,但 `demo_ui.f90` 全靠这一条。

!      This file is not affected, but `demo_ui.f90` depends entirely on this rule.


program demo_std
  implicit none
  integer :: i
  integer :: sum
  integer :: fact
  integer :: lang

  ! 界面语言:0 = 中文 / 1 = 英文(ui_scr_get_language 是 syscall,开局查一次)

  ! UI language: 0 = Chinese / 1 = English (ui_scr_get_language is a syscall, queried once at startup)

  lang = ui_scr_get_language()

  if (lang == 0) print *, '=== Fortran 标准输出 demo ==='
  if (lang /= 0) print *, '=== Fortran std output demo ==='

  ! ① 字符串字面量(含中文 —— 源码按 UTF-8 存,词法器直通)

  ! ① String literal (contains Chinese -- the source is stored as UTF-8 and the lexer passes it through)

  if (lang == 0) print *, '字符串: 你好,世界'
  if (lang /= 0) print *, 'String: hello, world'

  ! ② 整数

  ! ② Integer

  if (lang == 0) print *, '整数: 42'
  if (lang /= 0) print *, 'Integer: 42'

  ! ③ 整数运算

  ! ③ Integer arithmetic

  if (lang == 0) print *, '计算: 7 * 6 = 42'
  if (lang /= 0) print *, 'Computed: 7 * 6 = 42'

  ! ④ 整数除法与取余(`/` 整除;取余用内建 `mod`)

  ! ④ Integer division and remainder (`/` is integer division; the remainder uses the built-in `mod`)

  if (lang == 0) print *, '整除: 17 / 5 = 3'
  if (lang /= 0) print *, 'Integer division: 17 / 5 = 3'
  if (lang == 0) print *, '取余: mod(17,5) = 2'
  if (lang /= 0) print *, 'Remainder: mod(17,5) = 2'

  ! ⑤ 用变量真算一遍 —— 上面几行是字面量,这几行让编译器真的去算

  ! ⑤ Actually compute it with variables -- the lines above are literals, these make the compiler really compute

  sum = 0
  do i = 1, 10
    sum = sum + i
  end do
  if (lang == 0) print *, '循环求和: 1..10 =', sum
  if (lang /= 0) print *, 'Loop sum: 1..10 =', sum

  fact = 1
  do i = 1, 10
    fact = fact * i
  end do
  if (lang == 0) print *, '阶乘: 10! =', fact
  if (lang /= 0) print *, 'Factorial: 10! =', fact

  ! ⑥ 实数:`print` 现在能正确打浮点了(见文件头那条"已修")

  ! ⑥ Reals: `print` can now print floats correctly (see the "already fixed" item in the file header)

  if (lang == 0) print *, '实数: 2.5 * 4.0 =', 2.5 * 4.0
  if (lang /= 0) print *, 'Real: 2.5 * 4.0 =', 2.5 * 4.0

  print *, '=== done ==='
end program demo_std