?? pl-0語言編譯程序分析.htm
字號:
(* 參數說明:fsys: 如果出錯可用來恢復語法分析的符號集合 *)
procedure factor(fsys: symset);
var
i: integer;
begin
test(facbegsys, fsys, 24); (* 開始因子處理前,先檢查當前token是否在facbegsys集合中。 *)
(* 如果不是合法的token,拋24號錯誤,并通過fsys集恢復使語法處理可以繼續進行 *)
while sym in facbegsys do (* 循環處理因子 *)
begin
if sym = ident then (* 如果遇到的是標識符 *)
begin
i := position(id); (* 查符號表,找到當前標識符在符號表中的位置 *)
if i = 0 then (* 如果查符號表返回為0,表示沒有找到標識符 *)
error(11) (* 拋出11號錯誤 *)
else
with table[i] do (* 如果在符號表中找到了當前標識符的位置,開始生成相應代碼 *)
case kind of
constant: gen(lit, 0, val); (* 如果這個標識符對應的是常量,值為val,生成lit指令,把val放到棧頂 *)
variable: gen(lod, lev - level, adr); (* 如果標識符是變量名,生成lod指令, *)
(* 把位于距離當前層level的層的偏移地址為adr的變量放到棧頂 *)
procedur: error(21) (* 如果在因子處理中遇到的標識符是過程名,出錯了,拋21號錯 *)
end;
getsym (* 獲取下一token,繼續循環處理 *)
end
else
if sym = number then (* 如果因子處理時遇到數字 *)
begin
if num > amax then (* 如果數字的大小超過允許最大值amax *)
begin
error(31); (* 拋出31號錯 *)
num := 0 (* 把數字按0值處理 *)
end;
gen(lit, 0, num); (* 生成lit指令,把這個數值字面常量放到棧頂 *)
getsym (* 獲取下一token *)
end
else
if sym = lparen then (* 如果遇到的是左括號 *)
begin
getsym; (* 獲取一個token *)
expression( [rparen] + fsys ); (* 遞歸調用expression子程序分析一個子表達式 *)
if sym = rparen then (* 子表達式分析完后,應遇到右括號 *)
getsym (* 如果的確遇到右括號,讀取下一個token *)
else
error(22) (* 否則拋出22號錯誤 *)
end;
test(fsys, facbegsys, 23) (* 一個因子處理完畢,遇到的token應在fsys集合中 *)
(* 如果不是,拋23號錯,并找到下一個因子的開始,使語法分析可以繼續運行下去 *)
end
end(* factor *);
begin (* term *)
factor([times, slash] + fsys); (* 每一個項都應該由因子開始,因此調用factor子程序分析因子 *)
while sym in [times, slash] do (* 一個因子后應當遇到乘號或除號 *)
begin
mulop := sym; (* 保存當前運算符 *)
getsym; (* 獲取下一個token *)
factor(fsys + [times, slash]); (* 運算符后應是一個因子,故調factor子程序分析因子 *)
if mulop = times then (* 如果剛才遇到乘號 *)
gen(opr, 0, 4) (* 生成乘法指令 *)
else
gen(opr, 0, 5) (* 不是乘號一定是除號,生成除法指令 *)
end
end (* term *);
begin (* expression *)
if sym in [plus, minus] then (* 一個表達式可能會由加號或減號開始,表示正負號 *)
begin
addop := sym; (* 把當前的正號或負號保存起來,以便下面生成相應代碼 *)
getsym; (* 獲取一個token *)
term(fsys + [plus, minus]); (* 正負號后面應該是一個項,調term子程序分析 *)
if addop = minus then (* 如果保存下來的符號是負號 *)
gen(opr, 0, 1) (* 生成一條1號操作指令:取反運算 *)
(* 如果不是負號就是正號,不需生成相應的指令 *)
end
else (* 如果不是由正負號開頭,就應是一個項開頭 *)
term(fsys + [plus, minus]); (* 調用term子程序分析項 *)
while sym in [plus, minus] do (* 項后應是加運算或減運算 *)
begin
addop := sym; (* 把運算符保存下來 *)
getsym; (* 獲取下一個token,加減運算符后應跟的是一個項 *)
term(fsys + [plus, minus]); (* 調term子程序分析項 *)
if addop = plus then (* 如果項與項之間的運算符是加號 *)
gen(opr, 0, 2) (* 生成2號操作指令:加法 *)
else (* 否則是減法 *)
gen(opr, 0, 3) (* 生成3號操作指令:減法 *)
end
end (* expression *);
(* 條件處理過程condition *)
(* 參數說明:fsys: 如果出錯可用來恢復語法分析的符號集合 *)
procedure condition(fsys: symset);
var
relop: symbol; (* 用于臨時記錄token(這里一定是一個二元邏輯運算符)的內容 *)
begin
if sym = oddsym then (* 如果是odd運算符(一元) *)
begin
getsym; (* 獲取下一個token *)
expression(fsys); (* 對odd的表達式進行處理計算 *)
gen(opr, 0, 6); (* 生成6號操作指令:奇偶判斷運算 *)
end
else (* 如果不是odd運算符(那就一定是二元邏輯運算符) *)
begin
expression([eql, neq, lss, leq, gtr, geq] + fsys); (* 對表達式左部進行處理計算 *)
if not (sym in [eql, neq, lss, leq, gtr, geq]) then (* 如果token不是邏輯運算符中的一個 *)
error(20) (* 拋出20號錯誤 *)
else
begin
relop := sym; (* 記錄下當前的邏輯運算符 *)
getsym; (* 獲取下一個token *)
expression(fsys); (* 對表達式右部進行處理計算 *)
case relop of (* 如果剛才的運算符是下面的一種 *)
eql: gen(opr, 0, 8); (* 等號:產生8號判等指令 *)
neq: gen(opr, 0, 9); (* 不等號:產生9號判不等指令 *)
lss: gen(opr, 0, 10); (* 小于號:產生10號判小指令 *)
geq: gen(opr, 0, 11); (* 大于等號號:產生11號判不小于指令 *)
gtr: gen(opr, 0, 12); (* 大于號:產生12號判大于指令 *)
leq: gen(opr, 0, 13); (* 小于等于號:產生13號判不大于指令 *)
end
end
end
end (* condition *);
begin (* statement *)
if sym = ident then (* 所謂"語句"可能是賦值語句,以標識符開頭 *)
begin
i := position(id); (* 在符號表中查到該標識符所在位置 *)
if i = 0 then (* 如果沒找到 *)
error(11) (* 拋出11號錯誤 *)
else
if table[i].kind <> variable then (* 如果在符號表中找到該標識符,但該標識符不是變量名 *)
begin
error(12); (* 拋出12號錯誤 *)
i := 0 (* i置0作為錯誤標志 *)
end;
getsym; (* 獲得下一個token,正常應為賦值號 *)
if sym = becomes then (* 如果的確為賦值號 *)
getsym (* 獲取下一個token,正常應為一個表達式 *)
else
error(13); (* 如果賦值語句的左部標識符號后所接不是賦值號,拋出13號錯誤 *)
expression(fsys); (* 處理表達式 *)
if i <> 0 then (* 如果不曾出錯,i將不為0,i所指為當前語名左部標識符在符號表中的位置 *)
with table[i] do
gen(sto, lev - level, adr) (* 產生一行把表達式值寫往指定內存的sto目標代碼 *)
end
else
if sym = readsym then (* 如果不是賦值語句,而是遇到了read語句 *)
begin
getsym; (* 獲得下一token,正常情況下應為左括號 *)
if sym <> lparen then (* 如果read語句后跟的不是左括號 *)
error(34) (* 拋出34號錯誤 *)
else
repeat (* 循環得到read語句括號中的參數表,依次產生相應的“從鍵盤讀入”目標代碼 *)
getsym; (* 獲得一個token,正常應是一個變量名 *)
if sym = ident then (* 如果確為一個標識符 *)
(* 這里略有問題,還應判斷一下這個標識符是不是變量名,如果是常量名或過程名應出錯 *)
i := position(id) (* 查符號表,找到它所在位置給i,找不到時i會為0 *)
else
i := 0; (* 不是標識符則有問題,i置0作為出錯標志 *)
if i = 0 then (* 如果有錯誤 *)
error(35) (* 拋出35號錯誤 *)
else (* 否則生成相應的目標代碼 *)
with table[i] do
begin
gen(opr, 0, 16); (* 生成16號操作指令:從鍵盤讀入數字 *)
gen(sto, lev - level, adr) (* 生成sto指令,把讀入的值存入指定變量所在的空間 *)
end;
getsym (* 獲取下一個token,如果是逗號,則read語還沒完,否則應當是右括號 *)
until sym <> comma; (* 不斷生成代碼直到read語句的參數表中的變量遍歷完為止,這里遇到不是逗號,應為右括號 *)
if sym <> rparen then (* 如果不是我們預想中的右括號 *)
begin
error(33); (* 拋出33號錯誤 *)
while not (sym in fsys) do (* 依靠fsys集,找到下一個合法的token,恢復語法分析 *)
getsym
end
else
getsym (* 如果read語句正常結束,得到下一個token,一般為分號或end *)
end
else
if sym = writesym then (* 如果遇到了write語句 *)
begin
getsym; (* 獲取下一token,應為左括號 *)
if sym = lparen then (* 如確為左括號 *)
begin
repeat (* 依次獲取括號中的每一個值,進行輸出 *)
getsym; (* 獲得一個token,這里應是一個標識符 *)
expression([rparen, comma] + fsys); (* 調用expression過程分析
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -