本课目标
完成本课后,你将能够:
-
完整理解Ada程序的结构与语法元素
-
掌握
with子句的多种用法和作用域规则 -
正确使用Ada的标识符、保留字和注释规范
-
区分声明部分与执行部分的职能边界
-
编写符合工业标准的规范Ada代码
一、程序结构全景解析
1.1 Hello World的完整解剖
回顾上节课的代码:
ada
with Ada.Text_IO;
procedure Hello is
-- 声明部分(Declarative Part)
begin
-- 执行部分(Executable Part)
Ada.Text_IO.Put_Line ("Hello, Ada World!");
end Hello;
Ada程序的四大组成部分:
| 部分 | 关键字 | 作用 | 可否为空 |
|---|---|---|---|
| 上下文子句 | with / use |
引入外部依赖 | 可以 |
| 单元头 | procedure / function / package |
程序单元类型和名称 | 不可 |
| 声明部分 | is 与 begin 之间 |
局部常量、变量、类型、子程序 | 可以 |
| 执行部分 | begin 与 end 之间 |
实现具体逻辑 | 不可 |
1.2 最简单的合法程序
ada
procedure Minimal is
begin
null; -- 空语句,表示"什么都不做"
end Minimal;
null语句是Ada的占位符,用于语法上必须有语句但逻辑上无需操作的场景。
二、上下文子句深度解析
2.1 with 子句的本质
with 不是简单的"文件包含",而是语义化的单元依赖声明:
ada
with Ada.Text_IO; -- 引入标准输入输出包
with Ada.Integer_Text_IO; -- 引入整数输入输出包
with Ada.Float_Text_IO; -- 引入浮点数输入输出包
与C语言 #include 的核心区别:
| 特性 | C #include |
Ada with |
|---|---|---|
| 机制 | 文本替换 | 语义检查 |
| 重复引用 | 需用 #ifndef 防护 |
自动处理,无重复问题 |
| 依赖分析 | 预处理器处理 | 编译器原生支持,可精准追踪 |
| 信息隐藏 | 头文件暴露所有细节 | 规范(.ads)控制可见性 |
2.2 use 子句:简化访问
频繁使用 Ada.Text_IO.Put_Line 很冗长,可用 use :
ada
with Ada.Text_IO;
use Ada.Text_IO; -- 将包的内容直接引入当前作用域
procedure Greetings is
begin
Put_Line ("Hello!"); -- 无需前缀
Put_Line ("Goodbye!"); -- 直接调用
end Greetings;
对比两种风格:
| 风格 | 代码 | 适用场景 |
|---|---|---|
| 全限定 | Ada.Text_IO.Put_Line (...) |
大型项目,避免命名冲突 |
| use字句 | Put_Line (...) |
小型程序,提高可读性 |
工业建议 :规范文件(.ads)中避免
use,包体(.adb)中可酌情使用。
2.3 use type :精确控制
只想引入某个类型的操作符,而非整个包:
ada
with Ada.Calendar;
use type Ada.Calendar.Time; -- 只引入Time类型的操作符
procedure Time_Example is
T1, T2 : Ada.Calendar.Time;
begin
if T1 < T2 then -- 可直接使用<操作符
...
end if;
end Time_Example;
三、标识符与保留字
3.1 标识符命名规则
ada
-- 合法标识符
Hello_World
Get_Value
Temperature_2
HTTP_Request -- 连续下划线非法!应为HTTP_Request或Http_Request
-- 非法标识符
2nd_Value -- 数字开头
Get-Value -- 连字符非法(这是减号)
Hello__World -- 连续下划线非法
hello world -- 空格非法
Ada标识符规则:
-
必须以字母开头
-
只能包含字母、数字、下划线
-
不能连续使用两个下划线
-
不能以数字开头
-
不区分大小写 (
Hello与HELLO相同)
3.2 保留字(关键字)
Ada有73个保留字,不可用作标识符:
| 类别 | 保留字 |
|---|---|
| 声明 | procedure , function , package , type , subtype , constant |
| 控制 | if , then , else , elsif , case , when , loop , while , for , exit , return |
| 并发 | task , entry , accept , select , delay , abort |
| 异常 | exception , raise , begin , end |
| 其他 | is , in , out , access , new , null , others |
完整列表见Ada Reference Manual
3.3 命名规范(工业标准)
| 元素 | 规范 | 示例 |
|---|---|---|
| 包/过程/函数 | PascalCase | Ada.Text_IO , Get_Value |
| 变量/常量 | Snake_Case | current_temperature , Max_Size |
| 常量 | 大写 或PascalCase | PI , Buffer_Size |
| 类型/子类型 | PascalCase | Integer , Positive , My_Record |
四、注释与文档
4.1 单行注释
ada
-- 这是单行注释,从--到行尾
X := 10; -- 行尾注释,解释X的初始值
4.2 多行注释(Ada无原生支持)
Ada标准没有 /* */ 风格的多行注释,需每行加 -- :
ada
-- 这是第一段说明
-- 这是第二段说明
-- 这是第三段说明
X := 20;
历史原因:Ada设计于1980年,当时认为多行注释容易导致注释嵌套混乱,且不利于工具处理。
4.3 文档注释(AdaDoc风格)
ada
-- 计算圆的面积
-- 参数:
-- Radius - 圆的半径,必须为正数
-- 返回:
-- 圆的面积
function Circle_Area (Radius : Float) return Float is
begin
return 3.14159 * Radius ** 2;
end Circle_Area;
五、声明部分详解
5.1 可以声明什么?
ada
procedure Declarations is
-- 1. 常量声明
Pi : constant Float := 3.14159;
-- 2. 变量声明
Counter : Integer := 0;
-- 3. 类型声明
type Day is (Mon, Tue, Wed, Thu, Fri, Sat, Sun);
-- 4. 子类型声明
subtype Weekday is Day range Mon .. Fri;
-- 5. 子程序声明(前向声明)
procedure Helper (X : in out Integer);
-- 6. 其他包的使用
package My_IO renames Ada.Text_IO;
begin
-- 执行部分可以使用上述所有声明
Counter := Counter + 1;
Helper (Counter);
end Declarations;
-- 子程序体必须在主单元之后或单独文件中
procedure Helper (X : in out Integer) is
begin
X := X * 2;
end Helper;
__
5.2 声明的顺序规则
重要 :Ada要求先声明后使用!
ada
procedure Order_Matters is
A : Integer := B; -- ERROR! B尚未声明
B : Integer := 10;
begin
null;
end Order_Matters;
正确写法:
ada
procedure Correct_Order is
B : Integer := 10; -- 先声明B
A : Integer := B; -- 再使用B,合法
begin
null;
end Correct_Order;
六、执行部分详解
6.1 语句序列
begin 与 end 之间是语句序列,每条语句以分号结束:
ada
procedure Statements is
begin
-- 过程调用语句
Ada.Text_IO.Put_Line ("First");
-- 赋值语句
X := 10;
-- 控制语句
if X > 5 then
Ada.Text_IO.Put_Line ("Big");
end if;
-- 空语句(合法但无操作)
null;
end Statements;
6.2 语句的终止
| 元素 | 是否需要分号 | 示例 |
|---|---|---|
| 语句 | 必须 | X := 10; |
| 声明 | 必须 | A : Integer; |
end 行 |
必须 | end Hello; |
begin |
不需要 | begin |
loop , if , then 等 |
不需要 | if X > 5 then |
七、完整示例:温度转换器
ada
-- 文件名: temperature_converter.adb
-- 功能:摄氏度与华氏度相互转换
with Ada.Text_IO;
with Ada.Float_Text_IO;
procedure Temperature_Converter is
-- 常量声明
Freezing_C : constant Float := 0.0;
Freezing_F : constant Float := 32.0;
Factor : constant Float := 5.0 / 9.0;
-- 变量声明
Celsius : Float;
Fahrenheit : Float;
begin
-- 摄氏度转华氏度
Celsius := 100.0;
Fahrenheit := Freezing_F + Celsius / Factor;
Ada.Text_IO.Put ("Celsius: ");
Ada.Float_Text_IO.Put (Celsius, Fore => 3, Aft => 1, Exp => 0);
Ada.Text_IO.Put (" => Fahrenheit: ");
Ada.Float_Text_IO.Put (Fahrenheit, Fore => 3, Aft => 1, Exp => 0);
Ada.Text_IO.New_Line;
-- 华氏度转摄氏度
Fahrenheit := 212.0;
Celsius := Factor * (Fahrenheit - Freezing_F);
Ada.Text_IO.Put ("Fahrenheit: ");
Ada.Float_Text_IO.Put (Fahrenheit, Fore => 3, Aft => 1, Exp => 0);
Ada.Text_IO.Put (" => Celsius: ");
Ada.Float_Text_IO.Put (Celsius, Fore => 3, Aft => 1, Exp => 0);
Ada.Text_IO.New_Line;
end Temperature_Converter;
编译运行:
bash
gnatmake temperature_converter.adb
./temperature_converter
输出:
text
Celsius: 100.0 => Fahrenheit: 212.0
Fahrenheit: 212.0 => Celsius: 100.0
八、常见编译错误速查
| 错误信息 | 原因 | 解决 |
|---|---|---|
missing ";" |
语句末尾缺少分号 | 添加 ; |
incorrect use of "with" |
with 子句位置错误 |
移到最开头 |
identifier cannot be use clause name |
use 后直接跟包名,缺少 ; |
with P; use P; |
declaration expected |
声明部分写了执行语句 | 移到 begin 后 |
statement expected |
begin 后写了声明 |
移到 is 与 begin 之间 |
九、本课总结
-
Ada程序由上下文子句、单元头、声明部分、执行部分四部分组成
-
with引入依赖,use简化访问,规范中避免use -
标识符不区分大小写,不能连续下划线,不能以数字开头
-
注释只有
--单行形式,文档化注释需每行加-- -
先声明后使用是铁律 ,声明在
is与begin之间,执行语句在begin与end之间
十、课后练习
1.修正错误:以下代码有3处错误,找出并修正:
ada
procedure Broken is
begin
with Ada.Text_IO;
Ada.Text_IO.Put_Line ("Test")
end broken;
2.规范命名:将以下不规范标识符改为Ada标准形式:
getValue → ?
2nd_item → ?
HTTP__Request → ?
3.扩展程序:修改温度转换器,增加开尔文温度转换(K = C + 273.15)。
4.代码风格 :重写Hello World,使用 use Ada.Text_IO; ,对比可读性差异。
十一、下节预告
第4课|程序结构与编译流程
我们将:
-
理解库单元、子单元、主程序的层级关系
-
掌握
gnatmake的依赖分析原理 -
学习分离编译与分别编译的区别
-
构建第一个多文件Ada项目
关键术语表
上下文子句 :
with和use子句的统称,用于管理单元依赖声明部分 :
is与begin之间的区域,用于定义局部实体执行部分 :
begin与end之间的区域,包含实际执行的语句保留字:Ada语言预定义的关键字,不可用作标识符
前向声明:先声明子程序签名,稍后提供实现的机制
提示警告:本课程内容(包括但不限于文字、图片、音频、视频等)版权归原作者所有,未经授权严禁转载、复制、翻录、传播或以任何方式用于商业用途。本课程仅供个人学习使用,请尊重知识产权,共同维护良好的创作环境。如有疑问或需授权合作,请联系版权方。感谢您的理解与支持!