跳到内容

Pascal 编程/入门

来自维基教科书,开放的书籍,开放的世界

在本章中,你将学习

  • Pascal 源代码文件的结构
  • 基本术语

所有编程任务都需要一个源代码文件,在 Pascal 中称为 program。一个 program 源代码文件由编译器翻译成可执行应用程序,你可以运行它。让我们看看一个最小的 program 源代码文件

program nop;
begin
	{ intentionally empty }
end.
  1. 第一行 program nop; 表示该文件是 Pascal 程序的源代码文件。
  2. beginend 标记一个框架。在接下来的内容中,我们将详细解释这一点。
  3. { intentionally empty } 是一个 注释。注释将被编译器忽略,因此不会以任何方式影响可执行程序的外观或行为。
  4. 最后一个点 . 在最后一个 end 后告诉编译器程序源代码文件的结束位置。
Note 如果你觉得这本书的节奏让你难以理解,维基教科书 编程基础 可能更适合你。

为了启动你的程序,你需要编译它。

首先,复制上面显示的程序。我们建议你实际输入这些示例,而不是复制粘贴代码。将文件命名为 nop.pasnop 是程序的名称,文件扩展名 .pas 帮助你识别 源代码 文件。

完成后,告诉编译器你已经选择编译程序了

如果你使用的是 FPC,在控制台中输入 fpc,后跟一个指向源代码文件的(相对或绝对)文件名路径
FPC 输入:
fpc nop.pas
结果
Target OS: Linux for x86-64
Compiling nop.pas
Linking nop
4 lines compiled, 0.1 sec
如果没有输入错误,成功的编译看起来像这样(一些数据可能会有所不同)。在当前目录中,将会有一个名为 nop 的新文件。这是你可以启动的可执行程序。


如果你使用的是 GPC,在控制台中输入 gpc,后跟一个指向源代码文件的(相对或绝对)文件名路径
GPC 输入:
gpc nop.pas
结果
如果没有输入错误,gpc 不会报告任何错误,但将会有一个(默认情况下)名为 a.out 的新文件。


最后,你可以通过你的 OS 提供的其中一种方法来执行程序。例如,在控制台中,你只需输入可执行文件的名称:./nop(其中 ./ 指的是 Unix 类环境中的当前工作目录)。由于此程序(有意地)没有做任何事情,你不会注意到任何(明显的)变化。毕竟,程序名称 nop无操作 的缩写。

Note 程序需要为每个平台编译。 平台 指的是 OSOS 版本以及使用的微处理器体系结构和制造。只有当所有这些指标都匹配时,你才能将可执行文件复制到另一台计算机并运行它。否则,它可能会失败。现代 OSs 可以阻止你运行不兼容的程序(在一定程度上)。

计算机说话

[编辑 | 编辑源代码]

恭喜你编写了第一个 Pascal 程序!公平地说,这个程序没什么用处,对吧?作为一个小步骤,让我们让计算机说话(比喻地)并向世界介绍自己

program helloWorld(output);
begin
	writeLn('Hello world!');
end.

程序头

[编辑 | 编辑源代码]

你会注意到第一个区别在第一行。不仅程序名称发生了变化,而且还有 (output)。这是一个程序 参数。实际上,它是一个列表。在这里,它只包含一项,但一般形式是 (a, b, c, d, e, ) 等等。程序参数指定了 OS 需要向程序提供的一个外部实体,以便程序能够按预期运行。我们将在后面详细介绍,但现在我们需要知道有两个 特殊 程序参数:inputoutput。这些参数象征着与 OS 交互的默认方式。通常,如果你在控制台中运行程序,output 是控制台的显示。

写入控制台

[编辑 | 编辑源代码]

下一个区别是 writeLn('Hello world!')。这是一个语句。语句是一个例程调用。例程名为 writeLnWriteLn 有(可选)参数。参数是,同样,以逗号分隔的列表,用括号括起来。

例程

[edit | edit source]

例程是可重用的代码片段,可以反复使用。例程 writeLn,缩写为 write line,将所有提供的参数写入目标,然后是一个“换行符”(一些使光标移动到下一行的魔法)。然而,这里目标是不可见的。这是因为它是可选的,可以省略。如果省略,目标将变为 output,因此我们的控制台输出。如果我们想要明确命名目标,我们必须写 writeLn(output, 'Hello world!')WriteLn(output, 'Hello world!')writeLn('Hello world!')完全相同的。缺少的可选参数将自动插入,但它减轻了程序员的输入负担。

为了使用一个例程,我们写它的名称,作为一个语句,后面跟着参数列表。我们在上面第 2 行做了这件事。

Note 例程需要在使用之前定义。

然而,例程 writeLn 作为 Pascal 语言的组成部分被定义。在接下来的章节中,我们将学习定义我们自己的例程。

字符串字面量

[edit | edit source]

参数 'Hello world!' 是一个所谓的字符串字面量。字面量意味着,你的程序将按原样使用这个字符序列,不会以任何方式解释它,并将它传递给例程。一个 string 字面量由打字机(直线)撇号分隔。

保留字

[edit | edit source]

与之相反,单词 programbeginend(以及你在代码示例中以粗体显示的许多其他单词)是所谓的保留字。它们传达了关于如何解释和构建可执行程序的特殊含义。你只能在特定的地方写它们。

Note 但是,你可以string 字面量 'program'。字符串分隔符“禁用”了解释。

行为

[edit | edit source]
现在,我们知道源代码包含什么,创建一个新的文件 helloWorld.pas,复制源代码(通过手动输入),编译并运行它

代码:

program helloWorld(output);
begin
	writeLn('Hello world!');
end.

输出:

Hello world!
程序将在控制台上打印 Hello world!没有直引号,在一个单独的行上。这不是很棒吗?
“救命!我只看到终端窗口打开又关闭!”
在这种情况下,试试这个程序
program helloWorld(input, output);
begin
	writeLn('Hello world!');
	readLn();
end.
更改的行已突出显示。额外的 readLn() 将使你的程序停顿,因此程序不被认为是完成的。在你按下 ↵ Enter 后,终端窗口应该再次关闭。

顺便说一下,这种类型的程序是“Hello world”程序类别的一个例子。它们用于演示任何编程语言的源代码文件需要满足的最低要求。更多示例请参见 WikiBook“计算机编程”中的 Hello world(并欣赏 Pascal 与其他编程语言相比的简单性)。

注释

[edit | edit source]

我们已经看到了写注释的选项。注释的目的是作为程序员的提醒。

注释语法

[edit | edit source]

Pascal 将大括号定义为注释分隔符:{ comment }(空格用于视觉引导,没有意义)。左大括号打开开始注释,右大括号关闭注释。

Note 在注释“内部”,你不能使用注释结束符作为文本的一部分。第一个出现的正确结束符将是注释的结束。

然而,当 Pascal 被开发时,并非所有计算机系统都拥有键盘上的大括号。因此,使用括号和星号的双字母组合也变得合法:(* comment *)

这样的注释被称为块注释。它们可以跨越多行。Delphi 引入了另一种注释风格,行注释。它们以两个斜杠 // 开始,包含当前行结束之前的所有内容。

Delphi、FPC 以及 GPC 都支持所有三种注释风格。

有用的注释

[edit | edit source]

好的注释是一种“艺术”。

注释应该解释不明显的信息
program nop;
begin
	{ intentionally empty }
end.


写注释时,坚持使用一种自然语言。在接下来的章节中,你将看到许多“好的”注释(除非它们清楚地展示了以下内容)。

术语

[edit | edit source]

熟悉以下术语(即右侧以注释形式打印的术语)

program demo(input, output);     // program header
                                 // ───────────────────────────────────┐
const                            // ────────────────────┐              │
  answer = 42;                   // constant definition ┝ const-section│
                                 // ────────────────────┘              │
type                             // ────────────────────┐              │
  employee = record              // ─┐                  │              │
      number: integer;           //  │                  │              │
      firstName: string;         //  ┝ type definition  │              │
      lastName: string;          //  │                  ┝ type-section │
    end;                         // ─┘                  │              │
                                 //                     │              │
  employeeReference = ^employee; // another type def.   │              │
                                 // ────────────────────┘              ┝ block
                                 //                                    │
var                              // ────────────────────┐              │
  boss: employeeReference;       // variable declaration┝ var-section  │
                                 // ────────────────────┘              │
                                 //                                    │
begin                            // ────────────────────┐              │
  boss := nil;                   // statement           │              │
  writeLn('No boss yet.');       // another statement   ┝ sequence     │
  readLn();                      // another statement   │              │
end.                             // ────────────────────┘              │
                                 // ───────────────────────────────────┘

请注意,每个常量和类型定义,以及每个变量声明都进入专门的部分。保留字 consttypevar 充当标题。

一个序列也称为复合语句。定义、声明和序列的组合称为。定义和声明是可选的,但序列是必需的。序列可以为空,正如我们在上面已经证明的那样,但这通常不是这种情况。

不用担心,定义声明之间的区别将在后面解释。现在你应该知道和认识

注释可以包含注释吗?尝试编写一个测试程序来找出答案!混合使用各种注释分隔符,看看混合使用它们会发生什么。
是/否。虽然你可以在注释内部开始另一个注释,但终止字符将标记注释的结束。以下情况不会造成问题
program commentDemo;
begin
	{ (* Hello { { { }
	(* (* { (* Foo }
	{ (* Bar *)

第一个注释结束字符标记整个注释的结束,无论它以{还是(*开头。这意味着,这里编译器会报错

	{ start (* again? } *)

行注释不受此影响,因为它们没有显式的结束分隔符。这将编译通过,不会报错

	// *) } { (*
end.
是/否。虽然你可以在注释内部开始另一个注释,但终止字符将标记注释的结束。以下情况不会造成问题
program commentDemo;
begin
	{ (* Hello { { { }
	(* (* { (* Foo }
	{ (* Bar *)

第一个注释结束字符标记整个注释的结束,无论它以{还是(*开头。这意味着,这里编译器会报错

	{ start (* again? } *)

行注释不受此影响,因为它们没有显式的结束分隔符。这将编译通过,不会报错

	// *) } { (*
end.


writeLn(注意缺少参数列表)的作用是什么?
WriteLn在没有提供任何参数的情况下,会将一个空行打印到默认目标,即output
WriteLn在没有提供任何参数的情况下,会将一个空行打印到默认目标,即output


编写一个program,演示这一点(或类似的功能)
     ####     ####
   ######## ########
  ##     #####     ##
  ##       #       ##
  ##      ILY      ##
   ##   sweetie   ##
    ###         ###
      ###     ###
        ### ###
          ###
           #
一个可接受的实现可能如下所示
program valentine(output);
begin
	writeLn('     ####     ####');
	writeLn('   ######## ########');
	writeLn('  ##     #####     ##');
	writeLn('  ##       #       ##');
	writeLn('  ##      ILY      ##');
	writeLn('   ##   sweetie   ##');
	writeLn('    ###         ###');
	writeLn('      ###     ###');
	writeLn('        ### ###');
	writeLn('          ###');
	writeLn('           #');
end.

注意,程序参数列表(第一行)只列出了output。注意,虽然代码中的空格数量无关紧要,但它们在字符串文字中很重要。

维基百科上有更多关于ASCII 艺术的信息。
一个可接受的实现可能如下所示
program valentine(output);
begin
	writeLn('     ####     ####');
	writeLn('   ######## ########');
	writeLn('  ##     #####     ##');
	writeLn('  ##       #       ##');
	writeLn('  ##      ILY      ##');
	writeLn('   ##   sweetie   ##');
	writeLn('    ###         ###');
	writeLn('      ###     ###');
	writeLn('        ### ###');
	writeLn('          ###');
	writeLn('           #');
end.

注意,程序参数列表(第一行)只列出了output。注意,虽然代码中的空格数量无关紧要,但它们在字符串文字中很重要。

维基百科上有更多关于ASCII 艺术的信息。
下一页: 变量和常量 | 上一页: 入门
主页: Pascal 编程
华夏公益教科书