?? 123.txt
字號:
s[3] := 0; (* 數據內存中為SL,DL,RA三個單元均為0,標識為主程序 *)
repeat (* 開始依次運行程序目標代碼 *)
i := code
; (* 獲取一行目標代碼 *)
p := p + 1; (* 指令指針加一,指向下一條代碼 *)
with i do
case f of (* 如果i的f,即指令助記符是下面的某種情況,執行不同的功能 *)
lit: (* 如果是lit指令 *)
begin
t := t + 1; (* 棧頂指針上移,在棧中分配了一個單元 *)
s[t] := a (* 該單元的內容存放i指令的a操作數,即實現了把常量值放到運行棧棧頂 *)
end;
opr: (* 如果是opr指令 *)
case a of (* operator *) (* 根據a操作數不同,執行不同的操作 *)
0: (* 0號操作為從子過程返回操作 *)
begin (* return *)
t := b - 1; (* 釋放這段子過程占用的數據內存空間 *)
p := s[t + 3]; (* 把指令指針取到RA的值,指向的是返回地址 *)
b := s[t + 2] (* 把數據段基址取到DL的值,指向調用前子過程的數據段基址 *)
end;
1: (* 1號操作為棧頂數據取反操作 *)
s[t] := -s[t]; (* 對棧頂數據進行取反 *)
2: (* 2號操作為棧頂兩個數據加法操作 *)
begin
t := t - 1; (* 棧頂指針下移 *)
s[t] := s[t] + s[t + 1] (* 把兩單元數據相加存入棧頂 *)
end;
3: (* 3號操作為棧頂兩個數據減法操作 *)
begin
t := t - 1; (* 棧頂指針下移 *)
s[t] := s[t] - s[t + 1] (* 把兩單元數據相減存入棧頂 *)
end;
4: (* 4號操作為棧頂兩個數據乘法操作 *)
begin
t := t - 1; (* 棧頂指針下移 *)
s[t] := s[t] * s[t + 1] (* 把兩單元數據相乘存入棧頂 *)
end;
5: (* 5號操作為棧頂兩個數據除法操作 *)
begin
t := t - 1; (* 棧頂指針下移 *)
s[t] := s[t] div s[t + 1] (* 把兩單元數據相整除存入棧頂 *)
end;
6: (* 6號操作為判奇操作 *)
s[t] := ord(odd(s[t])); (* 數據棧頂的值是奇數則把棧頂值置1,否則置0 *)
8: (* 8號操作為棧頂兩個數據判等操作 *)
begin
t := t - 1; (* 棧頂指針下移 *)
s[t] := ord(s[t] = s[t + 1]) (* 判等,相等棧頂置1,不等置0 *)
end;
9: (* 9號操作為棧頂兩個數據判不等操作 *)
begin
t := t - 1; (* 棧頂指針下移 *)
s[t] := ord(s[t] <> s[t + 1]) (* 判不等,不等棧頂置1,相等置0 *)
end;
10: (* 10號操作為棧頂兩個數據判小于操作 *)
begin
t := t - 1; (* 棧頂指針下移 *)
s[t] := ord(s[t] < s[t + 1]) (* 判小于,如果下面的值小于上面的值,棧頂置1,否則置0 *)
end;
11: (* 11號操作為棧頂兩個數據判大于等于操作 *)
begin
t := t - 1; (* 棧頂指針下移 *)
s[t] := ord(s[t] >= s[t + 1]) (* 判大于等于,如果下面的值大于等于上面的值,棧頂置1,否則置0 *)
end;
12: (* 12號操作為棧頂兩個數據判大于操作 *)
begin
t := t - 1; (* 棧頂指針下移 *)
s[t] := ord(s[t] > s[t + 1]) (* 判大于,如果下面的值大于上面的值,棧頂置1,否則置0 *)
end;
13: (* 13號操作為棧頂兩個數據判小于等于操作 *)
begin
t := t - 1; (* 棧頂指針下移 *)
s[t] := ord(s[t] <= s[t + 1]) (* 判小于等于,如果下面的值小于等于上面的值,棧頂置1,否則置0 *)
end;
14: (* 14號操作為輸出棧頂值操作 *)
begin
write(s[t]); (* 輸出棧頂值 *)
write(fa2, s[t]); (* 同時打印到文件 *)
t := t - 1 (* 棧頂下移 *)
end;
15: (* 15號操作為輸出換行操作 *)
begin
writeln; (* 輸出換行 *)
writeln(fa2) (* 同時輸出到文件 *)
end;
16: (* 16號操作是接受鍵盤值輸入到棧頂 *)
begin
t := t + 1; (* 棧頂上移,分配空間 *)
write('?'); (* 屏顯問號 *)
write(fa2, '?'); (* 同時輸出到文件 *)
readln(s[t]); (* 獲得輸入 *)
writeln(fa2, s[t]); (* 把用戶輸入值打印到文件 *)
end;
end; (* opr指令分析運行結束 *)
lod: (* 如果是lod指令:將變量放到棧頂 *)
begin
t := t + 1; (* 棧頂上移,開辟空間 *)
s[t] := s[base(l) + a] (* 通過數據區層差l和偏移地址a找到變量的數據,存入上面開辟的新空間(即棧頂) *)
end;
sto: (* 如果是sto指令 *)
begin
s[base(l) + a] := s[t]; (* 把棧頂的值存入位置在數據區層差l偏移地址a的變量內存 *)
t := t - 1 (* 棧項下移,釋放空間 *)
end;
cal: (* 如果是cal指令 *)
begin (* generat new block mark *)
s[t + 1] := base(l); (* 在棧頂壓入靜態鏈SL *)
s[t + 2] := b; (* 然后壓入當前數據區基址,作為動態鏈DL *)
s[t + 3] := p; (* 最后壓入當前的斷點,作為返回地址RA *)
(* 以上的工作即為過程調用前的保護現場 *)
b := t + 1; (* 把當前數據區基址指向SL所在位置 *)
p := a; (* 從a所指位置開始繼續執行指令,即實現了程序執行的跳轉 *)
end;
int: (* 如果是int指令 *)
t := t + a; (* 棧頂上移a個空間,即開辟a個新的內存單元 *)
jmp: (* 如果是jmp指令 *)
p := a; (* 把jmp指令操作數a的值作為下一次要執行的指令地址,實現無條件跳轉 *)
jpc: (* 如果是jpc指令 *)
begin
if s[t] = 0 then (* 判斷棧頂值 *)
p := a; (* 如果是0就跳轉,否則不跳轉 *)
t := t - 1 (* 釋放棧頂空間 *)
end;
end(* with,case *)
until p = 0; (* 如果p等于0,意味著在主程序運行時遇到了從子程序返回指令,也就是整個程序運行的結束 *)
close(fa2) (* 關閉用于記錄屏幕輸入輸出的fa2文件 *)
(* PCODE代碼的解釋執行過程結束 *)
end(* interpret *);
begin (* main *)
for ch := ' ' to '!' do (* 這個循環把ssym數組全部填nul *)
ssym[ch] := nul;
(* changed because of different character set
note the typos below in the original where
the alfas were not given the correct space *)
(* 下面初始化保留字表,保留字長度不到10個字符的,多余位置用空格填充,便于詞法分析時以二分法來查找保留字 *)
word[1] := 'begin ';
word[2] := 'call ';
word[3] := 'const ';
word[4] := 'do ';
word[5] := 'end ';
word[6] := 'if ';
word[7] := 'odd ';
word[8] := 'procedure ';
word[9] := 'read ';
word[10] := 'then ';
word[11] := 'var ';
word[12] := 'while ';
word[13] := 'write ';
(* 保留字符號列表,在上面的保留字表中找到保留字后可以本表中相應位置該保留字的類型 *)
wsym[1] := beginsym;
wsym[2] := callsym;
wsym[3] := constsym;
wsym[4] := dosym;
wsym[5] := endsym;
wsym[6] := ifsym;
wsym[7] := oddsym;
wsym[8] := procsym;
wsym[9] := readsym;
wsym[10] := thensym;
wsym[11] := varsym;
wsym[12] := whilesym;
wsym[13] := writesym;
(* 初始化符號表,把可能出現的符號賦上相應的類型,其余符號由于開始處的循環所賦的類型均為nul *)
ssym['+'] := plus;
ssym['-'] := minus;
ssym['*'] := times;
ssym['/'] := slash;
ssym['('] := lparen;
ssym[')'] := rparen;
ssym['='] := eql;
ssym[','] := comma;
ssym['.'] := period;
ssym['#'] := neq;
ssym[';'] := semicolon;
(* 初始化類PCODE助記符表,這個表主要供輸出類PCODE代碼之用 *)
mnemonic[lit] := ' lit ';
mnemonic[opr] := ' opr ';
mnemonic[lod] := ' lod ';
mnemonic[sto] := ' sto ';
mnemonic[cal] := ' cal ';
mnemonic[int] := ' int ';
mnemonic[jmp] := ' jmp ';
mnemonic[jpc] := ' jpc ';
(* 我修改的代碼:書上此處均為'xxx '形式,即助記符后兩個空格,通過上網查詢原版程序確認為助詞符前后各一空格。 *)
(* 這樣改的目的是使后面的輸出結果比較美觀 *)
declbegsys := [constsym, varsym, procsym];
statbegsys := [beginsym, callsym, ifsym, whilesym];
facbegsys := [ident, number, lparen];
(* page(output) *)
(* 由于Turbo Pascal 7.0的文本文件處理方法與源程序中使用的方法有很大不同,因此下面的有關文件處理的代碼進行了不少更改。 *)
assign(fa1, 'fa1.txt'); (* 把文本文件fa1與fa1.txt文件關聯起來,用于輸出生成的類PCODE代碼 *)
rewrite(fa1); (* 建立并打開fa1.txt文件 *)
write('input file? '); (* 提示輸入PL/0源程序名 *)
write(fa1, 'input file? '); (* 同樣的提示輸出到fa1.txt文件 *)
readln(fname); (* 獲得鍵盤輸入的文件名 *)
writeln(fa1, fname); (* 把鍵盤輸入打印到fa1.txt文件 *)
{ openf(fin,fname,'r'); }
assign(fin, fname); (* 把PL/0的源程序文件與fin關聯 *)
reset(fin); (* 打開fin所關聯的PL/0源程序文件 *)
write('list object code ?'); (* 提示是否要列出類PCODE代碼 *)
readln(fname); (* 獲得用戶輸入 *)
write(fa1, 'list object code ?'); (* 同樣的提示寫到fa1.txt文件中 *)
listswitch := (fname[1] = 'y'); (* 如果輸入'y'開頭的字符串,把listswitch標志置true,否則為false *)
err := 0; (* 出錯次數置0 *)
cc := 0; (* 詞法分析行緩沖區指針置0 *)
cx := 0; (* 類PCODE代碼表指針置0 *)
ll := 0; (* 詞法分析行緩沖區長度置0 *)
ch := ' '; (* 詞法分析當前字符為空格 *)
kk :=
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -