Oberon/ETH Oberon/Tutorial/编译器
这些教程页面由 André Fischer (afi) 编写,Hannes Marais 提供编辑协助,托管在 ETHZ,并保留在 ETH 许可 下。相关内容可以在系统中通过 Book.Tool 找到。扩展内容也可在 纸质版 上找到。一些教程页面在 WayBack 存档 中。
学习使用 Oberon 编译器及其称为构建器的前端。
预计时间:30 分钟。
编译器的输入是文本。这些文本方便地在文本查看器中使用系统编辑器[1]创建。以下命名约定 (广泛使用) 建议用于存储源程序的文件
- name.Mod 其中 name 通常对应于模块的名称 (MODULE name;)。
有关 Oberon 编程语言的介绍,请参阅 有关 Oberon 的文献。但学习一门新的编程语言的唯一方法是阅读和编写该语言的程序。
第一个程序对于所有编程语言都是一样的!在 Oberon 中,编写 hello, world 的程序是
MODULE Hello; IMPORT Out; PROCEDURE World*; BEGIN Out.String("hello, world"); Out.Ln END World; END Hello.
要学习如何使用编译器,请按照以下步骤操作
- 标记 上面的文本并执行 Compiler.Compile * ,[2]
- 观察 Oberon 日志中的消息
正在编译 Hello 33
模块名称后面的数字是现在存储在当前目录中的目标文件的大小。 - 执行 Hello.World 并观察日志中的输出 hello, world。
编译器是 Oberon 系统的重要组成部分。除了内核的一部分,Oberon 系统 3 是用原始的 Oberon 语言实现的。提供的编译器是 Oberon-2 编译器。原则上,任何 Oberon-2 编译器都与系统 3 兼容,并且可以使用 Oberon-2 编写和编译系统 3 程序。 编译器可以生成两种类型的目标文件:包含目标机器代码的经典本地目标文件,或者默认情况下,瘦二进制文件。瘦二进制文件是一种新的目标文件形式,它根本不包含目标代码,而是一个模块内容的便携式描述,这使得这些文件完全独立于最终的目标机器 (平台无关)。目标代码生成是由模块加载器 (取决于底层硬件) 在运行时进行的,并且与加载传统目标文件的时间一样长。
模块 Compiler 只导出两个命令,它们在 Compiler.Tool 中的几个变体中都有文档,并在下面描述。
Compiler.Compile @[\options] 编译从最近的文本选择开始的源代码。
Compiler.Compile *[\options] 编译标记的查看器的源代码。
这两个第一个命令变体允许直接从文本编辑器编译模块:不需要先存储文本。
Compiler.Compile {[\dst=pathName] [\options] {fileName[\options]}}~ | ^ 编译参数列表中命名的文件的文本。pathName 指示编译器将新目标文件存储在指定的子目录中。
options 是
- s - 启用生成新的 symbol 文件
- e - 启用生成 extended 符号文件
- u - 如果目标文件是最新的,则抑制编译
- w - 启用生成 warning 消息
编译一系列模块时,文件名顺序必须符合模块导入层次结构:从底层到顶层;也就是说,模块的客户端必须在模块本身之后编译。您可以通过使用 构建器 功能来避免这种情况。请注意,每个文件名后都可以跟选项。
以下选项仅在编译器必须生成本地目标文件时才有效。这些文件不跨平台边界可移植。因此,这些选项应仅在编写使用低级模块 SYSTEM 或内置 SIZE 函数的扩展时使用。示例:Win.Audio.Mod
- N - nable 生成本地目标文件
- a - 抑制为 ASSERT 函数生成代码
- p - 抑制将本地 pointers 初始化为 NIL
- x - 禁用 Index 检查
- n - 禁用 NIL 检查
- t - 禁用 Type 检查
- v - 启用 Overflow 检查
- c - 禁用 Range Checks
- r - 抑制生成 ref-info
- d - 生成 MacsBug debugger 信息 (MacOberon)
- f - find 对应于所选程序计数器值的文本位置
- g - 抑制此次编译后的 garbage 收集
如果抑制垃圾收集,编译运行速度更快,但如果使用了太多内存或太多文件,则可能无法完成编译 (将捕获)。
指定目标文件路径 - Compiler.SetDestPath
[edit | edit source]Compiler.SetDestPath pathName 指示编译器将新的目标文件存储在指定的子目录中。
指导加载精简二进制文件
[edit | edit source]以下命令影响精简二进制文件的加载
OMI.AssertsOn / OMI.AssertsOff 启用/禁用为 ASSERTS 函数生成代码。
OMI.ChecksOn / OMI.ChecksOff 启用/禁用索引检查。
OMI.RefsOn / OMI.RefsOff 启用/禁用生成详细引用信息。
这些命令可以方便地放在 Configuration.Text 文件中。
在执行之前卸载模块
[edit | edit source]如果您对模块进行更改,并在使用(即加载)后重新编译它,您必须使用 System.Free 命令或使用鼠标将其卸载
当鼠标焦点位于命令名称 M.P 上并且按下鼠标中键时,□ ■ 左键点击会卸载包含该命令的模块 M 并加载它的新副本,然后执行该命令。
程序员提示和警告: 这在开发和调试 Oberon 过程时非常有用。这是一个方便的快捷方式来执行 System.Free 命令,但只有在模块 M 没有客户端时才会卸载它。因此,请记住 System.Free 以及 Builder.Free 提供了额外的可能性。
如果您的更正没有产生任何影响,请不要感到惊讶:旧的 模块版本仍在控制中!您经常会忘记强制系统使用更新的版本。
以下示例应有助于具体化之前所说的话
MODULE Client; IMPORT Hello; PROCEDURE MyAction*; BEGIN Hello.World END MyAction; END Client.
- 选择模块文本的开头
- 执行 Compiler.Compile @
- 执行 Client.MyAction
- 执行 System.Free Hello ~
- 观察并解释日志消息:Hello 卸载失败
编译修改后的示例
[edit | edit source]MODULE Hello; IMPORT Out; PROCEDURE World*; BEGIN Out.String("hello, world"); Out.Ln END World; END HELLO.
- 修改文本 "hello, world"(例如 "Hello Oberon")
- 执行 Compiler.Compile *(即重新编译程序)
- 执行 Hello.World 并查看 Oberon 日志中如何显示相同的 "hello, world"。
- 强制系统卸载模块并使用鼠标中键 + 左键点击执行命令 Hello.World 的新版本。
定位和纠正语法错误
[edit | edit source]MODULE Hello; IMPORT Out; PROCEDURE World*; BEGIN Out.String("hello, world"); Out.Ln END World; END HELLO.
- 删除程序中的分号
- 将插入符号移动到文本中的另一个位置
- 执行 Compiler.Compile *
然后 Oberon 日志显示compiling Hello pos nn err 39
- 选择包含错误消息的行,然后单击 Oberon 日志菜单栏中的 [Locate] 按钮。这将把插入符号设置在缺少分号的位置。错误可以很容易地纠正。
调试编译器检测到的语法错误
[edit | edit source]编译器检测到的错误在 Oberon 日志中以以下形式的消息报告
pos <错误位置> err <错误编号>
含义:错误 <错误编号> 发生在源文本中的位置 <错误位置>。
以下过程将插入符号放置在源文本中的错误位置
- 确保源文本出现在查看器中
- 标记查看器
- 在 Oberon 日志中选择包含错误消息的行
- 单击菜单栏中的 [Locate] 按钮或
- 执行命令 TextDocs.Locate 或
- 执行命令 Edit.Locate.
在某些版本中,Oberon 编译器错误编号及其简短说明列在 OberonErrors.Text 中。在 PlugIn Oberon 中,它运行在各种 MS Windows 系统上,该文件名为 OP2.Errors。在 Oberon 2.3.7 中,类似的列表位于 Oberon.Text 的 Errors 部分。 [3]
您需要重新编译模块,直到没有报告错误。但是,可能会发出警告,但它们不被视为错误,因此会创建目标文件。
陷阱查看器
[edit | edit source]如果命令执行失败,运行时错误会导致程序异常终止,并且会在文本查看器 'System.Trap' 中显示错误报告。导致陷阱的错误由陷阱代码标识,显示某些系统寄存器的内容,并显示过程激活堆栈,从调用堆栈顶部的过程开始。所有标量变量和字符串以及它们的值也列出。
MODULE Trap; VAR arr: ARRAY 3 OF INTEGER; PROCEDURE count(n: INTEGER); BEGIN arr[n] := n; count(n+1) END count; PROCEDURE ForceIt*; BEGIN count(0) END ForceIt; END Trap.
- 选择模块文本的开头
- 执行 Compiler.Compile @
- 执行 Trap.ForceIt 并研究查看器的内容。
最初,陷阱代码在 OberonErrors.Text 的末尾进行了解释。随后,当陷阱查看器被创建或增强时,OberonErrors.Text 中的解释变得多余并被删除。
为了找到失败的语句,只需显示源程序并标记其查看器。然后在陷阱查看器中选择包含感兴趣过程名称的行,并使用 "\d" 或 "\f" 选项重新编译程序。
使用构建器
[edit | edit source]Builder 为上面描述的 Oberon 编译器提供了一个方便的前端。它确保模块文本以正确的顺序呈现给编译器,无论参数列表中文件名的顺序如何。但是,它不是真正的 make 工具:必须指定所有要编译的模块。请注意,参数列表必须包含文件名:这些文件名可能与模块名称不同,但这只是一个约定问题。Builder 模块命令在 Builder.Tool 中有记录。
编译源文本 - Builder.Compile
[edit | edit source]Builder.Compile [\options] * 编译标记的查看器的源文本。文本中插入的所有错误标记都将被删除。
Builder.Compile [\options] ({fileName}~ | ^ | *) 编译参数列表中命名的文件的文本,自动确定模块的正确编译顺序。必须指定所有要编译的模块,即它不是真正的 make 工具。选项与 Compiler.Compile 命令的选项相同。
有效处理编译器检测到的错误
[edit | edit source]Builder.MarkErrors [^] 当选择包含编译器在 Oberon 日志中写入的错误消息时,此命令会为该消息以及所有后续消息在标记的文本中插入错误标记。错误标记是一个特殊的(构建器)小工具,它显示在程序文本中该位置发现的错误代码的编号。以下错误消息
pos 111 err 4
将在位置 111 处放置 4
。
Builder.NextError 将插入符号前进到下一个错误标记。当到达文本末尾时,搜索将环绕回到开头。
Builder.ClearErrors 删除标记文本中的所有错误标记。由 Builder.Compile * 命令自动执行。
卸载模块 - Builder.Free
[edit | edit source]Builder.Free {fileName}~ | ^ 以正确的顺序卸载参数列表中命名的每个模块。由于文件名必须出现在参数列表中,因此此命令只能释放源文本可用的模块。要卸载其他模块,请使用 System.Free.
插入模块图标 - Builder.InsertHierarchy
[edit | edit source]Builder.InsertHierarchy {fileName}~ | ^ 在插入符号处为参数列表中命名的每个模块插入一个图标。图标以正确的编译顺序插入。每个图标都带有文件名作为标题,并且它的Cmd 属性值为 "Desktops.OpenDoc '#Caption '". 在 Compiler.Panel 中可以找到此类图标的示例。
使用分析器
[edit | edit source]分析器为 Oberon 编译器提供了一个便捷的补充,用于在语法正确的程序文本中查找其他潜在错误。编译器错误首先报告。不生成目标代码。分析器定位
- 未导出的项目(变量/常量/类型/字段),这些项目已声明但从未使用过,在初始化 (*) 之前使用过,从未初始化过,以及初始化过但从未使用过。
- 未导出的 [类型绑定] 过程,这些过程从未调用过。
- 从未使用的导入模块。
(*) 对于在不同范围内声明的变量,不会产生警告(但是,请参阅选项 \u)。
分析器模块命令在 Analyzer.Tool. 中有记录。
Analyzer.Analyze @[\options] 分析从最新文本选择开始的源文本。
Analyzer.Analyze *[\options] 分析标记查看器的源文本。
这两个命令的第一个变体允许直接从文本编辑器分析模块:无需先存储文本。
Analyzer.Analyze {fileName[\options]}~ | ^ 分析参数列表中命名的文件的源文本。
Analyzer.Analyze 通过以下形式的消息警告 Oberon 日志中可能出现的错误
pos <error position> warning <warning number>
请参阅 调试编译器检测到的语法错误.
Analyzer.Analyze 还报告模块中语句(赋值、if、while、过程调用等)的数量。这对于确定程序的复杂性(而不是行数)很方便。
错误标记可以插入源文本中,如 有效处理编译器检测到的错误 中所述。
可以通过指定一个或多个 选项 获得更多信息
- i (intermediate) - 定位
- - 已经在外部范围内声明的项目。
- - 对中间项目的使用或赋值,例如在外部范围内声明的局部变量/参数。
- s (evaluation sequence) - 定位参数列表中出现函数调用的多参数过程的调用。参数的求值顺序可能会影响这些函数的副作用。
- t (type-bound) - 定位
- - 类型绑定过程的重新定义。
- - 在扩展类型中对类型绑定过程的重新定义。
- u (used) - 定位在不同范围内声明并在设置之前使用的变量。
- v (VAR parameter) - 定位用作 VAR 参数的变量,因此不能确保已初始化这些变量。
- x (exported) - 定位已声明但模块本身未使用、在初始化之前使用、从未初始化或已初始化但从未使用的导出项目。
A
Analyzer.Analyze
Analyzer.Tool
B
Builder.ClearErrors
Builder.Compile
Builder.Free
Builder.InsertHierarchy
Builder.MarkErrors
Builder.NextError
Builder.Tool
C
Compiler.Compile
Compiler.Panel
Compiler.SetDestPath
Compiler.Tool
E
N
O
S
T
U
修订,afi 1996 年 12 月 10 日
安装于 1997 年 05 月 30 日
- ↑ 在 V2(Ceres Oberon)中 Edit.Open <fileName> 。在 ETH Oberon 中 Edit.Open <fileName> 或 ET.Open <fileName> 。在 V5(FPGA Oberon)中 Edit.Open <fileName> 。
- ↑ 可以在 ETH Oberon 中使用 MM 执行的命令是深红色。目标超链接是蓝色。非目标超链接是猩红色。
- ↑ 邮件列表有一个从 2023-01-07 开始的讨论。