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.
BUAA 编译源码阅读_pascal
猜你喜欢
转载自www.cnblogs.com/sbs384/p/10526393.html
今日推荐
周排行