program PASCALS(INPUT,OUTPUT,PRD,PRR);
{ author:N.Wirth, E.T.H. CH-8092 Zurich,1.3.76 }
{ modified by R.E.Berry
Department of computer studies
University of Lancaster
Variants of this program are used on
Data General Nova,Apple,and
Western Digital Microengine machines. }
{ further modified by M.Z.Jin
Department of Computer Science&Engineering BUAA,0ct.1989
}
{常量定义}
const nkw = 27; { no. of key words } {*保留字数目*}
alng = 10; { no. of significant chars in identifiers } {*标识符最大长度*}
llng = 121; { input line length } {*输入一行文件内容长度*}
emax = 322; { max exponent of real numbers } {*最大指数大小*}
emin = -292; { min exponent } {*最小指数大小*}
kmax = 15; { max no. of significant digits } {*数字最大长度*}
tmax = 100; { size of table } {*符号表最大长度*}
bmax = 20; { size of block-talbe } {*分程序表最大长度*}
amax = 30; { size of array-table } {*数组向量表最大长度*}
c2max = 20; { size of real constant table } {*实常量表最大长度*}
csmax = 30; { max no. of cases } {*case语句最大分支数目*}
cmax = 800; { size of code } {*目标代码表最大长度*}
lmax = 7; { maximum level } {*最大嵌套层数*}
smax = 600; { size of string-table } {*字符串表最大长度*}
ermax = 58; { max error no. } {*错误种类最大数目*}
omax = 63; { highest order code } {*最大标识符数目*}
xmax = 32767; { 2**15-1 }
nmax = 32767; { 2**15-1 } {*整型最大值*}
lineleng = 132; { output line length } {*输出文件一行最大长度*}
linelimit = 200; {*输出文件行数限制*}
stacksize = 1450; {*栈大小*}
{类型定义}
type symbol = ( intcon, realcon, charcon, stringcon,
notsy, plus, minus, times, idiv, rdiv, imod, andsy, orsy,
eql, neq, gtr, geq, lss, leq,
lparent, rparent, lbrack, rbrack, comma, semicolon, period,
colon, becomes, constsy, typesy, varsy, funcsy,
procsy, arraysy, recordsy, programsy, ident,
beginsy, ifsy, casesy, repeatsy, whilesy, forsy,
endsy, elsesy, untilsy, ofsy, dosy, tosy, downtosy, thensy); {*所有符号种类枚举编码*}
index = -xmax..+xmax; {*index子界限制*}
alfa = packed array[1..alng]of char; {*字符数组存储标识符*}
objecttyp = (konstant, vvariable, typel, prozedure, funktion ); {*种类枚举变量*}
types = (notyp, ints, reals, bools, chars, arrays, records ); {*类型枚举变量*}
symset = set of symbol; {*符号编码枚举变量组成的集合*}
typset = set of types; {*类型枚举变量组成的集合*}
item = record
typ: types;
ref: index;
end;
order = packed record
f: -omax..+omax;
x: -lmax..+lmax;
y: -nmax..+nmax
end;
{变量定义}
var ch: char; { last character read from source program } {*最近读入字符*}
rnum: real; { real number from insymbol } {*实数实型部分*}
inum: integer; { integer from insymbol } {*实数整型部分*}
sleng: integer; { string length } {*字符串长度*}
cc: integer; { character counter } {*字符指针*}
lc: integer; { program location counter } {*目标码指针*}
ll: integer; { length of current line } {*当前读入行长度*}
errpos: integer;
t,a,b,sx,c1,c2:integer; { indices to tables } {*各个表的指针*}
iflag, oflag, skipflag, stackdump, prtables: boolean; {*各个标志变量*}
sy: symbol; { last symbol read by insymbol } {*当前读入的符号*}
errs: set of 0..ermax; {*错误集合*}
id: alfa; { identifier from insymbol } {*读入的符号的值*}
progname: alfa; {*主程序名*}
stantyps: typset; {*标准类型集合*}
constbegsys, typebegsys, blockbegsys, facbegsys, statbegsys: symset; {*一系列test*}
line: array[1..llng] of char; {*当前读入行临时存储数组*}
key: array[1..nkw] of alfa; {*保留字表*}
ksy: array[1..nkw] of symbol; {*保留字对应编码表*}
sps: array[char]of symbol; { special symbols } {*特殊符号对应编码数组*}
display: array[0..lmax] of integer; {*display表*}
tab: array[0..tmax] of { indentifier lable } {*符号表*}
packed record
name: alfa;
link: index;
obj: objecttyp;
typ: types;
ref: index;
normal: boolean;
lev: 0..lmax;
adr: integer
end;
atab: array[1..amax] of { array-table } {*数组向量表*}
packed record
inxtyp,eltyp: types;
elref,low,high,elsize,size: index
end;
btab: array[1..bmax] of { block-table } {*分程序表*}
packed record
last, lastpar, psize, vsize: index
end;
stab: packed array[0..smax] of char; { string table } {*字符表*}
rconst: array[1..c2max] of real; {*常量表*}
code: array[0..cmax] of order; {*目标指令表*}
psin,psout,prr,prd:text; { default in pascal p } {*代码输入,代码输出,键盘,显示屏文件指针*}
inf, outf, fprr: string; {*代码输入,代码输出,运行结果输出文件路径*}
{*
函数名:errormsg;
功能:打印源程序出错信息的摘要;
*}
procedure errormsg;
var k : integer;
msg: array[0..ermax] of alfa; {*出错信息数组*}
begin {*给数组各项赋值*}
msg[0] := 'undef id '; msg[1] := 'multi def ';
msg[2] := 'identifier'; msg[3] := 'program ';
msg[4] := ') '; msg[5] := ': ';
msg[6] := 'syntax '; msg[7] := 'ident,var ';
msg[8] := 'of '; msg[9] := '( ';
msg[10] := 'id,array '; msg[11] := '( ';
msg[12] := '] '; msg[13] := '.. ';
msg[14] := '; '; msg[15] := 'func. type';
msg[16] := '= '; msg[17] := 'boolean ';
msg[18] := 'convar typ'; msg[19] := 'type ';
msg[20] := 'prog.param'; msg[21] := 'too big ';
msg[22] := '. '; msg[23] := 'type(case)';
msg[24] := 'character '; msg[25] := 'const id ';
msg[26] := 'index type'; msg[27] := 'indexbound';
msg[28] := 'no array '; msg[29] := 'type id ';
msg[30] := 'undef type'; msg[31] := 'no record ';
msg[32] := 'boole type'; msg[33] := 'arith type';
msg[34] := 'integer '; msg[35] := 'types ';
msg[36] := 'param type'; msg[37] := 'variab id ';
msg[38] := 'string '; msg[39] := 'no.of pars';
msg[40] := 'real numbr'; msg[41] := 'type ';
msg[42] := 'real type '; msg[43] := 'integer ';
msg[44] := 'var,const '; msg[45] := 'var,proc ';
msg[46] := 'types(:=) '; msg[47] := 'typ(case) ';
msg[48] := 'type '; msg[49] := 'store ovfl';
msg[50] := 'constant '; msg[51] := ':= ';
msg[52] := 'then '; msg[53] := 'until ';
msg[54] := 'do '; msg[55] := 'to downto ';
msg[56] := 'begin '; msg[57] := 'end ';
msg[58] := 'factor';
writeln(psout); {*向代码输出文件中打印空行并换行*}
writeln(psout,'key words'); {*向代码输出文件打印'key words'并换行*}
k := 0;
while errs <> [] do {*输出错误集合中的全部错误信息摘要*}
begin
while not( k in errs )do k := k + 1; {*变量k不在错误集合中则遍历下一错误序号*}
writeln(psout, k, ' ', msg[k] ); {*打印输出错误序号k,空格,错误信息摘要*}
errs := errs - [k] {*从错误集合中去除已遍历过的错误序号k*}
end { while errs }
end { errormsg } ;
{*
函数名:endskip;
功能:源程序出错后在被跳读的部分下面印出下划线标志;
*}
procedure endskip;
begin { underline skipped part of input }
while errpos < cc do
begin
write( psout, '-');
errpos := errpos + 1
end;
skipflag := false
end { endskip };
{*
函数名:nextch;
功能:读取下一字符,处理行结束符,打印出被编译的源程序;
*}
procedure nextch; { read next character; process line end }
begin
if cc = ll {*如果本行已经读完*}
then begin
if eof( psin ) {*如果到文件末尾*}
then begin
writeln( psout ); {*输出空行*}
writeln( psout, 'program incomplete' ); {*输出'文件已经读完'*}
errormsg; {*打印错误信息*}
exit; {*退出程序*}
end;
if errpos <> 0 {*如果本行跳过的错误字符个数不为零*}
then begin
if skipflag then endskip; {*如果本行错误信息未被输出,则在本行的错误信息下面加下划线并输出*}
writeln( psout ); {*输出空行*}
errpos := 0 {*清空erropos变量*}
end;
write( psout, lc: 5, ' '); {*输出源程序指针值*}
ll := 0; {*更新行指针为0*}
cc := 0; {*更新字符指针为0*}
while not eoln( psin ) do {*只要没有读到本行末尾*}
begin
ll := ll + 1; {*行指针加1*}
read( psin, ch ); {*读取一个字符到ch中*}
write( psout, ch ); {*输出该字符*}
line[ll] := ch {*将该字符补充到文件行内容数组line的末尾*}
end;
ll := ll + 1; {*行指针加1*}
readln( psin ); {*读取下一行*}
line[ll] := ' '; {*文件行内容数组末尾加空格*}
writeln( psout ); {*输出空行*}
end;
cc := cc + 1; {*字符指针加1*}
ch := line[cc]; {*读取本行的当前字符*}
end { nextch };
{*
函数名:error;
功能:打印出错位置和出错编号;
参数:n:错误信息种类;
*}
procedure error( n: integer );
begin
if errpos = 0 {*如果没有跳过的错误信息*}
then write ( psout, '****' ); {*输出'****'*}
if cc > errpos {*如果字符指针大于跳过的错误字符数*}
then begin
write( psout, ' ': cc-errpos, '^', n:2); {*输出空格,'^'指出错误信息*}
errpos := cc + 3; {*跳过的错误信息指针加3*}
errs := errs +[n]; {*将该错误加入到错误信息集合中*}
end
end { error };
{*
函数名:fatal;
功能:打印表格溢出信息;
参数:n:表格编号;
*}
procedure fatal( n: integer );
var msg : array[1..7] of alfa; {*溢出信息数组*}
begin
writeln( psout ); {*输出空行*}
errormsg; {*打印错误信息摘要*}
msg[1] := 'identifier'; msg[2] := 'procedures';
msg[3] := 'reals '; msg[4] := 'arrays ';
msg[5] := 'levels '; msg[6] := 'code ';
msg[7] := 'strings ';
writeln( psout, 'compiler table for ', msg[n], ' is too small'); {*输出表格溢出信息*}
exit; {terminate compilation } {*退出程序*}
end { fatal };
{*
函数名:insymbol;
功能:读取下一单词符号,处理注释行;
*}
procedure insymbol; {reads next symbol}
label 1,2,3; {*定义跳转标签*}
var i,j,k,e: integer;{*k记录整数部分位数,asb(e)记录小数部分位数*}
{*
过程名:readscale;
功能:处理实数的指数部分;
*}
procedure readscale;
var s,sign: integer;
begin
nextch; {*读取下一个字符*}
sign := 1; {*符号变量*}
s := 0; {*存储指数部分数值*}
if ch = '+' {如果指数部分以'+'开头,则不做处理}
then nextch
else if ch = '-' {*如果指数部分以'-’开头,则设置符号为负号*}
then begin
nextch;
sign := -1
end;
if not(( ch >= '0' )and (ch <= '9' )) {*如果符号后读入的字符不是数字,则进行报错err40*}
then error( 40 )
else repeat{*否则,将指数部分字符串转化为整数存储至s中*}
s := 10*s + ord( ord(ch)-ord('0'));
nextch;
until not(( ch >= '0' ) and ( ch <= '9' ));
e := s*sign + e {*e>0:rnum实际向右移动的位数;e<0,rnum实际向左移动的位数*}
end { readscale };
{*
过程名:adjustable;
功能:根据小数位数和指数大小求出实数数值;
*}
procedure adjustscale;
var s : integer;
d, t : real;
begin
if k + e > emax {*如果整数位数加上移动位数位数大于上限则报错*}
then error(21)
else if k + e < emin {*如果小于下限*}
then rnum := 0 {*则无法精确到该小值,记该实数为0*}
else begin
s := abs(e); {*s为e的绝对值*}
t := 1.0;
d := 10.0;
repeat
{*将s表示成2^n的形式进行计算10的次幂*}
while not odd(s) do {*如果s是偶数*}
begin
s := s div 2; {*给s除2,div为整除*}
d := sqr(d) {*给d进行平方*}
end;
s := s - 1; {*如果s是奇数,则给s-1*}
t := d * t {*计算以10为底,s为指数的结果*}
until s = 0;
if e >= 0
then rnum := rnum * t {*如果指数部分大于0,则实数等于小数部分乘求得的10的次幂*}
else rnum := rnum / t {*如果指数部分小于0,则实数等于小数部分除求得的10的次幂*}
end
end { adjustscale };
{*
过程名:options;
功能:处理编译时的可选项;
*}
procedure options;
{*
过程名:swicth;
功能:处理编译可选项中的'+','-'标志;
参数:b:是否打印相关表格的特征变量;
*}
procedure switch( var b: boolean );
begin
b := ch = '+'; {*如果当前字符为'+',b=true;否则,b=false*}
if not b {*如果ch不为'+'*}
then if not( ch = '-' ) {*如果ch不为'-'*}
then begin { print error message }
while( ch <> '*' ) and ( ch <> ',' ) do {*略过所有的'*'和','*}
nextch;
end
else nextch {*如果ch为'-',则读入下一个字符*}
else nextch {*如果ch为'+',则读入下一个字符*}
end { switch };
begin { options }
repeat
nextch;
if ch <> '*' {*如果ch不为'*'*}
then begin
if ch = 't' {*如果ch为't',则读入下一个字符,并将是否打印表格的特征变量prtables根据'+,-'置为true或false}
then begin
nextch;
switch( prtables )
end
else if ch = 's' {*如果ch为's',则读入下一个字符,并将是否打印运行错误信息的特征变量stackdump根据'+,-'置为true或false*}
then begin
nextch;
switch( stackdump )
end;
end
until ch <> ','
end { options };
begin { insymbol }
1: while( ch = ' ' ) or ( ch = chr(9) ) do
nextch; { space & htab } {*如果读入的字符为空格或者\t则跳过*}
case ch of
'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':
begin { identifier of wordsymbol } {*如果读入的字符是小写字母*}
k := 0;
id := ' '; {*清空id数组*}
repeat {*一直读入字符并取前10个连接到id字符数组的尾部,直到读入的字符不再是小写字母或者数字为止*}
if k < alng {*限制单词的字母个数最多为10*}
then begin
k := k + 1;
id[k] := ch
end;
nextch
until not((( ch >= 'a' ) and ( ch <= 'z' )) or (( ch >= '0') and (ch <= '9' )));
i := 1;
j := nkw; { binary search } {*二分法查找保留字表,判断当前读入的单词是否为保留字*}
repeat
k := ( i + j ) div 2;
if id <= key[k]
then j := k - 1;
if id >= key[k]
then i := k + 1;
until i > j;
if i - 1 > j {*如果当前单词为保留字,则sy为相应的保留字对应的编码*}
then sy := ksy[k]
else sy := ident {*如果不是保留字,则当前单词为标识符*}
end;
'0','1','2','3','4','5','6','7','8','9': {*如果当前字符为数字*}
begin { number }
k := 0;
inum := 0;
sy := intcon; {*sy被赋值为数字编码*}
repeat {*一直读取字符直到不再是数字为止,并将该数字字符串转化为整型数字并存入inum中*}
inum := inum * 10 + ord(ch) - ord('0');
k := k + 1;
nextch
until not (( ch >= '0' ) and ( ch <= '9' ));
if( k > kmax ) or ( inum > nmax ) {*如果数字的位数超过kmax或者数字的大小超过nmax,则进行报错err21*}
then begin
error(21);
inum := 0; {*将当前读入的数字大小置为0*}
k := 0 {*清空数字位数计数器*}
end;
if ch = '.' {*如果读入的字符为'.',处理小数*}
then begin
nextch;
if ch = '.'
then ch := ':'
else begin
sy := realcon; {*当前符号为实型*}
rnum := inum; {*实型整数部分为刚刚求得的inum*}
e := 0; {*实型指数部分为0*}
while ( ch >= '0' ) and ( ch <= '9' ) do {*先不算小数点,得到全部整数部分和小数部分*}
begin
e := e - 1; {*e记录需要移动小数点的位数*}
rnum := 10.0 * rnum + (ord(ch) - ord('0'));
nextch
end;
if e = 0 {*如果e为0,则说明小数点后面没有数字,报错err40*}
then error(40);
if ch = 'e' {*如果小数部分后面紧跟着'e',则说明为科学计数法表示的实型,调用指数分析过程*}
then readscale;
if e <> 0 then adjustscale
end
end
else if ch = 'e'{*如果当前字符为'e',处理科学计数法表示的实型*}
then begin
sy := realcon;
rnum := inum; {*实型整数部分即为刚刚得到的整数部分*}
e := 0;
readscale; {*调用处理指数部分过程*}
if e <> 0
then adjustscale
end;
end;
':': {*如果是':'*}
begin
nextch;
if ch = '=' {*如果下一个字符为':',则当前符号为赋值符号,并赋给sy对应的编码*}
then begin
sy := becomes;
nextch
end
else sy := colon {*否则,当前符号为冒号*}
end;
'<': {*如果是'<'*}
begin
nextch;
if ch = '=' {*'如果是'=',则当前符号为<='*}
then begin
sy := leq;
nextch
end
else
if ch = '>' {*如果是'>',则当前符号为<>号*}
then begin
sy := neq;
nextch
end
else sy := lss {*否则当前符号为<*}
end;
'>': {*如果是'>'*}
begin
nextch;
if ch = '=' {*如果是'=',则当前符号为>=*}
then begin
sy := geq;
nextch
end
else sy := gtr {*否则,当前符号为>*}
end;
'.': {*如果是'.'*}
begin
nextch;
if ch = '.' {*如果下一个符号也是'.',则当前符号为..,并赋值sy为冒号对应的编码*}
then begin
sy := colon;
nextch
end
else sy := period {*否则当前符号为.*}
end;
'''': {*如果当前符号是'*}
begin
k := 0;
2: nextch;
if ch = '''' {*如果第二个符号也是'*}
then begin
nextch;
if ch <> '''' {*如果第三个符号不是',此时输入并不合法,因为引号中没有任何字符串或字符,跳转到label3*}
then goto 3
end;
if sx + k = smax {*如果第二个符号不是'并且字符串表已满*}
then fatal(7); {*则打印字符串表溢出信息*}
stab[sx+k] := ch; {*若字符串表没有溢出,则将当前字符记录到stab中*}
k := k + 1; {*当前字符计数器加1*}
if cc = 1 {*如果一行结束,即当前字符指针指向新一行的第一个字符,则置k为0*}
then begin { end of line }
k := 0;
end
else goto 2; {*如果一行没有结束,则继续读入下一个字符*}
3: if k = 1 {*如果单引号内的字符计数为1*}
then begin
sy := charcon; {*则的引号内内容为字符类型*}
inum := ord( stab[sx] ) {*将inum值赋为该字符对应的ASCII码值*}
end
else if k = 0 {*如果单引号内的字符计数为0*}
then begin
error(38); {*则进行报错err38*}
sy := charcon; {*将sy赋值为字符类型*}
inum := 0 {*inum赋值为0*}
end
else begin {*如果单引号内的字符计数大于1,则说明引号内的内容为一个字符串*}
sy := stringcon; {*sy赋值为字符串类型*}
inum := sx; {inum赋值为字符串起始地址}
sleng := k; {sleng记录字符长度}
sx := sx + k {更新字符串表指针}
end
end;
'(': {*如果当前字符是'('*}
begin
nextch;
if ch <> '*' {*当前字符不为'*'*}
then sy := lparent (*则说明读入的符号为左括号*)
else begin { comment } {*如果当前字符为'*'*}
nextch;
if ch = '$' {*如果当前字符为'$',则说明为编译可选项,调用option函数进行分析,形式为(*$t-,s+*)*}
then options;
repeat {*处理注释*}
while ch <> '*' do nextch;
nextch
until ch = ')';
nextch;
goto 1 {*跳过无用信息,重新进入读取符号函数*}
end
end;
'{': {*如果是大括号*}
begin
nextch;
if ch = '$' {*处理编译可选项,形式为{$t+}*}
then options;
while ch <> '}' do {*处理注释*}
nextch;
nextch;
goto 1
end;
'+', '-', '*', '/', ')', '=', ',', '[', ']', ';': {*如果当前符号为分隔符*}
begin
sy := sps[ch];
nextch
end;
'$','"' ,'@', '?', '&', '^', '!': {*如果当前符号为不合法字符,则报错err24*}
begin
error(24);
nextch;
goto 1
end
end { case }
end { insymbol };
{*
过程名:enter;(分程序外)
功能:把标准类型、过程和函数的名字登录到符号表中;
参数:x0:名字;
x1:种类;
x2:类型;
x3:地址;
*}
procedure enter(x0:alfa; x1:objecttyp; x2:types; x3:integer );
begin
t := t + 1; { enter standard identifier } {*符号表初始指针加1*}
with tab[t] do
begin {*各个域内容的填写*}
name := x0;
link := t - 1;
obj := x1;
typ := x2;
ref := 0; {*规定主程序层次为1,此时为0*}
normal := true;
lev := 0;
adr := x3;
end
end; { enter }
{*
过程名:enterarray;
功能:登陆数组信息向量表;
参数:tp:数组类型;
l:数组下界;
h:数组上届;
*}
procedure enterarray( tp: types; l,h: integer );
begin
if l > h {*下界大于上届*}
then error(27);
if( abs(l) > xmax ) or ( abs(h) > xmax ) {*下界或上界的绝对值超过允许的最大整数值*}
then begin
error(27);
l := 0;
h := 0;
end;
if a = amax {*数组信息向量表溢出,则打印溢出信息*}
then fatal(4)
else begin {*登陆数组信息*}
a := a + 1;
with atab[a] do
begin
inxtyp := tp;
low := l;
high := h
end
end
end { enterarray };
{*
过程名:enterblock;
功能:登录分程序表;
*}
procedure enterblock;
begin
if b = bmax {*分程序表溢出,则打印溢出信息*}
then fatal(2)
else begin {*登录分程序信息*}
b := b + 1;
btab[b].last := 0; {*指向过程或函数最后一个符号在表中的位置,用于建表*}
btab[b].lastpar := 0; {*向过程或者函数的最后一个'参数'符号在tab中的位置,用于退栈*}
end
end { enterblock };
{*
过程名:enterreal;
功能:登录实常数表;
参数:x:实常数常量;
*}
procedure enterreal( x: real );
begin
if c2 = c2max - 1 {*实常数表溢出,打印溢出信息*}
then fatal(3)
else begin
rconst[c2+1] := x; {*登录信息*}
c1 := 1; {*查表*}
while rconst[c1] <> x do
c1 := c1 + 1;
if c1 > c2
then c2 := c1
end
end { enterreal };
{*
过程名:emit;
功能:生成P-code,没有操作数;
参数:fct:助记符编号;
*}
procedure emit( fct: integer );
begin
if lc = cmax {*P-code表溢出,打印溢出信息*}
then fatal(6);
code[lc].f := fct; {*登录助记符信息*}
lc := lc + 1
end { emit };
{*
过程名:emit1;
功能:生成P-code,只有一个操作数;
参数:fct:助记符编号;
b:第二个操作数;
*}
procedure emit1( fct, b: integer );
begin
if lc = cmax
then fatal(6);
with code[lc] do
begin
f := fct;
y := b;
end;
lc := lc + 1
end { emit1 };
{*
过程名:emit2;
功能:生成P-code,有两个操作数;
参数:fct:助记符编号;
a:第一个操作数;
b:第二个操作数;
*}
procedure emit2( fct, a, b: integer );
begin
if lc = cmax then fatal(6);
with code[lc] do
begin
f := fct;
x := a;
y := b
end;
lc := lc + 1;
end { emit2 };
{*
过程名:printtables;
功能:打印编译生成的符号表,分程序表,实常量数表,以及P-code表;
*}
procedure printtables;
var i: integer;
o: order;
mne: array[0..omax] of
packed array[1..5] of char;
begin
mne[0] := 'LDA '; mne[1] := 'LOD '; mne[2] := 'LDI ';
mne[3] := 'DIS '; mne[8] := 'FCT '; mne[9] := 'INT ';
mne[10] := 'JMP '; mne[11] := 'JPC '; mne[12] := 'SWT ';
mne[13] := 'CAS '; mne[14] := 'F1U '; mne[15] := 'F2U ';
mne[16] := 'F1D '; mne[17] := 'F2D '; mne[18] := 'MKS ';
mne[19] := 'CAL '; mne[20] := 'IDX '; mne[21] := 'IXX ';
mne[22] := 'LDB '; mne[23] := 'CPB '; mne[24] := 'LDC ';
mne[25] := 'LDR '; mne[26] := 'FLT '; mne[27] := 'RED ';
mne[28] := 'WRS '; mne[29] := 'WRW '; mne[30] := 'WRU ';
mne[31] := 'HLT '; mne[32] := 'EXP '; mne[33] := 'EXF ';
mne[34] := 'LDT '; mne[35] := 'NOT '; mne[36] := 'MUS ';
mne[37] := 'WRR '; mne[38] := 'STO '; mne[39] := 'EQR ';
mne[40] := 'NER '; mne[41] := 'LSR '; mne[42] := 'LER ';
mne[43] := 'GTR '; mne[44] := 'GER '; mne[45] := 'EQL ';
mne[46] := 'NEQ '; mne[47] := 'LSS '; mne[48] := 'LEQ ';
mne[49] := 'GRT '; mne[50] := 'GEQ '; mne[51] := 'ORR ';
mne[52] := 'ADD '; mne[53] := 'SUB '; mne[54] := 'ADR ';
mne[55] := 'SUR '; mne[56] := 'AND '; mne[57] := 'MUL ';
mne[58] := 'DIV '; mne[59] := 'MOD '; mne[60] := 'MUR ';
mne[61] := 'DIR '; mne[62] := 'RDL '; mne[63] := 'WRL ';
writeln(psout);
writeln(psout);
writeln(psout);
{*打印tab表信息*}
writeln(psout,' identifiers link obj typ ref nrm lev adr');
writeln(psout);
for i := btab[1].last to t do
with tab[i] do {*除去编译初启登录的类型,函数名等信息*}
writeln( psout, i,' ', name, link:5, ord(obj):5, ord(typ):5,ref:5, ord(normal):5,lev:5,adr:5);
writeln( psout );
writeln( psout );
writeln( psout );
{*打印btab信息*}
writeln( psout, 'blocks last lpar psze vsze' );
writeln( psout );
for i := 1 to b do
with btab[i] do
writeln( psout, i:4, last:9, lastpar:5, psize:5, vsize:5 );
writeln( psout );
writeln( psout );
writeln( psout );
{*打印atab信息*}
writeln( psout, 'arrays xtyp etyp eref low high elsz size');
writeln( psout );
for i := 1 to a do
with atab[i] do
writeln( psout, i:4, ord(inxtyp):9, ord(eltyp):5, elref:5, low:5, high:5, elsize:5, size:5);
writeln( psout );
writeln( psout );
writeln( psout );
{*打印P-code表信息*}
writeln( psout, 'code:');
writeln( psout );
for i := 0 to lc-1 do
begin
write( psout, i:5 );
o := code[i];
write( psout, mne[o.f]:8, o.f:5 ); {*打印输出助记符*}
if o.f < 31 {*按照操作数个数输出P-code指令*}
then if o.f < 4
then write( psout, o.x:5, o.y:5 )
else write( psout, o.y:10 )
else write( psout, ' ' );
writeln( psout, ',' )
end;
writeln( psout );
writeln( psout, 'Starting address is ', tab[btab[1].last].adr:5 )
end { printtables };
{*
过程名:block;
功能:分析处理分程序;
参数:fsys:传入的test集合检验符号合法性,容错处理;
isfun:
level:处理的分程序所在层数;
*}
procedure block( fsys: symset; isfun: boolean; level: integer );
type conrec = record {*该记录可以根据不同类型的变量来保存数据*}
case tp: types of
ints, chars, bools : ( i:integer );
reals :( r:real )
end;
var dx : integer ; { data allocation index } {*数据分配索引*}
prt: integer ; { t-index of this procedure } {*本过程tab头索引*}
prb: integer ; { b-index of this procedure } {*本过程btab头索引*}
x : integer ;
{*
过程名:skip;
功能:跳读源程序,直至取来的符号属于给出的符号集为止,并打印出出错标志;
参数:fsys: 给定的符号集;
n:错误编号;
*}
procedure skip( fsys:symset; n:integer);
begin
error(n);
skipflag := true;
while not ( sy in fsys ) do
insymbol;
if skipflag then endskip
end { skip };
{*
过程名:test;
功能:测试当前符号是否为分号;
参数:s1:
s2:
n:
*}
procedure test( s1,s2: symset; n:integer );
begin
if not( sy in s1 )
then skip( s1 + s2, n )
end { test };
{*
过程名:testmicolon;
功能;测试当前符号是否为分号;
*}
procedure testsemicolon;
begin
if sy = semicolon
then insymbol
else begin
error(14);
if sy in [comma, colon]
then insymbol
end;
test( [ident] + blockbegsys, fsys, 6 )
end { testsemicolon };
{*
过程名:enter;
功能:在符号表中登录分程序说明部分出现的名字;
参数:id:名字;
k:种类;
*}
procedure enter( id: alfa; k:objecttyp );
var j,l : integer;
begin
if t = tmax {*tab溢出,打印溢出信息*}
then fatal(1)
else begin
tab[0].name := id;{*每一层过程的在tab中的第一个符号link值为0*}
j := btab[display[level]].last; {*为当前层最后一个 标识符在tab中的位置*}
l := j;
while tab[j].name <> id do
j := tab[j].link;
if j <> 0 {*如果j!=0则说明该符号已被重复定义*}
then error(1)
else begin {*将信息登录到tab表中*}
t := t + 1;
with tab[t] do {*登录符号信息*}
begin
name := id;
link := l;
obj := k;
typ := notyp; {*类型此时不确定,在typ过程中得到*}
ref := 0;
lev := level; {*当前静态层次*}
adr := 0;
normal := false { initial value }
end;
btab[display[level]].last := t {*更新当前过程的最后一个符号在tab中的位置*}
end
end
end { enter };
{*
过程:loc;
功能:查找标识符在符号表中的位置;
参数:id:查找的参数名;
返回值:loc:interger,若找到id,则返回id在tab表中的位置;否则返回0;
*}
function loc( id: alfa ):integer;
var i,j : integer; { locate if in table }
begin
i := level;
tab[0].name := id; { sentinel }
repeat
j := btab[display[i]].last;
while tab[j].name <> id do {*在本层查找*}
j := tab[j].link;
i := i - 1; {*本层为找到在上一层继续查找*}
until ( i < 0 ) or ( j <> 0 );
if j = 0 {*如果j=0,则未找到该符号,报错err0*}
then error(0);
loc := j {*如果找到,则返回该符号的位置*}
end { loc } ;
{*
过程名:entervariable;
功能:将变量名登录到符号表中;
*}
procedure entervariable;
begin
if sy = ident
then begin
enter( id, vvariable ); {*调用enter过程登录变量名*}
insymbol
end
else error(2) {*如果要登录的符号不是一个标识符,则报错err2*}
end { entervariable };
{*
过程名:constant;
功能:处理程序中出现的常量,并由参数(c)返回该常量的类型和数值;
参数:fsys:给定检测符号集合;
c:返回该常量的类型和数值;
*}
procedure constant( fsys: symset; var c: conrec );
var x, sign : integer; {*正负号标志*}
begin
c.tp := notyp;
c.i := 0;
test( constbegsys, fsys, 50 );
if sy in constbegsys {*第一个符号是常量开始的符号才继续进行分析*}
then begin
if sy = charcon {*如果当前符号为字符类型*}
then begin
c.tp := chars; {*在c中记录字符类型*}
c.i := inum; {*在c中记录字符值*}
insymbol
end
else begin {*当前符号为数值或者标识符*}
sign := 1;
if sy in [plus, minus] {*为正负号*}
then begin
if sy = minus
then sign := -1; {*负sign标记为-1*}
insymbol
end;
if sy = ident {*为标识符*}
then begin
x := loc(id); {*在符号表中查找该符号*}
if x <> 0 {*查到*}
then
if tab[x].obj <> konstant {*判断类型标记是否为常量,不是常量则报错err25,常量定义中等号后面必须为常数或常量标识符*}
then error(25)
else begin
c.tp := tab[x].typ; {*c.ty赋值为当前符号的类型*}
if c.tp = reals {*如果当前为real型*}
then c.r := sign*rconst[tab[x].adr] {*tab[x].adr为id在rconst中的索引值,求得当前的实数值后赋给c.r*}
else c.i := sign*tab[x].adr {*如果不为常实数,则tab中的adr即为当前的常量值*}
end;
insymbol
end
else if sy = intcon {*如果当前符号为数字型*}
then begin
c.tp := ints;
c.i := sign*inum;
insymbol
end
else if sy = realcon{*如果当前符号为实数型*}
then begin
c.tp := reals;
c.r := sign*rnum;
insymbol
end
else skip(fsys,50) {*否则略过非法字符*}
end;
test(fsys,[],6) {*对后继符号进行检查*}
end
end { constant };
{*
过程名:typ;
功能:处理类型描述,由参数得到它的类型(tp),指向类型详细信息表的指针(ref)和该类型的大小;
参数:fsys:合法的符号集合,用来检测字符的合法性;
tp:返回参数的类型;
rf:返回参数的详细信息表的指针;
sz:返回该类型的大小;
*}
procedure typ( fsys: symset; var tp: types; var rf,sz:integer );
var eltp : types;
elrf, x : integer;
elsz, offset, t0, t1 : integer;
{*
过程名:arraytyp;
功能:处理数组类型,由参数返回值指向该数组信息向量表的指针(aref)和数组大小(arsz);
参数:aref:返回该数组信息向量表的指针;
arsz:返回该数组大小;
*}
procedure arraytyp( var aref, arsz: integer );
var eltp : types;
low, high : conrec; {*上下界类型*}
elrf, elsz: integer;
begin
constant( [colon, rbrack, rparent, ofsy] + fsys, low ); {*查找该low常量并返回其值和类型*}
if low.tp = reals {*如果下标为实型*}
then begin
error(27); {*报错err27实型上下界违法*}
low.tp := ints;
low.i := 0
end;
if sy = colon {*如果当前符号为..*}
then insymbol
else error(13);
constant( [rbrack, comma, rparent, ofsy ] + fsys, high ); {*查找high常量并返回其值和类型*}
if high.tp <> low.tp {*如果上下界类型不同,报错err27*}
then begin
error(27);
high.i := low.i
end;
enterarray( low.tp, low.i, high.i ); {*上下界类型相同,则将该数组登录到atab中*}
aref := a; {*返回值aref指向当前atab索引值*}
if sy = comma {*如果当前符号为,则说明该数组为多维数组*}
then begin
insymbol;
eltp := arrays; {*该数组元素类型为数组类型,为下面计算size做准备*}
arraytyp( elrf, elsz ) {*递归调用arraytyp,分析多维数组*}
end
else begin
if sy = rbrack {*如果当前符号不是右中括号,则进行报错err12*}
then insymbol
else begin
error(12);
if sy = rparent {*如果数组下标右侧符号为右括号,则进行容错处理*}
then insymbol
end;
if sy = ofsy {*如果当前符号为of*}
then insymbol
else error(8);
typ( fsys, eltp, elrf, elsz ) {*对数组类型符号进行查找,并且将该类型的种类,符号表中的位置,大小记录在对应的参数中*}
end;
with atab[aref] do {*完善atab中的当前数组信息*}
begin
arsz := (high-low+1) * elsz; {*返回值arsz记录数组大小*}
size := arsz;
eltyp := eltp;
elref := elrf;
elsize := elsz
end
end { arraytyp };
begin { typ }
tp := notyp;
rf := 0;
sz := 0;
test( typebegsys, fsys, 10 );
if sy in typebegsys
then begin
if sy = ident {*如果当前符号为标识符*}
then begin
x := loc(id); {*查找ident在tab中的位置*}
if x <> 0
then with tab[x] do
if obj <> typel {*如果不是type类型,则报错err29*}
then error(29)
else begin
tp := typ; {*返回值tp记录该类型描述符的类型*}
rf := ref; {*返回该类型详细信息表指针*}
sz := adr; {*返回类型大小*}
if tp = notyp {*如果未定义类型,报错err30*}
then error(30)
end;
insymbol
end
else if sy = arraysy {*如果是数组类型*}
then begin
insymbol;
if sy = lbrack {*如果array后不为[*}
then insymbol
else begin
error(11); {*报错err11*}
if sy = lparent {*如果是(,则进行容错处理*}
then insymbol
end;
tp := arrays; {*返回类型描述符的类型为array*}
arraytyp(rf,sz) {*调用arrtyp,类型描述符指针信息和大小*}
end
else begin { records } {*如果是记录*}
insymbol;
enterblock; {*登录btab,为当前记录分配一块btab表项*}
tp := records; {*返回typ为记录类型*}
rf := b; {*rf为btab当前索引值*}
if level = lmax {*如果当前嵌套层次超过限制的最大值,则报告溢出错误*}
then fatal(5);
level := level + 1; {*记录的信息登录相当于进入新的一层程序,level+1*}
display[level] := b; {*更新display表,建立分层次索引*}
offset := 0; {*域名偏移初始值为0*}
while not ( sy in fsys - [semicolon,comma,ident]+ [endsy] ) do {*循环处理record中的所有字符*}
begin { field section }
if sy = ident {*如果当前符号为标识符*}
then begin
t0 := t; {*记录该类型第一个标识符在tab中的位置*}
entervariable; {*登录tab表,将该变量信息加入tab中*}
while sy = comma do {*只要遇到,说明还有同一类型的变量需要记录到tab中*}
begin
insymbol;
entervariable
end;
if sy = colon {*如果当前符号为:*}
then insymbol
else error(5); {*不为:,报错err5*}
t1 := t; {*记录该类型最后一个域名在tab表中的位置*}
typ( fsys + [semicolon, endsy, comma,ident], eltp, elrf, elsz ); {*查找该类域名的类型信息*}
while t0 < t1 do {*对同一类型的所有域名在tab中登录其详细信息*}
begin
t0 := t0 + 1;
with tab[t0] do
begin
typ := eltp; {*记录类型*}
ref := elrf;
normal := true;
adr := offset; {*记录该域名相对于起始变量的偏移值*}
offset := offset + elsz
end
end
end; { sy = ident }
if sy <> endsy {*如果是end符号,变量声明结束*}
then begin
if sy = semicolon {*检测end后是否为;*}
then insymbol
else begin
error(14); {*不是;则报错*}
if sy = comma {*如果是逗号则进行容错处理*}
then insymbol
end;
test( [ident,endsy, semicolon],fsys,6 ) {*对后继符号合法性进行检查*}
end
end; { field section }
btab[rf].vsize := offset; {完善btab中record的信息,记录record的大小}
sz := offset; {*返回该类型的大小*}
btab[rf].psize := 0; {*没有参数,记录为0*}
insymbol;
level := level - 1 {*登录信息完毕,退出该层*}
end; { record }
test( fsys, [],6 )
end;
end { typ };
{*
过程名:parameterlist;
功能:处理过程或函数说明中的形参表,将形参及其有关信息登录到符号表中;
*}
procedure parameterlist; { formal parameter list }
var tp : types;
valpar : boolean;
rf, sz, x, t0 : integer;
begin
insymbol;
tp := notyp;
rf := 0;
sz := 0;
test( [ident, varsy], fsys+[rparent], 7 ); {*形参的第一个参数必须是var或者标识符*}
while sy in [ident, varsy] do {*循环处理所有参数*}
begin
if sy <> varsy {*如果当前符号不是var*}
then valpar := true {*标记valpar变量为true*}
else begin
insymbol;
valpar := false {*是var则标记valpar为false,并读入下一个符号*}
end;
t0 := t; {*记录tab表此时的索引位置*}
entervariable;
while sy = comma do {*循环处理同一类型的形式参数*}
begin
insymbol;
entervariable; {*将所有的形参登录到tab表中*}
end;
if sy = colon {*如果当前符号为:,其后的符号为该类形参的类型描述符*}
then begin
insymbol;
if sy <> ident {*如果类型描述符不是标识符,则报错err2*}
then error(2)
else begin
x := loc(id); {*查找该标识符在tab中的位置*}
insymbol;
if x <> 0 {*如果找到了这个标识符*}
then with tab[x] do
if obj <> typel {*如果不是typ类型,则报错err29*}
then error(29)
else begin
tp := typ; {*记录当前类型描述符的类型*}
rf := ref; {*记录当前描述符在符号表中的位置*}
if valpar
then sz := adr {*如果是值形参,则sz为当前参数相应的取值地址*}
else sz := 1 {*如果是引用参数,则使sz为1*}
end;
end;
test( [semicolon, rparent], [comma,ident]+fsys, 14 ) {*检验后继符号是否合法,不合法报错err14*}
end
else error(5); {*如果形参的后继符号不是冒号,则报错err5*}
while t0 < t do {*对同一类型的形参信息进行反填*}
begin
t0 := t0 + 1;
with tab[t0] do
begin
typ := tp;
ref := rf;
adr := dx; {*填入的地址为该形参在运行栈中分配存储单元的相对地址*}
lev := level;
normal := valpar; {*如果是变量形参就置normal为false;如果是值形参就置normal为true*}
dx := dx + sz {*对栈中的存储单元的地址进行更新*}
end
end;
if sy <> rparent {*如果是),则说明形式参数已经全部处理完*}
then begin
if sy = semicolon {*过程或者函数的头部结尾应该为;*}
then insymbol
else begin
error(14); {*如果不是;则报告err14*}
if sy = comma {*如果是逗号,则进行容错处理*}
then insymbol
end;
test( [ident, varsy],[rparent]+fsys,6) {*检测尾部符号是否合法,否则报告err6*}
end
end { while };
if sy = rparent {*如果当前符号是),则说明该过程或者函数没有参数*}
then begin
insymbol;
test( [semicolon, colon],fsys,6 ) {*测试后继符号的合法性*}
end
else error(4) {*缺少右括号,不完整的过程或者函数头部或说明,报告err4*}
end { parameterlist };
{*
过程名:constdec;
功能:处理常量定义,将常量名及其相应信息填入符号表;
*}
procedure constdec;
var c : conrec;
begin
insymbol;
test([ident], blockbegsys, 2 ); {*合法的常量应该以标识符为开头符号*}
while sy = ident do {*循环处理所有的常量标识符*}
begin
enter(id, konstant); {*将该标识符登录到tab中*}
insymbol;
if sy = eql {*如果常量标识符的后继符号是=,则读取下一个符号*}
then insymbol
else begin
error(16); {*如果不是=,则进行报错err16*}
if sy = becomes {*如果是:=,则进行容错处理*}
then insymbol
end;
constant([semicolon,comma,ident]+fsys,c); {*查找:=后的常量值,并将信息赋给返回值c*}
tab[t].typ := c.tp; {*对该常量标识符的相关信息反填以完善,在tab中记录该常量标识符的类型*}
tab[t].ref := 0; {*该常量标识符的相关索引指针记为0*}
if c.tp = reals {*如果这个常量的类型为实型*}
then begin
enterreal(c.r); {*则将该常量登录到rconst中*}
tab[t].adr := c1; {*将tab中该常量的地址记为为rconst中常量对应的索引值*}
end
else tab[t].adr := c.i; {*否则adr为该常量的值*}
testsemicolon
end
end { constdec };
{*
过程名:typedeclaration;
功能:处理类型定义,并将类型名及其信息填入符号表;
*}
procedure typedeclaration;
var tp: types;
rf, sz, t1 : integer;
begin
insymbol;
test([ident], blockbegsys,2 ); {*类型声明符号必须以ident标识符开头*}
while sy = ident do {*循环处理type关键字后的所有类型符号*}
begin
enter(id, typel); {*将该typel符号登录到符号表中*}
t1 := t; {*记录第一个类型声明符号在tab中的位置*}
insymbol;
if sy = eql {*如果标识符的后继符号是=,则读入下一个符号*}
then insymbol
else begin
error(16); {*标识符后继符号不是=,则报告错误err16*}
if sy = becomes {*如果是:=,则进行容错处理*}
then insymbol
end;
typ( [semicolon,comma,ident]+fsys, tp,rf,sz ); {*对该类型声明符号被赋予的类型进行检测*}
with tab[t1] do {*对该类型声明符号的其他信息进行反填以完善*}
begin
typ := tp; {*标记类型*}
ref := rf; {*标记指针*}
adr := sz {*标记地址*}
end;
testsemicolon {*检测类型声明符号尾部符号是否为;*}
end
end { typedeclaration };
{*
过程名:variabledeclaration;
功能:处理变量定义,并将变量名及相应信息填入符号表;
*}
procedure variabledeclaration;
var tp : types;
t0, t1, rf, sz : integer;
begin
insymbol;
while sy = ident do {*循环处理所有变量名*}
begin
t0 := t; {*记录当前符号表的位置,即第一个变量名登录符号表的位置*}
entervariable; {*将该变量名登录符号表*}
while sy = comma do {*循环处理同一类型的变量,同一类型的变量用逗号分隔开*}
begin
insymbol;
entervariable;
end;
if sy = colon {*如果是冒号,则接下来进行类型说明*}
then insymbol
else error(5); {*如果不是冒号则报告错误err5*}
t1 := t; {*记录同一类型最后一个变量名在符号表中的位置*}
typ([semicolon,comma,ident]+fsys, tp,rf,sz ); {*检测该类型的相关信息*}
while t0 < t1 do {*在符号表中对该种类型的所有变量进行反填以完善信息*}
begin
t0 := t0 + 1;
with tab[t0] do
begin
typ := tp; {*记录类型*}
ref := rf; {*记录指针*}
lev := level; {*记录当前分层信息*}
adr := dx; {*变量地址为和运行栈现在的栈指针头部*}
normal := true; {*给normal域赋值*}
dx := dx + sz {*累加运行栈存储空间,更新栈顶指针*}
end
end;
testsemicolon
end
end { variabledeclaration };
{*
过程名:procedclaration;
功能:处理过程或者函数说明,将过程名填入符号表,递归调用block分析处理程序(层次level+1);
*}
procedure procdeclaration;
var isfun : boolean;
begin
isfun := sy = funcsy; {*如果是function,isfun赋值为true;为procedure,isfun赋值为false*}
insymbol;
if sy <> ident {*function和procedure后继符号必须为一标识符作为名字*}
then begin
error(2); {*如果不是标识符则报告错误err2*}
id :=' '
end;
if isfun
then enter(id,funktion) {*如果是function,则将该函数名登录到tab表中,并标记类型为function*}
else enter(id,prozedure); {*如果是procedure,则将该函数名登录到tab表中,并标记类型为procedure*}
tab[t].normal := true;
insymbol;
block([semicolon]+fsys, isfun, level+1 ); {*分析处理该function或者procedure分程序*}
if sy = semicolon {*如果是;,则读入下一符号,否则报告错误err14*}
then insymbol
else error(14);
emit(32+ord(isfun)) {exit} {*生成p-code指令;32:退出过程;31:退出函数*}
end { proceduredeclaration };
{*
过程名:statement;
功能:分析处理各种语句;
*}
procedure statement( fsys:symset );
var i : integer;
{*
过程名:expression;
功能:分析处理表达式,由参数(x)返回求值结果的类型;
*}
procedure expression(fsys:symset; var x:item); forward;
{*
过程名:sector;
功能:处理结构变量;数组下标变量或记录成员变量;
参数:fsys:合法字符集合,检测字符是否合法;
v:一个结构体;
typ:类型,v是一个数组还是一个记录;
index:v在btab或者atab中的索引;
*}
procedure selector(fsys:symset; var v:item);
var x : item;
a,j : integer;
begin { sy in [lparent, lbrack, period] } {*首符号为(,[,.之一*}
repeat
if sy = period {*处理记录成员变量,.xx*}
then begin
insymbol; { field selector }
if sy <> ident {*.后不是标识符,则报错err2*}
then error(2)
else begin
if v.typ <> records {*如果访问的数据不是记录类型,报错err31,即没有这样的记录*}
then error(31)
else begin { search field identifier } {*如果是合法的记录类型,开始查找对应的记录成员变量的值*}
j := btab[v.ref].last; {*该记录最后一个标识符在tab中的位置*}
tab[0].name := id; {*令tab[0]为当前访问的记录成员名*}
while tab[j].name <> id do {*在该记录的所有成员变量里从后往前找需要访问的成员变量在tab中的位置*}
j := tab[j].link;
if j = 0 {*如果没有找到,则说明该成员变量未被声明过,报告错误err0*}
then error(0);
v.typ := tab[j].typ; {*v.typ为成员类型*}
v.ref := tab[j].ref; {*v.ref为成员变量所在分程序在btab中的位置*}
a := tab[j].adr; {*a为成员变量相对于起始变量的位移*}
if a <> 0 {*如果位移不为0*}
then emit1(9,a) {*生成p-code指令,栈顶指针加a,计算该成员变量的地址*}
end;
insymbol
end
end
else begin { array selector } {*处理数组成员变量*}
if sy <> lbrack
then error(11);
repeat {*如果是合法的[*}
insymbol;
expression( fsys+[comma,rbrack],x); {*处理[]内的表达式,并将结果值返回于x中*}
if v.typ <> arrays {*如果需要访问的v不是数组类,报告错误err28*}
then error(28)
else begin
a := v.ref; {*a为数组v在atab中的索引位置*}
if atab[a].inxtyp <> x.typ {*如果数组指定下标与[]内计算得出的下标类型不符,报告错误err26*}
then error(26)
else if atab[a].elsize = 1
then emit1(20,a) {*p-code,取下标变量地址,元素长度为1,即为形参*}
else emit1(21,a); {*p-code,取下标变量地址,为实参*}
v.typ := atab[a].eltyp; {*v-typ为被访问元素的类型*}
v.ref := atab[a].elref {*v-ref为被访问元素在atab或btab中的位置*}
end
until sy <> comma; {*访问多维数组*}
if sy = rbrack {*检查]是否存在*}
then insymbol
else begin
error(12);
if sy = rparent {*)容错处理*}
then insymbol
end
end
until not( sy in[lbrack, lparent, period]); {*循环处理直到所有子结构或数组都被处理完*}
test( fsys,[],6)
end { selector };
{*
过程名:call;
功能:处理非标准的过程或函数调用;
参数:fsys:合法的字符集合,对字符的合法性进行检测;
i:被调用过程或函数在tab表中的位置;
*}
procedure call( fsys: symset; i:integer );
var x : item;
lastp,cp,k : integer;
begin
emit1(18,i); { mark stack } {*生成p-code指令,标记栈,i为被调用的过程或者函数在tab表中的位置,建立新的内务信息区*}
lastp := btab[tab[i].ref].lastpar; {*lastp为该过程或者函数最后一个参数在tab中的位置*}
cp := i; {*cp记录该function或procedure在tab中的位置*}
if sy = lparent {*遇到(,处理过程或函数中的参数*}
then begin { actual parameter list }
repeat {*循环处理所有参数*}
insymbol;
if cp >= lastp {*如果当前符号名在tab中的位置大于其最后一个参数在tab中的位置,则说明报错err39,否则还有参数没有被处理完*}
then error(39)
else begin
cp := cp + 1;
if tab[cp].normal {*如果当前参数是值形参或其他参数*}
then begin { value parameter }
expression( fsys+[comma, colon,rparent],x); {*求得实参值和类型记录在x中*}
if x.typ = tab[cp].typ {*如果实参类型和形参类型相同*}
then begin
if x.ref <> tab[cp].ref {*如果形参和实参的指针不同*}
then error(36) {*则报错err36*}
else if x.typ = arrays {*如果实参为数组类型*}
then emit1(22,atab[x.ref].size) {*生成p-code,装入块,将该数组装入数据栈的预留参数单元中*}
else if x.typ = records {*如果实参为记录类型*}
then emit1(22,btab[x.ref].vsize) {*生成p-code,装入块*}
end
else if ( x.typ = ints ) and ( tab[cp].typ = reals ) {*如果实参为整数而形参为实数型*}
then emit1(26,0) {*生成p-code指令,浮点数转换*}
else if x.typ <> notyp {*如果实参未声明类型,则报错err36*}
then error(36);
end
else begin { variable parameter } {*如果参数为变量形参*}
if sy <> ident {*如果读到的不为标识符,则报错err2*}
then error(2)
else begin
k := loc(id); {*k记录当前标识符在tab中的位置*}
insymbol;
if k <> 0 {*如果ident在tab中有记录*}
then begin
if tab[k].obj <> vvariable {*如果该标识符的类型不是变量,则报错err37*}
then error(37);
x.typ := tab[k].typ;{*x.typ为该实参的类型*}
x.ref := tab[k].ref; {*x.ref为该实参的指针*}
if tab[k].normal {*如果标识符的类型不为变量形参,可能是一个数之类的*}
then emit2(0,tab[k].lev,tab[k].adr) {*生成p-code,将该实参的地址装入栈中*}
else emit2(1,tab[k].lev,tab[k].adr);{*否则将该变量形参的值装入栈中*}
if sy in [lbrack, lparent, period] {*如果该参数为记录或数组或记录成员变量*}
then selector(fsys+[comma,colon,rparent],x); {*调用selector分析*}
if ( x.typ <> tab[cp].typ ) or ( x.ref <> tab[cp].ref ) {*如果数组或记录的类型和形参不符,或其指针不等,则报错err36*}
then error(36)
end
end
end {variable parameter }
end;
test( [comma, rparent],fsys,6) {*检测后继符号的合法性*}
until sy <> comma; {*检测不到逗号为止,则已处理完所有参数*}
if sy = rparent {*如果参数结尾不是)则报告err4*}
then insymbol
else error(4)
end;
if cp < lastp {*如果实参个数小于形参个数,则报错err39,说明实参的个数太少*}
then error(39); { too few actual parameters }
emit1(19,btab[tab[i].ref].psize-1 ); {*生成p-code,调用过程或者函数*}
if tab[i].lev < level {*如果函数或过程名的静态层次小于当前层次,更新[lev,level]为下标的display区;lev>=level不更新是因为level用不到lev的变量值;比lev小的部分不用更新是因为递归更新*}
then emit2(3,tab[i].lev, level )
end { call };
{*
过程名:resulttype;
功能:处理整型或实行两个操作数运算时的类型转换;
参数:a:操作数1;
b: 操作数2;
返回值:返回转换类型结果;
*}
function resulttype( a, b : types) :types;
begin
if ( a > reals ) or ( b > reals ) {*如果操作数a或b为布尔型,字符型,数组或者记录,则报错err33,算术表达式类型不合法*}
then begin
error(33);
resulttype := notyp {*返回未定义类型*}
end
else if ( a = notyp ) or ( b = notyp ) {*如果a或b为未定义类型,则也返回未定义类型*}
then resulttype := notyp
else if a = ints {*如果a是整数*}
then if b = ints {*如果b也是整数*}
then resulttype := ints {*则返回值也为整数*}
else begin
resulttype := reals; {*否则将a转换为实型,返回值也为实型*}
emit1(26,1) {*生成p-code指令,转换浮点数*}
end
else begin
resulttype := reals; {*如果a是实型,则返回值为实型*}
if b = ints {*如果b是整型,则生成p-code指令,转换浮点数*}
then emit1(26,0)
end
end { resulttype } ;
{*
过程名:expression;
功能:分析处理表达式,由参数(x)返回求值结果的类型;
参数:fsys:合法字符集合,检查字符合法性;
x:
*}
procedure expression( fsys: symset; var x: item );
var y : item;
op : symbol;
{*
过程名:simpleexpression;
功能:处理简单表达式,由参数(x)返回求值结果的类型;
参数: fsys:合法字符集合,检查字符合法性;
x:
*}
procedure simpleexpression( fsys: symset; var x: item );
var y : item;
op : symbol;
{*
过程名:term;
功能:处理项,由参数返回结果类型;
*}
procedure term( fsys: symset; var x: item );
var y : item;
op : symbol;
{*
过程名:factor;
功能:处理因子,由参数返回结果类型;
*}
procedure factor( fsys: symset; var x: item );
var i,f : integer;
{*
过程名:standfct;
功能:处理标准函数调用;
参数:n:标准函数编码;
*}
procedure standfct( n: integer );
var ts : typset;
begin { standard function no. n }
if sy = lparent {*如果当前符号不是(,则报错err9,说明(缺省*}
then insymbol
else error(9);
if n < 17 {*如果编号<17,即为合法的编号*}
then begin
expression( fsys+[rparent], x ); {*计算表达式参数的值*}
case n of
{ abs, sqr } 0,2: begin {*如果是求绝对值,求平凡和函数函数*}
ts := [ints, reals]; {*实参类型要求为整数型或者实型*}
tab[i].typ := x.typ; {*定义返回值类型*}
if x.typ = reals {*如果实参类型为实型*}
then n := n + 1 {*则函数标号+1*}
end;
{ odd, chr } 4,5: ts := [ints]; {*如果是判断奇数和数字转换为符号的函数,实参类型要求为整数型*}
{ odr } 6: ts := [ints,bools,chars]; {*如果是符号转换为数字的函数,实参类型要求为整数型,布尔型,或者字符型*}
{ succ,pred } 7,8 : begin {*如果是后继函数和前驱函数*}
ts := [ints, bools,chars]; {*实参类型要求为整数型,布尔型或者字符型*}
tab[i].typ := x.typ {*定义返回值类型*}
end;
{ round,trunc } 9,10,11,12,13,14,15,16: {*如果是9-16号操作,即数学操作*}
{ sin,cos,... } begin
ts := [ints,reals]; {*实参要求类型为整数型或者实型*}
if x.typ = ints {*如果实参为整数型*}
then emit1(26,0) {*p-code指令,用于转化浮点数*}
end;
end; { case }
if x.typ in ts {*如果实参的类型在求得的类型集合中*}
then emit1(8,n) {*p-code指令,调用标准函数*}
else if x.typ <> notyp {*如果实参的类型未定义,则报告err48,即标准函数变元表达式类型不正确*}
then error(48);
end
else begin { n in [17,18] } {*如果n>17*}
if sy <> ident {*如果当前符号不为标识符,报错err2*}
then error(2)
else if id <> 'input ' {*如果标识符内容不为input,则报告错误err0,即该标识符未定义*}
then error(0)
else insymbol;
emit1(8,n); {*p-code指令,调用标准函数*}
end;
x.typ := tab[i].typ;{*x记录返回值类型*}
if sy = rparent {*如果当前符号为),说明调用过程结束*}
then insymbol
else error(4)
end { standfct } ;
begin { factor } {*因子分析程序*}
x.typ := notyp; {*初始化返回值类型*}
x.ref := 0; {*初始化返回值指针*}
test( facbegsys, fsys,58 );
while sy in facbegsys do {*因子的开头符号必须为合法的标识符*}
begin
if sy = ident {*如果是标识符类型*}
then begin
i := loc(id); {*在tab中查找位置*}
insymbol;
with tab[i] do
case obj of {*检查标识符类型*}
konstant: begin {*如果是常量*}
x.typ := typ; {*赋予返回值类型*}
x.ref := 0; {*赋予返回值指针*}
if x.typ = reals {*如果标识符是实型*}
then emit1(25,adr) {*则装入实数*}
else emit1(24,adr) {*否则,装入字面常量*}
end;
vvariable:begin {*如果是变量*}
x.typ := typ;
x.ref := ref;
if sy in [lbrack, lparent,period] {*如果标识符后方为[,(,.,即存在子结构*}
then begin
if normal {*如果不是变量形参,置f为0,否则置f为1*}
then f := 0
else f := 1;
emit2(f,lev,adr);{*将变量装入栈中,装入值或者地址*}
selector(fsys,x); {*处理子结构,可能为数组或者记录等*}
if x.typ in stantyps {*如果是标准类型,则取栈顶单元内容为地址的内容*}
then emit(34)
end
else begin {*变量没有子结构*}
if x.typ in stantyps {*该变量类型为标准类型*}
then if normal {*如果不是变量形参,置f为1,否则置f为2*}
then f := 1 {*取值*}
else f := 2 {*取地址*}
else if normal {*如果不是标准类型但也不为变量形参*}
then f := 0 {*取值*}
else f := 1; {*否则取地址*}
emit2(f,lev,adr) {*将该变量内容加载入栈,可为值或为地址*}
end
end;
typel,prozedure: error(44); {*如果是过程标识符或者是类型描述符,报错err44,即表达式中不能出现过程符号或类型描述符*}
funktion: begin {*如果是函数标识符*}
x.typ := typ;
if lev <> 0 {*如果该函数静态层次不为0,则调用call函数求得该函数值*}
then call(fsys,i)
else standfct(adr) {*否则,调用静态函数求值*}
end
end { case,with }
end
else if sy in [ charcon,intcon,realcon ] {*如果当前标识符为字符,整型,或者实型*}
then begin
if sy = realcon {*如果为实型*}
then begin
x.typ := reals;
enterreal(rnum); {*将该实型登录到tab表中*}
emit1(25,c1) {*在栈中装入实数*}
end
else begin
if sy = charcon {*如果是字符*}
then x.typ := chars
else x.typ := ints; {*如果是整型*}
emit1(24,inum) {*在栈中装入字面常量*}
end;
x.ref := 0;
insymbol
end
else if sy = lparent {*如果是(*}
then begin
insymbol;
expression(fsys + [rparent],x); {*调用表达式分析程序*}
if sy = rparent {*没有)报错err4*}
then insymbol
else error(4)
end
else if sy = notsy {*如果是not符号*}
then begin
insymbol;
factor(fsys,x); {*调用因子函数进行分析*}
if x.typ = bools {*如果因子为布尔型,逻辑非指令*}
then emit(35)
else if x.typ <> notyp {*如果类型未定义,则报错err32*}
then error(32)
end;
test(fsys,facbegsys,6)
end { while }
end { factor };
begin { term }
factor( fsys + [times,rdiv,idiv,imod,andsy],x); {*调用因子处理程序分析项*}
while sy in [times,rdiv,idiv,imod,andsy] do {*只要当前符号是*,/,div,mod,and,循环处理因子由符号连接仍然是项*}
begin
op := sy; {*记录因子前面的符号,便于后续运算*}
insymbol;
factor(fsys+[times,rdiv,idiv,imod,andsy],y );
if op = times {*如果是**}
then begin
x.typ := resulttype(x.typ, y.typ); {*转换上一个因子类型和当前因子类型*}
case x.typ of
notyp: ;
ints : emit(57); {*如果运算结果是整型,整型乘*}
reals: emit(60); {*如果运算结果是整型,实型乘*}
end
end
else if op = rdiv {*如果是div,实型除法*}
then begin
if x.typ = ints {*如果第一个操作数是整数型*}
then begin
emit1(26,1); {*整型转实型*}
x.typ := reals;
end;
if y.typ = ints {*如果第二个操作数是整数型*}
then begin
emit1(26,0); {*整型转实型*}
y.typ := reals;
end;
if (x.typ = reals) and (y.typ = reals) {*二者都为实型*}
then emit(61) {*实型除法*}
else begin
if( x.typ <> notyp ) and (y.typ <> notyp)
then error(33);
x.typ := notyp
end
end
else if op = andsy {*与运算*}
then begin
if( x.typ = bools )and(y.typ = bools) {*两个操作数都必须为布尔型*}
then emit(56) {*与运算*}
else begin
if( x.typ <> notyp ) and (y.typ <> notyp)
then error(32);
x.typ := notyp
end
end
else begin { op in [idiv,imod] } {*如果符号为整除或者取模*}
if (x.typ = ints) and (y.typ = ints) {*操作数都为整型*}
then if op = idiv {*为整除*}
then emit(58) {*整除指令*}
else emit(59) {*否则取模指令*}
else begin
if ( x.typ <> notyp ) and (y.typ <> notyp)
then error(34); {*否则类型出错*}
x.typ := notyp
end
end
end { while }
end { term };
begin { simpleexpression }
if sy in [plus,minus] {获得符号是+,-}
then begin
op := sy;
insymbol;
term( fsys+[plus,minus],x); {*处理因子*}
if x.typ > reals {*如果因子不是数*}
then error(33) {*报错,算术表达式类型不合法*}
else if op = minus {*如果是减号,生成取相反数指令指令*}
then emit(36)
end
else term(fsys+[plus,minus,orsy],x); {*否则是项,调用函数进行项处理*}
while sy in [plus,minus,orsy] do {*如果是+,-,循环处理,依靠+,-连接的项得到的依然是简单表达式*}
begin
op := sy;
insymbol;
term(fsys+[plus,minus,orsy],y);{*处理新读入的项*}
if op = orsy {*如果是或符号*}
then begin
if ( x.typ = bools )and(y.typ = bools) {*两个项的结果都必须为布尔型*}
then emit(51) {*生成or指令*}
else begin
if( x.typ <> notyp) and (y.typ <> notyp) {*否则操作数类型出错*}
then error(32);
x.typ := notyp
end
end
else begin {*否则进行实数加减*}
x.typ := resulttype(x.typ,y.typ); {*类型转换*}
case x.typ of
notyp: ;
ints: if op = plus {*整数加减*}
then emit(52)
else emit(53);
reals:if op = plus {*实数加减*}
then emit(54)
else emit(55)
end { case }
end
end { while }
end { simpleexpression };
begin { expression }
simpleexpression(fsys+[eql,neq,lss,leq,gtr,geq],x);
if sy in [ eql,neq,lss,leq,gtr,geq] {*如果当前符号为=,<,>,<=,>=,!=*}
then begin
op := sy;
insymbol;
simpleexpression(fsys,y);
if(x.typ in [notyp,ints,bools,chars]) and (x.typ = y.typ){*如果两个简单表达式同类型并且为notyp,整型,布尔型或者字符型*}
then case op of
eql: emit(45); {*是否相等比较运算*}
neq: emit(46); {*不相等*}
lss: emit(47); {*小于*}
leq: emit(48); {*小于等于*}
gtr: emit(49); {*大于*}
geq: emit(50); {*大于等于*}
end
else begin
if x.typ = ints {*第一个操作数为整型*}
then begin
x.typ := reals; {*第一个操作数转换为为实型*}
emit1(26,1)
end
else if y.typ = ints {*如果第二个操作数为整型*}
then begin
y.typ := reals; {*第二个操作数为实型*}
emit1(26,0)
end;
if ( x.typ = reals)and(y.typ=reals) {*操作数都为实型,进行运算*}
then case op of
eql: emit(39);
neq: emit(40);
lss: emit(41);
leq: emit(42);
gtr: emit(43);
geq: emit(44);
end
else error(35)
end;
x.typ := bools
end
end { expression };
{*
过程名:assignment;
功能:处理赋值语句;
*}
procedure assignment( lv, ad: integer );
var x,y: item;
f : integer;
begin { tab[i].obj in [variable,prozedure] } {*当前符号类型为变量或者过程*}
x.typ := tab[i].typ;
x.ref := tab[i].ref;
if tab[i].normal
then f := 0
else f := 1;
emit2(f,lv,ad);
if sy in [lbrack,lparent,period]
then selector([becomes,eql]+fsys,x);
if sy = becomes {*如果不为赋值符号,报错err51*}
then insymbol
else begin
error(51);
if sy = eql {*等号容错处理*}
then insymbol
end;
expression(fsys,y); {*得到赋值符号右侧表达式值*}
if x.typ = y.typ {*被赋值变量与赋值结果类型一致*}
then if x.typ in stantyps {*二者都为标准类型*}
then emit(38) {*将栈顶内容存入以次栈顶内容为地址的单元*}
else if x.ref <> y.ref {*二者不都为标准类型但指针不同,即在btab中的位置不同,报错err46*}
then error(46)
else if x.typ = arrays {*如果被赋值者为数组型*}
then emit1(23,atab[x.ref].size) {*复制atab数组块*}
else emit1(23,btab[x.ref].vsize){*复制btab记录块*}
else if(x.typ = reals )and (y.typ = ints) {*被赋值者为实型,赋值数为整型*}
then begin
emit1(26,0); {*类型转换*}
emit(38) {*赋值操作*}
end
else if ( x.typ <> notyp ) and ( y.typ <> notyp )
then error(46) {*类型不符报错*}
end { assignment };
{*
过程名:compoundstatement;
功能:处理复合语句;
*}
procedure compoundstatement;
begin
insymbol;
statement([semicolon,endsy]+fsys); {*调用语句分析函数处理第一个语句*}
while sy in [semicolon]+statbegsys do {*只要当前字符在复合语句的合法字符集内*}
begin
if sy = semicolon {*如果是分号,处理下一个语句如果不是分号,报错err14*}
then insymbol
else error(14);
statement([semicolon,endsy]+fsys)
end;
if sy = endsy {*如果是end,读入下一个字符;不是end,报错*}
then insymbol
else error(57)
end { compoundstatement };
{*
过程名:ifstatement;
功能:处理if语句;
*}
procedure ifstatement;
var x : item;
lc1,lc2: integer;
begin
insymbol;
expression( fsys+[thensy,dosy],x); {*处理条件表达式的值*}
if not ( x.typ in [bools,notyp]) {*如果结果不是布尔型或者未定义类型*}
then error(17); {报错etrr17}
lc1 := lc; {*labe1*}
emit(11); { jmpc }
if sy = thensy
then insymbol
else begin
error(52);
if sy = dosy {*容错处理*}
then insymbol
end;
statement( fsys+[elsesy]); {"then后处理语句"}
if sy = elsesy
then begin
insymbol;
lc2 := lc; {*label2*}
emit(10); {*无条件跳转*}
code[lc1].y := lc; {*填入有条件跳转指令地址,if后条件为假,跳转至else语句对应的指令*}
statement(fsys); {*处理else后的语句*}
code[lc2].y := lc {*如果处理完if-then后的语句,执行无条件跳转,跳转到else-then结束之后的语句*}
end
else code[lc1].y := lc
end { ifstatement };
{*
过程名;casestatement;
功能:处理case语句;
*}
procedure casestatement;
var x : item;
i,j,k,lc1 : integer;
casetab : array[1..csmax]of
packed record
val,lc : index
end;
exittab : array[1..csmax] of integer;
{*
过程名:caselabel;
功能:处理case语句中的标号,将各标号对应的目标代码入口地址填入case表中,并检查标号有无重复定义;
*}
procedure caselabel;
var lab : conrec;
k : integer;
begin
constant( fsys+[comma,colon],lab ); {*查找标号常量的相关信息*}
if lab.tp <> x.typ {*如果lable的类型和case后的变量类型不同,则报错err47*}
then error(47)
else if i = csmax {*如果case表已满,打印表格溢出信息*}
then fatal(6)
else begin {*case表未满*}
i := i+1; {*添加新的case表项*}
k := 0; {*检查是否重复的变量*}
casetab[i].val := lab.i; {*新的表项中填入label的值*}
casetab[i].lc := lc; {*记录生成case分支代码的位置,用于跳转到case分支语句*}
repeat {*查找重复表项*}
k := k+1
until casetab[k].val = lab.i;
if k < i {*如果找到了,报错err1*}
then error(1); { multiple definition }
end
end { caselabel };
{*
过程名:onecase;
功能:处理case语句的一个分支;
*}
procedure onecase;
begin
if sy in constbegsys
then begin
caselabel;
while sy = comma do {*处理一个分支的所有label项*}
begin
insymbol;
caselabel
end;
if sy = colon {*label后的符号必须为:*}
then insymbol
else error(5);
statement([semicolon,endsy]+fsys);{*处理case后执行语句*}
j := j+1; {*记录当前case对应的exittab的位置*}
exittab[j] := lc; {*记录case分支语句结束后的代码位置,之后在这个位置代码的跳转地址填入case执行结束后的地址*}
emit(10) {*无条件跳转结束当前case分支*}
end
end { onecase };
begin { casestatement }
insymbol;
i := 0;
j := 0;
expression( fsys + [ofsy,comma,colon],x ); {*处理case后的表达式值*}
if not( x.typ in [ints,bools,chars,notyp ]) {*case后表达式类型不符报错err23*}
then error(23);
lc1 := lc; {*记录case声明语句结束的位置,用于查找情况表代码*}
emit(12); {jmpx} {*生成一条条件跳转语句*}
if sy = ofsy {*变量后不为of报错err8*}
then insymbol
else error(8);
onecase; {*处理一条case语句*}
while sy = semicolon do {*循环处理所有case分支语句*}
begin
insymbol;
onecase
end;
code[lc1].y := lc; {*case*} {*code[lcl]为case声明语句结束后的代码,进行无条件跳转,lc为情况表的起始地址*}
for k := 1 to i do
begin
emit1( 13,casetab[k].val); {*生成情况表登记项的伪指令,用于查找情况和跳转地址*}
emit1( 13,casetab[k].lc);
end;
emit1(10,0); {*无条件跳转代码,case语句处理完毕*}
for k := 1 to j do
code[exittab[k]].y := lc; {*code[exittab]为所有cse分支执行结束后的无条件跳转语句,lc为case结束后的指令地址*}
if sy = endsy {*检查case语句结束符号是否为end,不是报错err57*}
then insymbol
else error(57)
end { casestatement };
{*
过程名:repeatstatement;
功能:处理repeat语句;
*}
procedure repeatstatement;
var x : item;
lc1: integer;
begin
lc1 := lc;{**}
insymbol;
statement( [semicolon,untilsy]+fsys); {*处理repeat后的语句,及执行语句*}
while sy in [semicolon]+statbegsys do {*只要语句后是分号,则继续处理执行语句*}
begin
if sy = semicolon
then insymbol
else error(14);
statement([semicolon,untilsy]+fsys)
end;
if sy = untilsy {*执行语句处理结束后为until关键字*}
then begin
insymbol;
expression(fsys,x); {*处理until判断条件内的表达式*}
if not(x.typ in [bools,notyp] ) {*如果表达式结果类型不符*}
then error(17); {*报错err17*}
emit1(11,lc1); {*如果栈顶内容为假,则跳转到lcl,即执行语句的开头*}
end
else error(53) {*不是until报错err53*}
end { repeatstatement };
{*
过程名:whilestatement;
功能:处理while语句
*}
procedure whilestatement;
var x : item;
lc1,lc2 : integer;
begin
insymbol;
lc1 := lc;
expression( fsys+[dosy],x); {*处理while后的判断条件表达式*}
if not( x.typ in [bools, notyp] ) {*如果表达式结果类型不正确,则报错err17*}
then error(17);
lc2 := lc; {*记录有条件跳转语句指令位置*}
emit(11); {*判断while后的条件,如果为假,则跳转到while循环体外的指令,跳转地址未填*}
if sy = dosy {*判断条件语句之后为do关键字,不是报错err54*}
then insymbol
else error(54);
statement(fsys); {*处理while内的执行语句*}
emit1(10,lc1); {*无条件转移到条件判断指令*}
code[lc2].y := lc {*如果条件为假,则跳转至while循环体外,填入跳转地址*}
end { whilestatement };
{*
过程名:forstatement;
功能:处理for语句;
*}
procedure forstatement;
var cvt : types;
x : item;
i,f,lc1,lc2 : integer;
begin
insymbol;
if sy = ident {*for开头语句第一个字符为标识符*}
then begin
i := loc(id); {*查找标识符即计数变量在tab中的位置*}
insymbol;
if i = 0 {*位置为0,即没有找到*}
then cvt := ints {*默认该计数变量的类型为整数型*}
else if tab[i].obj = vvariable {*如果找到了,并且该计数变量的种类为变量*}
then begin
cvt := tab[i].typ; {*记录计数变量类型*}
if not tab[i].normal {*如果是变量形参,报错err37,此处应为变量*}
then error(37)
else emit2(0,tab[i].lev, tab[i].adr ); {*将该计数变量的地址加载到栈顶*}
if not ( cvt in [notyp, ints, bools, chars]) {*如果该变量类型不符,报错err18,即for之后的变量必须是整型,布尔型,或者字符型*}
then error(18)
end
else begin
error(37); {*如果for后标识符不是变量则报错*}
cvt := ints
end
end
else skip([becomes,tosy,downtosy,dosy]+fsys,2); {*跳过无用符号*}
if sy = becomes {*如果是:=*}
then begin
insymbol;
expression( [tosy, downtosy,dosy]+fsys,x); {*处理:=后的表达式值*}
if x.typ <> cvt {*表达式的值类型与变量类型不符,报错err19*}
then error(19);
end
else skip([tosy, downtosy,dosy]+fsys,51); {*否则,跳过无用符号*}
f := 14; {*操作码先置为F1U*}
if sy in [tosy,downtosy] {*如果接下来是to或者downto*}
then begin
if sy = downtosy {*如果是downto,置操作码为F1D*}
then f := 16;
insymbol;
expression([dosy]+fsys,x); {*处理终值表达式*}
if x.typ <> cvt {*如果终值表达式和计数变量类型不符,报错err19*}
then error(19)
end
else skip([dosy]+fsys,55); {*跳过无用符号*}
lc1 := lc; {*记录循环体开头语句的位置*}
emit(f); {*比较变量初值和终值的大小,满足则将初值赋给循环变量并顺序执行指令,不满足则跳转出for循环体*}
if sy = dosy {*如果是do关键字,读取下一个符号,否则报错err54*}
then insymbol
else error(54);
lc2 := lc; {*记录循环体内语句开头位置*}
statement(fsys); {*处理循环体内语句*}
emit1(f+1,lc2); {*循环变量+1,,判断是否超过终值,未超过则跳转至lc2即循环体执行语句开头,超过则顺序执行下条指令,跳出for循环体*}
code[lc1].y := lc {*code[lcl]F1U或F1D类指令,初始值和终值条件关系不满足,则跳出for循环体外*}
end { forstatement };
{*
过程名:standproc;
功能:处理标准(输入/输出)过程调用;
*}
procedure standproc( n: integer );
var i,f : integer;
x,y : item;
begin
case n of
1,2 : begin { read } {*函数编号为1或2,则为read函数*}
if not iflag
then begin
error(20);
iflag := true
end;
if sy = lparent {*如果是(*}
then begin
repeat {*循环处理read括号内的所有参数,读取所有参数的值*}
insymbol;
if sy <> ident {*如果read函数内部参数不是标识符*}
then error(2)
else begin
i := loc(id); {*查找该标识符*}
insymbol;
if i <> 0
then if tab[i].obj <> vvariable
then error(37)
else begin
x.typ := tab[i].typ; {*记录标识符的种类和指针*}
x.ref := tab[i].ref;
if tab[i].normal
then f := 0
else f := 1;
emit2(f,tab[i].lev,tab[i].adr); {*加载标识符地址或值于栈顶*}
if sy in [lbrack,lparent,period] {*处理子结构*}
then selector( fsys+[comma,rparent],x);
if x.typ in [ints,reals,chars,notyp] {*如果参数类型符合输出条件,调用read指令读取该标识符内容*}
then emit1(27,ord(x.typ))
else error(41) {*否则报错err41,read或write参数不正确*}
end
end;
test([comma,rparent],fsys,6);
until sy <> comma;
if sy = rparent {*检测)*}
then insymbol
else error(4)
end;
if n = 2 {*如果n=2,则为readln函数,读完一行换行*}
then emit(62)
end;
3,4 : begin { write } {*如果是写指令*}
if sy = lparent
then begin
repeat {*循环处理输出函数的所有参数*}
insymbol;
if sy = stringcon {*如果输出的是字符串类型*}
then begin
emit1(24,sleng); {*装入字面常量,sleng为字符串长度*}
emit1(28,inum); {*否则写字符,inum为字符串在stab的起始位置*}
insymbol
end
else begin {*如果输出内容不是字符串*}
expression(fsys+[comma,colon,rparent],x); {*计算要输出的表达式的值*}
if not( x.typ in stantyps ) {*如果表达式不是标准类型,则报错err41*}
then error(41);
if sy = colon {*如果是冒号,处理输出场宽*}
then begin
insymbol;
expression( fsys+[comma,colon,rparent],y); {*计算输出场宽表达式的值*}
if y.typ <> ints {*如果输出格式不是整数,报错err43*}
then error(43);
if sy = colon {*如果还是冒号,处理输出指定实数的小数位数*}
then begin
if x.typ <> reals {*如果被输出内容不是实数,则报错err42*}
then error(42);
insymbol;
expression(fsys+[comma,rparent],y); {*处理指定小数位数的表达式*}
if y.typ <> ints {*如果场宽格式不是整数型,则报错err43*}
then error(43);
emit(37) {*否则按照给定场宽输出实数值*}
end
else emit1(30,ord(x.typ)) {*如果只有单场宽,则按照给定场宽输出数值*}
end
else emit1(29,ord(x.typ)) {*如果输出数值没有场宽限制,则隐含场宽输出数值*}
end
until sy <> comma;
if sy = rparent {*检查输出函数的右括号*}
then insymbol
else error(4)
end;
if n = 4 {*如果n=4,则是writeln函数,则换行继续进行写操作*}
then emit(63)
end; { write }
end { case };
end { standproc } ;
begin { statement }
if sy in statbegsys+[ident] {*检查开头字符是否属于合法的语句字符集合*}
then case sy of
ident : begin {*如果是标识符*}
i := loc(id); {*查找该标识符*}
insymbol;
if i <> 0
then case tab[i].obj of {*查找到对标识符的类型进行分析*}
konstant,typel : error(45); {*如果是常量或者类型描述符则报错err45*}
vvariable: assignment( tab[i].lev,tab[i].adr); {*如果是变量,处理赋值语句*}
prozedure: if tab[i].lev <> 0 {*如果是过程类型,如果被调用过程不为标准过程,则处理该过程*}
then call(fsys,i)
else standproc(tab[i].adr); {*否则处理标准过程*}
funktion: if tab[i].ref = display[level] {*如果该函数在btab中的位置等于当前层在栈中的地址,调用赋值语句,否则报错err45*}
then assignment(tab[i].lev+1,0)
else error(45)
end { case }
end;
beginsy : compoundstatement; {*如果是begin,则调用处理复合语句函数*}
ifsy : ifstatement; {*如果是if,则调用处理if语句函数*}
casesy : casestatement; {*如果是case,则调用处理case语句函数*}
whilesy : whilestatement; {*如果是while,则调用处理while语句函数*}
repeatsy: repeatstatement; {*如果是repeat,则调用处理repeat函数*}
forsy : forstatement; {*如果是for,则调用处理for语句函数*}
end; { case }
test( fsys, [],14);
end { statement };
begin { block }
dx := 5; {*dx为变量存储分配索引,初值为5,即每个分程序在运行栈s中的数据开头应留出5个单元作为内务信息区*}
prt := t; {*prt用来存储该过程进入tab表的位置*}
if level > lmax {*如果该过程静态层次大于嵌套最大值,则报告溢出错误*}
then fatal(5);
test([lparent,colon,semicolon],fsys,14);{检查块开始字符的合法性}
enterblock; {*登录该块的信息于btab表*}
prb := b; {*prb记录该块在btab中的起始位置*}
display[level] := b; {*更新display表,display表指向该过程在btab的位置*}
tab[prt].typ := notyp; {*过程没有类型,这里填入notyp*}
tab[prt].ref := prb; {*记录该块的指针,指向btab中的位置*}
if ( sy = lparent ) and ( level > 1 ) {*如果过程或函数后为(并且不为主函数*}
then parameterlist; {*处理该过程或函数的参数列表*}
btab[prb].lastpar := t; {*记录该过程的最后一个标识符在tab中的位置,有可能该过程或函数没有声明变量或者常量*}
btab[prb].psize := dx; {*记录内务信息区和参数占用的空间大小*}
if isfun {*如果是函数*}
then if sy = colon {*检测返回值类型前的冒号*}
then begin
insymbol; { function type }
if sy = ident {*如果返回值类型是标识符*}
then begin
x := loc(id); {*查找在tab中的位置*}
insymbol;
if x <> 0 {*如果找到了*}
then if tab[x].typ in stantyps {*如果是标准类型*}
then tab[prt].typ := tab[x].typ {将该函数的类型记为返回值类型,否则报错err15}
else error(15)
end
else skip( [semicolon]+fsys,2 ){*跳过无用符号*}
end
else error(5); {*函数括号之后没有冒号报错err5*}
if sy = semicolon {*如果括号之后不是分号报错err14*}
then insymbol
else error(14);
repeat{*循环处理block声明内容*}
if sy = constsy {*处理常量声明语句*}
then constdec;
if sy = typesy {*处理类型描述符*}
then typedeclaration;
if sy = varsy {*处理变量说明语句*}
then variabledeclaration;
btab[prb].vsize := dx; {*记录该block局部变量参数和内务信息区的大小*}
while sy in [procsy,funcsy] do {*循环处理该块内的所有过程声明*}
procdeclaration;
test([beginsy],blockbegsys+statbegsys,56)
until sy in statbegsys;
tab[prt].adr := lc; {*该块的地址为相应目标代码的入口地址*}
insymbol;
statement([semicolon,endsy]+fsys); {*处理block内的语句*}
while sy in [semicolon]+statbegsys do {*循环处理block内的所有语句*}
begin
if sy = semicolon {*如果语句没有以分号结束,则报错err14*}
then insymbol
else error(14);
statement([semicolon,endsy]+fsys); {*接着处理下一个语句*}
end;
if sy = endsy {*该块处理结束*}
then insymbol
else error(57); {*没有end,报错err57*}
test( fsys+[period],[],6 ) {*检测后继符号的合法性*}
end { block };
{*
过程名:interpret;
功能:p-code解释执行程序;
*}
procedure interpret;
var ir : order ; { instruction buffer }
pc : integer; { program counter }
t : integer; { top stack index }
b : integer; { base index } {*基址索引*}
h1,h2,h3: integer; {*临时变量*}
lncnt,ocnt,blkcnt,chrcnt: integer; { counters }
ps : ( run,fin,caschk,divchk,inxchk,stkchk,linchk,lngchk,redchk );
fld: array [1..4] of integer; { default field widths }
display : array[0..lmax] of integer;
s : array[1..stacksize] of { blockmark: }
record
case cn : types of { s[b+0] = fct result }
ints : (i: integer ); { s[b+1] = return adr }
reals :(r: real ); { s[b+2] = static link }
bools :(b: boolean ); { s[b+3] = dynamic link }
chars :(c: char ) { s[b+4] = table index }
end;
{*
过程名:dump;
功能:程序运行时.卸出打印现场剖析信息(display,t,b以及运行栈s的内容,满足编译预选项的要求)
*}
procedure dump;
var p,h3 : integer;
begin
h3 := tab[h2].lev; {*该函数在call指令被调用,h2此时代表当前分程序名字在tab表的位置,则h3代表该分程序的层次*}
writeln(psout);
writeln(psout);
writeln(psout,' calling ', tab[h2].name ); {*打印分程序名字*}
writeln(psout,' level ',h3:4); {*打印分程序层次*}
writeln(psout,' start of code ',pc:4); {*打印分程序语句部分的入口指令地址*}
writeln(psout);
writeln(psout);
writeln(psout,' contents of display ');
writeln(psout);
for p := h3 downto 0 do {*打印display表内容*}
writeln(psout,p:4,display[p]:6);
writeln(psout);
writeln(psout);
writeln(psout,' top of stack ',t:4,' frame base ':14,b:4); {*打印栈指针值和基址*}
writeln(psout);
writeln(psout);
writeln(psout,' stack contents ':20);
writeln(psout);
for p := t downto 1 do {*打印运行栈内容*}
writeln( psout, p:14, s[p].i:8);
writeln(psout,'< = = = >':22)
end; {dump }
{*
过程名:inter0;
功能:处理具体的指令;
*}
procedure inter0;
begin
case ir.f of
0 : begin { load addrss } {*把变量地址装入栈顶*}
t := t + 1; {*栈指针+1*}
if t > stacksize {*栈溢出*}
then ps := stkchk {*报告错误信息*}
else s[t].i := display[ir.x]+ir.y {*取x层相对地址为y的数据地址到当期栈顶*}
end;
1 : begin { load value } {*加载相应的值到栈顶*}
t := t + 1;
if t > stacksize
then ps := stkchk
else s[t] := s[display[ir.x]+ir.y]
end;
2 : begin { load indirect } {*间接装入数据,即以x层y为相对地址的数据为基址的数据*}
t := t + 1;
if t > stacksize
then ps := stkchk
else s[t] := s[s[display[ir.x]+ir.y].i]
end;
3 : begin { update display } {*更新display表*}
h1 := ir.y; {*调用过程或函数所在层次*}
h2 := ir.x; {*被调用过程或函数所在层次*}
h3 := b; {*h3为调用过程基址*}
repeat {*循环更新调用过程到被调用过程之间的层次的display表,h2<h1,这个在生成display这条指令的时候就确定了*}
display[h1] := h3; {*记录当前层次的display为当前过程的基址*}
h1 := h1-1; {*层次-1*}
h3 := s[h3+2].i {*下一个层次为下标的display数组记录值为当前过程SL值*}
until h1 = h2 {**}
end;
8 : case ir.y of {*标准函数处理*}
0 : s[t].i := abs(s[t].i); {*绝对值*}
1 : s[t].r := abs(s[t].r); {*实数求绝对值*}
2 : s[t].i := sqr(s[t].i); {*求平方*}
3 : s[t].r := sqr(s[t].r); {*实求平方*}
4 : s[t].b := odd(s[t].i); {*判断是否为奇数*}
5 : s[t].c := chr(s[t].i); {*将数字转化为符号*}
6 : s[t].i := ord(s[t].c); {*将符号转化为数字*}
7 : s[t].c := succ(s[t].c); {*求符号后继*}
8 : s[t].c := pred(s[t].c); {*求符号前驱*}
9 : s[t].i := round(s[t].r); {*求x的四舍五入*}
10 : s[t].i := trunc(s[t].r); {*求实数的整数部分*}
11 : s[t].r := sin(s[t].r); {*求sin值*}
12 : s[t].r := cos(s[t].r); {*求cos值*}
13 : s[t].r := exp(s[t].r); {*求开方*}
14 : s[t].r := ln(s[t].r); {*求对数*}
15 : s[t].r := sqrt(s[t].r); {*开方*}
16 : s[t].r := arcTan(s[t].r); {*求反三角函数*}
17 : begin {*判断是否为文件结尾并将结果入栈顶*}
t := t+1;
if t > stacksize
then ps := stkchk
else s[t].b := eof(prd)
end;
18 : begin {判断文件本行是否到结尾}
t := t+1;
if t > stacksize
then ps := stkchk
else s[t].b := eoln(prd)
end;
end;
9 : s[t].i := s[t].i + ir.y; { offset } {*栈顶元素加上y*}
end { case ir.y }
end; { inter0 }
procedure inter1;
var h3, h4: integer;
begin
case ir.f of
10 : pc := ir.y ; { jump }
11 : begin { conditional jump } {*栈顶元素条件为假,跳转至y指令处,栈指针回退1*}
if not s[t].b
then pc := ir.y;
t := t - 1
end;
12 : begin { switch } {*转移到y,查找case表*}
h1 := s[t].i; {*case后需要查找值的变量,即case x*}
t := t-1;
h2 := ir.y; {*情况表起始地址*}
h3 := 0; {*标志变量,情况表结束或情况表起始位置不正确,则置为0*}
repeat
if code[h2].f <> 13 {*情况表查找结束*}
then begin
h3 := 1;
ps := caschk {*没有查找到x的值*}
end
else if code[h2].y = h1 {*情况表的label=变量x*}
then begin
h3 := 1; {*置标志位*}
pc := code[h2+1].y {*pc跳转至case对应label的执行语句*}
end
else h2 := h2 + 2
until h3 <> 0
end;
14 : begin { for1up } {*比较for循环to情况的初值和终值*}
h1 := s[t-1].i; {*h1即次栈顶为初值*}
if h1 <= s[t].i {栈顶为终值}
then s[s[t-2].i].i := h1 {*如果初值<=终值,则将初值的值赋给计数变量*}
else begin
t := t - 3; {*初值>终值,栈指针回退,跳转至循环体外*}
pc := ir.y
end
end;
15 : begin { for2up } {*循环变量+1,判断是否超过终值并跳转或顺序执行*}
h2 := s[t-2].i; {*次栈顶存储变量地址*}
h1 := s[h2].i+1; {*计数变量值+1*}
if h1 <= s[t].i {*栈顶为终值,计数变量<=终值*}
then begin
s[h2].i := h1; {*计数变量更新值为旧值+1*}
pc := ir.y {*跳转地址,继续循环*}
end
else t := t-3; {*否则顺序执行并退回栈顶,跳出for循环体*}
end;
16 : begin { for1down } {*与14同理*}
h1 := s[t-1].i;
if h1 >= s[t].i
then s[s[t-2].i].i := h1
else begin
pc := ir.y;
t := t - 3
end
end;
17 : begin { for2down } {*与15同理*}
h2 := s[t-2].i;
h1 := s[h2].i-1;
if h1 >= s[t].i
then begin
s[h2].i := h1;
pc := ir.y
end
else t := t-3;
end;
18 : begin { mark stack } {*标记栈*}
h1 := btab[tab[ir.y].ref].vsize; {*找到被调过程在btab中的位置,进而求得该过程的vsize*}
if t+h1 > stacksize {*如果栈溢出*}
then ps := stkchk {*报错*}
else begin
t := t+5; {*栈指针+5,留出内务信息区空间*}
s[t-1].i := h1-1; {*内务信息区的第四个单元记录vsize-1*}
s[t].i := ir.y {*内务信息区第五个单元记录被调用过程在tab表中的位置*}
end
end;
19 : begin { call } {*调用用户过程或函数*}
h1 := t-ir.y; { h1 points to base } {*t位栈顶,此时指向被调用过程或函数新分配栈的参数区,ir.y为该过程或函数的p.size,即参数区和内务信息区的大小,因此h1即为该过程或函数的基址*}
h2 := s[h1+4].i; { h2 points to tab } {*h2为该过程名在tab表中的位置*}
h3 := tab[h2].lev; {*h3为该过程名的层次*}
display[h3+1] := h1; {*h3加1为该过程块的层次,因为过程名总比过程块层数小1,更新display表*}
h4 := s[h1+3].i+h1; {*s[h1+3]记录的是vsize-1,即局部变量,参数区和内务区的大小,所以h4为该过程分配完所需存储单元后的栈顶指针*}
s[h1+1].i := pc; {*记录RA*}
s[h1+2].i := display[h3]; {*记录SL*}
s[h1+3].i := b; {*记录DL*}
for h3 := t+1 to h4 do {*局部变量区数据清零*}
s[h3].i := 0;
b := h1; {*更新b为当前被调用过程的基址*}
t := h4; {*更新栈顶指针*}
pc := tab[h2].adr; {*pc为该过程的目标代码的入口地址*}
if stackdump
then dump
end;
end { case }
end; { inter1 }
procedure inter2;
begin
case ir.f of
20 : begin { index1 } {*取下标变量地址,元素长度为1*}
h1 := ir.y; { h1 points to atab }
h2 := atab[h1].low; {*数组下界*}
h3 := s[t].i; {*数组下标*}
if h3 < h2 {*所求数组下标小于数组下界,则记录错误错*}
then ps := inxchk
else if h3 > atab[h1].high {*所求数组下标大于数组上界,则记录错误*}
then ps := inxchk
else begin
t := t-1;
s[t].i := s[t].i+(h3-h2) {*当期栈顶存储数组起始基址*}
end
end;
21 : begin { index } {*取下标变量地址,元素长度不为1*}
h1 := ir.y ; { h1 points to atab }
h2 := atab[h1].low;
h3 := s[t].i;
if h3 < h2
then ps := inxchk
else if h3 > atab[h1].high
then ps := inxchk
else begin
t := t-1;
s[t].i := s[t].i + (h3-h2)*atab[h1].elsize
end
end;
22 : begin { load block } {*装入块*}
h1 := s[t].i; {*h1记录块起始地址*}
t := t-1; {*栈退1*}
h2 := ir.y+t; {*块装完栈指针*}
if h2 > stacksize {*栈溢出*}
then ps := stkchk
else while t < h2 do {*循环装入块*}
begin
t := t+1;
s[t] := s[h1];
h1 := h1+1
end
end;
23 : begin { copy block } {*复制块*}
h1 := s[t-1].i; {*将要被复制数据区起始地址*}
h2 := s[t].i; {*复制的数据区起始地址*}
h3 := h1+ir.y;
while h1 < h3 do
begin
s[h1] := s[h2];
h1 := h1+1;
h2 := h2+1
end;
t := t-2
end;
24 : begin { literal } {*装入字面常量*}
t := t+1;
if t > stacksize
then ps := stkchk
else s[t].i := ir.y {*y为被装入的字面常量*}
end;
25 : begin { load real } {*装入实数*}
t := t+1;
if t > stacksize
then ps := stkchk
else s[t].r := rconst[ir.y] {*y为实数在实数表中的位置*}
end;
26 : begin { float } {*转换浮点数*}
h1 := t-ir.y; {*被转换数的地址*}
s[h1].r := s[h1].i
end;
27 : begin { read } {*读内容*}
if eof(prd) {*文件内容读完*}
then ps := redchk {*报错*}
else case ir.y of {*栈顶为被读内容的地址*}
1 : read(prd, s[s[t].i].i); {*读整型*}
2 : read(prd, s[s[t].i].r); {*读实数*}
4 : read(prd, s[s[t].i].c); {*读字符*}
end;
t := t-1 {*栈退1*}
end;
28 : begin { write string } {*写字符*}
h1 := s[t].i; {*栈顶为字符长度*}
h2 := ir.y; {*被写字符起始地址*}
t := t-1;
chrcnt := chrcnt+h1;
if chrcnt > lineleng {*超出可输出最大字符数限制*}
then ps := lngchk;
repeat
write(prr,stab[h2]);
h1 := h1-1;
h2 := h2+1
until h1 = 0
end;
29 : begin { write1 } {*写隐含场宽*}
chrcnt := chrcnt + fld[ir.y]; {*fld[ir.y]场宽*}
if chrcnt > lineleng
then ps := lngchk
else case ir.y of
1 : write(prr,s[t].i:fld[1]); {*输出整数*}
2 : write(prr,s[t].r:fld[2]); {*输出实数*}
3 : if s[t].b {*输出布尔值*}
then write('true')
else write('false');
4 : write(prr,chr(s[t].i)); {*输出字符*}
end;
t := t-1
end;
end { case }
end; { inter2 }
procedure inter3;
begin
case ir.f of
30 : begin { write2 } {*写给定场宽*}
chrcnt := chrcnt+s[t].i;
if chrcnt > lineleng
then ps := lngchk
else case ir.y of
1 : write(prr,s[t-1].i:s[t].i);
2 : write(prr,s[t-1].r:s[t].i);
3 : if s[t-1].b
then write('true')
else write('false');
end;
t := t-2
end;
31 : ps := fin;{*停止*}
32 : begin { exit procedure } {*退出过程*}
t := b-1; {*栈顶为原来过程基址-1*}
pc := s[b+1].i;{*pc转为RA即过程指令返回地址基址*}
b := s[b+3].i {*b转为动态链存储的基址,即调用该过程的基址*}
end;
33 : begin { exit function } {*退出函数*}
t := b; {*t不-1,是因为存储函数返回结果*}
pc := s[b+1].i;
b := s[b+3].i
end;
34 : s[t] := s[s[t].i]; {*取栈顶内容为基址的单元内容*}
35 : s[t].b := not s[t].b; {*逻辑非*}
36 : s[t].i := -s[t].i; {*求负*}
37 : begin {*写实数,给定场宽*}
chrcnt := chrcnt + s[t-1].i;
if chrcnt > lineleng
then ps := lngchk
else write(prr,s[t-2].r:s[t-1].i:s[t].i);
t := t-3
end;
38 : begin { store } {*将栈顶内容存入以栈顶次高元为地址的单元*}
s[s[t-1].i] := s[t];
t := t-2
end;
39 : begin {**实型等于比较}
t := t-1;
s[t].b := s[t].r=s[t+1].r
end;
end { case }
end; { inter3 }
procedure inter4;
begin
case ir.f of
40 : begin {*实型不等比较*}
t := t-1;
s[t].b := s[t].r <> s[t+1].r
end;
41 : begin {*实型小于比较*}
t := t-1;
s[t].b := s[t].r < s[t+1].r
end;
42 : begin {*实型小于等于比较*}
t := t-1;
s[t].b := s[t].r <= s[t+1].r
end;
43 : begin {*实型大于比较*}
t := t-1;
s[t].b := s[t].r > s[t+1].r
end;
44 : begin {*实型大于等于比较*}
t := t-1;
s[t].b := s[t].r >= s[t+1].r
end;
45 : begin {*整型相等比较*}
t := t-1;
s[t].b := s[t].i = s[t+1].i
end;
46 : begin {*整型不等比较*}
t := t-1;
s[t].b := s[t].i <> s[t+1].i
end;
47 : begin {*整型小于比较*}
t := t-1;
s[t].b := s[t].i < s[t+1].i
end;
48 : begin {*整型小于等于比较*}
t := t-1;
s[t].b := s[t].i <= s[t+1].i
end;
49 : begin {*整型大于等于比较*}
t := t-1;
s[t].b := s[t].i > s[t+1].i
end;
end { case }
end; { inter4 }
procedure inter5;
begin
case ir.f of
50 : begin {*整型大于等于比较*}
t := t-1;
s[t].b := s[t].i >= s[t+1].i
end;
51 : begin {*逻辑或*}
t := t-1;
s[t].b := s[t].b or s[t+1].b
end;
52 : begin {*整型加*}
t := t-1;
s[t].i := s[t].i+s[t+1].i
end;
53 : begin {*整型减*}
t := t-1;
s[t].i := s[t].i-s[t+1].i
end;
54 : begin {*实型加*}
t := t-1;
s[t].r := s[t].r+s[t+1].r;
end;
55 : begin {*实型减*}
t := t-1;
s[t].r := s[t].r-s[t+1].r;
end;
56 : begin {*逻辑与*}
t := t-1;
s[t].b := s[t].b and s[t+1].b
end;
57 : begin {*整型乘*}
t := t-1;
s[t].i := s[t].i*s[t+1].i
end;
58 : begin {*整型除*}
t := t-1;
if s[t+1].i = 0 {*除数为0*}
then ps := divchk
else s[t].i := s[t].i div s[t+1].i
end;
59 : begin {*取模*}
t := t-1;
if s[t+1].i = 0
then ps := divchk
else s[t].i := s[t].i mod s[t+1].i
end;
end { case }
end; { inter5 }
procedure inter6;
begin
case ir.f of
60 : begin {*实型乘*}
t := t-1;
s[t].r := s[t].r*s[t+1].r;
end;
61 : begin {*实型除*}
t := t-1;
s[t].r := s[t].r/s[t+1].r;
end;
62 : if eof(prd) {*readln*}
then ps := redchk
else readln;
63 : begin {*writeln*}
writeln(prr);
lncnt := lncnt+1;
chrcnt := 0;
if lncnt > linelimit
then ps := linchk
end
end { case };
end; { inter6 }
begin { interpret }
s[1].i := 0; {初始化运行栈}
s[2].i := 0;
s[3].i := -1;
s[4].i := btab[1].last;
display[0] := 0; {*初始化display表*}
display[1] := 0;
t := btab[2].vsize-1; {*栈指针为栈指针为全程变量区的最后一个单元*}
b := 0;
pc := tab[s[4].i].adr; {*初始化pc运行指令地址*}
lncnt := 0; {*初始化各种计数变量*}
ocnt := 0;
chrcnt := 0;
ps := run; {*运行标志记为run*}
fld[1] := 10; {*初始化场宽相关信息*}
fld[2] := 22;
fld[3] := 10;
fld[4] := 1;
repeat {*取指令,出现错误即ps不为run,则停止运行*}
ir := code[pc];
pc := pc+1;
ocnt := ocnt+1;
case ir.f div 10 of {*运行指令*}
0 : inter0;
1 : inter1;
2 : inter2;
3 : inter3;
4 : inter4;
5 : inter5;
6 : inter6;
end; { case }
until ps <> run;
if ps <> fin {*处理错误情况*}
then begin
writeln(prr);
write(prr, ' halt at', pc :5, ' because of '); {*打印出错指令信息*}
case ps of
caschk : writeln(prr,'undefined case');
divchk : writeln(prr,'division by 0');
inxchk : writeln(prr,'invalid index');
stkchk : writeln(prr,'storage overflow');
linchk : writeln(prr,'too much output');
lngchk : writeln(prr,'line too long');
redchk : writeln(prr,'reading past end or file');
end;
{*进行事后卸出打印*}
h1 := b; {*当前运行分程序基址*}
blkcnt := 10; {*已打印分程序计数器,回溯打印最多不超过10个分程序*} { post mortem dump }
repeat {*循环打印分程序内容,直到分程序基址<0*}
writeln( prr );
blkcnt := blkcnt-1;
if blkcnt = 0 {*打印超过10个分程序,置h1为0,则开始打印主程序内容*}
then h1 := 0;
h2 := s[h1+4].i; {*h2为当前分程序名字在tab表中的位置*}
if h1 <> 0
then writeln( prr, '',tab[h2].name, 'called at', s[h1+1].i:5); {*打印分程序名字和该程序被调用地址*}
h2 := btab[tab[h2].ref].last; {*h2为该程序最后一个标识符在tab中的位置*}
while h2 <> 0 do {*打印该分程序的每一个标识符信息*}
with tab[h2] do
begin
if obj = vvariable {*如果该标识符为变量*}
then if typ in stantyps {*如果该标识符的类型是标准类型*}
then begin
write(prr,'',name,'='); {*打印名字*}
if normal {*如果不是变量形参*}
then h3 := h1+adr {*h3为该变量相对于基址的偏移+基址,即该变量在栈中的基址*}
else h3 := s[h1+adr].i; {*如果是变量形参,求得该过程+offset为基址单元的内容为该变量基址*}
case typ of {*判断变量类型并输出值*}
ints : writeln(prr,s[h3].i);
reals: writeln(prr,s[h3].r);
bools: if s[h3].b
then writeln(prr,'true')
else writeln(prr,'false');
chars: writeln(prr,chr(s[h3].i mod 64 ))
end
end;
h2 := link {*h2记录该过程下一个变量在tab中的位置*}
end;
h1 := s[h1+3].i {*h1为调用该分程序的分程序在栈中的基址*}
until h1 < 0
end;
writeln(prr);
writeln(prr,ocnt,' steps');
end; { interpret }
{*
过程名:setup;
功能:建立初始信息;
*}
procedure setup;
begin
{*初始化保留字表*}
key[1] := 'and ';
key[2] := 'array ';
key[3] := 'begin ';
key[4] := 'case ';
key[5] := 'const ';
key[6] := 'div ';
key[7] := 'do ';
key[8] := 'downto ';
key[9] := 'else ';
key[10] := 'end ';
key[11] := 'for ';
key[12] := 'function ';
key[13] := 'if ';
key[14] := 'mod ';
key[15] := 'not ';
key[16] := 'of ';
key[17] := 'or ';
key[18] := 'procedure ';
key[19] := 'program ';
key[20] := 'record ';
key[21] := 'repeat ';
key[22] := 'then ';
key[23] := 'to ';
key[24] := 'type ';
key[25] := 'until ';
key[26] := 'var ';
key[27] := 'while ';
{*初始化保留字编码表*}
ksy[1] := andsy;
ksy[2] := arraysy;
ksy[3] := beginsy;
ksy[4] := casesy;
ksy[5] := constsy;
ksy[6] := idiv;
ksy[7] := dosy;
ksy[8] := downtosy;
ksy[9] := elsesy;
ksy[10] := endsy;
ksy[11] := forsy;
ksy[12] := funcsy;
ksy[13] := ifsy;
ksy[14] := imod;
ksy[15] := notsy;
ksy[16] := ofsy;
ksy[17] := orsy;
ksy[18] := procsy;
ksy[19] := programsy;
ksy[20] := recordsy;
ksy[21] := repeatsy;
ksy[22] := thensy;
ksy[23] := tosy;
ksy[24] := typesy;
ksy[25] := untilsy;
ksy[26] := varsy;
ksy[27] := whilesy;
{*初始化特殊字符编码表*}
sps['+'] := plus;
sps['-'] := minus;
sps['*'] := times;
sps['/'] := rdiv;
sps['('] := lparent;
sps[')'] := rparent;
sps['='] := eql;
sps[','] := comma;
sps['['] := lbrack;
sps[']'] := rbrack;
sps[''''] := neq;
sps['!'] := andsy;
sps[';'] := semicolon;
end { setup };
{*
过程名:enterids;
功能:在符号表中登录标准的类型(基本类型),函数和过程的名字,以及它们的相应信息;
*}
procedure enterids;
begin
enter(' ',vvariable,notyp,0); { sentinel }
enter('false ',konstant,bools,0);
enter('true ',konstant,bools,1);
enter('real ',typel,reals,1);
enter('char ',typel,chars,1);
enter('boolean ',typel,bools,1);
enter('integer ',typel,ints,1);
enter('abs ',funktion,reals,0);
enter('sqr ',funktion,reals,2);
enter('odd ',funktion,bools,4);
enter('chr ',funktion,chars,5);
enter('ord ',funktion,ints,6);
enter('succ ',funktion,chars,7);
enter('pred ',funktion,chars,8);
enter('round ',funktion,ints,9);
enter('trunc ',funktion,ints,10);
enter('sin ',funktion,reals,11);
enter('cos ',funktion,reals,12);
enter('exp ',funktion,reals,13);
enter('ln ',funktion,reals,14);
enter('sqrt ',funktion,reals,15);
enter('arctan ',funktion,reals,16);
enter('eof ',funktion,bools,17);
enter('eoln ',funktion,bools,18);
enter('read ',prozedure,notyp,1);
enter('readln ',prozedure,notyp,2);
enter('write ',prozedure,notyp,3);
enter('writeln ',prozedure,notyp,4);
enter(' ',prozedure,notyp,0);
end;
begin { main } {*主函数*}
setup; {*初始化所有初始信息*}
{*初始化所有合法字符集合*}
constbegsys := [ plus, minus, intcon, realcon, charcon, ident ];
typebegsys := [ ident, arraysy, recordsy ];
blockbegsys := [ constsy, typesy, varsy, procsy, funcsy, beginsy ];
facbegsys := [ intcon, realcon, charcon, ident, lparent, notsy ];
statbegsys := [ beginsy, ifsy, whilesy, repeatsy, forsy, casesy ];
stantyps := [ notyp, ints, reals, bools, chars ];
lc := 0; {*代码地址索引为0*}
ll := 0; {*行内容长度置为0*}
cc := 0; {*字符指针置为0*}
ch := ' '; {*当前字符为' '*}
errpos := 0; {*错误位置记为0*}
errs := []; {*错误编号集合初始化为空*}
writeln( 'NOTE input/output for users program is console : ' ); {*输出提示语句*}
writeln;
write( 'Source input file ?');
readln( inf ); {*读入源码文件路径*}
assign( psin, inf );
reset( psin );
write( 'Source listing file ?');
readln( outf ); {*读入输出文件路径*}
assign( psout, outf );
rewrite( psout );
assign ( prd, 'con' ); {**}
write( 'result file : ' );
readln( fprr ); {*读入输出结果文件路径*}
assign( prr, fprr );
reset ( prd );
rewrite( prr );
t := -1; {*符号表初始指针置为-1*}
a := 0; {*atab初始指针置为0*}
b := 1; {*btab初始指针置为1*}
sx := 0; {*stab初始指针置为0*}
c2 := 0; {*rconst初始指针置为0*}
display[0] := 1; {*初始化display表*}
iflag := false; {*初始化一系列flag值*}
oflag := false;
skipflag := false;
prtables := false;
stackdump := false;
insymbol;
if sy <> programsy {*程序第一个关键字必须为program,否则报错err3*}
then error(3)
else begin
insymbol;
if sy <> ident {*如果当前符号为标识符*}
then error(2)
else begin
progname := id; {*记录program的名字*}
insymbol;
if sy <> lparent {*如果不为(,则报错*}
then error(9)
else repeat {*循环处理主程序参数,通常为标准输入或者标准输出文件名,一般对应键盘,显示器,代表程序与外界的联系,与具体运行环境有关*}
insymbol;
if sy <> ident {*如果不是标识符,则报错*}
then error(2)
else begin
if id = 'input ' {*如果是input*}
then iflag := true
else if id = 'output ' {*如果是output*}
then oflag := true
else error(0); {*否则报错该标识符未定义*}
insymbol
end
until sy <> comma;
if sy = rparent {*检查)合法性*}
then insymbol
else error(4);
if not oflag then error(20){*程序头部未包含参数output或者input*}
end
end;
enterids; {*登录标准信息到tab中*}
with btab[1] do {*登录初始信息到btab中*}
begin
last := t;
lastpar := 1;
psize := 0;
vsize := 0;
end;
block( blockbegsys + statbegsys, false, 1 ); {*分析程序块*}
if sy <> period {*如果程序不以.结尾,则报错*}
then error(2);
emit(31); { halt } {*31号指令停止程序*}
if prtables {*如果需要打印相关编译信息表格*}
then printtables; {*则打印信息表格*}
if errs = [] {*如果错误集合为空集*}
then interpret {*则开始执行解释程序*}
else begin
writeln( psout ); {*如果有错误则输出编译错误提示信息于输出文件中*}
writeln( psout, 'compiled with errors' );
writeln( psout );
errormsg;
end;
writeln( psout );
close( psout );
close( prr )
end.