PL0.docx

上传人:b****6 文档编号:8381847 上传时间:2023-01-30 格式:DOCX 页数:28 大小:79.99KB
下载 相关 举报
PL0.docx_第1页
第1页 / 共28页
PL0.docx_第2页
第2页 / 共28页
PL0.docx_第3页
第3页 / 共28页
PL0.docx_第4页
第4页 / 共28页
PL0.docx_第5页
第5页 / 共28页
点击查看更多>>
下载资源
资源描述

PL0.docx

《PL0.docx》由会员分享,可在线阅读,更多相关《PL0.docx(28页珍藏版)》请在冰豆网上搜索。

PL0.docx

PL0

二、实验原理:

就像一个翻译要把汉语翻译成英语,必须对汉语和英语的单词、语法结构都很精通,才有可能翻译得准确无误。

另外,编译程序既然是为了完成这种功能的一个程序,就存在用什么语言来编写这个程序的问题。

这些问题在本节将逐步介绍。

  现对PL/0语言编译程序的功能用“T”型图表示,并用图形概括描述PL/0编译程序的结构框架。

用语法图描述语法规则的优点是直观、易读。

在图1.1的语法图中用椭圆和圆圈中的英文字表示终结符,用长方形内的中文字表示非终结符。

所谓终结符,是构成语言文法的单词,是语法成分的最小单位,而每个非终结符也是一个语法成分。

  但非终结符可由其它文法符号定义,终结符不能由其它文法符号定义。

例如,程序是由非终结符'分程序'和终结符"."组成的串定义的。

由于对某些非终结符可以递归定义,如图1.1(b)、2.1(c)、2.1(e)中:

分程序、表达式和语句。

第一个非终结符'程序'为文法的开始符号。

程序

.

分程序

1.1(a)

语句序列

语句

 

;

1.1(c)

条件

表达式

odd

 

表达式

>=

<=

>

<

<>

=

表达式

1.1(e)

分程序

=

ident

number

const

 

;

var

ident

 

;

 

;

ident

procedure

 

;

程序体

 

语句

1.1(b)

语句

:

=

表达式

 

ident

 

语句序列

 

条件

if

语句

then

 

do

while

条件

语句

ident

call

end

begin

1.1(d)

表达式

+

 

 

-

+

-

 

1.1(f)

/

因子

因子

*

 

1.1(g)

因子

ident

 

number

 

表达式

1.1(h)

如:

{*}表示*重复任意次,{*}38表示*重复3-8次。

  []:

方括号表示其内的成分为任选项。

  ():

表示圆括号内的成分优先。

例:

用EBNF描述<整数>文法的定义:

  <整数>∷=[+|-]<数字>{<数字>}

  <数字>∷=0|1|2|3|4|5|6|7|8|9

  或更好的写法

  <整数>∷=[+|-]<非零数字>{<数字>}|0

  <非零数字>∷=1|2|3|4|5|6|7|8|9

  <数字>∷=0|<非零数字>

PL/0语言文法的EBNF表示为:

  〈程序〉∷=〈分程序〉.

  〈分程序〉∷=[〈常量说明部分〉][〈变量说明部分〉][〈过程说明部分〉]〈语句〉

  〈常量说明部分〉∷=CONST〈常量定义〉{,〈常量定义〉};

  〈常量定义〉∷=〈标识符〉=〈无符号整数〉

  〈无符号整数〉∷=〈数字〉{〈数字〉}

  〈变量说明部分〉∷=VAR〈标识符〉{,〈标识符〉};

  〈标识符〉∷=〈字母〉{〈字母〉|〈数字〉}

  〈过程说明部分〉∷=〈过程首部〉〈分程序〉{;〈过程说明部分〉};

  〈过程首部〉∷=PROCEDURE〈标识符〉;

  〈语句〉∷=〈赋值语句〉|〈条件语句〉|〈当型循环语句〉|

