编译原理上机实习指导书解析

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

编译原理上机实习》指导书
一、上机实习目的理解编译程序的构造原理,掌握编译程序的构造方法与技术。

通过实习,使学生既加深对编译原理基础理论的理解,又提高动手能力,特别是提高软件设计能力。

二、上机实习要求在理解编译原理基本思想的基础上,选择一个自己熟悉的程序设计语言,完成编译程序的设计和实现过程。

编译程序的设计可以采用自顶向下和自底向上两种不同的方法。

由于许多高级语言(如
PASCAL C)中的语法成分都是递归定义的,所以本实验要求学生采用递归下降分析技术,这是
一种自顶向下的的编译方法,其基本思想是对语言的每个(或若干个)语法成分编制一个处理子程序,从处理<程序>这个语法成分的子程序开始,在分析过程中调用一系列过程或函数,对源程
序进行语法和语义分析,直到整个源程序处理完毕为止。

本上机实习是为C语言(子集)设计一个编译程序,完成词法分析、语法分析、语义分析等功能,并生成某种机器上的目标代码(汇编语言)或中间代码(四元式)。

三、上机实习步骤
1.阅读《上机实习指导书》。

2.根据设计要求写算法,画程序框图
3.根据框图编写编译程序4.输入编译程序并上机调试5.撰写上机实习报告
四、上机实习内容
1、题目:C语言小子集编译程序的实现
2、C语言小子集的文法规则:
<程序>::=ma in (){<分程序>}
<分程序>::=< 变量说明部分>;<语句部分>
<变量说明部分>::=< 变量说明><标识符表>
<变量说明>::=int
<标识符表>::=< 标识符表>,<标识符>
<标识符表>::=< 标识符>
<标识符>::=< 字母>
<标识符>::=< 标识符><字母>
<标识符>::=< 标识符><数字>
<语句部分>::=< 语句部分>;<语句>|<语句>
<语句>::= <赋值语句>|<条件语句>|<循环语句>|
<赋值语句>::=< 标识符>=<表达式>
<条件>::=< 表达式> <关系运算符><表达式>
<表达式>::=< 项>|< 表达式><加法运算符><项>
<项>::=< 因子>|< 项> <乘法运算符><因子>
<因子>::= <标识符>|<常量>|(<表达式>)
<常量>::= <无符号整数>
<无符号整数>::=< 数字序列>
<数字序列>::=< 数字序列><数字>
<数字序列>::=< 数字>
<加法运算符>::=+卜
<乘法运算符>::=*| /
<关系运算符>::=
<|>|!=|>=|<=|==
<复合语句>::={< 语句部分>}
<语句1>::= <语句>|<复合语句>
<条件语句>::=if (<条件>)<语句1>else< 语句1>
<循环语句>::=while (<条件>)do<语句1>
<字母>::=a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z
< 数字>::=0|1|2|3|4|5|6|7|8|9
3、实现功能:
(1)词法分析扫描源程序,根据词法规则,识别单词,填写相应的表。

(2)语法分析
对源程序作语法分析,确定是否属于C 语言小子集,同时揭示出程序的内在结构。

(3)语法错误检查
根据C 语言小子集的文法规则设置检测手段,通过查错子程序或一些查错语句,报告源程序出错位置、性质等,直至整个程序结束为止。

(4)语义分析与目标代码生成
在语法分析的基础上,进行语义分析,生成输入源程序的目标代码。

输入源程序的目标代码可以建立在一个假想的处理机(虚拟机)上,或者以所学的汇编语言为基础,也可以生成四元式序列。

输入源程序样本:
main ()
{ int a,b,y,max;
a=10; b= ;
while (a>0)
{ b=a+b*a;
a=a-1
};
x=a+b; y=b+b;
if (x>y) max=x
else max=y
}
五、附录:PL0 编译程序的实现
1. PLO概述
PLO语言是一种类PASCAL语言,是教学用程序设计语言,它比PASCAL语言简单,作了一
些限制。

PL0的程序结构比较完全,赋值语句作为基本结构,构造概念有顺序执行、条件执行和重复执行,分别由BEGIN/END IF和WHILE语句表示。

此外,PL0还具有子程序概念,包括过程说明和过程调用语句。

在数据类型方面,PL0 只包含唯一的整型,可以说明这种类型的常量和变量。

运算符有+,-,*,/,=,<>,<,>,<=,>=,(,)。

说明部分包括常量说明、变量说明和过程说明。

2.PL0 语言的文法规则
<程序>::= <分程序>.
<分程序>::=[< 常量说明部分);][< 变量说明部分>;]{< 过程说明部分>;}<语句部分> <常量说明部分>::=const< 常量定义>{ ,<常量定义>}
<常量定义>::= <标识符>= <无符号整数>
<无符号整数>::=< 数字>{<数字>}
<变量说明部分>::=var< 标识符>{< 标识符>}
<标识符>::=< 字母>{<字母>|<数字>}
<过程说明部分>::=< 过程首部><分程序>
<过程首部>::=procedure< 标识符>
<语句部分>::=< 语句>|< 复合语句>
<复合语句>::=begi* 语句>{; <语句>}end
<语句>::= <赋值语句>|<条件语句>|<当型循环语句>|<过程调用语句>|
< 读语句>|< 写语句>|< 复合语句>|< 空语句>
<赋值语句>::=< 标识符>:=<表达式>
<条件>::=< 表达式><关系运算符><表达式>|odd< 表达式>
<表达式>::=[+|-]< 项>|< 表达式><加法运算符><项>
<项>::=< 因子>|<项><乘法运算符><因子>
<因子>::= <标识符>|<常量>|(<表达式>)
<常量>::= <无符号整数>
<加法运算符>:: = +|-
<乘法运算符>::=*| /
<关系运算符>:: = <|>|<>|>=|<=|=
<条件语句>::=if< 条件>then< 语句>
<过程调用语句>::=call< 标识符>
<当型循环语句>::=while< 条件>do<语句>
<读语句>::=read(< 标识符>{,<标识符>})
< 写语句>::=write(< 表达式>{,<表达式>})
<字母>::=a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z
<数字>::=0|1|2|3|4|5|6|7|8|9
3. PL0 编译程序的设计思想
编译程序的设计可以采用自顶向下和自底向上两种不同的方法。

由于许多高级语言(如
PASCAL C)中的语法成分都是递归定义的,PLO也是如此,所以本实验采用递归子程序法,这
是一种自顶向下的的编译方法,其基本思想是对源程序的每个(或若干个)语法成分编制一个处理子程序,从处理<程序>这个语法成分的子程序开始,在分析过程中调用一系列过程或函数,对
源程序进行语法和语义分析,直到整个源程序处理完毕为止。

4.PLO编译程序的功能
(1)语法分析
对由PL/0 语言编制的程序作语法分析,确定是否属于PL/0语言,同时揭示出程序的内在结构。

(2)语法错误检查
根据PL/0 语言的文法规则设置检测手段,通过查错子程序和一些查错语句,报告源程序出错位置、性质等,直至整个程序结束为止。

(3)生成目标代码
PL /0 语言的目标代码是建立在一个假想的处理机上,此处理机称为PL/0 处理机。

(4)执行目标代码
PL /0 处理机是一种假想的处理机,其目标代码不能在实际的机器上执行,故此编译程序设置了一个子程序,它对PL/0 语言的目标代码逐条解释执行,最后得出所需结果。

5.PL/0 编译程序的有关过程及函数
在PL/0语言的编译文本中,除了常量和变量说明外,共有18个相互嵌套或并列的过程(或
函数) 。

现对这些过程和函数作扼要说明。

(1)error(n):其功能是报告PL/0源程序的出错信息。

n为错误类型号,共可查出36种错误。

(2)getsym :词法分析子程序。

其功能为读单词。

getch :读字符子程序。

它嵌套于读单词子程序中。

(3)gen(x ,y,z) ,伪代码生成子程序。

其功能是根据不同的x、y、z 生成不同的伪代码。

x
表示指令码,y 表示层差,z 表示位移量或数。

(4)test(sl ,s2,n) :查错子程序。

其功能是检测源程序中的语法错误。

(5)block(1ev ,tx ,fsys) :分程序处理模块。

其功能为对分程序进行处理。

lev 表示层差,
tx 表示标识符表的下标,fsys 是符号集,表示可能出现的符号。

分程序处理模块是整个编译程序的核心,它包含以下的过程和函数。

①enter(k) :其功能是造符号表table 。

k 表示符号的类型,其取值范围是(constant ,
variable ,proceable) ,即此子程序对常量、变量和过程造符号表table ,以备检查标识符是否说明过。

②position(id):其功能是查符号表,它是一个函数。

