PL/I
范例 | 程序性,命令性,结构化 |
---|---|
设计 | IBM ,共享语言发展委员会和ISO |
首先出现 | 1964 |
网站 | www.ibm.com/products/pli-compiler-zos |
方言 | |
参见方言 | |
被影响 | |
COBOL , FORTRAN , ALGOL 60 | |
受影响 | |
控制语言, PL/M , PL/S , PL-6 , PL/8 , REXX | |
|
pl/i (编程语言一,发音为有时书面pl/1 )是一种最初由IBM开发的程序性计算机编程语言。它是为科学,工程,业务和系统编程而设计的。自1960年代推出以来,它一直在学术,商业和工业组织不断使用。
PL/1 ANSI标准X3.53-1976于1976年出版。
PL/I的主要领域是数据处理,数值计算,科学计算和系统编程。它支持递归,结构化编程,链接的数据结构处理,固定点,浮点,复杂,字符串处理和位字符串处理。语言语法类似于英语,适合描述具有广泛的功能来验证和操纵它们的复杂数据格式。
早期历史
在1950年代和1960年代初,使用不同的编程语言为不同的计算机硬件编程的业务和科学用户。企业用户正在通过COMTRAN从自动编码器转移到COBOL ,而科学用户则在Fortran , Algol , George等编程中进行了编程。 IBM System/360 (于1964年宣布并于1966年宣布)是针对两组用户的通用机器架构,取代了所有现有的IBM架构。同样,IBM想要所有用户的单一编程语言。它希望可以扩展Fortran以包括商业程序员所需的功能。 1963年10月,成立了一个委员会,最初由纽约的三个IBMER组成,三名共享成员IBM Scientific用户小组将这些扩展为Fortran。鉴于Fortran的限制,他们无法做到这一点,并开始基于Algol标记为NPL的新编程语言的设计。该首字母缩写与英国国家物理实验室的缩写相矛盾,并由MPPL (多功能编程语言)简要替代,并于1965年与PL/I (带有罗马数字“ I”)。第一个定义出现在1964年4月。
IBM将NPL作为起点,并将设计完成到可以编写的第一个编译器的级别:NPL定义在范围和详细范围内是不完整的。 PL/I语言的控制最初是归属于纽约节目中心的,后来又归于Hursley的IBM英国实验室。共享和指南用户组参与了扩展语言,并在IBM通过其PL/I项目控制该语言的过程中发挥了作用。定义如此大语言的经验表明需要对PL/I进行正式定义。 1967年在IBM实验室维也纳建立了一个项目,以制定明确而完整的规范。这又导致了第一个大规模开发方法之一, VDM 。
弗雷德·布鲁克斯(Fred Brooks)以确保PL/I具有字符数据类型而被认为。
该语言首先是在1965年在纽约撰写的“ PL/I语言规格”手册中详细指定的,并取代了“ PL/I语言规格。GY33-6003”,由Hursley于1967年撰写。 IBM在六十年代末和七十年代初继续开发PL/I,并在GY33-6003手册中发布。这些手册是由Multics Group和其他早期实施者使用的。
第一个编译器于1966年交付。PL/I的标准于1976年获得批准。
目标和原则
PL/I的目标在语言的早期开发过程中得到了发展。需要使用COBOL的记录处理和报告写作的竞争力。该语言的实用性范围越来越多,包括系统编程和事件驱动的编程。 PL/I的其他目标是:
为了实现这些目标,PL/I从当代语言中藉了想法,同时添加了实质性的新功能,并以独特的简洁和可读性的语法进行铸造。许多原则和能力共同使语言具有特征,并且在满足语言的目标方面很重要:
- 块结构,具有基本语义(包括递归),类似于Algol 60 。参数是使用逐个引用的呼叫传递的,在需要的地方使用虚拟变量(按值调用)。
- 广泛的计算数据类型,程序控制数据类型以及数据结构的形式(强键入)。
- 阵列和字符串的动态范围,并通过过程参数继承扩展。
- 简洁的语法,用于表达式,声明和陈述,并带有允许的缩写。适用于60个字形的字符集,可置于48个字形。
- 语句,选项和声明中默认的广泛结构,以隐藏一些复杂性并促进语言,同时最大程度地减少击键。
- 强大的迭代处理以及对结构化编程的良好支持。
- 没有保留的单词(尽管功能名称
DATE
和TIME
最初被证明是不可能实现这一目标的)。可以将新属性,语句和语句选项添加到PL/I中,而无需使现有程序无效。甚至不IF, THEN, ELSE
, 和DO
被保留。 - 正交性:每个能力都独立于其他能力,并与其他有意义的其他功能自由结合。每个能力都可以在有意义的所有情况下可用,以尽可能广泛地利用它并避免“任意限制”。正交性有助于使语言“大”。
- 在运行时控制和拦截异常条件的例外处理功能。
- 程序分为单独的编译部分,其中包含广泛的编译时间设施(又称宏),而不是标准的一部分,用于裁缝和组合源代码的各部分。外部名称将单独编译的过程绑定到一个程序中。
- 调试设施集成到该语言中。
语言摘要
该语言被设计为所有程序员的万物。摘要是从ANSI PL/I标准和ANSI PL/I通用子集标准中提取的。
一个PL/I程序由一组过程组成,每个程序都写为一系列语句。这%INCLUDE
构造用于在程序翻译过程中包括来自其他来源的文本。所有语句类型都在此处汇总在分组中,这些分组概述了该语言(标准使用本组织)。
类别 | 陈述 |
---|---|
结构 | PROCEDURE (或者PROC )ENTRY BEGIN DO END |
声明性 | DECLARE (或者DCL )DEFAULT (或者DFT )FORMAT |
控制流 | CALL IF SELECT GO TO RETURN STOP null语句 |
类别 | 陈述 |
---|---|
中断处理 | ON SIGNAL REVERT |
贮存 | ALLOCATE (或者ALLOC )FREE 分配声明 |
输入输出 | OPEN CLOSE |
流输入/输出 | GET PUT |
记录输入/输出 | READ WRITE REWRITE LOCATE DELETE |
(诸如多任务和PL/I预处理器之类的功能不在标准中,而是在PL/中支持编译器和语言演化部分中讨论其他一些实现的功能。)
可以声明名称表示以下类型的数据,或以阵列的形式为汇总,每个维度的较低和上限或结构(包括嵌套结构,阵列和标量变量) :
|
|
|
这arithmetic
类型包括以下属性:
|
基础,规模,精度和比例因子Picture-for-arithmetic
类型在picture-specification
。该模式分别指定picture specification
应用于真实和虚构部分。
值是由使用特定的操作和内置功能编写的表达式计算的,其中大多数可以应用于聚集体以及单个值,以及用户定义的过程,同样可以操作并返回聚合以及单个值。分配语句将值分配给一个或多个变量。
pl/i中没有保留的单词。声明由半彩色终止。语句的最大长度是定义的。评论可能会出现在允许空间的程序中的任何地方,并在字符前向前斜线,星号,并由字符星号,前向斜杠终止(即/* This is a comment. */
)。语句可能具有介绍条目名称的标签前缀(ENTRY
和PROCEDURE
语句)或标签名称,以及启用或禁用计算条件的条件前缀 - 例如(NOSIZE)
)。输入和标签名称可能是单个标识符或标识符,后面是常数的下标(如L(12,2):A=0;
).
在先进之前,一系列陈述变为一组DO
声明,然后是END
陈述。组可能包括嵌套组并开始块。这IF
语句将组或单个语句指定为THEN
零件和ELSE
零件(请参阅示例程序)。该小组是迭代单位。开始块(BEGIN; stmt-list END;
)可以包含该块本地本地名称和内部程序的声明。一个过程以一个PROCEDURE
声明,并由句法终止END
陈述。过程的正文是一系列块,组和语句,并包含该过程本地名称和过程的声明或EXTERNAL
到程序。
单个单位是一个或多个这些条件发生时,单个单位或书面的语句块:
计算条件,
|
|
|
或输入/输出条件,
|
|
或其中一个条件:
AREA
,CONDITION (identifier)
,ERROR
,FINISH
标识符的声明可能包含以下一个或多个属性(但需要相互一致):
数据属性 | 输入/输出属性 | 其他属性 |
---|---|---|
ALIGNED | DIRECT | AUTOMATIC or AUTO |
AREA[(area-size)] | ENVIRONMENT(options) or ENV... | BASED[(reference)] |
BINARY [(precision)] or BIN... | INPUT | BUILTIN |
BIT [(maximum-length)] | KEYED | CONDITION or COND |
CHARACTER[(maximum-length)] or CHAR... | OUTPUT | CONSTANT |
COMPLEX [(precision)] or CPLX... | PRINT | CONTROLLED or CTL |
DECIMAL [(precision)] or DEC... | SEQUENTIAL or SEQL | DEFINED[(reference)] or DEF... |
(dimension-attribute) | STREAM | EXTERNAL or EXT |
ENTRY[(parameter descriptor list] | UPDATE | GENERIC(criteria list) |
FILE | RECORD | INITIAL(value-list) or INIT... |
FIXED [(precision)] | INTERNAL or INT | |
FLOAT [(number of digits)] | LIKE unsubscripted reference | |
FORMAT | LOCAL | |
LABEL | OPTIONS(options) | |
MEMBER | PARAMETER or PARM | |
NONVARYING or NONVAR | POSITION [(expression)] or POS... | |
OFFSET[(reference)] | STATIC | |
PICTURE picture-specification or PIC... | VARIABLE | |
POINTER or PTR | ||
STRUCTURE | ||
UNALIGNED or UNAL | ||
VARYING or VAR |
当前来自Micro Focus的编译器,尤其是IBM的编译器,对该语言的标准化版本实现了许多扩展。 IBM扩展程序稍后在编译器的实施子部分中汇总。尽管这些编译器有一些共有的扩展,但缺乏当前标准意味着不能保证兼容性。
标准化
语言标准化始于1966年4月在欧洲, ECMA TC10开始。 1969年, ANSI成立了一个绰号为“ Kludge”的“综合语言发展委员会”,后来更名为X3J1 PL/I。标准化成为ECMA TC/10和ANSI X3J1的共同努力。 IBM向共同努力提供了GY33-6003文件的子集,并成为标准化的基本文件。基本文档省略的主要功能是多任务和程序优化的属性(例如NORMAL
和ABNORMAL
).
两个委员会都对更改基本文件的提议进行了投票。如果委员会不同意,椅子最初是通用汽车的迈克尔·马科蒂(Michael Marcotty),代表ICL的汽车hoare必须解决分歧。除了IBM, Honeywell , CDC , Data General , Digital Equipment Corporation , Prime Compure , Burroughs , RCA和Univac以及主要用户伊斯特曼·柯达(Eastman Kodak) , Miter , Union Carbide , Bell Laboratories以及各种政府和大学代表以及主要用户。该语言的进一步发展发生在标准机构中,并在结构化编程和内部一致性以及遗漏更晦涩或有争议的功能方面持续改进。
随着语言发展的结尾,X3J1/TC10意识到用英语文本编写的文档存在许多问题。对单个项目的讨论可能会出现在可能或可能不同意的多个地方。很难确定是否存在遗漏和不一致之处。因此,戴维·比奇(IBM),罗伯特·弗雷伯格豪斯(Robert Freiburghouse(Honeywell),米尔顿·巴伯(CDC),M。DonaldMaclaren( Argonne National Laboratory ),Craig Franklin(数据将军) ,Lois Frampton(数字设备公司)和编辑DJ Andrews,DJ Andrews,DJ Andrews IBM进行了重写整个文档,每个文档都产生一个或多个完整的章节。该标准是使用“ PL/I Machine”来指定语义的正式定义。这是第一个编写为半正式定义的编程语言标准。
ANSI于1981年发布了“ PL/I通用子集”(“子集-G”)标准,并于1987年发布了修订。通用子集被广泛采用为PL/I实施的内核。
实施
IBM PL/IF和D编译器
PL/I首先是由IBM在其英国的Hursley Laboratories中实施的,作为System/360开发的一部分。第一个制作PL/I编译器是由John Nash在英国Hursley的团队建造的OS/360操作系统的IF/IF编译器:运行时图书馆团队由IM(Nobby)Clarke管理。 PL/如果编译器完全用System/360汇编语言编写。版本1在1966年发货。OS/360是一个真实的环境,编译器是针对具有64千座真实存储的系统设计的 - f为64 kb,S/360词典。为了将大型编译器安装到64千射流机上可用的44千字节内存中,该编译器由控制阶段和大量编译器阶段组成(接近100)。这些阶段一次从一个磁盘中进入记忆,一次是处理特定的语言特征和编译方面。每个阶段都会通过部分编译的程序进行一次通过,通常保存在内存中。
该语言的各个方面仍被设计为PL/如果实现了,则省略了一些语言,直到后来发行。 pl/i记录I/O已使用PL/IF/IF版本2。清单处理功能 - 基于变量,指示器,区域和偏移以及定位模式I/O-首先在版本4中发货。 UP PL/I代码与Fortran对象代码竞争,请使用PL/如果Release 5确实对Re-Re-Reops进行了实质性的程序优化,则可以在程序上促进。
PL/IF的版本是在系统/360型67的TSS/360分时操作系统上发布的,该操作系统适用于IBM Mohansic Lab。法国的IBM La Gaude Lab开发了“语言转换程序”,以将Fortran,Cobol和Algol程序转换为PL/IF PL/I级别。
PL/ID编译器使用16千元的内存,由IBM德国为DOS/360低端操作系统开发。它实现了PL/I语言的子集,需要所有字符串和数组才能具有固定的范围,从而简化了运行时的环境。反映基础操作系统,它缺乏动态存储分配和受控存储类。它在PL/I F的一年内发货。
Multics PL/I和衍生物
编译器在1960年代初由几个小组实施。 MIT的Multics项目是最早以高级语言开发操作系统的项目之一,使用了PL/I的subset方言,作为1964年的实施语言。贝尔实验室和麻省理工学院,道格拉斯·麦克罗伊,罗伯特·莫里斯等。最初,它是使用TMG编译器编译器开发的。有影响力的多技术PL/I编译器是许多制造商和软件组使用的编译器技术的来源。 EPL是一种系统编程语言,是PL/I的方言,在原始PL/I中没有某些功能。
Honeywell PL/I编译器(用于系列60)是完整的ANSI X3J1标准的实现。
IBM PL/I优化和结帐编译器
Hursley生产的PL/I优化器和结帐编译器支持PL/I语言的共同水平,并旨在替换PL/IF/IF编译器。结帐编译器是PL的重写/如果在BSL中,IBM的PL/I类专有实施语言(后来的PL/S )。为编译器设定的性能目标显示在BCS的IBM演示文稿中。编译器必须产生相同的结果 - 结帐编译器用于调试程序,然后将其提交给优化器。鉴于编译器具有完全不同的设计,并且正在处理完整的PL/I语言,这一目标是具有挑战性的:实现了这一目标。
IBM介绍了新属性和语法,包括内置的属性,案例语句( select / wher /否则),循环控件(迭代和离开)以及null参数列表以删除歧义,例如,date () 。
PL/I优化的编译器从PL/IF编译器接管,并且是IBM从1970年代到1990年代的IBM的工作马编译器。像PL/IF一样,它是一个具有44千键设计点的多次通行证编译器,但它是一个全新的设计。与F编译器不同,它必须使用运行时库对恒定表达式进行编译时间评估,从而将编译器阶段的最大存储器减少到28千字节。第二次围绕设计,它成功地消除了PL的烦恼。它是由托尼·伯布里奇(Tony Burbridge)领导的团队用S/360宏汇编程序编写的,其中大多数人都在PL/I F.宏(PL/I F.)工作。模式存储,允许编译器轻松移动到其他内存模型。为当代IBM Fortran H编译器开发的程序优化技术的范围是部署的:优化器在优秀程序员手中等于Fortran的执行速度。 1970年在IBM S/370宣布,它于1971年8月首次为DOS/360操作系统发货,此后不久为OS/360,以及第一个虚拟内存IBM操作系统OS/VS1 , MVS和VM/CMS 。 (开发人员不知道,当他们将代码分为28 kb部分时,IBM Poughkeepsie终于准备在OS/360中运送虚拟内存支持)。它支持批处理编程环境,在TSO和CMS下,可以进行交互运行。该编译器浏览了许多版本,涵盖了所有大型机器人操作系统,包括日本插头机器(PCM)的操作系统。
在下面,编译器已被“ IBM PL/I for OS/2,AIX,Linux,Z/OS”取代。
PL/I Checkout编译器(通俗地“ Checker”)于1970年8月宣布,旨在加快PL/I程序的调试。球队由布莱恩·马克斯(Brian Marks)领导。三通设计削减了将程序编译为F编译器采用的25%的时间。它可以从交互式终端运行,将PL/I程序转换为内部格式“ H文本”。该格式在运行时由结帐编译器解释,几乎所有类型的错误都检测到。指针在16个字节中表示,其中包含目标地址和引用项目的描述,因此可以诊断出“不良”指针。在检测到错误时,在对话环境中,控制将传递给可以检查任何变量,介绍调试语句并编辑源程序的用户。随着时间的流逝,大型机编程环境的调试功能开发了该编译器提供的大多数功能,并被撤回(在1990年代?)?
dec pl/i
除了IBM's之外,也许是商业上最成功的实施,这是数字设备公司的VAX-11 PL/I,后来被称为VAX PL/I,然后是DEC PL/I。该实现是“严格的ANSI X3.4-1981 PL/I通用子集的超集,并提供了新的ANSI X3.74-1987 PL/I通用供电子集的大部分功能”,并于1980年首次发布。它最初使用由Dave Cutler领导的团队创建的名为VAX Code Generator(VCG)的编译器后端。前端是由Robert Freiburghouse设计的,并从Multics上移植到VAX/VMS 。它在VAX和Alpha上的VM上以及TRU64上运行。在1990年代,Digital将编译器卖给了Uniprise Systems ,后者后来将其卖给了一家名为Kednos的公司。 Kednos将编译器销售为Kednos PL/I,直到2016年10月该公司停止交易。
教授子集编译器
在1960年代末和1970年代初,许多美国和加拿大大学正在校园内建立时间共享服务,并需要对话编译器/口译员用于教学科学,数学,工程和计算机科学。达特茅斯(Dartmouth)正在开发基本,但是pl/i是一个流行的选择,因为它简洁且易于教学。由于IBM产品不合适,因此许多学校建立了自己的PL/I子集及其自己的互动支持。示例是:
在1960年代和1970年代初, Allen-Babcock实施了IBM System/360模型50的共享硬件(RUSH)时间共享系统的远程用户,并随后实现了IBM的CPS ,这是一个用于OS/360的交互式时间共享系统旨在教授计算机科学基础知识,除了基本和远程职位入学设施外,还提供了PL/I语言的有限子集。
PL/C是一种教学方言,是康奈尔大学开发的编译器,具有不寻常的能力,即通过使用广泛的自动校正许多语法错误,并通过将任何剩余的语法错误转换为输出语句,从而从不构成任何程序。该语言几乎是IBM实施的所有PL/I。 PL/C是一个非常快速的编译器。
SL/1 (学生语言/1,学生语言/1或子集语言/1)是PL/I子集,最初可在1960年代末获得,在IBM 1130上进行了解释;教学用途是它的强项。
在布鲁克林理工学院创建的Plago使用了PL/I语言的简化子集,并专注于良好的诊断错误消息和快速汇编时间。
多伦多大学的计算机系统研究小组生产了SP/K编译器,该编译器支持一系列PL/I的子集,称为Sp/1,Sp/2,Sp/3,Sp/3,..., Sp/8用于教学编程。在SP/K编译器下没有错误的程序在其他当代PL/I编译器(例如IBM的PL/If Compiler,IBM的结帐编译器或Cornell University的PL/C Commiter)下产生了相同的结果。
其他例子是新南威尔士大学的P. Shrouse ,马里兰大学的Marvin Victor Zelkowitz的P. Shrouse ,以及多伦多大学的冥王星。
IBM PL/I用于OS/2,AIX,Linux,Z/OS
在PL/I的重大改造中,加利福尼亚州的IBM Santa Teresa于1992年推出了全新的编译器。最初的发货用于OS/2,其中包括大多数ANSI-G功能和许多新的PL/I功能。随后的版本提供了其他平台( MVS , VM , OS/390 , AIX和Windows ),但截至2021年,唯一受支持的平台是Z/OS和AIX。 IBM继续添加功能,以使PL/I完全竞争与其他语言(尤其是C ++)的竞争力。相应的“ IBM语言环境”支持PL/I程序与数据库和事务系统的操作,以及在C,C ++和COBOL中编写的程序,编译器支持与这些语言进行交互所需的所有数据类型。
保留了PL/I设计原理,并经受了这一重大扩展,包括几种新的数据类型,新的语句和语句选项,新的异常条件以及计划来源的新组织。由此产生的语言是PL/I标准和早期IBM编译器的兼容超级集合。 PL/I添加的主要主题是:
- 新属性以更好地支持用户定义的数据类型 -
DEFINE ALIAS
,ORDINAL
, 和DEFINE STRUCTURE
语句介绍用户定义类型,HANDLE
定位器数据类型,TYPE
数据类型本身,UNION
数据类型和用于操纵新类型的内置功能。 - 与常见PC数据类型相对应的其他数据类型和属性(例如
UNSIGNED
,VARYINGZ
). - 程序的可读性提高 - 通常呈现暗示的用法(例如
BYVALUE
参数的属性) - 其他结构化编程结构。
- 中断处理。
- 编译时间预处理器扩展,以提供几乎所有PL/I字符串处理功能,并与应用程序开发环境接口
Z/OS的最新系列PL/I编译器,称为Z/OS的Enterprise PL/I,使用最新Z/Architecture处理器的代码生成(Z14,Z13,ZEC12,ZBC12,ZBC12,Z196,Z114) ArchLVL PARM控制在编译过程中通过,并且是Z/OS语言环境支持的第二个高级语言(XL C/C ++是第一个,而Enterprise Cobol V5则是最后一个。
数据类型
ORDINAL
是一种新的计算数据类型。序数设施就像帕斯卡(Pascal)一样,例如DEFINE ORDINAL Colour (red, yellow, green, blue, violet);
但是此外,可以通过内置功能访问名称和内部值。内置功能提供了对序数价值的前身和继任者的访问。
这DEFINE-statement
(见下文)允许其他TYPE
s要由PL/I的内置属性组成。
这HANDLE(data structure)
定位器数据类型类似于POINTER
数据类型,但强烈键入仅与特定数据结构结合。这=>
操作员用于使用句柄选择数据结构。
这UNION
属性(相当于CELL
在PL/I早期规格中)允许几个标量变量,阵列或结构共享相同的存储空间,该单元占据了最大替代方案所需的存储量。
PC和C的竞争力
添加了这些属性:
- 字符串属性
VARYINGZ
(对于零终止字符字符串),HEXADEC
,WIDECHAR
, 和GRAPHIC
. - 可选算术属性
UNSIGNED
和SIGNED
,BIGENDIAN
和LITTLEENDIAN
.UNSIGNED
需要UPTHRU
和DOWNTHRU
迭代组的选项使得可以执行反对循环而不超过限制值(对于ORDINAL
S,非常适合记录循环)。 - 这
DATE(pattern)
控制日期表示的属性,并增加了时间和日期,以达到最佳当前实践。操纵日期的新功能包括 -DAYS
和DAYSTODATE
用于在日期和天数之间转换,以及一般DATETIME
更改日期格式的功能。
添加了新的字符串处理功能 - 以中心文本,使用图片格式编辑,并从文本的头部或尾部修剪空白或选定字符,VERIFYR
到VERIFY
从右边。和SEARCH
和TALLY
功能。
复合分配运营商l la c eg+=
,&=
,-=
,||=
添加。A+=1
等同于A=A+1
.
为省略的参数和可变长度参数列表添加了其他参数描述符和属性。
程序可读性 - 明确表示意图
这VALUE
属性将标识符声明为常数(源自特定的文字值或受限表达式)。
参数可以具有BYADDR
(通过地址通过)或BYVALUE
(按值通过)属性。
这ASSIGNABLE
和NONASSIGNABLE
属性可以防止意外任务。
DO FOREVER;
消除了对人为构造的需求DO WHILE ( '1'B );
.
这DEFINE-statement
介绍用户指定的名称(例如INTEGER
)用于内置属性的组合(例如FIXED BINARY(31,0)
)。因此DEFINE ALIAS INTEGER FIXED BINARY(31.0)
创建TYPE
姓名INTEGER
作为一组内置属性的别名固定二进制(31.0)。DEFINE STRUCTURE
适用于结构及其成员;它提供了TYPE
一组结构属性和相应的子结构成员声明的名称,用于在结构声明中使用(概括LIKE
属性)。
结构化编程添加
ALEAVE
退出循环的声明,一个ITERATE
继续进行下一个循环的迭代。
UPTHRU
和DOWNTHRU
迭代组的选项。
包装结构由一组程序和声明组成,以用作单位。该程序之外声明的变量是包装本地的,并且可以使用STATIC
,BASED
或者CONTROLLED
贮存。软件包中使用的过程名称也是局部的,但可以通过EXPORTS
选项PACKAGE-statement
.
中断处理
这RESIGNAL-statement
在单个单元中执行终止单位的执行,并在称为当前一个的过程中再次提高条件(从而将控件传递到该过程的相应单位)。
这INVALIDOP
条件处理PC处理器检测到的无效操作代码以及非法算术操作,例如两个无限值的减法。
这ANYCONDITION
提供了截距条件,该条件在当前程序中未提供特定单位的条件。
这STORAGE
当ALLOCATE
声明无法获得足够的存储空间。
其他大型计算机编译器
许多供应商生产了编译器,以与IBM PL/IF/IF/IF/IF竞争,或在1970年代在大型机和微型计算机上优化编译器。在1980年代,目标通常是新兴的ANSI-G子集。
- 1974年, Burroughs Corporation宣布了B6700和B7700的PL/I。
- Univac发布了Univac PL/I,并在1970年代还使用了PL/I,PL/I Plus的变体进行系统编程。
- 从1978年开始,数据将军在其日食和日食MV平台上提供了PL/I,运行AOS , AOS/VS和AOS/VS II操作系统。许多操作系统实用程序以该语言编写。
- 纽约大学库兰特(Courant)数学科学学院的保罗·亚伯拉罕(Paul Abrahams)于1972年在PL/I中写了CIMS PL/I,通过pl/i F进行了引导。它支持“约70%” PL/I汇编为CDC 6600
- CDC为网络70、170和6000系列提供了优化的子集PL/I编译器。
- Fujitsu提供了与PL/I优化器相当的PL/I编译器。
- Stratus Technologies pl/I是VOS操作系统的ANSI G实现。
- IBM系列/1 pl/i是IBM系列/1实时编程系统的ANSI编程语言PL/I(ANSI X3.53-1976)的扩展子集。
Microsoft .NET的PL/I编译器
- 2011年,Rain Code为Microsoft .NET和.NET Core平台设计了一个完整的旧版编译器,名为Rain Code PL/I编译器。
PL/I个人计算机和UNIX的编译器
- 在1970年代和1980年代,数字研究出售了CP/M (PL/I-80), CP/M-86 (PL/I-86)和带有DOS的个人计算机的PL/I编译器。它基于PL/I的子集G,并以PL/M编写。
- Micro Focus实施了从Liant获得的Windows和Unix/Linux系统的开放式PL/I。
- IBM于1994年为OS/2提供了PL/I,并在1995年为AIX提供了PL/I。
- 2007年推出了OS/2的铁弹簧PL/I,后来引入了Linux 。
PL/I方言
- pl/s是PL/I的方言,最初称为BSL的方言是在1960年代后期开发的,并成为IBM大型机的系统编程语言。 1970年代和1980年代,几乎所有IBM大型机器人系统软件都用PL/S编写。它与PL/I不同,因为没有数据类型转换,没有运行时环境,结构的映射不同,并且分配是字节副本。所有字符串和阵列都有固定的范围,或者使用了
REFER
选项。 PL/S由PL/AS,然后由PL/X继承,PL/X是当前用于当前操作系统的内部工作的语言, OS/390 ,现在是Z/OS 。它也用于某些Z/VSE和Z/VM组件。 Z/OS的IBM DB2也以PL/X编写。 - PL/C是PL/I计算机编程语言的教学方言,该语言于1970年代在康奈尔大学开发。
- IBM在System/38和AS/400平台的系统软件中使用了PL/I的两个PL/I PL/I(机器产品)和PL/MI(机器接口)。 PL/MP用于实现这些平台的所谓垂直微码,并针对IMPI指令集。 PL/MI针对这些平台的机器接口,并用于系统/38控制程序设施中,以及OS/400的XPF层。当OS/400移植到IBM RS64处理器家族时,PL/MP代码大多被C ++替换,尽管有些是为PowerPC / Power ISA架构进行了保留和重新定位的。 PL/MI代码未替换,并且在IBM I中仍在使用。
- PL/8 (或PL.8)之所以被称为PL/I的80%,最初是由IBM Research在1970年代针对IBM 801体系结构开发的。后来,它获得了摩托罗拉68000和System/370架构的支持。它继续用于几个IBM内部系统开发任务(例如Z/Architecture Systems的Millicode和固件),并已重新设计以使用基于64位GCC的后端。
- Honeywell,Inc。开发了PL-6用于创建CP-6操作系统。
- Prime Computer使用两个不同的PL/I方言作为Primos操作系统的系统编程语言: PL/P ,从版本18开始,然后从版本19开始。
- XPL是PL/I的方言,用于使用XPL编译器技术编写其他编译器。 XPL在其PL/I的小子集中添加了一个堆字符串数据类型。
- HAL/S是一种实时航空航天编程语言,以其在航天飞机计划中的使用而闻名。它是由Intermetrics在1970年代为NASA设计的。 HAL/S在XPL中实现。
- IBM和各种分包商还在1970年代初开发了另一种PL/I变体,以支持称为SPL/I的海军的信号处理。
- Sabretalk ,PL/I的实时方言用于编程Saber Airline Reservation系统。
用法
PL/I的实施是为1960年代后期的大型机开发的,1970年代的迷你计算机以及1980年代和1990年代的个人计算机。尽管它的主要用途是在大型机上,但仍有用于DOS , Microsoft Windows , OS/2 , AIX , OpenVMS和UNIX的PL/I版本。
它已被广泛用于业务数据处理和系统使用,用于在某些平台上编写操作系统。非常复杂且功能强大的系统是使用PL/I建造的:
- SAS系统最初是用PL/I编写的; SAS数据步骤仍在PL/I语法上建模。
- 开创性的在线航空公司预订系统Saber最初是为IBM 7090编写的。 S/360版本主要使用Sabretalk编写,Sabretalk是专用控制程序的专用子集PL/I编译器。
- Multics操作系统主要用PL/I编写。
- PL/I用于编写可执行的正式定义,以解释IBM的系统网络体系结构。
- OpenVMS操作系统的某些组件最初是用PL/I编写的,但随后在VMS端口中重写为IA64体系结构。
PL/我没有满足其支持者的希望,它将取代Fortran和Cobol并成为大型机上的主要参与者。它仍然是少数人,但重要的球员。对此并不是一个明确的解释,但是1970年代和1980年代的某些趋势通过逐步降低PL/我享有竞争优势的领土而对其成功进行了武装。
首先,大型机软件环境的性质发生了变化。用于数据库和交易处理的应用程序子系统(System 370上的CICS和IMS以及Oracle )和应用程序生成器成为大型机用户应用程序开发的重点。由于需要使用子系统的相应本机特征(例如任务和大部分输入/输出),该语言的重要部分变得无关紧要。在这些应用领域没有使用Fortran,将PL/I限制在Cobol的领土上;大多数用户都留在COBOL。但是,随着PC成为计划开发的主要环境,Fortran,Cobol和PL/I都成为C ++ , Java等所取代的少数族裔语言。
其次,PL/I在系统编程字段中被取代。 IBM系统编程社区还没有准备好使用PL/I;相反,IBM开发并采用了PL/I的专有方言,用于系统编程。 - pl/s 。随着PL/S在IBM内部以及IBM外部C的成功,系统编程的独特PL/I优势变得不那么有价值。
第三,开发环境增强了交互式软件开发的功能,这再次使独特的PL/I交互式和调试优势降低了价值。
第四,将结构化编程,字符串操作和对象方向等功能添加到COBOL和FORTRAN中,从而进一步降低了PL/I的相对优势。
在大型机上,也存在重大业务问题。 IBM的硬件竞争对手几乎没有收获,而从PL/I的成功中损失了很多。编译器开发很昂贵,IBM编译器组具有内置的竞争优势。许多IBM用户希望避免被锁定在专有解决方案中。由于没有其他供应商对PL/I的早期支持,因此最好避免使用PL/I。
PL/I语言的演变
本文使用PL/I标准作为语言功能的参考点。但是,早期实施中的许多显著特征并不是标准。有些是由非IBM编译器提供的。事实上的语言在标准之后继续增长,最终是由个人计算机上的开发驱动的。
标准省略了重要功能
多线程
多线程以“多任务”的名称由PL/IF,PL/I结帐和优化编译器以及较新的AIX和Z/OS编译器实现。它包括数据类型EVENT
和TASK
, 这TASK-option
在CALL-statement
(叉),WAIT-statement
(加入DELAY(delay-time)
,EVENT-option
记录I/O语句和UNLOCK
声明以解锁锁定记录EXCLUSIVE
文件。事件数据确定特定事件,并指示其完成('1'b)还是不完整('0'b):任务数据项标识特定任务(或过程),并指示其相对于其他任务的优先级。
预处理器
第一个IBM编译时间预处理器是由位于马萨诸塞州剑桥市的IBM波士顿高级编程中心构建的,并用PL/IF/IF编译器发货。这%INCLUDE
声明是标准的,但其余功能却没有。 DEC和KEDNOS PL/I编译器与IBM实现了与IBM相同的功能,并进行了一些添加。 IBM继续将预处理器功能添加到其编译器中。预处理器将书面源程序视为一个令牌序列,将其复制到输出源文件或对它们作用。遇到%令牌时,执行以下编译时间语句:遇到标识符令牌并且标识符已DECLARE
D,ACTIVATE
D,并分配了一个编译时间值,标识符被此值替换。如果输出流不需要操作,则将令牌添加到输出流中(例如+
),以及激活的编译时间表达式的值。因此编译时间变量PI
可以使用%PI='3.14159265'
。随后的发生PI
将取代3.14159265
.
支持的数据类型是FIXED DECIMAL
整数和CHARACTER
长度不同,没有最大长度。结构语句是:
%[label-list:]DO iteration: statements; %[label-list:]END;
%procedure-name: PROCEDURE (parameter list) RETURNS (type); statements...;
%[label-list:]END;
%[label-list:]IF...%THEN...%ELSE..
和简单的语句,也可能具有[标签列表:]
%ACTIVATE(identifier-list) and %DEACTIVATE
assignment
陈述%DECLARE identifier-attribute-list
%GO TO label
%INCLUDE
null
陈述
该功能使程序员可以使用标识符对常数(例如产品零件号或数学常数)使用标识符,并用标准用命名常数用于计算数据中的标准。该标准不支持有条件的编译和迭代生成源代码,该源代码可能具有编译时间设施。几家制造商实施了这些设施。
结构化编程添加
在标准化期间,对PL/I进行了结构化编程,但未被接受。这些功能是LEAVE-statement
退出迭代DO
, 这UNTIL-option
和REPEAT-option
添加到DO
,以及一般形式的案例声明:SELECT (expression) {WHEN (expression) group}... OTHERWISE group
这些功能都包含在IBM的PL/I结帐和优化编译器以及DEC PL/I中。
调试设施
PL/如果提供了一些未提出标准的调试设施,而是由其他标准实施的 - 尤其是支票(可变列表)条件前缀,CHECK
条件和SNAP
选项。 IBM优化和结帐编译器添加了适合对话大型机编程环境的其他功能(例如ATTENTION
状态).
自标准以来就开发了重要的功能
已经尝试了一些尝试设计一种可能具有几种数据类型之一的结构成员类型(CELL
在IBM早期)。随着编程理论课程的增长,在PL/I基础上进行了这种方法 -UNION
,TYPE
等等是由几个编译器添加的。
pl/i曾在单字节角色世界中受孕。随着对日语和中文的支持以及国际代码页面上的发展,角色字符串概念得到了扩展,以适应广泛的非ASCII/EBCDIC字符串。
大修了时间和日期处理以处理千年问题,并引入了DateTime功能,该功能以约35种不同格式之一返回日期和时间。其他几个日期的功能涉及到几天和秒的转换。
批评
实施问题
尽管该语言易于学习和使用,但是实施PL/I编译器却很困难且耗时。与PL/I一样大的语言需要大多数供应商可以生产的子集和大多数用户的主体。直到发布“ ANSI G”才能解决。 PL/I独有的编译时间设施采用了增加的实施工作和其他编译器通行证。 PL/I编译器的大小是可比的Fortran或COBOL编译器的两倍,并且速度也较慢,因此被程序员生产率的提高所抵消。在第一批编译器撰写之前,IBM预计这是预期的。
有人认为PL/I很难解析。 PL/I关键字不是保留的,因此程序员可以将其用作程序中的变量或过程名称。因为原始的PL/I(F)编译器在遇到不正确上下文中使用的关键字时会尝试自动校正,因此通常假设它是可变名称。这导致了“级联诊断”,这是后来的编译器解决的问题。
在语言的初始设计中,可能会低估生产良好对象代码所需的努力。程序优化(与可用的fortran编译器进行的优秀程序优化所需的竞争)非常复杂,这是由于变量的副作用和普遍性问题。在异常处理程序中可能会异步进行不可预测的修改,这可以由(看不见的)呼叫者中的“语句”提供。在一起,这些使得很难可靠地预测程序的变量何时可以在运行时进行修改。但是,在典型的使用中,用户写入的错误处理程序(ON-unit
)通常不会对变量进行作业。尽管存在上述困难,但IBM还是在1971年产生了PL/I优化编译器。
pl/i包含许多罕见使用的功能,例如多任务支持(语言的IBM扩展),这些功能增加了编译器的成本和复杂性,其协调设施需要一个多编程的环境,并具有对非块多线程的支持用于操作系统的过程。编译器作家可以自由选择是否实现这些功能。
默认情况下,一个未申报的变量是首次出现的声明 - 因此,拼写错误可能会导致不可预测的结果。这种“隐性声明”与Fortran计划没有什么不同。但是,对于PL/I(F),属性列表使程序员能够检测任何拼写错误或未宣布的变量。
程序员问题
由于PL/IF/IF编译器的语言和不成熟性的复杂性,许多程序员从COBOL或FORTRAN转移缓慢。程序员被彻底划分为科学程序员(使用Fortran)和商业程序员(使用COBOL),两组之间有很大的紧张甚至不喜欢。 PL/I语法从COBOL和FORTRAN语法借用。因此,当时的Fortran程序员并没有注意到会使他们的工作变得更容易的功能,而是注意到Cobol语法,并认为这是一种商业语言,而Cobol程序员注意到Fortran语法并将其视为科学语言。
Cobol和Fortran程序员都将其视为自己语言的“更大”版本,并且两者都被该语言吓倒了,并且不愿采用它。另一个因素是对Cobol,Fortran和Algol的伪类似性。这些是PL/I元素,看起来与其中一种语言相似,但在PL/I中的工作不同。这样的挫败感使许多经验丰富的程序员对PL/I的轻浮视图,并且常常对这种语言感到积极的厌恶。早期的Unix Fortune文件包含以下语言中的舌头描述:
我敢肯定,作为一个涉足PL/I复杂性的人,我敢肯定,只有真正的男人才能写出这样的机器,刺耳的,无所不包的怪物。分配一个阵列并免费三分之一?当然!为什么不?将字符串乘以一点字符串并将结果分配给浮点数十进制?前进!在将其传递回去之前,免费一个受控的变量过程参数并将其重新分配?在同一内存位置叠加三种不同类型的变量?你说什么!写一个递归宏?好吧,不,但是真正的男人使用扫描。真正的人设计和编写的语言如何不打算用于真正的人使用?
从积极的一面来看,对所有数据类型的指针(包括结构指针),递归,多任务处理,字符串处理和广泛的内置功能的全力支持意味着PL/I确实是一个很大的飞跃,与其编程语言相比时间。但是,这些不足以说服大多数程序员或商店切换到PL/I。
PL/如果编译器的编译时间预处理器在使用其目标语言的语法和语义(例如与C预处理器的“#”指令相比,在LISP世界之外)。
PL/I的特殊主题
存储类
PL/I提供了几个“存储类”,以指示如何管理变量存储的寿命 -STATIC
,AUTOMATIC
,CONTROLLED
, 和BASED
。实施最简单的是STATIC
,这表明在加载时间分配和初始化内存,就像在COBOL “工作储存”和早期福特兰中所做的那样。这是默认EXTERNAL
变量。 PL/I的默认存储类INTERNAL
变量是AUTOMATIC
,类似于Algol影响的其他块结构化语言,例如C语言中的“自动”存储类,以及pascal中的默认存储分配和IBM COBOL中的“本地存储”。存储AUTOMATIC
进入时分配变量BEGIN
- 块,程序或ON
- 宣布它们的单元。编译器和运行时系统为堆栈框架分配内存,以包含它们和其他管家信息。如果用INITIAL
- 属性,将其设置为初始值的代码目前执行。需要护理才能正确管理初始化的使用。每次输入范围时,都可以执行大量代码以初始化变量,尤其是当变量是数组或结构时。存储AUTOMATIC
变量在块出口处被释放:STATIC
,CONTROLLED
, 或者BASED
变量用于在过程或块的调用之间保留变量的内容。CONTROLLED
还使用堆栈管理存储,但是堆栈上的分配和弹出由程序员管理,ALLOCATE
和FREE
语句。存储BASED
变量是使用的ALLOCATE
/FREE
,但是这些分配没有堆栈具有独立的生命,并通过OFFSET
或者POINTER
变量。
这AREA
属性用于声明程序员定义的堆。可以在特定区域内分配和释放数据,并且可以将区域删除,读取和编写为单位。
存储类型共享
有几种方法可以通过不同的数据声明访问分配的存储。其中一些是明确且安全的,有些可以通过仔细的编程安全地使用,而有些可以天生不安全和/或机器依赖。
通过参考将变量作为参数传递给参数,允许使用参数引用参数的分配存储。这DEFINED
属性(例如DCL A(10,10), B(2:9,2:9) DEFINED A
)允许将变量的部分或所有存储使用与不同但一致的声明一起使用。语言定义包括CELL
属性(后来重命名UNION
)允许对数据的不同定义共享相同的存储空间。这不受许多早期IBM编译器的支持。这些用法是安全且独立的。
记录I/O和列表处理产生的情况,在知道其具有哪种类型的数据结构之前,程序员需要将声明符合声明的存储符合下一个记录或项目的存储。基于基于的变量和指针是此类程序的关键。数据结构必须适当设计,通常使用数据结构中的字段来编码有关其类型和大小的信息。这些字段可以保存在前面的结构中,也可以在当前的结构中具有一些约束。如果编码在前面的结构中,则该程序需要用与当前项目匹配的声明(在需要时使用Extentes的表达式)分配基于的变量。在当前结构(“自定义结构”)中,将类型和大小信息保存在类型定义字段中必须比类型相关的项目和同一位置的每个版本的数据结构中的位置。这REFER
- 选项用于自定义的范围(例如字符串长度如DCL 1 A BASED, 2 N BINARY, 2 B CHAR(LENGTH REFER A.N.), etc
- 在哪里LENGTH
用于分配数据结构的实例。用于自定义结构,任何打字和REFERed
字段位于“真实”数据之前。如果数据集中的记录或数据结构列表中的项目以这种方式组织起来,则可以以机器独立的方式安全地处理它们。
PL/I实现(除了PL/I Checkout编译器除外),请跟踪首先分配存储时使用的数据结构。任何BASED
声明可与指针一起使用存储,以访问存储 - 固有的不安全和机器依赖性。但是,对于“指针算术”(通常将一定数量的数量添加到已知地址)变得很重要。这是计算机科学中的一个有争议的主题。除了野生参考和缓冲区超支的问题外,由于与特定机器和编译器所使用的数据类型的一致性和长度而引起的问题。许多可能需要指针算术的情况涉及在较大的数据结构中找到指向元素的指针。这ADDR
函数可以安全和机器独立计算此类指针。
指针算术可以通过用指针将二进制变量混合在一起来实现DCL P POINTER, N FIXED BINARY(31) BASED(ADDR(P));
N=N+255;
它依赖于指针的长度与FIXED BINARY(31)
整数并在相同的边界上对齐。
随着C的普遍性及其对指针算术的自由且轻松的态度,最近的IBM PL/I编译器允许将指针与加法和减法操作员一起使用,以提供最简单的语法(但是编译器选项可以禁止这些实践和安全性独立性的实践是最重要的)。
在线和例外处理
当设计PL/I时,程序仅在批处理模式下运行,而在终端的程序员不可能进行干预。诸如“零”之类的特殊条件将中止该程序,仅产生十六进制的核心转储。 PL/I例外处理,通过ON
- 单位,允许该程序在面对硬件或操作系统异常方面保持控制权,并在更优雅地关闭之前恢复调试信息。随着程序的适当调试,可以删除或禁用大多数例外处理:当对话执行变得司空见惯时,这种控制水平变得不那么重要。
计算异常处理是通过语句,块上的条件前缀启用和禁用的(包括ON
- 单位)和程序。 - 例如(SIZE, NOSUBSCRIPTRANGE): A(I)=B(I)*C;
。始终启用输入/输出和存储管理的操作系统例外。
这ON
- 单位是一个语句或BEGIN
- 由ON
-陈述。执行ON
语句启用指定条件,例如ON ZERODIVIDE ON
-单元。当发生这种情况的例外并启用条件时,ON
- 执行条件的单位。ON
- 单位继承在呼叫链上。当块,程序或ON
- 单位被激活,ON
- 由调用激活建立的单位由新激活继承。他们可能被另一个ON
- 陈述,可以由REVERT
-陈述。可以使用SIGNAL
- 陈述 - 例如帮助调试异常处理程序。动态的继承原则ON
- 单位允许例行程序来处理其使用的子例程中发生的异常。
如果不ON
- 在提出条件时,单位有效,采取标准系统操作(通常是为了提高ERROR
状态).可以使用SYSTEM
选项ON-statement
。在某些情况下,可以完成执行单元并返回中断点(例如,STRINGRANGE
,UNDERFLOW
,CONVERSION
,OVERFLOW
,AREA
, 和FILE
条件)并恢复正常执行。在其他条件下,例如(SUBSCRIPTRANGE)
, 这ERROR
尝试这种情况时会增加条件。一个单位可以用GO TO
防止返回中断点,但允许该程序继续执行,按照程序员确定。
一个ON
- 需要设计单元来处理在ON
- 单位本身。这ON ERROR SYSTEM;
语句允许嵌套错误陷阱;如果发生错误ON
- 单位,控制可能会传递到可能产生系统转储的操作系统,或者对于某些计算条件,继续执行(如上所述)。
PL/IRECORD
I/O语句具有相对简单的语法,因为它们没有为从文件末端到记录传输错误的许多情况提供选项,这些错误是在读取或编写记录时可能发生的。相反,这些复杂性在ON
- 各种文件条件的单位。采用了同样的方法AREA
子分配和AREA
状态.
异常处理的存在ON
- 单位可以对优化产生影响,因为可以检查或更改变量ON
-单位。否则可能会保存在语句之间的寄存器中的变量值,可能需要返回到语句之间的存储。这在上述实施问题部分中进行了讨论。
前往非固定目标
PL/I具有COBOL和FORTRAN的专业人士的同行。
COBOL和FORTRAN的语法都存在用于编码两种特殊两种类型的got,每个都有一个并不总是相同的目标。
- Alter(COBOL),分配(FORTRAN):
- ALTER段落_name_xxx继续前往para_name_zzz。
- 这些对这些有其他/有用的限制,尤其是“在程序中……递归属性,方法或..线程选项”。
- 将1860年分配到伊戈塔哥
去伊戈塔哥- 一个增强的增强功能是添加内置文档的
前往伊戈塔戈(1860,1914,1939)- (将变量的值限制为“列表中的标签之一”。)
- 一个增强的增强功能是添加内置文档的
- ALTER段落_name_xxx继续前往para_name_zzz。
- 转到...基于变量的类似标记的值。
- 转到(1914,1939,2140),Mychoice
- 根据Idecide,转到Para_one para_two para_three。
PL/I具有语句标签变量(带有标签属性),该变量可以存储语句标签的值,然后在Goto语句中使用。
LABL1: .... . . LABL2: ... . . . MY_DEST = LABL1; . GO TO MY_DEST; GO TO HERE(LUCKY_NUMBER); /* minus 1, zero, or ... */ HERE(-1): PUT LIST ("I O U"); GO TO Lottery; HERE(0): PUT LIST ("No Cash"); GO TO Lottery; HERE(1): PUT LIST ("Dollar Bill"); GO TO Lottery; HERE(2): PUT LIST ("TWO DOLLARS"); GO TO Lottery;
语句标签变量可以传递给调用过程,并用于返回调用例程中的其他语句。
示例程序
你好世界计划
Hello2: proc options(main);
put list ('Hello, World!');
end Hello2;
搜索字符串
/* Read in a line, which contains a string,
/* and then print every subsequent line that contains that string. */
find_strings: procedure options (main);
declare pattern character (100) varying;
declare line character (100) varying;
declare line_no fixed binary;
on endfile (sysin) stop;
get edit (pattern) (L);
line_no = 1;
do forever;
get edit (line) (L);
if index(line, pattern) > 0 then
put skip list (line_no, line);
line_no = line_no + 1;
end;
end find_strings;