〈过程调用语句〉|〈读语句〉|〈写语句〉|〈复合语句〉|〈空〉

  〈赋值语句〉∷=〈标识符〉∶=〈表达式〉

  〈复合语句〉∷=BEGIN〈语句〉{;〈语句〉}END

  〈条件〉∷=〈表达式〉〈关系运算符〉〈表达式〉|ODD〈表达式〉

  〈表达式〉∷=[+|-]〈项〉{〈加法运算符〉〈项〉}

  〈项〉∷=〈因子〉{〈乘法运算符〉〈因子〉}

  〈因子〉∷=〈标识符〉|〈无符号整数〉|'('〈表达式〉')'

  〈加法运算符〉∷=+|-

  〈乘法运算符〉∷=*|/

  〈关系运算符〉∷=#|=|<|<=|>|>=

  〈条件语句〉∷=IF〈条件〉THEN〈语句〉

  〈过程调用语句〉∷=CALL〈标识符〉

  〈当型循环语句〉∷=WHILE〈条件〉DO〈语句〉

  〈读语句〉∷=READ'('〈标识符〉{,〈标识符〉}')'

  〈写语句〉∷=WRITE'('〈表达式〉{,〈表达式〉}')'

  〈字母〉∷=a|b|…|X|Y|Z

  〈数字〉∷=0|1|2|…|8|9

EBNF表示的符号说明。

 〈〉:

用左右尖括号括起来的中文字表示语法构造成分,或称语法单位,为非终结符。

 ∷=:

该符号的左部由右部定义,可读作'定义为'。

 |:

表示'或',为左部可由多个右部定义。

 {}:

花括号表示其内的语法成分可以重复。

在不加上下界时可重复0到任意次数,有上下界时为可重复次数的限制。

用语法图描述语言的语法与EBNF描述相比较:

语法图描述:

直观,易读,易写。

EBNF表示:

形式化强,易机器识别。

无论用语法图或EBNF作为描述程序设计语言语法的工具,对描述的语法可以检查哪些符号序列是所给语言的合法程序,一个程序设计语言如C或JAVA,用户可用它写出成千上万个不同的程序,但C或JAVA它们各自的语法只有一个,这就使得无穷的句子集可用有穷的文法(语法)描述。

PL/0编译程序的使用限制

  ◇标识符的有效长度是10

  ◇数字最多为14位

  ◇过程最多可嵌套三层,可递归调用

  ◇标识符的作用域同PASCAL,内层可引用包围它的外层定义的标识符(如:

变量名,过程名,常量名)

目标指令有8条:

  ①LIT:

将常量值取到运行栈顶。

a域为常数值。

  ②LOD:

将变量放到栈顶。

a域为变量在所说明层中的相对位置,l为调用层

  与说明层的层差值。

  ③STO:

将栈顶的内容送入某变量单元中。

a,l域的含意同LOD指令。

  ④CAL:

调用过程的指令。

a为被调用过程的目标程序入口地址,l为层差。

  ⑤INT:

为被调用的过程(或主程序)在运行栈中开辟数据区。

a域为开辟的单元个数。

  ⑥JMP:

无条件转移指令,a为转向地址。

  ⑦JPC:

条件转移指令,当栈顶的布尔值为非真时,转向a域的地址,否则顺序执行。

  ⑧OPR:

关系运算和算术运算指令。

将栈顶和次栈顶的内容进行运算,结果存放在次栈顶,此外还可以是读写等特殊功能的指令,具体操作由a域值给出。

(详见解释执行程序)。

类pcode代码指令的详细解释(指令功能表)

  认识目标代码类pcode

  目标代码类pcode是一种假想栈式计算机的汇编语言。

  指令格式:

f

l

a

  f功能码

  l层次差(标识符引用层减去定义层)

  a根据不同的指令有所区别

指令功能表

LIT0a

将常数值取到栈顶,a为常数值

LODla

将变量值取到栈顶,a为偏移量,l为层差

STOla

将栈顶内容送入某变量单元中,a为偏移量,l为层差

CALla

调用过程,a为过程地址,l为层差

INT0a

在运行栈中为被调用的过程开辟a个单元的数据区

JMP0a

无条件跳转至a地址

JPC0a

条件跳转,当栈顶布尔值非真则跳转至a地址,否则顺序执行

OPR00

过程调用结束后,返回调用点并退栈

OPR01

栈顶元素取反

OPR02

次栈顶与栈顶相加,退两个栈元素,结果值进栈

OPR03

次栈顶减去栈顶,退两个栈元素,结果值进栈

OPR04

次栈顶乘以栈顶,退两个栈元素,结果值进栈

OPR05

次栈顶除以栈顶,退两个栈元素,结果值进栈

OPR06

栈顶元的奇偶判断,结果值在栈顶

OPR07

OPR08

次栈顶与栈顶是否相等,退两个栈元素,结果值进栈

OPR09

次栈顶与栈顶是否不等,退两个栈元素,结果值进栈

OPR010

次栈顶是否小于栈顶,退两个栈元素,结果进栈

OPR011

次栈顶是否大于等于栈顶,退两个栈元素,结果值进栈

OPR012

次栈顶是否大于栈顶,退两个栈元素,结果值进栈

OPR013

次栈顶是否小于等于栈顶,退两个栈元素,结果值进栈

OPR014

栈顶值输出至屏幕

OPR015

屏幕输出换行

OPR016

从命令行读入一个输入置于栈顶

PL/0语言可看成是PASCAL语言的子集,它的编译程序是一个编译解释执行系统。

PL/0的目标程序为假想栈式计算机的汇编语言,与具体计算机无关。

PL/0的编译程序和目标程序的解释执行程序都是用PASCAL语言书写的,因此PL/0语言可在配备PASCAL语言的任何机器上实现。

其编译过程采用一趟扫描方式,以语法分析程序为核心,词法分析程序和代码生成程序都作为一个独立的过程,当语法分析需要读单词时就调用词法分析程序,而当语法分析正确需生成相应的目标代码时,则调用代码生成程序。

此外,用表格管理程序建立变量、常量和过程标识符的说明与引用之间的信息联系。

用出错处理程序对词法和语法分析遇到的错误给出在源程序中出错的位置和错误性质。

当源程序编译正确时,PL/0编译程序自动调用解释执行程序,对目标代码进行解释执行,并按用户程序要求输入数据和输出运行结果。

本书所提供的PL/0语言编译器的基本工作流程如图1-1所示:

图1-1PL/0编译器基本工作流程

 

由于PL/0编译程序采用一趟扫描方法,所以语法分析过程BLOCK是整个编译过程的核心。

下面我们将在图2.4中先给出编译程序的总体流程,以弄清BLOCK过程在整个编译程序中的作用。

在流程图2.4中可以看出,主程序置初值后先调用读单词过程GETSYM取一个单词,然后再调用语法分析过程BLOCK,直到遇源程序的结束符"."为止。

语法分析过程BLOCK是整个编译过程的核心,是指开始由主程序调用GETSYM取一个单词,再调用语法分析过程BLOCK,BLOCK由当前单词根据语法规则再调用其它过程,如说明处理、代码生成或出错处理等过程进行分析,当分析完一个单词后,BLOCK再调用GETSYM取下一个单词,一直重复到当前单词为结束符"."表明源程序已分析结束。

若未取到结束符".",而源程序已没有输入符号,这时表明源程序有错误,无法再继续分析。

PL/0的词法分析程序GETSYM(图2.5)是一个独立的过程,其功能是为语法分析提供单词用的,是语法分析的基础,它把输入的字符串形式的源程序分割成一个个单词符号。

为此PL/0编译程序设置了三个全程量的公用单元如下:

  SYM:

存放每个单词的类别,用内部编码形式表示。

  ID:

存放用户所定义的标识符的值。

即标识符字符串的机内表示。

  NUM:

存放用户定义的数。

  单词的种类有五种。

  基本字:

也可称为保留字或关键字,如BEGIN,END,IF,THEN等。

  运算符:

如:

+、-、*、/、∶=、#、>=、<=等。

  标识符:

用户定义的变量名、常数名、过程名。

  常数:

如:

10,25,100等整数。

  界符:

如:

','、'.'、';'、'('、')'等。

  如果我们把基本字、运算符、界符称为语言固有的单词,而对标识符、常数称为用户定义的单词。

那么经词法分析程序分出的单词,对语言固有的单词只给出类别存放在SYM中,而对用户定义的单词(标识符或常数)既给类别又给值,其类别放在SYM中,值放在ID或NUM中,全部单词种类由编译程序定义的纯量类型SYMBOL给出,也可称为语法的词汇表。

如下面提到的IFSYM,THENSYM,IDENT,NUMBER均属SYMBOL中的元素。

当识别到字母开头的字母数字串时,先查关键字表。

若查不到则为标识符,查到则为关键字。

PL/0编译程序文本中主程序开始对关键字表置初值如下:

  关键字表为:

  word[1]:

='begin';word[2]:

='call';

  ...

  word[13]:

='write';

  每个数组元素的字符长度为10,不满10个字符时,以空格补满。

  查到时找到关键字相应的内部表示为:

  Wsym[1]:

=beginsym;wsym[2]:

=callsym;

  …

  wsym[13]:

=writesym;

  PL/0编译程序文本中开始对类型的定义中给出单词定义为:

  typesymbol=(nul,ident,number,plus,…,varsym,procsym);

  定义单词是纯量/枚举类型,又定义了3个全程量为:

  sym:

symbol;

  id:

alfa;

  num:

integer;

因此词法分析程序GETSYM将完成下列任务:

  

(1)滤空格:

空格在词法分析时是一种不可缺少的界符,而在语法分析时则是无用的,所以必须滤掉。

  

(2)识别保留字:

设有一张保留字表。

对每个字母打头的字母、数字字符串要查此表。

若查着则为保留字,将对应的类别放在SYM中。

如IF对应值IFSYM,THEN对应值为THENSYM。

若查不着,则认为是用户定义的标识符。

  (3)识别标识符:

对用户定义的标识符将IDENT放在SYM中,标识符本身的值放在ID中。

  (4)拼数:

当所取单词是数字时,将数的类别NUMBER放在SYM中,数值本身的值存放在NUM中。

  (5)拼复合词:

对两个字符组成的算符

  如:

>=、∶=、<=等单词,识别后将类别送SYM中。

  (6)输出源程序:

为边读入字符边输出(可输出在文件中)。

GETCH所用单元说明:

  CH:

存放当前读取的字符,初值为空。

  LINE:

为一维数组,其数组元素是字符,界对为1∶80。

用于读入一行字符的缓冲区。

  LL和CC为计数器,初值为0。

  GETSYM流程图的工作单元说明:

  A:

一维数组,数组元素为字符,界对[1∶10]。

  ID:

同A。

  WORD:

保留字表,一维数组,数组元素是以字符为元素的一维数组。

界对为[1∶13]。

查表方式采用二分法。

  单个字符对应的单词表的建立是,首先在主程序中定义了下标为字符的数组ssym,数组ssym的元素为单词,主程序开始对下标为字符的所有数组元素置初值为nul,对PL/0语言用到的单个字符为单词的,将其字符作为数组下标的元素置初值为对应的单词。

如:

  ssym['+']:

=plus;ssym['-']:

=minus;

  …

  ssym[';']:

=semicolon;

PL/0编译程序的语法分析

  PL/0编译程序语法、语义分析是整个编译程序设计与实现的核心部分,要求学员努力学习掌握实现技术和方法。

现分别说明语法分析实现的主要思想方法和语义分析的实现。

  语法分析的任务是识别由词法分析给出的单词符号序列在结构上是否符合给定的文法规则。

PL/0语言的文法规则已在2.1节中给出。

本节将以语法图描述的语法形式为依据,给出语法分析过程的直观思想。

  PL/0编译程序的语法分析采用了自顶向下的递归子程序法。

什么是自顶向下的语法分析?

  可形象地对该程序自顶向下构造一棵倒挂着的语法分析树,其构造方法是:

  

(1)由开始符号非终结符'程序'作为分析树的根结点,由非终结符'程序'规则的右部为子结点。

  

(2)对分析树中的每个非终结符结点,选择它规则的一个右部为子结点构造分析树的下一层。

  (3)重复

(2)直到分析树中的末端结点只有终结符。

  (4)若分析树中的末端结点从左到右连接的终结符号串刚好是输入的程序终结符号串,则说明所给程序在语法上是正确的。

粗略地说:

自顶向下的递归子程序法就是对应每个非终结符语法单元,编一个独立的处理过程(或子程序)。

语法分析从读入第一个单词开始由非终结符'程序'即开始符号出发,沿语法描述图箭头所指出的方向进行分析。

当遇到非终结符时,则调用相应的处理过程,从语法描述图看也就进入了一个语法单元,再沿当前所进入的语法描述图的箭头方向进行分析,当遇到描述图中是终结符时,则判断当前读入的单词是否与图中的终结符相匹配,若匹配,则执行相应的语义程序(就是翻译程序)。

再读取下一个单词继续分析。

遇到分支点时将当前的单词与分支点上的多个终结符逐个相比较,若都不匹配时,可能是进入下一非终结符语法单位或是出错。

如果一个PL/0语言的单词序列在整个语法分析中,都能逐个得到匹配,直到程序结束符'.',这时就说所输入的程序是正确的。

对于正确的语法分析做相应的语义翻译,最终得出目标程序。

以上所说语法分析过程非常直观粗浅,实际上应用递归子程序法构造语法分析程序时,对文法有一定的要求和限制,这个问题我们将在第5章详细讨论。

  此外,从PL/0的语法描述图中可以清楚地看到,当对PL/0语言进行语法分析时,各个非终结符语法单元所对应的分析过程之间必须存在相互调用的关系。

这种调用关系可用图1-2表示。

也可称为PL/0语法的依赖图,在图中箭头所指向的程序单元表示存在调用关系,从图中不难看出这些子程序在语法分析时被直接或间接递归调用。

  由图1-2PL/0语法调用关系图可以看出对分程序和语句为直接递归调用,对表达式为间接递归调用。

图1-2语法分析过程依赖关系

 

表达式的EBNF

  〈表达式〉∷=[+|-]〈项〉{(+|-)〈项〉}

  〈项〉∷=〈因子〉{(*|/)〈因子〉}

  〈因子〉∷=〈标识符〉|〈无符号整数〉|‘(’〈表达式〉‘)’

  〈表达式〉的递归子程序实现

  procedureexpr;

   begin

    ifsymin[plus,minus]then

     begin

      getsym;term;

     end

    elseterm;

    whilesymin[plus,minus]do

     begin

      getsym;term;

     end

   end;

  〈项〉的递归子程序实现

  procedureterm;

  begin

   factor;

   whilesymin[times,slash]do

   begin

    getsym;factor;

   end

  end;

  〈因子〉的递归子程序实现

  procedurefactor;

  begin

   ifsym<>identthen

    begin

     ifsym<>numberthen

      begin

       ifsym=‘(‘then

        begin

         getsym;

         expr;

         ifsym=‘)’then

          getsym

         elseerror

        end

       elseerror

      end

    end

  end;

  语法分析程序除总控外主要有两大部分的功能,即对说明部分的处理和对程序体部分的处理,也就是在语法单元中的分程序功能。

PL/0编译程序语法、语义分析的的核心程序是BLOCK过程,在BLOCK过程内又定义了许多嵌套及并列的过程。

  在过程BLOCK内对说明部分及程序体部分的分析说明如下:

