精华内容
下载资源
问答
  • 程序设计语言诞生  1946冯·诺依曼提出了冯·诺依曼原理:  CPU逐条从存储器取出指令执行,按指令取出存储的数据经运算后送回。  数据和指令(存储地址码、操作码)都统一按二进制编码输入。数据值的改变是重新...

    程序设计语言诞生

            1946冯·诺依曼提出了冯·诺依曼原理:

            CPU逐条从存储器中取出指令执行,按指令取出存储的数据经运算后送回。

           数据和指令(存储地址码、操作码)都统一按二进制编码输入。数据值的改变是重新赋值,即强行改变数据存储槽的内容,所以说它是命令式的(imperative)。

            第一台按冯·诺依曼原理制成的通用电动计算机是1951年美国兰德公司的UNIVAC-1。人们就开始了机器语言的程序设计: 指定数据区编制一条条指令。由于任何人也无法记住并自如地编排二进制码(只有1和0的数字串),则用8、16进制数写程序,输入后是二进制的。

           单调的数字极易出错,人们不堪其苦,想出了将操作码改作助记的字符,这就是汇编语言,汇编语言使编程方便得多。但汇编码编的程序必须要通过汇编程序翻译为机器码才能运行。尽管汇编码程序和机器码程序基本一一对应,但汇编语言出现说明两件事,一是开始了源代码——自动翻译器——目标代码的使用方式,一是计算机语言开始向宜人方向的进程。

     

    50年代高级语言出现

     

          1954年Backus根据1951年Rutishauser提出的用编译程序实现高级语言的思想,研究出第一个脱离机器的高级语言FORTRAN I。其编译程序用18个人一年完成(用汇编语言写)。到1957年的FORTRAN Ⅱ,它就比较完善了。它有变量、表达式、赋值、调用、输入/输出等概念; 有条件比较、顺序、选择、循环控制概念; 有满足科技计算的整、实数、复数和数组,以及为保证运算精度的双精度等数据类型。表达式采用代数模型。

           FORTRAN的出现使当时科技计算为主的软件生产提高了一个数量级,奠定了高级语言的地位。FORTRAN也成为计算机语言界的英语式世界语。

           1958年欧洲计算机科学家的一个组织GAMM和美国计算机协会ACM的专家在苏黎士会晤起草了一个“国际代数语言IAL”的报告,随后这个委员会研制了ALGOL 58得到广泛支持和响应。1960年欧美科学家再度在巴黎会晤对ALGOL 58进行了补充,这就是众所周知的ALGOL 60。1962年罗马会议上对ALGOL 60再次修订并发表了对“算法语言ALGOL 60修订的报告”。由于该报告对ALGOL 60定义采用相对严格的形式语法。ALGOL语言为广大计算机工作者接受,特别在欧洲。在美国,IBM公司当时经营世界计算机总额75%的销售量,一心要推行FORTRAN,不支持ALOGL,以致ALGOL 60始终没有大发展起来。尽管如此,ALGOL 60还是在程序设计语言发展史上是一个重要的里程碑。

           1959年为了开发在商用事务处理方面的程序设计语言,美国各厂商和机构组成一个委员会。在美国国防部支持下于1960年4月发表了数据处理的COBOL 60语言。开发者的目标要尽可能英语化,使没有计算机知识的老板们也能看得懂。所以像算术运算符+、*都用英文ADD、MULTIPLY。COBOL 60的控制结构比FORTRAN还要简单,但数据描述大大扩展了,除了表(相当于数组)还有纪录、文件等概念。COBOL 60虽然繁琐(即使一个空程序也要写150个符号),由于其优异的输入/出功能,报表、分类归并的方便快速,使它存活并牢固占领商用事务软件市场,直到今天在英语国家的商业领域还有一定的地位。

           50年代计算机应用在科学计算和事务处理方面有了FORTRAN、COBOL,因而应用得到迅速发展。工程控制方面刚刚起步,仍是汇编语言的市场。1957年,美国MIT科学家McCarthy提出LISP,并把它用于数学定理验证等较为智能性的程序上。但LISP在当时只是科学家的语言,没有进入软件市场。

     

    60年代奠基性研究

     

            60年代计算机硬件转入集成电路成本大幅度下降。应用普及的障碍是语言及软件。这就促使对编译技术的研究。编译技术的完善表现在大型语言、多种流派语言的出现。

           1962年哈佛大学的K. Iverson提出APL语言。它是面向数学(矩阵)的语言。它定义了一套古怪的符号,联机使用非常简洁,深得数学家喜爱。它提出动态数据(向量)的概念。

           1962年AT&T公司贝尔试验室R.Griswold提出正文处理的SNOBOL,可以处理代数公式、语法、正文、自然语言。以后发展为SNOBOL 3,SNOBOL 4。80年代后裔叫ICON,用于测试。

           1963-64年美国IBM公司组织了一个委员会试图研制一个功能齐全的大型语言。希望它兼有FORTRAN和COBOL的功能,有类似ALGOL 60完善的定义及控制结构,名字就叫程序设计语言PL/1。程序员可控制程序发生异常情况的异常处理、并行处理、中断处理、存储控制等。所以它的外号叫“大型公共汽车”。它是大型通用语言的第一次尝试,提出了许多有益的新概念、新特征。但终因过于复杂、数据类型自动转换太灵活、可靠性差、低效,它没有普及起来。但IBM公司直到80年代在它的机器上还配备PL/I。

           1967年为普及程序语言教育,美国达特茅斯学院的J.G. Kemeny和T.E.Kurtz研制出交互式、解释型语言BASIC(“初学者通用符号指令码”字头)。由于解释程序小(仅8K)赶上70年代微机大普及,BASIC取得众所周知的成就。但是它的弱类型、全程量数据、无模块,决定了它只能编制小程序。它是程序员入门的启蒙语言。

           LOGO语言是美国MIT的S. Papert教授于1967年开发的小型语言。其目的是无数学基础的青少年也能学习使用计算机,理解程序设计思想,自己编制过程或程序。但直到80年代初微机普及到家庭它才受到重视。LOGO是交互式语言,用户编程就在终端前定义过程命令,并利用系统提供的命令构成程序。LOGO的数据是数、字、表。由于它能方便地处理符号表,可以利用人工智能成果开发情报检索、演绎推理、自然语言会话小程序。青少年可设计各种智能游戏。屏幕上的海龟使青少年直观地构造各种图形。递归程序的表达能力使青少年可受到自动程序良好训练。1979年MIT LOGO小组推出Apple LOGO,及TI LOGO(德州仪器公司TI 99/4A机)。这两个版本最为普及。LOGO是青少年入门的启蒙语言。

            LOGO的近于自然语言的命令及海龟、键盘、程序、图形并用的使用风格,对以后的命令式语言、用户界面语言有一定的影响。

           1967年挪威计算机科学家O.J. DahI等人研制出通用模拟语言SIMULA67。它以ALGOL 60为基础,为分层模拟离散事件提出了类(Class)的概念。类将数据和其上的操作集为一体,定义出类似类型的样板。以实例进入运算。这是抽象数据类型及对象的先声。

           60年代软件发展史上出了所谓的“软件危机”。事情是由1962年美国金星探测卫星“水手二号”发射失败引起的。经多方测试在“水手一号”发射不出错的程序在“水手二号”出了问题。软件无法通过测试证明它是正确的。于是,许多计算机科学家转入对程序正确性证明的研究。这时,著名的荷兰科学家E. Dijkstra提出的“goto语句是有害的”著名论断,引起了一场大争论。从程序结构角度而言,滥用goto语句会使程序无法分析、难于测试、不易修改。这时也提出了全程变量带来的数据耦合效应、函数调用的副作用、类型隐含声明和自动转换所带来的难于控制的潜伏不安全因素等等过程语言中的一些致命性弱点。60年代对大型系统软件的需求大为增长(如编制较完善操作系统、大型军用系统),要求使用高级语言以解决生产率之需,加上高级语言使用以来积累的经验,加深了人们对软件本质、程序语言的理解。人们积极研制反映新理论的语言。

           1964年,ALGOL工作组成员N. Wirth改进了ALGO 60,提出结构化的语言ALGOL W。由于它结构简洁、完美。ALGOL W成为软件教程中示例语言。1968年,他带着ALGOL W参加新一代ALGOL的研究委员会,即开发ALGOL 68的工作组。

           ALGOL 68追求的目标也是能在多个领域使用的大型通用语言。1965年以Wijngaarden为首的一批科学家开始研究新ALGOL。强调了语言设计中冗余性(少作隐含约定)、抽象性(数据抽象与控制抽象)、正交性(一个语言机制只在一处定义并与其它机制无关)。强化了类型定义和显式转换; 有并发、异常处理功能; 保留goto允许有限制的函数边界效应: 过程可以作为参数传递; 用户可定义较复杂数据结构、定义运算符。语法定义是半英语半形式化的。语言作成可扩充式,也就是说,有一个相对完备的小语言核心,可以不断增加新特征以增强语言表达能力。表达式采用利于快速编译和提高目标码效率的逆波兰表示法。ALGOL 68集中了当时语言和软件技术之大成。但因学究气太重,一般程序员难于掌握。强调语言简单的人持有不同看法。但文本草案在Wijngaarden坚持下通过了。为此,Dijkstra等人发表了“少数人声明”。N.Wirth带着竞争失败的ALGOL W回去研究以后著称于世的Pascal。Pascal的研制者一开始就本着“简单、有效、可靠”的原则设计语言。1971年Pascal正式问世后取得了巨大的成功。它只限于顺序程序设计。是结构化程序设计教育示范语言。

           Pascal有完全结构化的控制结构。为了方便,除三种最基本的控制结构(顺序、if-then=else、while-do)外,又扩充了二种(do-until、for-do)。程序模块有子程序(过程和函数),分程序,可任意嵌套,因而有全程量、局部量、作用域与可见性概念。保留goto语句但不推荐使用。

          Pascal的数据类型大大丰富了,有整、实、字符、布尔等纯量类型: 有数组、记录、变体记录、串等结构类型; 增加了集合、枚举、指针类型。为用户描述复杂的数据结构乃至动态数据提供了方便。所有进入程序的数据都要显式声明、显式类型转换。并加强了编译时刻类型检查、函数的显式的值参和变量参数定义便于限制边界效应。在人们为摆脱软件危机而对结构化程序设计寄于极大希望的时代,Pascal得到很快的普及。它也是对以后程序语言有较大影响的里程碑式的语言。

     

    70年代完善的软件工程工具

     

            硬件继续降价,功能、可靠性反而进一步提高。人们对软件的要求,无论是规模、功能、还是开发效率都大为提高了。仅管Pascal得到普遍好评,但它只能描述顺序的小程序,功能太弱。在大型、并发、实时程序设计中无能为力。程序越大越要求高的抽象力、安全性、积少成多的模块拼合功能。为了对付日益加剧的新意义上的软件危机。70年代语言继续发展,在总结PL/1和ALGOL 68失败的基础上,研制大型功能齐全的语言又一次掀起高潮。

            70年代是微机大发展的时代。设计精巧的小型过程语言藉微机普及得到发展。软件市场FORTRAN、COBOL、汇编的三分天下开始缓慢地退却。结构化FORTRAN、COBOL力图在新的竞争中保全自己的地位,专用语言丛生。一旦证实它的普遍性,它就变为通用语言。C就是在这种情况下成长起来的优秀语言。

            硬件的完善使得过去难以实施的组合爆炸算法得以缓解。人工智能的专家系统进入实用。LISP发展为INTEL LISP和MAC LISP两大分支,其他智能语言陆续推出。特别是Backus在1978年发表“程序设计能从冯·诺依曼风格中解放出来吗?”一文。非过程式语言、高抽象模式语言大量涌现。

            70年代继60年代的形式语言语法研究,形式语义取得重大成果。最先是IBM维也纳实验室集合欧洲著名的计算机科学家于1972年写出PL/1的操作语义。该语义用维也纳定义语言VDL表达,长达1500页,终因抽象层次太低,而此时(1971年)牛津大学D.Scott和C.Strachey提出了更加数学化的指称语义学,维也纳实验室转而研究PL/1的指称语义描述。1973-1978年D. Bjorner和C. Jones开发了维也纳开发方法VDM。所用语言是Meta IV。虽然巨大投资(3.5亿)未见可见效益,IBM终止了维也纳实验室的语义学研究方向,但VDM方法及指称语言学对计算机语言发展影响是深远的。1973年C.Hoare和Wirth用指称语义写Pascal语义发现了Pascal的设计上的许多问题竟做不下去。VDM以后还用于多种语言如CHILL,Ada,指导编译器的开发。

           1971-72年,DEC公司和卡内基﹒梅隆大学的Wulf合作,开发了PDP(以后是VAX)上的系统程序设计语言Bliss。它是无类型的结构化语言,没有goto语句。有异常处理和汇编接口,面向表达式。直到80年代末DEC公司还用它作系统设计。

            1972年AT&T公司贝尔实验室Ritchie开发了C语言。C语言的原型是1969年Richard开发的系统程序设计语BCPL。K.Thompson将BCPL改造成B语言,用于重写UNIX多用户操作系统。在PDP-11机的UNIX第五版时用的是将B改造后的C。C扩充了类型(B是无类型的)。1973年UNIX第五版90%左右的源程序是用C写的。它使UNIX成为世界上第一个易于移植的操作系统。UNIX以后发展成为良好的程序设计环境,反过来又促进了C的普及。

           C语言是个小语言,追求程序简洁,编译运行效率高。是一个表达能力很强的、顺序的、结构化程序设计语言。它给程序员较大的自由度,下层数据转换灵活。程序正确性完全由程序员负责。上层是结构化的控制结构,有类似Pascal的数据类型。它的分别编译机制使它可构成大程序。输入/出依赖UNIX,使语言简短。语言学家极力反对的goto语句、无控制指针、函数边界效应、类型灵活转换、全程量这些不安全的根源C全部具备。在某种意义下C得益于灵活的指针、函数副作用和数据类型灵活的解释。易读性又不好,偏偏程序员都喜爱它。因为它简洁,近于硬件,代码高效,并有大量环境工具支持。C程序写起来又短,调试起来又快。微机上的各种移植版本的C语言,对C成为通用的程序设计语言起到了推波助澜的作用。C语言正以席卷系统程序设计领域的势头发展,并向应用领域扩展。以后的发展把与它同期出现的Pascal远远抛在后面,成为系统软件的主导语言。

           1972年法国Marseille大学的P.Roussel研制出非过程的Prolog语言。Prolog有着完全崭新的程序设计风格,它只需要程序员声明“事实”“规则”。事实和规则都以一阶谓词的形式表示。Prolog规则的执行是靠该系统内部的推理机,而推理机按一定的次序执行。在这个意义上它又有点过程性。以回溯查找匹配,Prolog的数据结构类似Pascal的记录或LISP的表。它是以子句为基础的小语言,最初被解释执行,编译Prolog是很久以后的事,由于Prolog是以逻辑推理作为模型的语言,它可以直接映射客观世界事物间逻辑关系。在人工智能研究中得到了广泛的应用,80年代日本声称研制的五代机以Prolog作为主导语言并研制Prolog机。

            70年代,在传统语言中出现了以下有代表性的语言:

           为了开发大型可维护程序,施乐公司1972-74年由Geschke领导研制了Mesa语言。Mesa是强类型结构化语言,有模块(若干子程序集合)概念和抽象数据类型。支持并发程序设计,由监控器协调各模块执行。有分别编译,异常处理机制。保留goto语句,也可以抑制类型检查。Mesa可配置语言编译后的各模块。

           1974年MIT的Liskov和Zilles提出CLU语言,它突出的是数据抽象。数据抽象是70年代类型强化和抽象技术的重要成果,它允许用户定义抽象的数据类型。这些类型的定义和它的实现可显式地分开。定义描述了语义,实现对于使用该数据的用户是无关紧要的,因而,利于修改。增强模块性和独立性,从而易于保证程序正确。数据抽象可定义更远离机器而近于人类的数据概念。如堆栈就可定义为抽象数据类型。人们可通过压入数据、弹出数据的操作对栈体进行操作。其外在行为就是后进先出的数据栈,而栈体可由数组、或链表、或记录任一种数据结构实现。

           CLU的抽象数据类型称之为簇(Cluster)。由构造算子(Constructor按簇的样板建立运算对象(实例)。CLU无goto,无全程量概念。用户可定义新的迭代(通过迭代算子Iterator)。

           数据抽象在1975年卡内基﹒梅降大学Wulf和Shaw开发的ALPHARD语言中是数据模型FORM。ALPHARD的特点是支持程序的验证。程序设计和验证同时进行。

           另一个支持程序验证的语言是加州大学Poperk和加拿大的Horning于1976年到77年开发的EUCLID。为了易于验证,无goto语句,指针仅限于集合类型,类型兼容有严格的定义,函数调用绝无边界效应。编译自动生成验证用的断言。EUCLID以后发展成数据流语言。

           在并发程序方面,1975年丹麦学者B.Hanson开发了并发Pascal。它没有追求大而全,只是将Pascal向并发方面作了扩充,希望用Pascal写操作系统。有抽象数据类型的类(Class)机制。控制方面提出进程类和管程类的概念。通过init语句激活类实例,cycle语句使进程无限循环地运行。通过管程(管理资源的模块)实现进程通讯。有较强的静态类型检查,可查出静态“死锁”。

           令人不解的是正当人们对进程、管理概念充分评价时,B.Hanson本人放弃了这些概念。1981年发表了小型系统程序设计语言Edison,仅用并发语句控制并发进程的执行。Hanson极力推崇语言的简单性,所以Edison比并发Pascal小得多,普通(不大的)微机都可以运行。但其表达能力比C差多了。没有达到并发Pascal那样的影响。

          Pascal在结构化程序设计方面是一个示范性语言,在推行结构化程序设计教学上发挥了卓越的作用,但在工程实践上暴露出设计上的许多缺点。Pascal除了无独立模块和分别编译机制不能编大程序而外,原来它的强类型是有漏洞的。类型等价似乎是按名等价,实现是按结构等价。最后的结论它是“伪强类型”。数组定长对处理字符串很不方便,布尔表达式求值定义不严,I/O规定太死,难于写出灵活的输入/输出。声明顺序过严,无静态变量概念(局部量一旦所在局部块执行完毕就消失)都给程序设计带来不便。从小而灵活方面,它又不及C,没有位(bit)级操作,指针操作限制过死。于是Pascal的设计者1975年又开始开发Modula语言,1977年正式发布为Modula-2。

           Modula-2除了改进Pascal的上述弱点而外,最重要的是有模块结构。可分别编译的模块是用户程序的资源。系统资源也以模块形式出现。模块封装了数据和操作(过程),模块定义和模块实现显式分开。程序员在定义模块中通过移入,移出子句控制程序资源(类型、变量、过程、子模块)的使用。

           Modula-2增加了同步进程机制以支持并发程序设计,有有限的低级设施直接和系统打交道。取消goto语句、增加case语句中otherwise机制,封装的模块可作抽象数据类型设计。它是用于系统设计的强类型语言。西欧的计算机科学家对Modula-2是欢迎的,但它不巧与美国开发的Ada非常近似,与Ada竞争处于非常不利的地位。尽管它的9000句编译器具有Ada20万句编译器80%的功能,也没有取得Pascal那样的成就。

           70年代中期美国软件的最大用户美国国防部(美国软件市场约2/3经费直接或间接与它相关)深感软件费用激增并开始研究原因。研究结果表明,在硬件成本降低和可靠性提高的同时,软件费用不仅相对数,绝对数也在增加。美国军用的大量大型、实时、嵌入式系统软件开发方法落后、可靠性差。语言众多(常用400-500种,加上派生方言多达1500种)造成不可移植、难于维护,为摆脱这种新的软件危机下定决心搞统一的军用通用语言。从1975年成立高级语言工作组开始投资五亿美元,前后八年研制出Ada程序设计语言。Ada是在国际范围内投标设计的,法国的一家软件公司中标,J.Ichbian成为Ada发明人。多达1500名第一流软件专家参与了开发或评审。它反映了70年代末软件技术、软件工程水平。为了提高软件生产率和改善软件可移植性,提出开发语言的同时开发支持该语言的可移植环境(APSE)。

           Ada是强类型结构化语言。封装的程序包是程序资源构件。用户只能看到程序包规格说明中显式定义的数据(包括抽象数据类型)和操作。数据结构和操作(过程或函数)的实现在程序包体中完成。封装支持模块性和可维护性。规格说明和体的分离支持早期开发(可延迟决策)。分别编译机制可组成复杂的大型软件。

           Ada有并发、异常机制。可定义精确的数据(如浮点数小数点后任意多的位数)。有将数据对象、类型、过程参数化的类属机制。有为目标机写目标程序(机器语言的或汇编语言地)的低级设施,可对字节、字位操作。Ada的私有类型支持数据隐藏,程序包可实现数据抽象。标识符和运算符重载概念,既方便程序员又使程序好读且安全。强调大型系统可读性胜于可写性,Ada程序自成清晰的文档。

           Ada语言的开发过程完全按软件工程方式进行。严格禁止方言。美国国防部有一个严格管理Ada及其环境的机构AJPO(Ada联合规划办公室)负责Ada的确认、修改、维护、培训。从业界转向软件工程方法开发软件的意义上,Ada也称之为里程碑式语言。

           由于Ada过多强调安全性和易读性,Ada编译程序要做较多的静态检查,因而体积庞大(约20万句、512KB的微机装下了微机Ada编译就剩不下工作空间了)。程序代码较长,虽不像COBOL繁琐但要比C语言程序长60%。运行效率,特别是嵌入式实时控制应用中,通过交叉编译得到的目标机代码一时还难满足要求。环境工具发展缓慢,因为除军方外民间公司更乐于开发对所有语言通用的计算机辅助软件工程环境(CASE)。自80年代第一个语言版本,83年修改定型至今, Ada没有达到投资者预想的成就。目前已看到Ada83只反映80年代初期的软件工程技术。随着软件工程本身向集成化、可重用、面向对象方向发展,Ada已有一些不适应了。但美国军方还在全力支持,1995年Ada完成面向对象改造推出了Ada-95。增加了标签类型、类宽类型、抽象类型;放宽了访问类型;使一个静态强类型语言可以支持OO的动态束定。这种改造非常痛苦,使Ada-95语法规则增至277条,成为最庞大臃肿的语言。耐人寻味的是Ada-95很块被ANSI和ISO 接受,它成为世界上第一个有法定标准的面向对象的语言。

           70年代末到80年代初值得一提的还有FORTH语言。FORTH是典型的中级语言。它是汇编语言指令码向用户自定义方向的发展。也就是说,用户可以面向一个堆栈机器模型定义操作命令——字(word)。最低层的字是指令码,逐层向上,上层字由下层组成。因此,FORTH系统有良好的继承性。系统提供核心字、解释器字、编译字和设备字。对于简单的计算解释器字直接执行命令(字),复杂计算可将字定义编译成目标码存入堆栈供以后执行。有汇编字集合以便用户直接使用机器,要求字集合操作数值计算,引用字集合使用户可以引用系统和用以前已定义的字。FORTH程序员首先查看系统中字的字典,以它们组合成新字,进而构成程序。FORTH程序的逆波兰表示法便利于解释和编译,这对长期从事汇编编程的程序员并不生疏。FORTH把具体的机器抽象为堆栈机,既可以使程序员直接操纵机器又不涉及具体机器指令码、操作码、存储安排。而且良好的继承性使程序越编越短,在最终用户层一两个命令就完成了程序设计。它大受控制领域、要求单片、单板计算机(例如仪表工业)领域的程序员喜爱。

            FORTH是C.Moore一个人开发的语言,他于1968年在IBM 1130机器上实现第一个FORTH。他说他的语言是第四代的(Fourth-Generation)。由于1130只允许五个字符的名字才叫FORTH。1973年成立FORTH公司并把它投入航天工程应用,发展了通用商务FORTH系统。此后世界各地开始重视FORTH。1976年成立欧洲FORTH用户小组(EFUG),1978年成立FORTH标准化国际组织,80年发布FORTH-79标准文本。与此同时美国FORTH爱好者小组FIG)也制定了标准fig FORTH。各国天文行业,仪表行业纷纷以其为行业用计算机语言。FORTH并不好读,也不宜编大程序。但在它自己的领域简单好用、扩充方便、编译迅速。与传统语言追求的目标大相径庭。给人耳目一新。


    80年代的面向对象发展

     

           Ada的大、功能齐全、开发耗资可以说是程序设计语言之最。但它还没有普及就有些落伍了。可能今后不再有人再投入巨资去开发大型过程语言。

           80年代继续向软件危机开战,但软件工程以陈旧技术难于作出庞杂的软件工具。为了改善这种情况,人们乞灵于面向对象技术。程序设计语言纷纷面向对象靠拢。正如上一个10年程序设计语言结构化一样。这是主要特点。

           80年代的第二个特点是“用户友好”的所谓第四代语言的出现。

           80年代的第三个特点是各种技术相互渗透各种更高级非过程性语言出现。

          1972年美国施乐公司保罗·奥特研究中心的A.Kay领导的软件概念小组为方便不同用户处理各种信息在小机器上搞了一个Dynabook计划。它以全部的“对象”概念建立自己的系统。1980年Smalltalk-80作为正式的发布版本。

           Smalltalk语言是该系统的软件。专用的硬件机、Smalltalk环境、用户界面、面向对象程序设计风格构成了整个系统。

         “对象”是有自己的数据和操作的实体,各对象相对封闭。程序设计就是建立应用系统中的对象群,并使之相互发消息。接到消息的对象就在自己封闭的存储中响应执行操作。操作的结果是改变这组对象的状态、完成计算(发出输出消息,对象响应后完成输出)。

           为了使各自封闭的对象数据和操作不致多次重复定义。Smalltalk有类和继承的概念。类如同传统语言中的类型,只有类的实例进入实际运算(叫实例对象)。类对象中的数据和操作可为它的子类继承,它自己的数据和操作也继承自超类。于是一个Smalltalk系统就必须有支持它的一个类库,它象一棵大树,所有的行之有效类都在这棵大树的某个位置上。用户只要选取其中某些类稍加修改变成自己问题所需要的类(子类),定出通讯协议,让它们的实例相互通讯完成计算。无论是系统对象和用户定义的对象都按不同的抽象层次放在统一的类库中。例如,向编译对象发消息并传送用户对象,该用户对象(程序)就被编译了。Smalltalk中只有不同抽象层次的对象,小到一个整数、大到一个系统都叫对象,且别无其它计算单元。面向对象程序设计的概念因此而出。

           Smalltalk因为它天然的封装性体现了模块性和数据隐藏,利于维护修改。它的继承性实质上是软件的重用。这对困惑于大程序难于管理的软件工程学无疑是一条绝好出路。

           Smalltalk类对象概念来自SIMULA 67,响应消息的方法表达式求值类似LISP的归约。它本身是在小机器上开发的小系统。庞大的类库占去了很大的空间,难于编制大型程序。加上它独特的编程风格,Smalltalk本身并未发展起来。但面向对象思想,语言和环境一致性; 交互式和极端用户友好(用菜单和鼠标即可上机),对80年代语言和计算系统产生了巨大影响。它也可称之里程碑式的语言。

            各种过程语言,甚至汇编语言都借鉴对象思想,以求能支持面向对象程序设计。82-86年相继出现Object Pascal、Objective-C、Objext Assembler(68000汇编程序改造)。Object、LOGO、Object FROTH它们以原有语言采纳对象——消息编程模式。

           另一些语言向类、对象延伸。以对象——引用编程模式编程。如85年AT&T公司推出的C++。87年Borland公司的Turbo Pascal 5.5。

           传统的人工智能语言也向面向对象上发展。施乐公司1983年在Intel LISP基础上研制了LOOPS。是面向对象LISP美国西海岸版本。85年美国符号处理公司在MIT的LISP机上开发了Flavos,称之为东海岸版本。Flavos有更为灵活和复杂的多继承性。85年施乐公司又作出Common LOOPS。1988年,ANSI X3J13组将它们统一为CLOS。85年,IBM日本分公司开发了SPOOL是Prolog面向对象的扩充。86年Valcan和施乐联合开发的并发Prolog预处理程序,也是支持面向对象的。


           70年代在软件发展史上是数据库成熟的年代。数据库有数据描述语言DDL数据操作语言DML。它们都是为实现某种模式数据库的专用语言。目标简单,在所应用的领域高效。因此,不能以通用程序设计语言代替。数据库给用户以界面(即查询)语言。对于简单程序没有必要转到通用语言再编程序。查询语言进一步扩充,就形成一系列查询命令加上约束条件控制的非过程语言。如SQL。1988年SQL成为正式ANSI/ISO标准。

           80年代软件环境大发展。操作系统原有的作业控制语言(JCL)和系统调用命令也逐步发展为该环境的统一的界面语言。如UNIX的Shell。

           80年代系统软件中开发环境的思想向各专业渗透。各专业都为本专业的最终用户提供简便的开发环境。即事先将程序模块以目标码存放计算机,用户只需简单的命令,甚至本专业常用的图形就可组成应用程序。这些图形、菜单、命令即用户界面语言。

            这些语言共同的特点是声明性(只需指明要做的事)、非过程性、简单、用户友好。而应用程序的实现可由系统自己完成(低层有固定不变的计算模型,如关系运算,也可以连接备用模块智能推理)。这就所谓的第四代语言(4GL)。

           4GL并没有为程序设计语言学带来什么新概念和新特征。一般用传统技术做出界面语言解释器。要求环境有较好的工具支持(应用程序、程序库、各种测试、调试、文档工具)。最简单的4GL是图形——菜单,用户不用击键即可完成计算(用鼠标器)。

           4GL是硬件高速发展和快速降价必然的结果。因为不可能在短期内培养出与硬件发展需要出匹配的那么多的程序员。但4GL不易编制开创性程序。

    九十年代网络计算语言

           九十年代计算机硬件发展速度依然不减。每片芯片上晶体管数目仍然是一年半增加一倍。计算机主频从12-25兆赫增加到500-600兆赫(每秒钟可执行750MIPS指令),价格进一步低廉。使用方式也从多人一机的分时系统到一人一机局域网计算,到每人都成为拥有全球资源的客户。建立在异质网上的多媒体环境已成为客户端使用环境的主流。支持“所见即所得”的用户界面的“语言”大量涌现。

           ·由于有良好环境支持,程序设计重点从算法加数据结构实现技术向规模说明描述方面转移。规模说明语言在80年代已有研究。(META-IV,EPROL,HOPE,CLEAR、SPECINT,Z)在个别具体领域也能实用。但作为通用,哪怕是某个行业建立在域分析基础上的规格说明语言尚未出现。

           ·环境智能化、规模说明语言自动生成目标码客观上要求加入人工智能技术。异质网环境推行后各结点上数据库资源共享都要求各语言间不要有人为的断层。因此,多范型语言研究会有较大发展。80年代向面向对象扩充已经出现多范型语言,如C++,Ada 95(命令式加对象式)、CLOS(函数式加对象式0。为外小型研究有TABLOG(关系式加逻辑式)、Funlog(函数式加逻辑式)值得注意的是加拿大的Nial(1983-88)和美国的G(1986)语言,它们试图将五种范型: 命令式+对象式+逻辑式+函数式+关系式统一在一个语言之中。虽然问题重重,但可由此发现许多新概念和新特征,对于程序设计语言研究是非常有利的。

           ·随着面向对象数据库和面向对象操作系统的成熟,完全消灭“语义断层”的数据库程序设计语言(DBPL)和持久性程序设计语言(PPL)终将汇合并标准化。这样,程序运行时大量文件到内存转换则可以取消,从而增大了计算机的实崐时性,甚至取消文件概念。

           ·4GL有了较大发展,种类花色增多,行业标准出现。支持它们的通用程序设计语言是C、C++、Ada。

     

    2010-01-20                  

    注:源自原百度博客“至美心"

    展开全文
  • 逻辑程序设计语言Prolog

    万次阅读 多人点赞 2017-06-23 10:16:23
    Prolog(PROgramming in LOGic的缩写)语言是一种基于 Horn 子句的逻辑型程序设计语言,也是一种陈述性语言。 Prolog 与人工智能的知识表示、自动推理、图搜索、产生式系统和专家(知识)系统有着天然的联系,很适合...

    Prolog 概念

    Prolog(PROgramming in LOGic的缩写)语言是一种基于 [Horn 子句](http://www.baidu.com)的逻辑型程序设计语言,也是一种陈述性语言。 Prolog 与人工智能的知识表示、自动推理、图搜索、产生式系统和专家(知识)系统有着天然的联系,很适合智能程序设计。 若想详细了解可自行百科:http://baike.baidu.com/item/Prolog

    今天我们先搞明白 Prolog 语言的基本原理,然后再详细学习一下 Turbo Prolog 语言程序设计。选择 Turbo Prolog 是因为它是一个功能较齐全的逻辑程序语言,其程序的可读性强而且简单易学,是一个很好的教学语言。另外, Turbo Prolog 程序既可以在 Trubo Prolog 和 PDC Prolog 环境下运行或编译,又可以在当前流行的可视化语言 Visual Prolog 的环境下运行或编译。


    Prolog 基础

    一、Prolog 的语句

    Prolog 语言仅有三种语句:事实(Fact)、规则(Rule)和问题(Question)。

    1、事实

    格式:

    <谓词名>(<项表>).
    
    • 谓词名是以大小写字母开头,字母、数字、下划线等组成的字符串;
    • 项表是以逗号隔开的项序列。

    Prolog 中的项包括由常量或变量表示的简单对象以及函数、结构和表等,即事实的形式是一个原子谓词公式

    功能:

    一般表示对象的性质或关系。

    举个例子:

    student(john).
    like(mary, music).
    

    这就是 Prolog 中两个合法的事实。分别表示“约翰是学生”和“玛丽喜欢音乐”。

    当然了,作为特殊情形,一个事实也可以只有谓词名而无参量。
    举个例子:

    abc.
    repeat.
    

    等也是允许的。

    2、规则

    格式:

    <谓词名>(<项表>):-<谓词名>(<项表>){,<谓词名>(<项表>)}.
    
    • “:-”号表示“if”(也可以直接写为 if ),其左部的谓词是规则的结论(亦称为头),右部的谓词是规则的前提(亦称为体);
    • “{}”表示零次或多次重复,逗号表示 and(逻辑与)。

    即规则的形式是一个逻辑蕴涵式

    功能:

    一般表示对象间的因果关系、蕴含关系或对应关系。

    举个例子:

    bird(X) :- animal(X), has(X, feather).
    grandfather(X, Y) :- father(X, Z), father(Z, Y).
    

    分别表示“如果 X 是动物,并且 X 有羽毛,则 X 是鸟”和“ X 是Y 的祖父,前提是如果存在 Z,X 是 Z 的父亲并且 Z 又是 Y 的父亲”。

    作为特殊情形,规则中的谓词也可以只有谓词而无参量。
    举个例子:

    run :- start, step1(X), step2(X), end.
    

    也是一个合法规则。

    3、问题

    格式:

    ?-<谓词名>(<项表>){,<谓词名>(<项表>)}.
    

    功能:

    问题表示用户的询问,它就是程序运行的目标。

    举个例子:

    ?-student(john).
    ?-like(mary, X).
    

    分别表示“约翰是学生吗?”和“玛丽喜欢谁?”。

    问题可以与规则及事实同时一起给出,也可以在程序运行时临时给出。

    二、Prolog 的程序

    Prolog 程序一般由一组事实、规则和问题组成。问题是程序执行的起点,称为程序的目标。


    我们首先写出一个 Prolog 的程序,如下:(为引用方便起见,我们把这个程序称为“程序0”

    likes(bell, sports).
    likes(mary, music).
    likes(mary, sports).
    likes(jane, smith).
    friend(john, X) :- likes(X, reading), likes(X, music).
    friend(john, X) :- likes(X, sports), likes(X, music).
    ?- friend(john, Y).
    

    接下来我们分析一下这个程序:
    可以看出,这个程序中有四个事实、两条规则和一个问题。其中事实、规则和问题都分行书写;规则和事实可连续排列在一起,其顺序可随意安排,但同一谓词名的事实或规则必须集中排列在一起;问题不能与规则及事实排在一起,它作为程序的目标要么单独列出,要么在程序运行时临时给出。
    这个程序的事实描述了一些对象(包括人和事物)间的关系;而规则则描述了 John 交朋友的条件,即如果一个人喜欢读书并且喜欢音乐(或者喜欢运动和喜欢音乐),那么这个人就是 John 的朋友(当然,这个规则也可看做 John 朋友的定义);程序中的问题是“约翰的朋友是谁?"

    Prolog 程序中的目标还可以变化,也可以含有多个语句(上例中只有一个)。如果有多个语句,则这些语句称为子目标。例如对上面的程序,其问题也可以是:

    	?-likes(mary, X).
    或
    	?-likes(mary, music).
    或
    	?-friend(X, Y).
    或
    	?-likes(bell, sports),
    	  likes(mary, music),
    	  friend(john, X).
    

    等。但对于不同的问题,程序运行的结果一般是不一样的。

    还需说明的是,Prolog程序中的事实或规则一般称为它们对应谓词的子句。例如,上面程序中的前4句都是谓词 likes 的子句。 Prolog 规定,同一谓词的子句应排在一起。从语句形式和程序组成来看, Prolog 就是一种基于 Horn 子句的逻辑程序。这种程序要求用事实和规则来求证询问,即证明所给出的条件子句和无条件子句与目标子句是矛盾的,或者说程序中的子句集是不可满足的。这就是所谓的 Prolog 的说明性语义。

    从 Prolog 的语句来看, Prolog 语言的文法结构相当简单。但由于它的语句是 Horn 子句,而 Horn 子句的描述能力是很强的,所以 Prolog 的描述能力也是很强的。例如,当它的事实和规则描述的是某一学科的公理,那么问题就是待证的命题;当事实和规则描述的是某些数据和关系,那么问题就是数据查询语句;当事实和规则描述的是某领域的知识,那么问题就是利用这些知识求解的问题;当事实和规则描述的是某初始状态和状态变化规律,那么问题就是目标状态。所以, Prolog 语言实际是一种应用相当广泛的智能程序设计语言。从上面最后一个目标可以看出,同过程性语言相比,对于一个 Prolog 程序,其问题就相当于主程序,其规则就相当于子程序,而其事实就相当于数据。

    三、Prolog 程序的运行机理

    要想了解 Prolog 的运行机理,首先需要了解几个基本概念。

    1、自由变量与约束变量

    Prolog中把无值的变量称为自由变量,有值的变量称为约束变量。一个变量取了某值就说该变量约束于某值,或者说该变量被某值所约束,或者说该变量被某值实例化了。在程序运行期间,一个自由变量可以被实例化而成为约束变量,反之,一个约束变量也可被解除其值而成为自由变量。

    2、匹配合一

    两个谓词可匹配合一,是指两个谓词的名相同,参量项的个数相同,参量类型对应相同,并且对应参量项还满足下列条件之一。

    1. 如果两个都是常量,则必须完全相同。
    2. 如果两个都是约束变量,则两个约束值必须相同。
    3. 如果其中一个是常量,一个是约束变量,则约東值与常量必须相同。
    4. 至少有一个是自由变量。

    例如下面的两个谓词:

    prel("ob1", "ob2", Z)
    prel("ob1", X, Y)
    

    只有当变量 X 被约束为"ob2",且 Y、Z 的约束值相同或者至少有一个是自由变量时,它们才是匹配合一的。
    Prolog 的匹配合一,与归结原理中的合一的意思基本一样,但这里的合一同时也是一种操作。这种操作可使两个能匹配的谓词合一起来,即为参加匹配的自由变量和常量,或者两个自由变量建立一种对应关系,使得常量作为对应变量的约束值,使得两个对应的自由变量始终保持一致,即若其中一个被某值约束,则另一个也被同一值约束;反之,若其中一个的值被解除,则另一个的值也被解除。

    3、回溯

    所谓回溯,就是在程序运行期间,当某一个子目标不能满足(即谓词匹配失败)时,控制就返回到前一个已经满足的子目标(如果存在的话),并撤销其有关变量的约束值,然后再使其重新满足。成功后,再继续满足原来的子目标。如果失败的子目标前再无子目标,则控制就返回到该子目标的上一级目标(即该子目标谓词所在规则的头部)使它重新匹配。回溯也是 Prolog 的一个重要机制。

    不懂没关系,下面有例子,看完这个 Prolog 程序的运行过程就懂了。

    有了上面的基本概念,下面就介绍所 Prolog 程序的运行过程。我们仍以上面给出的 Prolog 程序“程序0”为例。

    设所给的询问是:

    ?-friend(john, Y).			(john和谁是朋友?)
    

    则求解目标为:

    friend(john, Y).
    

    这时,系统对程序进行扫描,寻找能与目标谓词匹配合一的事实或规则头部。显然,程序中前面的 4 个事实均不能与目标匹配,而第 5 个语句的左端即规则为:

    friend(john, Y) :- likes(X, reading), likes(X, music).
    

    的头部可与目标谓词匹配合一。但由于这个语句又是一个规则,所以其结论要成立则必须其前提全部成立。于是,对原目标的求解就转化为对新目标:

    likes(X, reading), likes(X, music).
    

    的求解。这实际是经过归结,规则头部被消去,而目标子句变为:

    ?- likes(X, reading), likes(X, music).
    

    现在依次对子目标:

    likes(X, reading)和 likes(X, music)
    

    求解。
    子目标的求解过程与主目标完全一样,也是从头对程序进行扫描,不断进行测试和匹配合一等,直到匹配成功或扫描完整个程序为止。
    可以看出,对第一个子目标 like(X, reading)的求解因无可匹配的事实和规则而立即失败,进而导致规则:

    friend(john, X) :- likes(X, reading), likes(X, music).
    

    的整体失败。于是,刚才的子目标:

    likes(X, reading)和 likes(X, music)
    

    被撤销,系统又回溯到原目标 friend(john, X)。这时,系统从该目标刚才的匹配语句处(即第 5 句)向下继续扫描程序中的子句,试图重新使原目标匹配,结果发现第 6 条语句的左部,即规则

    friend(john, X) :- likes(X, sports), likes(X, music).
    

    的头部可与目标谓词匹配。但由于这个语句又是一个规则,于是,这时对原目标的求解就又转化为依次对子目标:

    likes(X, sports)和 likes(X, music)
    

    的求解。这次子目标 likes(X, sports)与程序中的事实立即匹配成功,且变量 X 被约束为 bell。于是,系统便接着求解第 2 个子目标。由于变量 X 已被约束,所以这时第 2 个子目标实际上已变成:

    likes(bell, music).
    

    由于程序中不存在事实 likes(bell, music),所以该目标的求解失败。于是,系统就放弃这个子目标,并使变量 X 恢复为自由变量,然后回溯到第一个子目标,重新对它进行求解。由于系统已经记住了刚才已同第一子目标谓词匹配过的事实的位置,所以重新求解时,便从下一个事实开始测试。易见,当测试到程序中的第 3 个事实时,第一个子目标便求解成功,且变量 X 被约束为 mary 。这样,第 2 个子目标也就变成:

    likes(mary, music).
    

    再对它进行求解。这次很快成功。
    由于两个子目标都求解成功,所以,原目标 friend(john, Y)也成功,且变量 Y 被约束为 mary(由 Y 与 X 的合一关系)。于是,系统回答:

    Y = mary
    

    程序运行结束。上述程序的执行过程如图下所示。
    Prolog 程序运行机理图解示例

    上述程序的运行是一个通过推理实现的求值过程。我们也可以使它变为证明过程。例如,把上述程序中的询问改为:

    friend(john, mary).
    

    则系统会回答“yes”。
    若将询问改为:

    friend(john, smith).
    

    则系统会回答“no”。

    从上述程序的运行过程来看, Prolog 程序的执行过程是一个(归结)演绎推理过程。其推理方式为反向推理,控制策略是深度优先且有回溯机制,具体实现方法是:自上而下匹配子句;从左向右选择子目标;(归结后)产生的新子目标总是插入被消去的目标处(即目标队列的左部)。Prolog 的这种归结演绎方法被称为 SLD(Linear resolution with Selection function for Definite clause)归结, 或 SLD 反驳 - 消解法。这样,SLD 归结就是 Prolog 程序的运行机理,也就是所谓的 Prolog 语言的过程性语义


    Turbo Prolog 程序设计

    Turbo Prolog 是一个编译型语言,1986 年由美国的 BORLAND 公司推出,运行在 IBM PC 系列机及其兼容机上。Turbo prolog 除了具有基本 prolog 的逻辑程序特点外还具有速度快、功能强,具有集成化开发环境,可同其他语言接口,能实现动态数据库和大型外部数据库,可直接访问机器系统硬软件和具有图形、窗口功能等一系列特点。

    本次我们以 Turbo prolog(2.0版)为例,介绍 prolog程序设计。

    一、程序结构

    一个完整的 Turbo prolog 程序一般包括常量段领域段数据库段谓词段目标段子句段 6 个部分。各段以其相应的关键字 constantsdomainsdatabasepredicatesgoalclauses 开头加以标识。另外,在程序的首部还可以设置指示编译程序执行特定任务的编译指令;在程序的任何位置都可设置注解。总之,一个完整的 Turbo prolog(2.0版)程序的结构如下:

    /*  < 注	释 >  */
        <编译指令>
    constants
        <常量说明>
    domains
        <域说明>
    database
        <数据库说明>
    predicates
        <谓词说明>
    goal
        <目标语句>
    clauses
        <子句集>
    

    当然,一个程序不一定要包括上述所有段,但一个程序至少要有一个 predicates 段clauses 段goal 段。在大多数情形中,还需要一个 domains段,以说明表、复合结构及用户自定义的域名。如若省略 goal 段,则可在程序运行时临时给出,但这仅当在开发环境中运行程序时方可给出。若要生成一个独立的可执行文件,则在程序中必须包含 goal 段。另外,一个程序也只能有个 goal 段。
    在模块化程序设计中,可以在关键字 domains, predicates 及 database前加上 global,以表明相应的说明是全局的,以便作用于几个程序模块。

    举个例子,如果要将上面的 Prolog 程序“程序0”作为 Turbo prolog程序,则应改写为

    DOMAINS
    	name = symbol
    PREDICATES
    	likes(name, name)
    	friend(name, name)
    GOAL
    			friend(john,Y), write("Y = ", Y).
    CLAUSES
    			likes(bell, sports).
    			likes(mary, music).
    			likes(mary, sports).
    			likes(jane, smith).
    			friend(john, X) :- likes(X, sports), likes(X, music).
    			friend(john, X) :- likes(X, reading), likes(X, music).
    

    下面对程序结构中的几个段作以说明。

    领域段 该段说明程序谓词中所有参量项所属的领域。领域的说明可能会出现多层说明,直到说明到 Turbo prolog 的标准领域为止(如上例所示)。Turbo prolog 的标准领域即标准数据类型,包括整数、实数、字符、串和符号等,其具体说明如下表所示。

    领域名称标识符取值范围例子
    整数integer-32 767 ~ +32 767
    实数real±IE-307 ~ ±IE+308
    字符char用单引号括住的所有可能的字符‘a’, ‘5’
    string用一对双引号括住的任意字符序列。程序中的串最长可达 255 个字符,文件中的可为 64k‘abc’, ‘123’
    符号symbol以小写字母打头的字母、数字和下划线序列;串‘abc’, abc
    Turbo Prolog 的标准领域表

    谓词段 该段说明程序中用到的谓词的名和参量项的名(但 Turbo prolog的内部谓词无须说明)。

    子句段 该段是 Turbo prolog 程序的核心,程序中的所有事实和规则就放在这里,系统在试图满足程序的目标时就对它们进行操作。

    目标段 该段是放置程序目标的地方。目标段可以只有一个目标谓词,例如上面的例子中就只有一个目标谓词;也可以含有多个目标谓词,如:

    goal
      readint(X), Y = X+3, write("Y ='%Y).
    

    就有3个目标谓词。这种目标称为复合目标。

    二、数据与表达式

    1、领域

    (1)标准领域。
    Turbo prolog中不定义变量的类型,只说明谓词中各个项的取值域。由上面我们知道, Turbo prolog 有整数实数字符符号这5种标准域。另外,它还有结构文件这3种复合域

    (2)结构。
    结构也称复合对象,它是 Turbo prolog 谓词中的一种特殊的参量项(类似于谓词逻辑中的函数)。结构的一般形式为:

    <函子>(<参量表>)
    

    其中函子及参量的标识符与谓词相同。注意,这意味着结构中还可包含结构。所以,复合对象可表达树形数据结构。例如下面的谓词:

    likes("Tom", sports(football, basketball, table_tennis)).
    

    中的

    sports(football, basketball, table_tennis)
    

    就是一个结构,即复合对象。又如:

    person("张华", student("清华大学"), address("中国", "北京")).
    reading("王宏", book("人工智能技术导论", "西安电子科技大学出版社")).
    friend(father("Li"), father("Zhao")).
    

    这几个谓词中都有复合对象。
    复合对象在程序中的说明,需分层进行。例如,对于上面的谓词:

    likes("Tom", sports(football, basketball, table_tennis)).
    

    在程序中可说明如下:

    domains
      name = symbol
      sy = symbol
      sp = sports(sy, sy, sy)
    predicates
      likes(name, sp)
    

    (3)表。
    表的一般形式是:

    [x1, x2, ..., xn]
    

    其中xi(i=1,2,...,n)为 Prolog 的项,一般要求同一个表的元素必须属于同一领域。不含任何元素的表称为空表,记为[]。例如下面就是一些合法的表。

    [1,2,3]
    [ apple, orange, banana, grape, cane]
    ["Prolog", "MAENS", "PROGRAMMING", "in logic"]
    [[a, b], [c, d], [e]]
    []
    

    表的最大特点是其元素个数可在程序运行期间动态变化。表的元素也可以是结构或表,且这时其元素可以属于不同领域。例如:

    [name("LiMing"), age(20), sex(male), address(xian)]
    [[1, 2], [3, 4, 5], [6, 7]]
    

    都是合法的表。后一个例子说明,表也可以嵌套。
    实际上,表是一种特殊的结构,它是递归结构的另一种表达形式。这个结构的函数名取决于具体的 Prolog 版本,这里我们就用一个圆点来表示。下面就是一些这样的结构及它们的表的表示形式:

    结构形式表形式
    ·(a, [])[a]
    ·(a, ·(b, []))[a, b]
    ·(a, ·(b, ·(c, [])))[a, b, c]

    表的说明方法是在其组成元素的说明符后加一个星号*。如:

    domains
        lists = string*
    predicates
    	pl(lists)
    

    就说明谓词 pl 中的项 lists 是一个由串 string 组成的表。
    对于由结构组成的表,至少分3步说明。例如对于下面谓 p 中的表

    p([name("Liming"), age(20)])
    

    则需这样说明:

    domains
      rec=seg*
      seg=name(string); age(integer)
    predicates
      p(rec)
    

    2、常量与变量

    由上面的领域可知, Turbo Prolog的常量有整数实数字符符号结构文件 这8种数据类型。同理, Turbo Prolog 的变量也就有这8种取值。另外,变量名要求必须是以大写字母或下划线开头字母、数字和下划线 序列,或者只有一个下划线(这种变量称为无名变量)

    3、算术表达式

    Turbo Prolog 提供了 5 种最基本的算术运算:加、减、乘、除 和 取模,相应运算符号为“+”、“-”、“*”、“/”、“mod”。这 5 种运算的顺序为:“*”、“/”、“mod”优先于“+”、“-”。同级从左到右按顺序运算,括号优先。
    算术表达式的形式与数学中的形式基本一样。例如:

    数学中的算术表达式Turbo Prolog 中的算术表达式
    x + yzX + Y * Z
    ab - c / dA * B - C / D
    u mod vU mod V(表示求U除以V所得的余数)

    即, Turbo Prolog 中算术表达式采用通常数学中使用的中缀形式。这种算术表达式为 Prolog 的一种异体结构,若以 Prolog 的结构形式来表示,则它们应为:

    +(X, *(Y, Z))
    -(*(A, B), /(C, D))
    mod(U, V)
    

    所以,运算符“+”、“-”、“*”、“/”和“mod”实际也就是 Prolog 内部定义好了的函数符。
    在 Turbo Prolog 程序中,如果一个算术表达式中的变元全部被实例化(即被约束),则这个算术表达式的值就会被求出。求出的值可用来实例化某变量,也可用来同其他数量进行比较,用一个算术表达式的值实例化一个变量的方法是用谓词“is”或“=”来实现的。例如:

    Y is X + 5
    或
    Y = X + 5		(*)
    

    就使变量 Y 实例化为 X+5 的值(当然 X 也必须经已被某值实例化),可以看出,这里对变量 Y 的实例化方法类似于其他高级程序语言中的“赋值”,但又不同于赋值。例如,在 Prolog 中下面的式子是错误的:

    X = X + 1
    

    需要说明的是,虽然 Prolog 是一种逻辑程序设计语言,但在目前的硬件条件下却非突破逻辑框架不可。这是因为有些实用操作是无法用逻辑描述的(如输入与输出),有些算术运算在原则上可用逻辑描述,但这样做效率太低。为此, Prolog 提供了若干内部谓词(亦称 预定义谓词),来实现算术运算、输入与输出等操作。所谓内部谓词,就是 Prolog 的解释程序中,预先用实现语言定义好的用户可直接作为子目标调用的谓词。一般的 Prolog 实用系统都配有 100 个以上的内部谓词,这些内部谓词涉及输入输出、算术运算、搜索控制、文件操作和图形声音等方面,它们是实用 Prolog 程序设计所必不可少的。这样,上面的(*)式以及下面的关系表达式称为异体谓词

    4、关系表达式

    Turbo Prolog 提供了 6 种常用的关系运算,即 小于小于或等于等于大于大于或等于不等于,其运算符依次为:

    <, <=, =, >, >=, <>
    

    Turbo Prolog 的关系表达式的形式和数学中的也基本一样,例如:

    数学中的关系式Turbo Prolog 中的关系式
    X + 1 ≥ YX + 1 >= Y
    X ≠ YX <> Y

    即, Turbo Prolog 中的关系式也用中缀形式。当然,这种关系式为 Turbo Prolog 中的异体原子。若按 Turbo Prolog 中的原子形式来表示,则上面的两个例子为:

    >=(X +1, Y) 和 <>(X, Y)
    

    所以上述 6 种关系运算符,实际上也就是 Turbo Prolog 内部定义好了的 6 个谓词。这 6 个关系运算符可用来比较两个算术表达式的大小。例如:

    brother(Name1, Name2) :- person(Name1, man, Age1),
    				   person(Name2, man, Age2),
    				   mother(Z, Name1), mother(Z, Name2), Age1 > Age2.
    

    需要说明的是,“=”的用法比较特殊,它既可以表示比较,也可以表示约束值,即使在同一个规则中的同一个“=”也是如此。例如:

    p(X, Y, Z) :- Z = X + Y.
    

    当变量 X、Y、Z全部被实例化时,“=”就是比较符。如对于问题:

    Goal: p(3, 5, 8).
    

    机器回答“yes”,而对于:

    Goal: p(3, 5, 7).
    

    机器回答“no”。即这时机器把 X+Y 的值与Z的值进行比较。但当 X,Y 被实例化,而 Z 未被实例化时, “=”号就是约束符,如:

    Goal: P(3, 5, Z).
    

    机器回答“Z = 8”。这时,机器使 Z 实例化为 X+Y 的结果。

    三、输入与输出

    虽然 Prolog 能自动输出目标子句中的变量的值,但这种输出功能必定有限,往往不能满足实际需要;另外,对通常大多数的程序来说,运行时从键盘上输人有关数据或信息也是必不可少的。为此每种具体 Prolog 一般都提供专门的输人和输出谓词,供用户直接调用。例如,下面就是 Turbo Prolog 的几种输入输出谓词:

    1. readin(X)。这个谓词的功能是从键盘上读取一个字符串,然后约束给变量 X 。
    2. readint(X)。这个谓词的功能是从键盘上读取一个整数,然后约束给变量 X,如果键盘上打入的不是整数,则该谓词失败。
    3. readreal(X)。这个谓词的功能是从键盘上读取一个实数,然后约束给变量 X,如果键盘上打入的不是实数,则该谓词失败。
    4. readchar(X)。这个谓词的功能是从键盘上读取一个字符,然后约束给变量 X,如果键盘上打入的不是单个字符,则该谓词失败。
    5. write(X1, X2, …, Xn)。这个谓词的功能是把项 Xi(i=1,2,…,n) 的值显示在屏幕上或者打印在纸上,当有某个 Xi 未实例化时,该谓词失败。其中的 Xi 可以是变量,也可以是字符串或数字。例如:
      write("computer", "Prolog", Y, 1992)
    6. nl(换行谓词)。它使后面的输出(如果有的话)另起一行。另外,利用 write的输出项“\n”也同样可起到换行作用。例如:
      write("name"), nl, write("age")

      write("name", "\n", "age")
      的效果完全一样。

    举个例子:
    用上面的输入输出谓词编写一个简单的学生成绩数据库查询程序。

    PREDICATES
       student(integer, string, real)
       grade
    GOAL
       grade.
    CLAUSES
       student(1, "张三", 90.2).
       student(2, "李四", 95.5).
       student(3, "王五", 96.4).
       grade :- write("请输人姓名:"), readln(Name), 
    		    student(_, Name, Score),
    		    nl, write(Name, "的成绩是", Score).
       grade :- write("对不起,找不到这个学生!").
    

    下面是程序运行时的屏幕显示

    请输入姓名:王五
    王五的成绩是96.4
    

    四、分支与循环

    Prolog 本来没有分支和循环语句,但可以利用其逻辑机制实现分支和循环效果。

    1、分支

    对于通常的 IF-THEN-ELSE 分支结构,Prolog可用两条同头的(同头即指结论相同)并列规则实现。例如,将:

    IF X>0 THEN X:=1
    ELSE X:=0
    

    用 Prolog实现则是:

    br :- X > 0, X = 1.
    br :- X = 0.
    

    类似地,对于多分支,可以用多条规则实现。例如:

    br :- X > 0, X = 1.
    br :- X = 0, X = 0.
    br :- X < 0, X = -1.
    

    2、循环

    Prolog 可以实现计循环次数的 FOR 循环,也可以实现不计循环次数的 DO 循环。

    举个例子:
    下面的程序段就实现了循环,它使得 write 语句重复执行了3次,而打印输出了3个学生的记录:

    student(1, "张三", 90.2).
    student(2, "李四", 95.5).
    student(3, "王五", 96.4).
    print :- student(Number, Name, Score),
    		write(Number, Name, Score), nl,
    		Number = 3.
    

    可以看出,程序第一次执行,student 谓词与第一个事实匹配,write 语句便输出了张三同学的记录。但当程序执行到最后一句时,由于 Number 不等于 3,则该语句失败,于是,引起回溯。而 write 语句和 nl 语句均只能执行一次,所以继续向上回溯到 student 语句。这样,student 谓词则因失败而重新匹配。这一次与第二个事实匹配,结果输出了李四的记录。同理,当执行到最后一句时又引起了回溯。write 语句第三次执行后,由于 Number 已等于3,所以最后一个语句成功,程序段便运行结束。
    这个例子可以看做是计数循环。当然,也可以通过设置计数器而实现真正的计数循环。下面的程序段实现的则是不计数的 DO 循环:

    student(1, "张三", 90.2).
    student(2, "李四", 95.5).
    student(3, "王五", 96.4).
    print :- student(Number, Name, Score),
    		write(Number, Name, Score), nl,
    		fail.
    print :-.
    

    这个程序段中的 fail 是一个内部谓词,它的语义是恒失败。这个程序段与上面的程序段的差别仅在于把原来用计数器(或标记数)进行循环控制的语句变成了恒失败谓词 fail,另外又增加了一个 print 语句,增加这个语句的目的是为程序设置一个出口。因为 fail 是恒失败,下面若无出口的话,将引起 print 本身的失败,进而又会导致程序的连锁失败。
    还需说明的是,用 Prolog的递归机制也可以实现循环,不过用递归实现循环通常需与表相配合。另外,递归的缺点是容易引起内存溢出,故通常的循环多是用上述方法实现的。

    五、动态数据库

    动态数据库就是在内存中实现的动态数据结构。它由事实组成,程序可以对它操作,所以在程序运行期间它可以动态变化。Turbo Prolog 提供了 3 个动态数据库操作谓词,即:

    asserta(< fact >)
    assertz(< fact >)
    retract(< fact >)
    

    其中 fact 表示事实。这 3 个谓词的功能如下:

    • asserta(< fact >) 把 fact 插入当前动态数据库中的同名谓词的事实之前。
    • assertz(< fact >) 把 fact 插入当前动态数据库中的同名谓词的事实之后。
    • retract(< fact >) 把 fact 从当前动态数据库中删除。

    例如语句:

    asserta(student(20, "李明", 90.5)).
    

    将在内存的谓词名为 student 的事实前插入一个新事实:

    student(20, ''李明", 90.5)
    

    如果内存中还没有这样的事实,则它就是第一个。又如语句:

    retract(student(20, _, _)).
    

    将从内存的动态数据库中的删除事实:

    student(20, _, _)
    

    它可解释为学号为 20 的一个学生的记录。注意,这里用了无名变量 “_”
    可以看出,Turbo Prolog 提供的动态数据库机制,可非常方便地实现堆栈、队列等动态数据结构,提供的数据库操作谓词大大简化了编程。
    另外,Turbo Prolog 还提供了两个文件操作谓词:

    save(< filename >).
    consult(< filename >).
    

    其中 save 可将当前内存中的事实存入文件“filename”中,consult 则将文件“filename”中的事实调入内存。

    六、表处理与递归

    1、表头与表尾

    表是 Prolog 中一种非常有用的数据结构。表的表述能力很强,数字中的序列、集合,通常语言中的数组、记录等均可用表来表示。表的最大特点是其长度不固定,在程序的运行过程中可动态地变化。具体来讲,就是在程序运行时,可对表施行一些操作,如给表中添加一个元素,或从中删除一个元素,或者将两个表合并为一个表等。用表还可以方便地构造堆栈、队列、链表、树等动态数据结构。
    表还有一个重要特点,就是它可分为两部分。表头是表中第一个元素,而表尾是表中除第一个元素外的其余元素按原来顺序组成的。例如下面的表所示就是一个例子。

    表 头表 尾
    [1, 2, 3, 4, 5]1[2, 3, 4, 5]
    [apple, orange, banana]apple[orange, banana]
    [[a, b], [c], [d, e]][a, b][[c], [d, e]]
    [“Prolog”]“Prolog”[]
    []无定义无定义
    **表头与表尾示例** 表

    2、表的匹配合一

    在程序中是用“|”来区分表头和表尾的,而且还可以使用变量。例如一般地用[H|T]来表示一个表,其中 H、T 都是变量,H 为表头,T为表尾。注意,此处 H 是一个元素(表中第一个元素),而 T 则是一个表(除第一个元素外表中的其余元素按原来顺序组成的表)。表的这种表示法很有用,它为表的操作提供了极大的方便。如下面的表所示即为用这种表示法通过匹配合一提取表头和表尾的例子。

    表1表2合一后的变量值
    [X | Y][a, b, c]X = a, Y = [b, c]
    [X | Y][a]X = a, Y = []
    [a | Y][X, b]X = a, Y = [b]
    [X, Y, Z][a, b, c]X = a, Y = b, Z = c
    [[a, Y] | Z][[X, b], [c]]X = a, Y = b, Z = [[c]]
    **表的匹配合一示例** 表

    还需说明的是,表中的“|”后面只能有一个变量。例如写法 [X | Y, Z] 就是错误的。但竖杠前面的变量可以多于一个。例如写法 [ X, Y | Z] 是允许的。这样,这个表同 [a, b, c] 匹配合一后,有:

    X = a, Y = b, Z = [c]
    

    另外,竖杠的前面和后面也可以是常量,例如 [a | Y] 和 [X | b] 都是允许的,但需要注意,后一个表称为无尾表,如果它同表 [a | Y] 匹配,则有:

    X = a, Y = b	(而不是 Y = [b])
    

    如果无“|”,则不能分离出表尾。例如,表 [X, Y, Z] 与 [a, b, c] 合一后得 X = a,Y = b,Z = c,其中变量 Z 并非等于 [c] 。

    接下来我们通过三个例子来更详细地了解表的操作

    例6-1:设计一个能判断对象 X 是表 L 的成员的程序。
    我们可以这样设想:
    如果 X 与表 L 中的第一个元素(即表头)是同一个对象,则 X 就是 L的成员;
    如果 X 是 L 的尾部的成员,则 X 也就是 L 的成员。
    根据这种逻辑关系,有下面的 Prolog 程序:

    member(X, [X | Tail]).
    member(X, [Head | Tail]) :- member(X, Tail).
    

    其中第一个子句的语义就是上面的第一句话;第二个子句的语义就是上面的第二句话。可以看出,这个程序中使用了递归技术,因为谓词 member 的定义中又含有它自身。利用这个程序就可以判定任意给定的一个对象和一个表之间是否具有 member(成员)关系。例如,取表 L 为 [a, b, c, d],取 X 为 a,对上面的程序提出如下询问:

    Goal : member(a, [a, b, c, d]).
    

    则回答“yes”。同样对于询问:

    Goal : member(b, [a, b, c, d]).
    Goal : member(c, [a, b, c, d]).
    Goal : member(d, [a, b, c, d]).
    

    均回答“yes”。但若询问:

    Goal : member(e, [a, b, c, d]).
    

    则回答“no”。如果我们这样询问:

    Goal : member(X, [a, b, c, d]).
    

    意思是要证明存在这样的 X,它是该表的成员,这时系统返回 X 的值,即:

    X = a
    

    如果需要的话,系统还会给出 X 的其他所有值。

    例6-2:写一个表的拼接程序,即把两个表连接成一个表。

    append([], L, L).
    append([H | T], L2, [H | Tn]) :- append(T, L2, Tn).
    

    程序中第一个子句的意思是空表同任一表 L 拼接的结果仍为表 L;第二个子句的意思是说,一个非空的表 L1 与另一个表 L2 拼接的结果 L3 是这样一个表,它的头是 L1 的头,它的尾是由 L1 的尾 T 同 L2 拼接的结果 Tn。这个程序刻画了两个表与它们的拼接表之间的逻辑关系。
    可以看出,谓词 append 是递归定义的,子句append([], L, L).为终结条件即递归出口。
    对于这个程序,如果我们询问:

    Goal : append([1, 2, 3], [4, 5], L).
    

    则系统便三次递归调用程序中的第二个子句,最后从第一个子句终止,然后反向依次求出每次的拼接表,最后输出:

    L=[1, 2, 3, 4, 5]
    

    当然,对于这个程序也可以给出其他各种询问,如:

    Goal : append([1, 2, 3], [4, 5], [1, 2, 3, 4, 5]).
    

    系统回答yes

    Goal : append([1, 2, 3], [4, 5], [1, 2, 3, 4, 5, 6]).
    

    系统回答no

    Goal : append([1, 2, 3], Y, [1, 2, 3, 4, 5]).
    

    系统回答X = [4, 5]

    Goal : append(X, [4, 5], [1, 2, 3, 4, 5]).
    

    系统回答X = [1, 2, 3]

    Goal : append(X, Y, [1, 2, 3, 4, 5]).
    

    系统回答

    X = [], Y = [1, 2, 3, 4, 5]
    X = [1], Y = [2, 3, 4, 5]
    X = [1, 2], Y = [3, 4, 5]
    X = [1, 2, 3], Y = [4, 5]
    等(如果需要所有解的话)。
    

    例6-3:表的输出

    print([]).
    print([H | T]) :- write(H), print(T).
    

    例6-4:表的倒置,即求一个表的逆序表。

    reverse([], []).
    reverse([H | T], L) :- reverse(T, L1), append(L1, [H], L).
    

    这里,reverse的第一个项是输入,即原表;第二个项是输出,即原表的倒置。

    七、回溯控制

    Prolog 在搜索目标解的过程中,具有回溯机制,即当某一个子目标“Gi”不能满足时,就返回到该子目标的前一个子目标“Gi-1”,并放弃“Gi-1”的当前约束值,使它重新匹配合一。在实际问题中,有时却不需要回溯,为此 Prolog 中就专门定义了一个阻止回溯的内部谓同——“!”,称为截断谓词

    截断谓词的语法格式很简单,就是一个感叹号“!”。! 的语义如下。

    1. 若将“!”插在子句体内作为一个子目标,它总是立即成功。
    2. 若“!”位于子句体的最后,则它就阻止对它所在子句的头谓词的所有子句的回溯访向,而让回溯跳过该头谓词(子目标),去访问前一个子目标(如果有的话)。
    3. 若“!”位于其他位置,则当其后发生回溯且回溯到“!”处时,就在此处失败,并且“!”还使它所在子句的头谓词(子目标)整个失败(即阻止再去访问头谓词的其余子向(如果有的话),即迫使系统直接回溯到该头谓词(子目标)的前一个子目标(如果有的话))。

    举个例子:
    考虑下面的程序

    p(a).						(7 - 1)
    p(b).						(7 - 2)
    q(b).						(7 - 3)
    r(X) :- p(X), q(X).			(7 - 4)
    r(c).
    

    对于目标:r(X).可有一个解:
    Y = b
    但当我们把式(7 - 4)改为:

    r(X) :- p(X), !, q(X).		(7 - 4')
    

    时,却无解。为什么?
    这是由于添加了截断谓词“!”。因为式(7 - 4’)中求解子目标 p(X) 时,X 被约束到 a,然后跳过“!”,但在求解子目标 q(a) 时遇到麻烦,于是又回溯到“!”,而“!”阻止了对 p(X)的下一个子句 p(b) 和 r 的下一个定义子句 r© 的访问。从而导致整个求解失败。

    再举个例子:
    设有程序:

    g0 :- g11, g12, g13.		(7 - 5)
    g0 :- g14.					(7 - 6)
    g12 :- g21, !, g23.			(7 - 7)
    g12 :- g24, g25.			(7 - 8)
    ... ...
    

    给出目标:g0
    假设运行到子目标 g23 时失败,这时如果子句(7 - 7)中无“!”的话,则会回溯到 g21,并且如果 g21 也失败的话,则会访问下面的子句(7 - 8)。但由于有“!”存在,所以不能回溯到 g21,而直接宣告 g12 失败。于是由子句(7 - 5),这时则回溯到 g11。如果我们把子句(7 - 7)改为:

    g12 :- g21, g23, !.			(7 - 9)
    

    当然这时若 g23 失败时,便可回溯到 g21,而当 g21 也失败时,便回溯到 g12,即子句(7 - 8)被“激活”。但对于修改后的程序,如果 g13 失败,则虽然可回溯到 g12,但对 g12 不做任何事情便立即跳过它,而回溯到 g11。如果子句(7 - 9)中无“!”,则当 g13 失败时,回溯到 g12 便去考虑子句(7 - 8),只有当子句(7 - 8)再失败时才回溯到 g11。

    八、程序举例

    下面给出几个简单而又典型的程序实例。通过这些程序,读者可以进一步体会和理解 Prolog 程序的风格和能力,也可以掌握一些基本的编程技巧。

    例8-1:下面是一个简单的路径查询程序。程序中的事实描述了如下图所示的有向图,规则是图中两节点间有通路的定义。
    这里写图片描述

    predicates
    	road(symbol, symbol)
    	path(symbol, symbol)
    clauses
    	road(a, b).
    	road(a, c).
    	road(b, d).
    	road(c, d).
    	road(d, e).
    	road(b, e).
    	path(X, Y) :- road(X, Y).
    	path(X, Y) :- road(X, Z), path(Z, Y).
    

    程序中未含目标,所以运行时需给出外部目标。例如当给出目标:

    path(a, e).
    

    时,系统将回答yes,但当给出目标:

    path(e, a).
    

    时,系统则回答no,如果给出目标:

    run.
    

    且在程序中增加子句:

    run :- path(a, X), write("X =", X), nl, fail.
    run.
    

    屏幕上将会输出:

    X = b
    X = c
    X = d
    X = e
    X = d
    X = e
    X = e
    

    即从 a 出发到其他节点的全部路径。

    例8-2:下面是一个求阶乘程序,程序中使用了递归。

    /* a Factorial Program */
    domains
    	n, f = integer
    predicates
    	factorial(n, f)
    goal
    	readint(I),
    	factorial(I, F),
    	write(I, "!=", F).
    clauses
    	factorial(1, 1).
    	factorial(N, Res) :-
    						N > 0,
    						N1 = N - 1,
    						factorial(N1, FacN1),
    						Res = N * FacN1.
    

    程序运行时,从键盘上输入一个整数,屏幕上将显示其阶乘数。

    例8-3:下面是一个表的排序程序,采用插入排序法。

    /* insert sort */
    domains
    	listi = integer*
    predicates
    	insert_sort(listi, listi)
    	insert(integer, listi, listi)
    	asc_order(integer, integer)
    clauses
    	insert_sort([], []).
    	insert\_sort([H | Tail], Sorted_list) :-
    										insert_sort(Tail, Sorted\_Tail),
    											insert(H, Sorted_Tial, Sorted\_list).
    	insert(X, [Y | Sorted_list1]) :-
    								asc_order(X, Y), !,
    								insert(X, Sorted_list, Sorted\_list1).
    	insert(X, Sorted_list, [X | Sorted\_list]).
    	asc_order(X, Y) :- X > Y.
    

    程序中对表的处理使用了递归。程序中也未给出目标,需要在运行时临时给出。例如当给出目标:

    insert_sort([5, 3, 4, 2, 6, 1, 7, 8, 9, 0], L).
    

    时,系统将输出:

    L = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    

    Visual Prolog 语言简介

    Visual Prolog 是一种可视化逻辑程序设计语言。它是美国的 Prolog 开发中心(PDC)推出的新一代 Prolog 语言,其语言特性符合相应的国际标准 ISO/IEC13211-1:1995;并自带可视化集成开发环境。
    Visual Prolog 与 Turbo Prolog 及 PDC Prolog 最显著的区别就是支持图形用户界面程序设计。Visual Prolog 及其 Visual Prolog 程序不仅能够运行于 Windows 系列操作系统环境,而且也可以运行于 Linux、SCOUNIX 和 OS/2 等操作系统环境。
    Visual Prolog 不仅可以用于逻辑程序设计,而且还支持模块化和面向对象程序设计。它几乎是一个融逻辑、函数、过程和面向对象等程序设计范型为一体的综合型程序设设计语言。
    Visual Prolog 几乎包含了各种应用程序和系统程序所需要的所有特性和功能。例如,它不仅具有诸如模式匹配、递归、回溯、动态数据库、谓词库、文件操作、图形开发、字符串处理、位级运算、算术与逻辑运算、与其他语言的接口、编译器、连接器和调试器等传统功能,而且还具有对象机制、动态连接库 DLL、多线程、异常处理,支持基于网络的应用开发,支持与 C/C++ 的直接链接,对 Win32 API 函数的直接访问以及数据库、多媒体等。而且随着版本的升级,这些特性和功能还在不断扩充和提高。
    从结构来看, Visual Prolog 包含一个大型库,捆绑了大量的 API函数,包括 Windows GUI 函数族、ODBC/OCI 数据库函数族和 Internet 函数族(socket、FTP、HTTP、CGI等)。其开发环境包含对话框、菜单、工具栏等若干编码专家和图形编辑器。
    正因为有如此强大的功能和优势,所以 Visual Prolog 已是当今智能化应用开发的有力工具。据悉,Visual Prolog 在美国、加拿大、西欧、澳大利亚、新西兰、日本、韩国、新加坡等国家和地区广为流行。
    由于篇幅所限,本节仅对 Visual Prolog 作简单介绍。有兴趣的读者可登录 PDC 网站:http://www.visual-prolog.com/,对 Visual Prolog 及其编程作进一步了解和学习。


    参考文献:《人工智能技术简明教程》–廉师友 编著

    展开全文
  • PLC常用程序设计语言简介

    千次阅读 2006-09-05 20:51:00
    PLC常用程序设计语言简介PLC常用程序设计语言简介 可编程控制器程序设计语言: 在可编程控制器有多种程序设计语言,它们是梯形图语言、布尔助记符语言、功能表图语言、功能模块图语言及结构化语句描述语言等。...

    PLC常用程序设计语言简介
    PLC常用程序设计语言简介

            可编程控制器程序设计语言: 在可编程控制器中有多种程序设计语言,它们是梯形图语言、布尔助记符语言、功能表图语言、功能模块图语言及结构化语句描述语言等。

            梯形图语言和布尔助记符语言是基本程序设计语言,它通常由一系列指令组成,用这些指令可以完成大多数简单的控制功能,例如,代替继电器、计数器、计时器完成顺序控制和逻辑控制等,通过扩展或增强指令集,它们也能执行其它的基本操作。

            功能表图语言和语句描述语言是高级的程序设计语言,它可根据需要去执行更有效的操作,例如,模拟量的控制,数据的操纵,报表的报印和其他基本程序设计语言无法完成的功能。

            功能模块图语言采用功能模块图的形式,通过软连接的方式完成所要求的控制功能,它不仅在可编程序控制器中得到了广泛的应用,在集散控制系统的编程和组态时也常常被采用,由于它具有连接方便、操作简单、易于掌握等特点,为广大工程设计和应用人员所喜爱。 根据可编程器应用范围,程序设计语言可以组合使用,常用的程序设计语言是: 梯形图程序设计语言  布尔助记符程序设计语言(语句表) 功能表图程序设计语言 功能模块图程序设计语言  结构化语句描述程序设计语言   梯形图与结构化语句描述程序设计语言  布尔助记符与功能表图程序设计语言  布尔助记符与结构化语句描述程序设计语言 

            1、梯形图(Ladder Diagram)程序设计语言: 梯形图程序设计语言是用梯形图的图形符号来描述程序的一种程序设计语言。采用梯形图程序设计语言,程序采用梯形图的形式描述。这种程序设计语言采用因果关系来描述事件发生的条件和结果。每个梯级是一个因果关系。在梯级中,描述事件发生的条件表示在左面,事件发生的结果表示在后面。梯形图程序设计语言是最常用的一种程序设计语言。它来源于继电器逻辑控制系统的描述。在工业过程控制领域,电气技术人员对继电器逻辑控制技术较为熟悉,因此,由这种逻辑控制技术发展而来的梯形图受到了欢迎,并得到了广泛的应用。 

             梯形图程序设计语言的特点是:(1)与电气操作原理图相对应,具有直观性和对应性;

        (2)与原有继电器逻辑控制技术相一致,对电气技术人员来说,易于撑握和学习;

        (3)与原有的继电器逻辑控制技术的不同点是,梯形图中的能流(Power FLow)不是实际意义的电流,内部的继电器也不是实际存在的继电器,因此,应用时,需与原有继电器逻辑控制技术的有关概念区别对待; (4)与布尔助记符程序设计语言有一一对应关系,便于相互的转换和程序的检查。 

             2、布尔助记符(Boolean Mnemonic)程序设计语言 布尔助记符程序设计语言是用布尔助记符来描述程序的一种程序设计语言。布尔助记符程序设计语言与计算机中的汇编语言非常相似,采用布尔助记符来表示操作功能。布尔助记符程序设计语言具有下列特点: 

    (1)采用助记符来表示操作功能,具有容易记忆,便于撑握的特点; 

    (2)在编程器的键盘上采用助记符表示,具有便于操作的特点,可在无计算机的场合进行编程设计; (3)与梯形图有一一对应关系。其特点与梯形图语言基本类同。      

            3、功能表图(Sepuential Function Chart)程序设计语言 功能表图程序设计语言是用功能表图来描述程序的一种程序设计语言。它是近年来发展起来的一种程序设计语言。采用功能表图的描述,控制系统被分为若干个子系统,从功能入手,使系统的操作具有明确的含义,便于设计人员和操作人员设计思想的沟通,便于程序的分工设计和检查调试。功能表图程序设计语言的特点是: 

    (1)以功能为主线,条理清楚,便于对程序操作的理解和沟通; 

    (2)对大型的程序,可分工设计,采用较为灵活的程序结构,可节省程序设计时间和调试时间; (3)常用于系统的规模校大,程序关系较复杂的场合; 

    (4)只有在活动步的命令和操作被执行,对活动步后的转换进行扫描,因此,整个程序的扫描时间较其他程序编制的程序扫描时间要大大缩短。 功能表图来源于佩特利(Petri)网,由于它具有图形表达方式,能较简单和清楚地描述并发系统和复杂系统的所有现象,并能对系统中存有的象死锁、不安全等反常现象进行分析和建模,在模型的基础上能直接编程,所以,得到了文泛的应用。近几年推出的可编程控制器和小型集散控制系统中也已提供了采用功能表图描述语言进行编程的软件。关于佩特利(Petri)网的一些基本概念,我在以后有机会时再介绍给各位,以有助于对功能表图的进一步理解。 

            4、功能模块图(Function Block)程序设计语言  功能模块图程序设计语言是采用功能模块来表示模块所具有的功能,不同的功能模块有不同的功能。它有若干个输入端和输出端,通过软连接的方式,分别连接到所需的其它端子,完成所需的控制运算或控制功能。功能模块可以分为不同的类型,在同一种类型中,也可能因功能参数的不同而使功能或应用范围有所差别,例如,输入端的数量、输入信号的类型等的不同使它的使用范围不同。由于采用软连接的方式进行功能模块之间及功能模块与外部端子的连接,因此控制方案的更改、信号连接的替换等操作可以很方便实现。功能模块图程序设计语言的特点是: (1)以功能模块为单位,从控制功能入手,使控制方案的分析和理解变得容易; (2)功能模块是用图形化的方法描述功能,它的直观性大大方便了设计人员的编程和组态,有较好的易操作性; (3)对控制规模较大、控制关系较复录的系统,由于控制功能的关系可以较清楚地表达出来,因此,编程和组态时间可以缩短,调试时间也能减少; (4)由于每种功能模块需要占用一定的程序内存,对功能模块的执行需要一定的执行时间,因此,这种设计语言在大中型可编程控制器和集散控制系统的编程和组态中才被采用。 

            5、结构化语句(Structured Text)描述程序设计语言: 结构化语句描述程序设计语言是用结构化的描述语句来描述程序的一种程序设计语言。它是一种类似于高级语言的程序设计语言。在大中型的可编程序控制器系统中,常采用结构化语句描述程序设计语言来描述控制系统中各个变量的关系。它也被用于集散控制系统的编程和组态。 结构化语句描述程序设计语言采用计算机的描述语句来描述系统中各种变量之间的各种运算关系,完成所需的功能或操作。大多数制造厂商采用的语句描述程序设计语言与BASIC语言、PASCAL语言或C语言等高级语言相类似,但为了应用方便,在语句的表达方法及语句的种类等方面都进行了简化。结构化程序设计语言具有下列特点: 

    (1)采用高级语言进行编程,可以完成较复杂的控制运算; 

    (2)需要有一定的计算机高级程序设计语言的知识和编程技巧,对编程人员的技能要求较高,普通电气人员无法完成。 

    (3)直观性和易操作性等性能较差; 

    (4)常被用于采用功能模块等其他语言较难实现的一些控制功能的实施。 部分可编程序控制器的制造厂商为用户提供了简单的结构化程序设计语言,它与助记符程序设计语言相似,对程序的步数有一定的限制,同时,提供了与可编程序控制器间的接口或通信连接程序的编制方式,为用户的应用程序提供了扩展余地。

     
    展开全文
  • 程序设计语言基本概念

    千次阅读 2012-09-10 08:46:45
    在计算机程序设计语言可划分为低级语言和高级语言两大类,与高级语言相比,用低级语言开发的程序,其运行效率高,但开发效率低。与程序设计相关的基本概念如下。 (1)低级语言:又称面向机器语言,它是特定的...

    一、基本概念

    在计算机中,程序设计语言可划分为低级语言和高级语言两大类,与高级语言相比,用低级语言开发的程序,其运行效率高,但开发效率低。与程序设计相关的基本概念如下。

    (1)低级语言:又称面向机器语言,它是特定的计算机系统所固有的语言。

    (2)汇编语言:是机器语言的一种提升,它使用了一些助记符来表示机器指令中的操作码和操作数。但它仍然是一种和计算机机器语言十分接近的语言,使用起来仍然不太方便。

    (3)高级语言:与人们的自然语言比较接近,使用起来很方便,也极大的提高了程序设计效率。

    (4)编译程序:也称编译器,将源程序翻译成目标语言程序,然后在计算机上运行目标程序。虽然执行效率高,但编写出来的程序可读性很差,且难以修改和维护。

    (5)解释程序:也称解释器,它或者直接解释执行源程序,或者将源程序翻译成某种中间代码后再加以执行。

    (6)程序设计语言:程序设计语言的定义都涉及语法、语义和语用等方面。

    (7)语法是指由程序语言的基本符号组成程序中的各个语法成分(包括程序)的一组规则,其中由基本字符构成的符号(单词)书写规则称为词法规则,由符号构成语法成分的规则称为语法规则。

    (8)语义是程序语言中按语法规则构成的各个语法成分的含义,分为静态语义和动态语义。

    (9)语用表示了构成语言的各个记号和使用者的关系,涉及符号的来源、使用和影响。

    (10)语境是指理解和实现程序设计语言的环境,包括编译环境和运行环境。

    二、程序设计语言的分类

    1.命令式程序设计语言

    命令式程序设计语言是基于动作的语言,在这种语言中,计算被看成是动作的序列。

    结构化程序设计语言属于命令式语言类,其结构特性主要有:一是用自顶向下逐步精化的方法编程,二是按照模块组装的方法编程,三是程序只包含顺序、判定(分支)及循环结构,而且每种构造只允许单入口和单出口。C语言、PASCAl等都是典型的结构化程序设计语言。

    2.面向对象程序设计语言

    面向对象的程序设计在很大程度上应归功于从模拟领域发展起来的Simula,Simula提出了类和对象的概念。C++、Java和smalltalk是面向对象程序设计语言的代表。

    3.函数式程序设计语言

    函数式程序设计语言是一类以λ-演算为基础的语言,其概念来自于Lisp,一个在 1958年为了人工智能应用而设计的语言。函数是一种对应规则(映射),它使定义域中每个元素和值域中唯一的元素对应。

    函数定义1:Square[x]:=x×x

    函数定义2:Plustwo[x]:= Plusone[Plusone[x]]

    函数定义3:fact[n]:=if n =0 then 1 else n×fact[n-1]

    4.逻辑型程序设计语言

    逻辑型程序设计语言是一类以形式逻辑为基础的语言,其代表是建立在关系理论和一阶谓词理论基础上的Prolog(Programming in Logic)。Prolog程序是一系列事实、数据对象或事实间的具体关系和规则的集合。通过查询操作把事实和规则输入数据库。用户通过输入查询来执行程序。在 Prolog中,关键操作是模式匹配,通过匹配一组变量与一个预先定义的模式并将该组变量赋给该模式来完成操作。

    三、程序设计语言的基本成分

    1.数据成分

    数据成分指的是一种程序语言的数据类型。

    (1)常量和变量

    按照程序运行时数据的值能否改变,将数据分为常量和变量。变量具有左值和右值,在程序运行过程中其右值可以改变;常量只有右值,在程序运行过程中不能改变。

    (2)全局变量和局部变量

    按照数据的作用域范围,可分为全局变量和局部变量。系统为全局变量分配的存储空间在程序运行的过程中一般是不改变的,而为局部变量分配的存储单元是动态改变的。

    (3)数据类型

    按照数据组织形式不同可将数据分为基本类型、用户定义类型、构造类型和其他类型。

    基本类型:整型(int)、字符型(char)、实型(float、double)和布尔类型(bool)。

    特殊类型:空类型(void)。

    用户定义类型:枚举类型(enum)。

    构造类型:数组、结构、联合。

    指针类型:type *。

    抽象数据类型:类类型。

    2.运算成分

    程序语言的运算成分指明允许使用的运算符号及运算规则。大多数高级程序语言的基本运算可分成算术运算、关系运算和逻辑运算,有些语言如C(C++)还提供位运算。

    3.控制成分

    控制成分指明语言允许表述的控制结构。

    (1)顺序结构

    顺序结构用来表示一个计算操作序列,从第一个操作开始,按顺序依次执行后续的操作,直到最后一个操作,如图2-1所示。(2)选择结构选择结构提供了在两种或多种分支中选择其中一个的逻辑,如图2-2所示。

     
    图 2-1 顺序结构示意图
     
    图 2-2 选择结构示意图

    (3)循环结构

    循环结构描述了重复计算的过程,通常由三部分组成:初始化、循环体和循环条件。主要有两种形式:while型循环结构和do-while型循环结构,如图2-3所示。

     

    (4)C(C++)语言提供的控制语句

    ①复合语句

    复合语句用于描述顺序控制结构。复合语句是一个整体,要么全部执行,要么一条语句也不执行。

    ② if语句和switch语句

    if语句实现的是双分支的选择结构,其一般形式为: 

     
    1. if(表达式)  
    2. 语句1;   
    3. else   
    4. 语句2; 

    需要注意的是if和else的匹配关系。

    switch语句描述了多分支的选择结构,其一般形式为:

     
    1. switch(表达式){   
    2. case 常量表达式1:语句1;  
    3.  case 常量表达式2:语句2;  
    4.  
    5.  …  
    6.  case 常量表达式n:语句n;  
    7.  default:语句n+1;   
    8.  
    9. }  
    ③ 循环语句主要指while语句、do-while语句和for语句。 while语句描述了先判断条件再执行循环体的控制结构,其一般形式为:
     
    1. while(条件表达式)   
    2. {   
    3.  
    4. 循环体语句;   
    5.  
    6. }  
    do-while语句描述了先执行循环再判断条件的控制结构,其一般格式是:
     
    1. do   
    2.  
    3. 循环体语句;   
    4. while(条件表达式);  

    for语句的基本格式是:

     
    1. for(表达式1;表达式2;表达式3;)循环体语句; 
    可用while语句等价地表示为:
     
    1. 表达式1;   
    2. while(表达式2){   
    3. 循环体语句;  
    4. 表达式3;   
    5. }  

    4.函数

    函数是程序模块的主要成分,它是一段具有独立功能的程序。函数的使用涉及三个概念:函数定义、函数声明和函数调用。

    ①函数定义

    函数定义包括两部分:函数首部和函数体。函数定义描述了函数做什么和怎么做。其一般格式是:

     
    1. 返回值类型函数名(形参表)   
    2. {   
    3. 函数体;   

    ②函数声明

    函数应该先声明后引用。如果程序中对一个函数的调用在该函数的定义之前进行,则应该在调用前对被调用函数进行声明。函数原型用于声明函数。函数声明的一般形式为:

     
    1. 返回值类型函数名(形参表); 

    ③函数调用

    当在一个函数(称为主调函数)中需要使用另一个函数(称为被调函数)实现的功能时,便以名字进行调用,称为函数调用。函数调用的一般形式为:

     
    1. 函数名(实参表); 

    四、值调用和引用调用

    在C程序的执行过程中,通过函数调用实现了函数定义时描述的功能。函数体中若调用自己,则称为递归调用。C和C++通过传值方式将实参传递给形参。

    调用函数和被调用函数之间交换信息的方法主要有两种:一种是由被调函数把返回值返回给主调函数,另一种是通过参数带回信息。函数调用时实参与形参间交换信息的方法有值调用和引用调用两种。

    (1)传值调用(Call by Value)

    若实现函数调用时实参向形式参数传递相应类型的值(副本),则称为是传值调用。

    C语言采用的是传值调用的方式。传值调用最显著的特征是被调用的函数内部对形参的修改不影响实参的值。传值调用的参数传递和被调用函数内对参数的使用主要按下述原则:函数定义时形参被当作局部变量看待,在函数被调用时为形参分配存储单元;调用函数前,首先计算实参的值,调用时将实参的值放入形参的存储单元;被调用函数内部对形参单元中的数据进行直接访问。

    (2)引用调用(Call by Reference)引用是C++中增加的数据类型,当形式参数为引用类型时,形参名实际上是实参的别名,函数中对形参的访问和修改实际上就是针对相应实际参数所作的访问和改变。

    实际上,引用调用是将实参的地址传递给形参,使得形参的地址就是对应实参的地址。引用调用的参数传递和被调用函数内对参数的使用主要按下述原则处理:函数定义时形参被当作局部变量看待,在函数被调用时为形参分配存储单元;调用时将实参的地址放入形参的存储单元;被调用函数内部对形参单元中的数据(地址)进行间接访问。

    怎么考

    【试题 2-1】2011年 11月真题 20

    若C程序的表达式中引用了未赋初值的变量,则( 20)。

    (20)A. 编译时一定会报告错误信息,该程序不能允许

    B. 可以通过编译并运行,但运行时一定会报告异常

    C. 可以通过编译,但链接时一定会报告错误而不能运行

    D. 可以通过编译并运行,但运行结果不一定是期望的结果

    分析:全局变量和静态局部变量在定义时如果没有初始化,编译时会自动初始化为0;而普通的局部变量,如果没有初始化,则其值是一个随机数。在 C程序表达式中,只要引用的变量定义了,就可以通过编译并运行,但运行结果不一定是期望的结果。【答案:d】

    【试题 2-2】2011年 11月真题 49、50

    函数t、f的定义如下所示,其中, a是整型全局变量。设调用函数t前a的值为5,则在函数中以传值调用( call by value)方式调用函数f时,输出为(49);在函数t中以引用调用(call by reference)方式调用函数时,输出为(50)。


     

    (49)A. 12  B. 16  C. 20  D. 24

    (50)A. 12  B. 16  C. 20  D. 24

    分析:本题主要考查函数调用时参数的传递方式。如果采用传值方式调用,则形参值的变化不会影响实参;而采用引用方式调用,则形参值的变化直接反映到实参。

    本题中如果在函数t中采用传值方式调用函数f,a的值传给形参r,在函数f中,a的值变为6,r的值为10并返回赋给变量x,由于a是全局变量,退出函数f后a的值依然为6,所以函数t的输出结果为16。如果函数t采用传值方式调用函数f,则形参r就是对实参a的引用,对r的修改就是对a的修改,在执行a=r+1时,a和r的值都变为6,执行r=r*2,a和r的值都变为12,并将r的值返回给x,因此函数t的输出结果为24。

    【答案:(49)B (50)D】

    【试题 2-3】2011年 11月真题 57

    在KMP模式匹配算法中,需要求解模式串 p的next函数值,其定义如下(其中, j为模式串字符的序号)。对于模式串“abaabaca”,其next函数值序列为( 57)。

     

    (57)A. 01111111  B. 01122341  C. 01234567  D. 01122334

    分析:模式串“abaabaca”的next函数值序列如下。

     

    当j=1时,next[1]=0;当j=2时,k不存在,next[2]=1;当j=3时,不存在满足条件的k,next[3]=1;当j=4时,p1=p3=a,存在k=2,使得 ' p1 p2 Lpk .1'=' pj.k +1 pj.k +2 L pj.1' ,故next[4]=2;当j=5时,存在k=2,使得 ' p1 p2 Lpk .1'=' pj.k +1 pj.k +2 L pj.1' ,即p1=p4=a,故next[5]=2;当j=6时,存在k=3,使得’p1p2’ =’p4p5’ ,故 next[6]=3;当j=7时,存在k=4,使得’p1p2 p3’ =’p4p5 p6’ ,故next[7]=4;当j=8时,不存在满足条件的k值,故 next[8]=1。【答案:B】

    【试题 2-4】2011年 5月真题 22

    若一种程序设计语言规定其程序中的数据必须具有类型,则有利于( 22)。

    ①在翻译程序的过程中为数据合理分配存储单元

    ②对参与表达式计算的数据对象进行检查

    ③定义和应用动态数据结构

    ④规定数据对象的取值范围及能够进行的运算

    ⑤对数据进行强制类型转换

    (22)A.①②③ B.①②④ C.②④⑤ D.③④⑤

    分析:数据是程序操作的对象,类型说明数据占用的内存和存放形式。数据类型不仅可用于在基础机器中完成对值得布局,还可以用于检查表达式中对运算的应用是否正确。【答案:B】

    【试题 2-5】2011年 5月真题 48

    以下关于高级程序设计语言翻译的叙述中,正确的是( 48)。

    (48)A.可以先进行语法分析,再进行词法分析

    B.在语法分析阶段可以发现程序中的所有错误

    C.语义分析阶段的工作与目标机器的体系结构密切相关

    D.目标代码生成阶段的工作与目标机器的体系结构密切相关

    分析:对于高级程序设计语言,编译程序会把编写的源程序翻译成与之等价的目标程序。编译程序的工作过程分为:词法分析、语法分析、语义分析、中间代码生成、代码优化、目标代码生成。语法分析要在词法分析的基础上,根据语言的语法规则将单词符号序列分解成各类语法单位。可见,要先进行词法分析,然后进行语法分析,故选项A错误。在语法分析阶段能发现语法错误,但不能发现语义错误,因此选项B错误。语义分析阶段主要检查源程序是否包含静态语义错误,并收集类型信息供后面的代码生成阶段使用,可见,语义分析阶段工作与与目标机器的体系结构关联不大,选项C错误。目标代码生成阶段的任务是把中间代码变化成特定机器上的绝对指令代码、可重定位的指令代码或汇编指令代码,这个阶段的工作与具体的机器密切相关。【答案: D】

    【试题 2-6】2011年 5月真题 50

    传值与传地址是函数调用时常采用的信息传递方式,( 50)。

    (50)A.在传值方式下,是将形参的值传给实参

    B.在传值方式下,形参可以是任意形式的表达式

    C.在传地址方式下,是将实参的地址传给形参

    D.在传地址方式下,实参可以是任意形式的表达式分析:在传值方式下,是将实参的值传给形参,形参不能向实际参数传递信息;实参可以是表达式或常量,也可以是变量或数组元素。

    在传地址方式下,是将实参的地址传给形参,实参和形参都指向同一个对象,被调用函数中对形式参数的修改实际上就是对实际参数的修改,可以实现数据的双向传递。实参必须是变量地址、数组名,不能是表达式或常量。

    形参就是形式参数,用一个变量来代表,不能是表达式。【答案:C】

    【试题 2-7】2010年 11月真题 50

    以下关于汇编语言的叙述中,错误的是(50)。

    (50)A.汇编语言源程序中的指令语句将被翻译成机器代码

    B.汇编程序先将源程序中的伪指令翻译成机器代码,然后再翻译指令语句

    C.汇编程序以汇编语言源程序为输入,以机器语言表示的目标程序为输出

    D.汇编语言的指令语句必须具有操作码字段,可以没有操作数字段

    分析:汇编程序的功能是将会变语言所编写的源程序翻译成机器指令程序。汇编语言源程序语句可分为指令语句、伪指令语句和宏指令语句。指令语句汇编后产生相应的机器代码;伪指令语句指示汇编程序在汇编源程序时完成某些操作,汇编后不产生机器代码。【答案:B】

    【试题 2-8】2010年 11月真题 64

    下面C程序段中count++语句执行的次数为(64)。

    for(int i=1;i<=11;i*=2)

    for(int j=1;j<=i;j++)

    count++;

    (64)A.15 B.16 C.31 D.32

    分析:第1轮循环,i=1,count++执行1次,然后i=2;第2轮循环,i=2,count++执行2次,然后i=4;第 3轮循环,i=4,count++执行4次,然后i=8;第4轮循环,i=8,count++执行8次,然后i=16,i>11,不满足循环条件,循环结束。可以计算count++语句执行的次数为:1+2+4+8=15【答案:A】

    【试题 2-9】2010年 5月真题 33

    程序的三种基本控制结构是(33)。

    (33)A.过程、子程序分程序 B.顺序、选择和重复

    C.递归、堆栈和队列 D.调用、返回和跳转
    分析:程序的三种基本控制结构是顺序结构、选择结构和重复结构。【答案:B】

    【试题 2-10】2009年 5月真题 20

    函数调用时,基本的参数传递方式有传值与传地址两种,( 20)。

    (20)A.在传值方式下,形参将值传给实参

    B.在传值方式下,实参不能是数组元素

    C.在传地址方式下,形参和实参间可以实现数据的双向传递

    D.在传地址方式下,实参可以是任意的变量和表达式

    分 析:首先看A选项,传值方式下,对应的实参和形参是两个独立的实体,占用不同的内存单元,调用函数时,系统把实参值复制一份给形参,便断开二者的联系,形参值的改变对实参无影响。因此,“传值”是单向的,只能由实参传递给形参。

    B选项,形参为传值方式下的简单变量,实参可以是与其同类型的常量、变量、数组元素或表达式。

    C选项,在传址方式下,函数调用时,系统将实参的地址传递给形参,即这时参数传递的不是数据本身,而是数据在内存中的地址。所以在函数被调用中,任何对形参的访问,都被认为是对形参的间接访问。实参与形参占用相同的存储单元,传递方式是双向的,形参值的改变将影响实参值。故C选项正确。

    D选项,形参为传址方式时,实参如果为常量或表达式,则传址无效,相当于传值方式。【答案: C】

    【试题 2-11】2009年 5月真题 22

    下面关于程序语言的叙述,错误的是( 22)。

    (22)A.脚本语言属于动态语言,其程序结构可以在运行中改变

    B.脚本语言一般通过脚本引擎解释执行,不产生独立保存的目标程序

    C.php、JavaScript属于静态语言,其所有成分可在编译时确定

    D.C语言属于静态语言,其所有成分可在编译时确定

    分 析:脚本语言,又叫动态语言,是一种编程语言控制软件的应用程序。脚本语言与编程语言有很多相似地方,其函数与编程语言比较类似,也涉及到变量,它与编程语言最大的区别是编程语言的语法和规则更为严格和复杂一些。脚本语言一般都有相应的脚本引擎来解释执行,一般需要解释器才能运行。 Python、JavaScript、ASP、PHP、PERL、Nuva都是脚本语言。另外,脚本语言是一种解释性的语言,它不像 C\C++等可以编译成二进制代码,以可执行文件的形式存在。【答案:C】

    【试题 2-12】2008年 12月真题 21

    程序设计语言一般都提供多种循环语句,例如实现先判断循环条件再执行循环体的while语句和先执行循环体再判断循环条件的do-while语句。关于这两种循环语句,在不改变循环体的条件下,( 21)是正确的。

    (21)A.while语句的功能可由do-while语句实现

    B.do-while语句的功能可由while语句实现

    C.若已知循环体的次数,则只能使用while语句

    D.循环条件相同时,do-while语句的执行效率更高分 析:do-while语句的循环体至少执行一次,即执行1~n次,而while语句的循环体可以不执行,也可

    以执行n次,因此do-while语句的功能可由while语句实现。【答案:B】

    【试题 2-13】2008年 5月真题 22

    下列叙述中错误的是( 22)。

    (22)A.面向对象程序设计语言可支持过程化的程序设计

    B.给定算法的时间复杂性与实现该算法所采用的程序设计语言无关

    C.与汇编语言相比,采用脚本语言编程可获得更高的运行效率

    D.面向对象程序设计语言不支持对一个对象的成员变量进行直接访问

    分 析:本题考查基本概念问题。C选项明显是错误的,脚本语言与汇编语言不是一个意义层面上的语言,而且汇编语言是接近计算机硬件的语言,运行效率是非常高的。【答案:C】



    展开全文
  • 选择学习新程序设计语言的技巧

    千次阅读 热门讨论 2009-11-30 14:59:00
     我经常被人问道:“在开发工作你是如何选择使用哪种程序设计语言的呢?”这是一个合乎情理的问题,特别是对于那些在开发领域只有极少或者没有的经验的人而言。直接了当地说“使用某某语言。”对我来说是一个巨大...
  • 教程使用了 Microsoft 宏汇编器(称为 MASM)的最新版本。Microsoft Visual Studio 的大多数版本(专业版,旗舰版,精简版……)都包含 MASM。 可以访问(asmirvine.com),了解 Visual Stud...
  • C程序设计语言(第2版·新版) 练习2-6:编写一个函数setbits(x, p, n, y),该函数返回对x执行下列操作后的结果值:将x从第p位开始的n个(二进制)位设置为y最右边n位的值,x的其余各位保持不变。  这道题想了...
  • 程序设计语言基本概念语 与经典真题

    千次阅读 热门讨论 2016-04-30 14:49:04
    在计算机程序设计语言可划分为低级语言和高级语言两大类,与高级语言相比,用低级语言开发的程序,其运行效率高,但开发效率低。与程序设计相关的基本概念如下。 (1)低级语言:又称面向机器语言,它是特定的...
  • 《C程序设计语言》练习2-1答案

    千次阅读 2014-12-22 18:21:52
    练习 2-1 编写一个程序以确定分别由signed及unsigned 限定的char、short、 int与long类型变量的取值范围。采用打印标准头文件的相应值以及直接计算两种方式实 现。后一种方法的实现较困难一些,因为要确定各种...
  • 程序设计语言编译原理课后题答案 比较全的
  • 程序设计语言及其文法1 文法:G:S→xSx | y所识别的语言是( )。 2 给定文法A→bA|ca,为该文法句子的是( )。A. bbaB. cabC. bcaD. Cba 3 设有文法G[S]:S-&gt;S1|S0|Sa|Sc|a|b|c,下列符号串是该文法的句子...
  • 以下关于程序设计语言的叙述,不正确的是() A. 脚本语言不使用变量和函数 B. 标记语言常用描述格式化和链接 C. 脚本语言采用解释方式实现 D. 编译型语言的执行效率更高 解释: 编程语言:是用来定义计算机程序...
  • 下列语言中不属于面向过程的语言是( )  ①高级语言 ②低级语言 ③C语言 ④PASCAL语言  「解」 C语言和 PASCAL等程序设计语言都是高级语言,它们用于描述复杂加工的处理过程,所以也称它们是面向过程语言。低级...
  • 面向对象程序设计JAVA语言程序设计期末复习试题及部分答案 一单选题 在下列概念Java语言只保留了D A运算符重载 B结构和联合 C指针 D 方法重载 下列类定义不正确的是B Aclass x { . } Bstatic class x implements...
  • 语言程序设计习题-答案 语言程序设计习题-答案 PAGE / NUMPAGES 语言程序设计习题-答案 4.1 分析执行下列指令序列后的结果 1 MOV AX1234H MOV BX00FFH AND AXBX 答(AX)=0034H 2 MOV AL01010101B AND AL00011111B (AL...
  • 1 文法:G:S→xSx | y所识别的语言是( )。 2 给定文法A→bA|ca,...S1|S0|Sa|Sc|a|b|c,下列符号串是该文法的句子有( )。 A. ab0 B. a0b01 C. a0b0a D. bc10 4 文法G产生的( )的全体是该文法描述的语言。 A. 句...
  • * 对程序entab和detab的功能扩充,以接受下列缩写的命令: * entab -m +n * 表示制表符从第m列开始,每隔n列停止。 */ int mygetline(char *s, int lim); void detab(const char *s, char *t, int m, int n); ...
  • PAGE / NUMPAGES 一单选题 在下列概念Java语言只保留了D A运算符重载 B结构和联合 C指针 D 方法重载 下列类定义不正确的是B Aclass x { } Bstatic class x implements y1,y2 { } Cpublic class x extends Applet...
  • 一单选题 在下列概念 Java 语言只保留了 D A运算符重载 B结构和联合 C指针 D 方法重载 下列类定义不正确的是 B Aclass x { . } B static class x implements y1,y2 { . } Cpublic class x extends Applet { . } ...
  • 下列概念 Java 语言只保留了 D A运算符重载 B结构和联合 C指针 D 方法重载 2. 下列类定义不正确的是 B Aclass x { } B static class x implements y1,y2 { } Cpublic class x extends Applet { } Dclass x ...
  • 下列概念Java 语言只保留了 D A运算符重 B结构和联合 C指针 D 方法重 2. 下列类定义不正确的是 B Aclass x { } Bstatic class x implements y1,y2 { } Cpublic class x extends Applet { } Dclass x extends ...
  • 汇编程序语言设计复习题整理

    千次阅读 2011-11-27 14:57:46
    1-10 写出下列十进制数的十六进制表示。 18 34 87 255 4095 62472 解:18=12H;34=22H;87=57H; 255=0FFH;4095=0FFFH; 62472=0F408H; 1-12 处理器的主要功能是实现所有指令的执行并处理数据。 1-14 指出...
  • 教育资料 汇编语言程序设计实验 网络* * 实验一 顺序与分支程序设计 一 实验目的 掌握顺序程序设计方法 掌握分支程序的结构及分支程序的设计调试方法 2) 学习数据传送及算术和逻辑运算指令的用法 3) 熟悉在pc机上...
  • 编写一个Octagon类,它扩展GeometricObject类并实现Comparable 和Cloneable接口,假设八边形八条边的边长相等,编写一个测试程序,创建一个边长值为5的Octagon 对象,然后显示它的周长和面积。使用colon 方法创建一...
  • 第2章基本程序设计 作者:wwj 复习题 2.2~2.7节 2.1.下列哪些标识符是合法的?哪些是java关键字? applet ,Applet , a++ , --a , 4#R , $4 , #44 , apps , class , public ,  int ,x ,y ,radius   解:...
  • 下列书籍配套使用的PPT课件: ...( 清华大学 IBM-PC 汇编语言程序设计(第二版) 沈美明 温冬婵 编著). PS:本系列资源上传一共有3个:  1\汇编语言教程. 2\配套习题集. 3\PPT课件
  • 《JAVA语言程序设计》期末考试试题及答案

    万次阅读 多人点赞 2019-12-27 10:06:57
    文章目录《JAVA语言程序设计》期末考试试题及答案1(应考必备题库)一、单选择题二、填空题三、写出下面程序的运行结果《JAVA语言程序设计》期末考试试题及答案2(应考必备题库)一.判断题二.单项选择题三.程序...
  • 一单项选择题 1Java语言是一门什么语言) A高级程序设计语言 B低级语言 C接近于硬件的语言 D脚本语言 2Java语言不能用于下列什么事项) A应用程序开发 B硬件开发 C网络编程开发 DApplet开发 3Java语言不封装在类的是...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 91,028
精华内容 36,411
关键字:

下列程序设计语言中