id是所检查的标识符,若查到则给
出标识符id 在标识符表中的位置,否则给0。

③constdeclaration :常量造表子程序。

其功能是为常量造一张常量表,内填常量名、常量
值。

它通过调用子程序enter(k)完成,此时k = constant。

④vardeclaration :变量造表子程序。

其功能是为变量造一张变量表,内填变量名、所处层号。

它也是通过调用子程序enter(k) 来完成的,此时k=variable 。

⑤listcode ,打印(伪)代码子程序。

其功能是输出生成的目标代码。

⑥statement(fsys) :语句处理子程序。

其功能是处理语句,它是递归调用的核心部分。

其递归调用顺序如下:
expression(fsys) :处理算术表达式子程序;
term(fsys) :处理项子程序;condition(fsys) :处理因子子程序。

(6)interpret ,执行目标代码子程序。

其功能是对编译过程中生成的目标代码(伪代码)逐条解释执行。

base(l) :提供计算静态链信息子程序。

它为过程调用提供调用所需的基地址。

整个PL/0 编译程序通过主程序调用分程序处理模块block ,再通过block 递归调用上述的子程序,达到对PL/0 语言的程序进行编译的目的。

6.编译步骤
程序中用数组word 存贮PL/0 语言的所有保留字。

保留字有begin 、call 、const 、do、end、if 、odd、procedure 、read 、then 、var 、while 、write ;
用数组swym存贮保留字所对应的符号表symbol中的符号;
用数组ssym 存贮关系运算符及特殊符号+、-、*、/ 、(、)、=、,、<、>及;所对应的符号
表symbol 中的符号;
用数组mnemonic存贮目标代码的指令码部分。

其具体步骤如下:
①在主程序中给出编译程序所需的初始值。

置字符字数cc、行长II、代码分配下标cx、错
误个数err 等为0。

调getsym 读单词;
②调bIock 模块,进入分程序处理;
③判断所读单词是否为常量说明符号constsym ,是则转4),否则转5)。

④读单词并作常量说明处理;查所读单词是否为“,”,是则重复本步;否则判断此单词是否
为“;”,是则读单词,否则给出出错信息。

进行下一步;
⑤所读单词是否为变量说明符号variabIe ,是则读单词并作变量说明处理,再读单词并判
断是否为“,”,是则重复本步;否则判断此单词是否为“;”,是则读单词,否则给出出错信息。

进行下一步;
⑥cxl:=cx,并生成jmp 0,0指令,判断所读单词是否为过程说明符号proceduresym,是
则读单词转7),否则转11);
⑦判断所读单词是否为标识符,是则转8),否则给出出错信息再进行下一步;
⑧标识符填表,再读单词。

判断所读单词是否为“;”,是则读单词,否则给出出错信息。


行下一步;
⑨递归调用分程序处理子程序bIock ;
⑩最近所读单词是否为“;”,是则继续读一单词,否则给出出错信息。

转6);
(11)code[cxl].a:=cx ,生成分配局部变量指令,语句处理,生成opr 0 , 0指令;
(12)返回主程序,err是否为0,是则调子程序interpret ,转13),否则给出出错信息,结束
编译;
(13)解释执行生成的目标代码,列出结果。

PL/0 编译程序及主要参数
1)PL /0 编译程序
program plO(input ,output ,ff ,fi ,fw2) ;{ 带有代码生成的PL/0 编译程序} label 99 ;const norw = 13;{保留字个数}
txmax=100 ,{ 标识符表的长度}
nmax=14,{ 数中数字的最大个数} a1=10;{ 标识符的长度} amax= 20471; {最大地址}
levmax = 3; {程序体嵌套的最大深度}
cxmax= 200; {代码数组的大小}
writex=20 ;
type symbol=(nul ,ident ,number,plus ,minus,times ,slash ,oddsym,eql ,neq,lss ,
leq ,gtr ,geq,lparen ,rparen ,comma,semicolon ,period ,becomes,beginsym ,endsym ,ifsym ,thensym ,whilesym ,dosym,callsym ,constsym ,varsym ,procsym ,readsym ,writesym ,upcomma);
alfa = packed array[1..a1] of char ;
object = (constant , variable , proceable);
symset = set Of symbol ;
fct=(1it , opr , lod , sto , cal , int , jmp , jpc ) ; {functions} instruction=packed record
f : fct ; { 功能码 } l: 0..1evmax ; {层} a :0..amax ; { 相对地址 }
end ;
{lit 0 ,a :取常数 a
opr 0 ,a
:执行运算 a
lod l ,a :取层差为 l , 相对地址为 a 的常量 sto l ,a :存到层差为 l
,相对地址为 a 的变量
cal l ,a :调用层差为 l 的过程
int 0 ,a
: t 寄存器增加 a
jmp 0 , a:
转移到指令地址 a 处
jpc 0
,a :条件转移到指令地址 a 处 }
var ff,fi
: text ; { 输入文件名 ff 和 fi}
fw2
: text ; { 输出文件名 fw2} ch : char ; { 最近读到的字符 } sym : symbol
; { 最近读到的符号 }
id : alfa ; { 最近读到的标识符 } num
: integer ; { 最近读到的数 } cc : integer ; { 字符计数 }
ll : integer ;
{ 行长 }
wx : integer