(1)说明部分的分析

  由于PL/0语言允许过程调用语句,且允许过程嵌套定义。

因此每个过程应有过程首部以定义局部于它自己过程的常量、变量和过程标识符,也称局部量。

每个过程所定义的局部量只能供它自己和它自己定义的内过程引用。

对于同一层并列过程的调用关系是先定义的可以被后定义的引用,反之则不行。

  说明部分的处理任务就是对每个过程的说明对象造名字表,填写所在层次、标识符的属性和分配的相对位置等。

标识符的属性不同时,所需要填写的信息也有所不同。

登录信息是调用ENTER过程完成的。

说明部分的处理对主程序看成是第0层过程,主程序定义的过程为第1层,随着嵌套的深度增加而层次数加大。

PL/0允许最大层次为3。

  所造名字表放在全程量一维数组TABLE表中。

TX为索引表的指针,表中的每个元素为记录型数据。

LEV给出层次,DX给出每层局部量当前已分配到的相对位置,可称地址指示器,每说明完一个变量后DX指示器加1。

  PL/0编译程序文本中对名字表定义有:

  说明类型的定义:

  typeobject=(constant,variable,procedur)

  (定义为纯量/枚举类型)

  名字表的定义:

  table:

array[0..txmax]ofrecord

  name:

alfa;

  casekind:

objectof

  constant:

(val:

integer);

  variable:

procedur:

(level,adr,size:

integer);

  end;

  例如:

一个过程的说明部分为:

  CONSTA=35,B=49;

  VARC,D,E;

  PROCEDUREP;

  VARG,...

  对常量,变量和过程说明分析后,在TABLE表中的信息如表2.2所示。

  在说明处理后TABLE表中的信息对于过程名的ADR域,是在过程体的目标代码生成后再反填过程体的入口地址。

例中在处理P过程的说明时对LEV就增加1。

在P过程中的变量名的层次为LEV+1后的值。

对过程还有一项数据SIZE,是记录该过程体运行时所需的数据空间。

至于在造表和查表的过程中,如何保证每个过程的局部量不被它的外层引用,请读者阅读完PL/0编译程序后自己总结。

(2)过程体的分析

  程序的主体是由语句构成的。

处理完过程的说明后就处理由语句组成的过程体,从语法上要对语句逐句分析。

当语法正确时就生成相应语句功能的目标代码。

当遇到标识符的引用时就调用POSITION函数查TABLE表,看是否有过正确的定义,若已有,则从表中取相应的有关信息,供代码的生成用。

若无定义则出错。

PL/0编译程序的目标代码结构和代码生成

  编译程序的目标代码是在分析程序体时生成的,在处理说明部分时并不生成目标代码,而当分析程序体中的每个语句时,当语法正确则调用目标代码生成过程以生成与PL/0语句等价功能的目标代码,直到编译正常结束。

  PL/0语言的代码生成是由过程GEN完成的。

GEN过程有三个参数,分别代表目标代码的功能码、层差和位移量(对不同的指令含意不同)。

生成的代码顺序放在数组CODE中。

CODE为一维数组,数组元素为记录型数据。

每一个记录就是一条目标指令。

CX为指令的指针,由0开始顺序增加。

实际上目标代码的顺序是内层过程的排在前边,主程序的目标代码在最后。

下面我们给出一个PL/0源程序和对应的目标程序的清单。

PL/0编译程序的目标代码生成是由GEN过程完成的,当语法分析正确则调用目标代码生成过程以生成与PL/0语句等价功能的目标代码,直到编译正常结束。

除了过程说明部分外,变量和常量的说明都不产生目标代码。

在block入口处生成一条(jmp,0,0)指令,作为过程体入口指令,该指令的第3区域的'0'需分析到过程体入口时才返填。

目标代码生成时所用到的变量地址和层差等信息是由名字表table提供的,而名字表的信息是在说明时填写的。

在代码生成时查名字表,这就是表格管理的作用。

这些信息之间的连接关系学

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 人文社科 > 教育学心理学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1