本课目标
完成本课后,你将能够:
-
掌握Ada字符集与词法单元的完整规范
-
熟练使用各种数值字面量表示形式
-
正确处理字符串字面量与宽字符类型
-
理解编译指示(Pragma)的基础与高级用法
-
应用分隔符与特殊符号编写规范代码
一、Ada字符集
1.1 基本字符集
Ada 2012定义了两级字符集:
| 级别 | 字符范围 | 用途 |
|---|---|---|
| 基本字符集 | ISO-646(ASCII子集) | 保证所有平台可移植 |
| 完整字符集 | ISO-10646(Unicode) | 扩展标识符与字符串 |
基本字符集包含:
-
大写字母:
A-Z -
小写字母:
a-z -
数字:
0-9 -
特殊字符:
!"#$%&'()*+,-./:;<=>?@[]^_ {|}~ -
空白字符:空格、水平制表符、换行、回车
1.2 扩展标识符字符
GNAT支持Unicode标识符(其他编译器可能不支持):
-- 基本字符集标识符(标准,强烈推荐)
procedure Calculate_Area is ...
-- 扩展标识符(GNAT特定,可移植性差)
procedure 计算面积 is ... -- 中文字符
procedure Εμβαδόν is ... -- 希腊字母
工业建议:生产代码严格使用基本字符集,确保跨平台编译器兼容性。
二、词法单元(Lexical Elements)
Ada源代码被分解为以下词法单元:
源代码 → 分隔符 / 标识符 / 保留字 / 数值字面量 /
字符字面量 / 字符串字面量 / 注释
三、分隔符(Delimiters)
3.1 单字符分隔符
| 符号 | 名称 | 用途 |
|---|---|---|
& | 与号 | 字符串连接 |
' | 撇号 | 字符字面量、属性 |
( ) | 括号 | 分组、参数列表 |
* | 星号 | 乘法、幂运算(**) |
+ | 加号 | 加法、正号 |
, | 逗号 | 分隔列表元素 |
- | 减号 | 减法、负号 |
. | 点号 | 选择组件、小数点 |
/ | 斜杠 | 除法 |
: | 冒号 | 类型标记、case 语句 |
; | 分号 | 语句/声明终止 |
< > | 尖括号 | 关系运算、泛型参数 |
= | 等号 | 相等比较、赋值(:=) |
3.2 双字符分隔符
| 符号 | 名称 | 用途 |
|---|---|---|
=> | 箭头 | case/when关联、参数映射 |
.. | 范围 | 范围运算符(1..10) |
** | 双星号 | 幂运算(2**10 = 1024) |
:= | 赋值 | 变量赋值 |
/= | 不等 | 不等比较 |
>= | 大于等于 | 比较运算 |
<= | 小于等于 | 比较运算 |
<< >> | 标号括号 | goto标号(极少使用) |
<> | 框 | 泛型形参默认、离散范围 |
3.3 分隔符使用示例
-- 各类分隔符综合展示
procedure Delimiter_Demo is
A, B : Integer range 1 .. 100; -- 逗号、范围..
Result : Float;
begin
A := 10;
B := 20;
-- 算术运算符
Result := Float (A + B) * 2.5 / 3.0; -- + * / := ()
-- 比较与逻辑
if A /= B and then Result >= 15.0 then -- /= >= and then
case A is
when 1 .. 5 => Put_Line ("Small"); -- => 箭头
when 6 .. 10 => Put_Line ("Medium"); -- | 隐式or
when others => Put_Line ("Large");
end case;
end if;
-- 字符串连接
Put_Line ("Value: " & Result'Image); -- & 连接, ' 属性
end Delimiter_Demo;
四、数值字面量
4.1 整数字面量
-- 十进制整数
Decimal : constant := 1234;
Negative : constant := -5678;
-- 下划线增强可读性(编译器忽略)
Million : constant := 1_000_000;
Hex_Mask : constant := 16#FF_FF_FF_FF#; -- 十六进制,见下文
4.2 基数值(基于的整数)
Ada支持2-16任意进制的整数表示:
-- 语法:基#数字# [指数]
-- 基范围:2 .. 16
Binary : constant := 2#1111_0000#; -- 240
Octal : constant := 8#377#; -- 255
Hexadecimal : constant := 16#FF#; -- 255
Base_7 : constant := 7#666#; -- 7^3 - 1 = 342
-- 带指数的基数值
Mega : constant := 10#1#E6; -- 1 * 10^6 = 1_000_000
Kibi : constant := 2#1#E10; -- 1 * 2^10 = 1024
基数值规则:
| 基数 | 允许数字 | 示例 |
|---|---|---|
| 2 | 0-1 | 2#1010# = 10 |
| 8 | 0-7 | 8#77# = 63 |
| 10 | 0-9 | 10#255# = 255 |
| 16 | 0-9, A-F | 16#FF# = 255 |
| N (2–16) | 0 到 N-1 | 12#BB# = 11×12 + 11 = 143 |
4.3 实数字面量
-- 十进制实数(必须有小数点)
Pi_Approx : constant := 3.14159;
Negative : constant := -0.001;
-- 科学计数法
Avogadro : constant := 6.022_140_76E23; -- 6.022... × 10^23
Tiny : constant := 1.0E-10;
-- 基数值实数(基数#尾数#E指数)
Hex_Float : constant := 16#1.FFFF#E2; -- 1.FFFF(16) × 16^2
实数字面量规则:
-
必须包含小数点或指数(或两者)
-
1.和.5都是合法的(但.5可读性较差,推荐0.5)
4.4 数值字面量类型
数值字面量本身无类型,根据上下文确定:
X : Integer := 100; -- 字面量100解释为Integer
Y : Float := 100.0; -- 字面量100.0解释为Float
Z : Duration := 100.0; -- 字面量100.0解释为Duration
-- 显式限定(Qualified Expression)
A := Integer'(100); -- 明确指定为Integer
B := Float'(100); -- 将整数字面量转为Float
五、字符与字符串字面量
5.1 字符字面量
-- 单引号包围单个字符
A : Character := 'A';
Digit : Character := '0';
Space : Character := ' ';
Newline : Character := ASCII.LF; -- 控制字符使用ASCII包
转义序列(GNAT支持):
| 序列 | 含义 |
|---|---|
ASCII.NUL | 空字符 |
ASCII.BEL | 响铃 |
ASCII.BS | 退格 |
ASCII.HT | 水平制表 |
ASCII.LF | 换行 |
ASCII.CR | 回车 |
ASCII.ESC | 退出 |
5.2 字符串字面量
-- 双引号包围
Message : String := "Hello, Ada!";
-- 连接长字符串
Long_Msg : constant String :=
"This is a very long message " &
"that spans multiple lines " &
"using the concatenation operator.";
-- 包含引号的字符串
Quote : String := "She said ""Hello"" to me."; -- 双引号转义
5.3 宽字符与宽字符串
Ada支持16位(Wide)和32位(Wide_Wide)字符:
-- Wide_Character(16位,UTF-16)
W_Char : Wide_Character := '中'; -- 中文字符
-- Wide_String
W_String : Wide_String := "Hello 世界";
-- Wide_Wide_Character(32位,完整Unicode)
WW_Char : Wide_Wide_Character := '囍'; -- Emoji
-- 类型转换
S : String := To_String (W_String); -- 可能丢失信息
输出宽字符串:
with Ada.Wide_Text_IO;
procedure Wide_Demo is
Msg : Wide_String := "Hello 世界";
begin
Ada.Wide_Text_IO.Put_Line (Msg);
end Wide_Demo;
六、编译指示(Pragma)
6.1 Pragma基础
Pragma是向编译器传递特殊指令的语法结构:
pragma 指示名 [(参数)];
常见分类:
| 类别 | 作用 | 示例 |
|---|---|---|
| 配置 | 控制编译行为 | pragma Optimize (Time) |
| 接口 | 外部语言/表示 | pragma Import (C, Func) |
| 任务 | 并发控制 | pragma Priority (10) |
| 程序 | 运行时检查 | pragma Assert (X > 0) |
| 预定义 | 标准定义的指示 | pragma Pure, pragma Preelaborate |
6.2 常用预定义Pragma
优化控制
pragma Optimize (Time); -- 优化执行速度
pragma Optimize (Space); -- 优化代码体积
pragma Optimize (Off); -- 关闭优化(调试用)
pragma Inline (Max); -- 请求内联展开函数Max
pragma No_Inline (Slow); -- 禁止内联函数Slow
运行时检查
pragma Assert (X >= 0, "X must be non-negative"); -- 断言检查
pragma Suppress (Range_Check); -- 关闭范围检查(危险!)
pragma Unsuppress (Range_Check); -- 强制开启范围检查
pragma Debug (Put_Line ("Debug: " & X'Image)); -- 调试代码
程序性质声明
pragma Pure (Math_Utils); -- 纯包:无状态、无副作用
pragma Preelaborate (Config); -- 预 elaborable:启动时初始化
pragma Elaborate_Body (Package_1); -- 强制体elaborate
pragma Convention (C, My_Record); -- 使用C调用约定
pragma Pack (Color_Array); -- 紧凑存储,最小化填充
6.3 配置Pragma(项目级设置)
可在项目文件( .gpr )或配置文件中设置:
-- config.adc 配置文件
pragma Profile (Ravenscar); -- Ravenscar实时配置
pragma Partition_Elaboration_Policy (Sequential);
pragma Detect_Blocking;
pragma Restrictions (
No_Allocators, -- 禁止动态分配
No_Task_Hierarchy, -- 禁止任务层次
No_Protected_Type_Allocators
);
6.4 自定义Pragma(GNAT扩展)
-- 定义自定义Pragma
pragma My_Company_Reviewed (Unit_Name => "Critical_Module");
-- 在代码中使用
pragma My_Company_Reviewed (Unit_Name => "Navigation");
七、特殊语法元素
7.1 标号(极少使用)
procedure Label_Demo is
begin
<<Start>> -- 标号定义
for I in 1 .. 10 loop
if Some_Condition then
goto Start; -- 跳转到标号(避免使用)
end if;
end loop;
end Label_Demo;
警告:
goto在Ada中受限,禁止跳入if、loop、block内部。
7.2 空语句与空声明
procedure Empty_Examples is
begin
null; -- 空语句:语法需要但无操作
declare
-- 空声明部分(合法)
begin
null;
end;
end Empty_Examples;
八、完整示例:配置寄存器操作
------------------------------------------------------------------------------
-- Hardware_Register --
-- --
-- 演示数值字面量与Pragma在嵌入式开发中的应用 --
------------------------------------------------------------------------------
with System;
with System.Storage_Elements;
package Hardware_Register is
pragma Preelaborate;
-- 此包可在启动时初始化
---------------------------------------------------------------------------
-- 寄存器地址定义(使用基数值增强可读性)
---------------------------------------------------------------------------
Base_Address : constant System.Address :=
System'To_Address (16#4000_0000#); -- 外设基地址
GPIO_Offset : constant := 16#1000#; -- GPIO寄存器偏移
TIMER_Offset : constant := 16#2000#; -- 定时器偏移
---------------------------------------------------------------------------
-- 控制寄存器位掩码(二进制字面量直观展示位模式)
---------------------------------------------------------------------------
type Control_Flags is record
Enable : Boolean; -- 位0
Interrupt: Boolean; -- 位1
Mode : Bits_2; -- 位2-3
Reserved : Bits_4; -- 位4-7
end record with Size => 8;
for Control_Flags use record
Enable at 0 range 0 .. 0;
Interrupt at 0 range 1 .. 1;
Mode at 0 range 2 .. 3;
Reserved at 0 range 4 .. 7;
end record;
-- 常用配置常量
CONFIG_ENABLE_INT : constant := 2#0000_0011#; -- 启用+中断
CONFIG_FAST_MODE : constant := 2#0000_1101#; -- 启用+中断+快速模式
---------------------------------------------------------------------------
-- 操作子程序
---------------------------------------------------------------------------
procedure Write_Control (Value : in Control_Flags)
with Inline,
Global => (Output => Hardware_Register);
function Read_Status return Control_Flags
with Inline,
Volatile_Function;
private
pragma Volatile (Control_Register);
-- 告诉编译器此变量可能被硬件异步修改
Control_Register : Control_Flags
with Address => System'To_Address (16#4000_1000#),
Import;
end Hardware_Register;
九、本课总结
-
基本字符集保证可移植,扩展Unicode标识符慎用
-
分隔符包括单字符(
+-*等)和双字符(=>..:=等) -
数值字面量支持2-16任意进制,使用
基#值#语法,下划线增强可读性 -
字符串有
String/Wide_String/Wide_Wide_String三级,支持UTF-16/32 -
Pragma向编译器传递指令,涵盖优化、检查、接口、任务等多领域
十、课后练习
1.进制转换:将以下数值转为Ada字面量:
-
二进制
10110101(十进制181) -
十六进制
DEADBEEF -
8兆字节(8 × 1024 × 1024)
2.Pragma应用:为前几课的 Math_Utils 包添加 pragma Pure 和 pragma Inline 。
3.宽字符实践:编写程序输出"Hello 囍 Ada 世界",正确处理Emoji。
4.寄存器定义:使用基数值定义一个32位状态寄存器,包含使能位、错误位、模式字段(2位)。
5.代码审查:找出以下代码中的词法错误:
X := 16#GG#; -- ?
Y := 2#1012#; -- ?
Z := 1.0E; -- ?
十一、下节预告
第8课|数据类型概述
我们将:
-
理解Ada类型系统的哲学:强类型与类型安全
-
学习标量类型与复合类型的分类体系
-
掌握类型声明、子类型、派生类型的区别
-
建立Ada类型系统的整体认知框架
关键术语表
词法单元:源代码分解的最小有意义单元(标识符、字面量、分隔符等)
基数值:任意进制(2-16)表示的整数,语法为
基#数字#Pragma:向编译器传递特殊指令的语法结构
Wide_String:16位字符字符串,支持UTF-16编码
Elaborate:Ada的初始化阶段,包体和任务的启动执行
提示警告:本课程内容(包括但不限于文字、图片、音频、视频等)版权归原作者所有,未经授权严禁转载、复制、翻录、传播或以任何方式用于商业用途。本课程仅供个人学习使用,请尊重知识产权,共同维护良好的创作环境。如有疑问或需授权合作,请联系版权方。感谢您的理解与支持!