kk , err
, cw : integer ;
cx : integer ; { 代码分配下标 }
line :array[1 ..81]of char ;
a : alfa ;
chwr :array[1 ..writex] of alfa
code :array[0..cxmax] of instruction word :array[1
..norw] of alfa ;
wsym :array[1..norw] of symbol
ssym : array[char] of symbol ;
mnemonic : array[fct] of packed array[1..3] of char declbegsys , statbegsys ,facbegsys : symset ; table : array[0..txmax] of record name : alfa ; case kind constant variable : object of
: (val :integer) ; , proceable : (1evel ,dr : integer) ; end ; procedure
error(n:integer) begin writeln(fw2 err:=err+1 end ; procedure getsym var i , j ,k : procedure getch; integer { ; { 出错显示子程序 } **** ', '':cc ,n :2) : 读单词子程序 }
读字符子程序 }
begin if cc=ll then begin if eof(ff)
then begin write(fw2 ll:=O ;
cc:=0 ;
while not(eoln(ff))
do begin ll:=ll+1
end
, 'program incompletet write(fw2 , cw : 5, ;read(ff ,
ch)
') ; goto ') ;'cw:=cw+1;
;write(fw2 ,ch) ; 99 ;
end ; line[ll]:=
ch
writeln(fw2) end ; cc:=cc+l
ll:=ll+1 ; read(ff , 1ine[ll]) ;
ch:=line[cc]
{ 读字符子程序结束 读单词
子程序开始 } ='dogetch ; ' a ' .. ' z ' ] then
end ; begin { while ch if ch
in [ begin kc:=0 ;
repeat if k<a1 then begin k:=k+1 getch until not(ch in[ if k>=kk then kk:=k else repeat a[kk]:= untll
kk=k
id:=a ;i:=1 ; j:=norw repeat k=(i+j) div 2 if id<=word[k] then j:=k-1 if id>=word[k] then i:=k+1 untll i>j ; if i-1>j then sym:=wsym[k]
; a[k]:=ch ; end
z ' '0'.. '9']) ;
' ; kk:=kk-1 ;
e1se sym:=ident ; end { 标识符或保留字处理结束 } else if ch in [ '0'..
'9'] then
begin { 数处理 } k:=0
;num:=0;sym:=number ;
repeat num:=10*num+(Ord(ch) 一 Ord( '0')) ; k:=k+1 ; getch ;
until not(ch in[
'0'.. '9 ']) ;
if k>nmax then error(30) end { 数处理结束 } else if ch
= ' :' then
begin getch
if ch=
end ;
{ 代码生成子程序结束
procedure test(s1 ,s2:symset ;
begin if not(sym in s1) then
begin error(n) ; s1 :=s1 +s2 ;
while not(sym in s1)do getsym
end
then
begin sym:=becomes
else sym:=nul end else case ch of
' +',' - ', ' * ','/' , ' (
; getch ; end
,' )',' =' , ' getch
end
;' , ' . ':begin sym:=ssym[ch] ;
'>': begin getch ;
if ch=
'
then begin sym:=geq getch ; end
else sym:=gtr
end ;
' <':begin getch ;
if ch=
'
else if ch=
then begin sym:=leq ' >'
then
getch ; end
begin
sym:=neq
else sym:=lss end end ; {case } end ; { 读单词子程序结束
getch ; end
procedure gen(x : fct ; begin if cx>cxmax then
begin write( with code[cx] do begin f:=x cx:=cx+1 y , z :integer) 代码生成子程序
'program too long ') ; goto 99 end ;
;l:=y ; a:=z end
}
n :
integer)
end ;
procedure block(1ev ,tx :integer ;fsys :symset) ;{ 分程序处理模块} var dx :integer ;{ 数据分配下标}
txO :integer ;{ 起始标识符的下标}
cxO :integer ;{ 起始代码的下标}
procedure enter(k :object) ;{ 把object 填入标识符表中}
begi n tx := tx+1 ;
with table[tx] do
begin name:=id ;kind:=k ;
case kind of
constant :begin if num>amax then
begin error(30) ;
num:=0 ;
end

val:=num
end
variable
proceable
end { case }
end
end ;{ 填标识符表子程序结束function position(id :
alfa)

:begin level:=levl ;dr:=dx ;dx:=dx+l
:level:=lev
}
integer ;{ 在标识符表中查标识符id }

end;
var i :integer ;
begin table[0].name:=id ;i:=tx ;
while table[I].name<>id do
i:=i-1
position:=i ;
end ;{position}
procedure constdeclaration begin if sym=ident then
begin getsym if sym in
[eql begin if sym ;{ 常量说明处理子程序}
,becomes] then
=becomes the n error(1)
getsym
if sym=number then
begin
enter(constant)
getsym ;
end else error(2)
end
else error(3)
end else error(4)
end ;{constdeclaration}
procedure vardeclaration ;{ 变量说明处理子程序} begin if sym=ident then
begin enter(variable) ;getsym ;end
else error(4)
end ;{ vardeclaration }
procedure listcode ;var i :integer ;begin for i:=cxO to cx-1 do with code[i] do writeln(fw2 end ;{listcode } procedure statement(fsys var i
列出本程序体生成的代码子程序}
,i ,mnemonic[i] :5,l:3 ,a::symset) ;
,cxl ,cx2.integer ;{ 语句处理子程序}
5)
procedure expression(fsys:symset) var addop :symbol ;procedure term(fsys:symset) var mulop :symbol ;procedure factor(fsys var i :
integer begin test(facbegsys { 表达式处理子程序项处理子程序}
:symset)

fsys ,while sym in facbegsys do begin
if sym=ident then begin
i:=position(id) if i=0 then
error(11) else with table[i] do
case kind of
constant
variable
proceable
end
getsym
end 24)
{ 因子处理子程序
:gen(1it ,0,
val) ;
:gen(lod ,lev-level
:error(21)

dr) ;
else
if sym=number then
begin if num>amax then begin
error(30) gen(lit end else if
sym=lparen then begin getsym
expression([rparen]+fsys) if
sym=rparen then getsym else
error(22)
,0,num);
end
test(fsy s
end ,
[1paren]
,23)
end ;{factor}
begin { 项处理子程序开始}
;num:=O;end;getsym ;
factor(fsys+[times , slash]) ; while sym in[times , slash] do begin mulop:=sym
; getsym ; factor(fsys+[times , slash]) ; if mulop=times then gen(opr , 0, 4)
else gen(opr ,0, 5)
end
end ; { 项处理子程序结束 } begin { 表达式处理子程序开始 ) if sym in [plus , minus] then
begin addop:=sym
;getsym ;
term(fsys+[plus , minus]) ; if addop=minus then gen(opr ,0, 1) end else term(fsys+[plus , minus]) ;
while sym in [plus , minus] do
begin add
/p:=sym ; getsym ;
term(fsys+[plus if addop=plus then gen(opr
else gen(opr end end ; {exprssion} procedure
condition(fsys:symset) var relop:symbol ;
begin if sym=oddsym then
begin getsym ;
expression(fsys) ; gen(opr , 0, 6);
end else
begin expression([eql
, neq , 1ss , gtr ,leq ,geq]+fsys) ; if not(sym in[eql
,neq ,1ss , leq ,
gtr , geq]) then
error(20) else begin relop:=sym
; getsym ; expression(fsys) ;
case relop of
eql : gen(opr ,0, 8); neq : gen(opr ,0, 9); lss
: gen(opr ,0, 10);
geq: gen(opr ,0, 11) ;
gtr : gen(opr ,0, 12) ; 1eq
: gen(opr ,0, 13) ;
end
end
end
end ; {condition} begin { 语句处理子程序开始 } if sym=ident then { 赋值语句处理 }
, minus]) ;
,0,2)
,0,3)
; { 条件表达式处理子程序开始
begin i:=position(id) ;
if i = 0 then error(11)
else if table[i].kind<>variable
then begin error(12)
i:=0 ;
end ;
getsym ;
if sym=becomes then getsym else
error(13) ;
expression(fsys) ;
if i<>0 then
with table[i] do gen(sto
end else
if sym = readsym the n {
begin getsym ;
if sym<>lparen then error(34)
e1se repeat
getsym
if sym=ident then
i:=position(id)
else i:=0
if i
else with table[i] do
begin gen(opr
gen(sto
end
getsym until sym<>comma if sym<>rparen then begin
error(33)
while not(sym in fsys) do
end else getsym end else
;{ 对非变量赋值}
,1ev-1evel ,dr) 读语句处理}
=0 then error(35)
getsym
if sym=writesym then { 写语句处理} begin getsym ;
if sym=1paren then
begin repeat
getsym ;
if sym=upcomma then
begin getsym ;
if sym=ident then
i:=position(id)
else
i:=0
if
i
else
chwr[wx]:=id ,0,16) ;,1ev-1evel
=0 the n
error(11)
,dr) ;
wx:=wx+1 ;

getsym
if sym=upcomma then getsym
else error(36) ;
getsym ;
expression([rparen ,comma]+fsys) ;
gen(opr ,0,14) ;
end else

begin getsym
expression([rparen,comma]+fsys)
gen(opr ,0,14) ;
end

until sym<>comma
if sym<>rparen then error(33)
e1se getsym
end ;
gen(opr ,0,15) ;
end else
if sym=callsym then { 过程语句处理}
begin getsym ;
if sym<>ident then error(14)
else begin i:=position(id) ;
if i=0 then error(11)
else with table[i] do
if kind =proceable the n
gen(cal,1ev-level,dr)

else error(15)
getsym ;
end
end e1se
if sym=ifsym then { 条件语句处理}
begin getsym ;

condition([thensym,dosym]+fsys)
if sym=thensym then getsym
else error(16) ;
cxl:=cx ;gen(jpc ,0,0) ;
statement(fsys) ;code[cxl].a:=cx ;
end e1se
if sym=beginsym then { 复合语句处理) begin
getsym ;
statement([semicolon , e ndsym]+fsys)
while sym in [semicolon]+statbegsys do
begin if sym=semicolon then getsym
else error(10) statement([semicolon,endsym]+fsys) end ; if
sym=endsym then getsym else error(17) end e1se
if sym=dosym then getsym else error(18) statement(fsys) gen(jmp code[cx2].a:=cx test(fsys end

end ;{语句处理子程序结束 } begin { 分程序处理子程序开始 }
dx:=3 ; txO:=tx ; table[tx].dr:=cx ; gen(jmp ,0, 0) ; if 1ev>levmax then error(32) ;
repeat
if sym=constsym then {
常量说明部分处理 }
begin getsym ;
repeat constdeclaration ; While sym=comma do
While sym=comma do
begin getsym ; constdeclaration ; end ; begin getsym
; constdeclaration ; end ;
if sym=semicolon then getsym
else error(5) ;
until sym<>ident
until sym<>ident end ;
{ 常量说明部分处理结束 }
end ;
{ 常量说明部分处理结束 }
if sym = varsym then {
变量说明部分处理}
begin getsym ;
repeat vardeclaration

if sym = varsym then {
变量说明部分处理}
begin getsym ; repeat vardeclaration ;
while sym=comma do begin getsym
;vardeclaration ; end ;
if sym
=whilesym then { 循环语句处理}
begin cxl:=cx
condition([dosym]+fsys) cx2:=cx
; getsym ;

;gen(jpc , 0,0) ;
, 0, cxl) ;

,[] , 19) ;
if sym=semicolon then getsym
else begin error(5)
until sym<>ident ;
end ; { 变量说明部分处理结束 )
while sym=procsym do { 过程说明部分处理 } begin getsym ;
if sym=ident then begin enter(proceable)
; getsym ; end
else error(4) ;
if sym=semicolon then getsym
else begin error(5)
; getsym ; end ;
block(lev+1 , tx , [semicolon]+fsys) ;
if sym=semicolon then
begin getsym ;
test(statbegsys+[ident , procsym] , fsys , 6) end

declbegsys ,7) ;
until not(sym in declbegsys)
cxO:=cx ;gen(int , 0,dx) ; statement([semicolon
, endsym]+fsys) ;
gen(opr ,0,0) ; { 返回} test(fsys ,[] , 8) ; listcode ;
end ; { 分程序处理结束 }
procedure interpret ; { 执行目录代码子程序 } const stacksize=500 ;
var p , b , t : integer ;{p :程序地址寄存器, b :基地址寄存器, t :栈顶地址寄存器 } i : instruction ; { 指令寄存器 } s : array[1..stacksize] of integer ;{ 数据存储 }
function base(l : integer) :integer ; var b1 : integer :
begin b1:=b ; { 顺静态链求层差为 1 的基地址 }
while l>0 do begin b1:=s[bl] ; l:=l-1 ; end ;
base:=b1 end ; {base}
begin writeln( 'start PL/0 ') ;
t:=0
;b:=1 ; p:=0 ; wx:=1 ;
s[1]:=0
; s[2]:=0 ; s[3]:=0 ;
repeat
i:=code[p] ; p:=p+1 ;
end ; { 过程说明部分处理结束 } ; getsym ; end ;
code[table[tx0].dr].a:=c x
with table[tx0] do
; { 代码开始地址 }
else error(5) test(statbegsys+[ident ]
with i do case f of lit :begin t:=t+1 ; s[t]:=a ; end ;
opr
: case a of { 运算 }
: begin t:=b-1 ; p:=s[t+3] ; b:=s[t+2] end ;{ 返回}
1:
s[t]:=
-s[t] ;
2
: begin t:=t-1 ; s[t]:
=s[t]+s[t+1] end ;
3
: begin t:=t-1 ; s[t]:
=s[t]-s[t+1] end ; 4
: begin t:=t-1 ; s[t]:
=s[t]*s[t+1] end ;
5
: begin t:=t-1 ; s[t]: =s[t] div s[t+1] end ;
6: s[t]:=ord(odd(s[t]))
8: begin t:=t-1
9: begin t:=t-; s[t]:=ord(s[t]=s[t+1])
end
; s[t]:=ord(s[t]<>s[t+1]) 10 : begin t:=t-1
; s[t]:=ord(s[t]<s[t+1]) end
11 : begin t:=t-1 ; s[t]:=ord(s[t]>=s[t+1])
end
12
: begin t:=t-1 ; s[t]:=ord(s[t]>s[t+1])
end
13: begin t:=t-1 ; s[t]:=ord(s[t]<=s[t+1])
end
14 : begin writeln(fw2) ;write(fw2 , chwr[wx]) ;
, s[t]) ; t:=t-1 ; wx:=wx+1;
end ;
15
: writeln(fw2)
sto : begin s[base(l)+a]:=s[t]
t:=t-1 ; end ;
cal: begin {generte new block mark}
s[t+1]:=base(l) ; s[t+2]:=b ; s[t+3]:=p ; b:=t+l ; p:=a ; end ;
int : t:=t+a ;
jmp : p:=a ;
jpc
: begin if s[t]=0 then
p:=a t:=t
1 ; end
end {with , case }
until p=0

write( '
end PL/0 ') ;
end ; {interpret}
begin { 主程序开始 }
reset(ff) ; reset(fi) ; rewrite(fW2) for ch:= 'a 'to '; ' do ssym[ch]:=nul word[1]:= 'begin ' ; word[2]:= 'call ' ; word[3]:= 'const ' ; word[4]:= 'do ' ; word[5]:= 'end
' ; word[6]:=
'if
' ;
16 begin t:=t+1 ; read(fi , s[t])
;end ;
end
lod: begin t:=t+1 ; s[t]:=s[base(l)+a] end write(fwZ
word[7]:= 'odd ' ;word[8]:= 'procedure ' ;
word[9]:= 'read ' ;word[10]:= 'then
'
word[11]:= 'var ';word[12]:= 'while ' ;
word[13]:= 'write ';
wsym[1]:=beginsym ;wsym[2]:=callsym ;
wsym[3]:=constsym ;wsym[4]:=dosym ;
wsym[5]:=endsym ;wsym[6]:=ifsym ;
wsym[7]:=oddsym ;wsym[8]:=procsym ;
wsym[9]:=readsym ;wsym[10]:=thensym ;wsym[11]:=varsym ;wsym[12]:=whilesym ;wsym[13]:=writesym ;
ssym[ '+']:=plus ;ssym[ '- ']:=minus ;ssym['* ']:=times ;ssym[ '/
']:=slash ;ssym[ '( ']:=lparen ;ssym[ ') ']:=rparen ;ssym[ '=']:=eql ;ssym[
', ']:=comma ;
ssym[ '. ']:=period ;ssym[ ' ;']:=semicolon ;
ssym[ ''']:'=upcomma ;
mnemonic[lit]:= '1it ' ;mnemonic[opr]:= 'opr ' ;
mnemonic[lod]:= 'lod ' ;mnemonic[sto]:= 'sto ' ;
mnemonic[cal]:= 'cal ' ;mnemonic[int]:= 'int ' ;
mnemonic[jmp]:= 'jmp' ;mnemonic[jpc]:= 'jpc ' ;
declbegsys:=[constsym ,varsym ,
procsym] ;
statbegsys:=[beginsym ,callsym ,
ifsym ,whilesym] ;
facbegsys:=[ident ,number,lparen] ;
err:=0 ;cw:=1 ;wx:=1 ;cc:=0 ;cx:=0 ;ll:=0 ;ch:= ' ';kk:=al ;getsym ;block(O ,0,[period]+declbegsys+statbegsys);
if sym<>period then error(9) ;
if err=0 then interpret
else write(fw2 ,'error in PL/0 program ') ;
99:writeln
end.{ 主程序结束}
出错编号出错信息
1:应为 '='而不是 ':= '
2:'=' 后应为数
3:标识符后应为” =”
4:const ,var ,procedure 后应为标识符
5:漏掉逗号或分号
6:过程说明后的符号不正确
7:应为语句
8:程序体内语句部分后的符号不正确9:应为句号
10: 语句之间漏分号
11:
标识符未说明
12不可向常量名或过程名赋值
13: 应为赋值运算符 ':= '
14: call 后应为标识符
15: 不可调用常量或变量
16:应为 'then '
17 :应为 'end ' 18: 应为 'do'
19:语句后的符号不正确
20:
应为关系运算符
21 表达式内不可有过程标识符
22 :漏右括号
23: 因子后不可为此符号
24 :表达式不能以此符号开始
30: 这个数太大
31: 表达式内常数越界
32: 嵌套深度超过允许值
33: read 或write 语句中缺” ) ”
34 :read 或write 语句中缺” ( ”
35: read 语句中标识符未说明
36

write 语句中需打印的标识符未加单引号2) 主要参数说明
ff: PL fi:
/O语言源程序文件名;
文件所需的数据文件;运行后存放结果的文件;
ch: 最近读到的字符;sym: 最近读到的单词;id: 最近读到的标识符;num: 最近读到的数;
cc: ll: 字符计数;行长;
cw: PL /0 语言源程序输出的行号;
cx: kk: 代码分配下标;读单词时的字符计数;
err: 出错次数;
wx: line: a:
写语句write 计数;读入字符的行缓冲区;读词时存放所读单词;
chwr: 存放输出的变量名;code: 存放目标代码的数组;
word: 保留字存贮区;
wsym: 存放保留字所对应的符号;
ssym: 存放关系运算符及特殊符;
mnemoric: 存放目标代码中的指令码;
table: 符号表,存放符号的类型、名字和值。

例如,用该编译程序对如下PL/0 语言程序:
var a ,b,c;
begin read(a);write('a=',a);
read(b);write('b=',b);
if a>b then
begin c:=a+b ;
write('c=',c);
end
end .
进行编译运行,有运行结果(输出文件中包括有源程序、生成的目标指令及执行PL/0 语言程序的计算结果等)如下:
1var a ,b,c;
2begin read(a);write('a=',a);
3read(b);write('b= ',b);
4if a>b then
5begin c:=a+b ;
6write('c=',c);
7end
8end.
1int 0 6
2opr 0 16
3sto 0 3
4lod 0 3
5opr 0 14
6opr 0 15
7opr 0 16
8sto 0 4
9lod 0 4
10opr 0 14
11opr 0 15
12lod 0 3
13lod 0 4
14opr 0 12
15jpc 0 23
16lod 0 3
17lod 0 4
18opr 0 2
19 sto 0 5
20 lod 0 5
21 opr 0 14
22 opr 0 15
23 opr 0 0
a= 50
b= 40
c= 90
预先建立PL/0 语言源程序文件ff 和其所需要的数据文件fi(文件名预先确定)。

运行时在键盘上根据提示信息键入输出文件fw2 的文件名(自行随时确定)。

相关文档
最新文档