pl0(pascal version)编译器

pl0(pascal version)编译器
pl0(pascal version)编译器

program pl0(input,output);

{pl/0 compiler with code generation} label 99;

const norw = 11; {no. of reserved words} {保留字个数} txmax = 100; {length of identifier table} { 标识符变长度}

nmax = 14; {max. no. of digits in numbers}{ }

al = 10; {length of identifiers} {标识符的长度。。。。为10} amax = 2047; {maximum address} {最大地址}

levmax = 3; {maximum depth of block nesting} {}

cxmax = 200; {size of code array} {代码数组长度}

type symbol =

(nul,ident,number,plus,minus,times,slash,oddsym,

{等号,标识符,数字, + , - ,* , / ,wsym[ 7] := oddsym } eql,neq,lss,leq,gtr,geq,lparen,rparen,comma,semicolon,

{=,#,<, [ , >, ], ( , ) , ‘ , ’, ; }

period,becomes,beginsym,endsym,ifsym,thensym,

{‘ . ’, 赋值,开始,结束,if , then } {不确定}

whilesym,dosym,callsym,constsym,varsym,procsym);

{while , do , call , const, var , procedure} {不确定}

alfa = packed array [1..al] of char;{字符数组,存放关键字}

object1 = (constant,varible,proc);{判断标识符是常量、变量还是过程?}

symset = set of symbol;

fct = (lit,opr,lod,sto,cal,int,jmp,jpc); {functions目标代码的功能码,具体如下:}

instruction = packed record {指令记录目标代码结构}

f: fct; {function code} {}

l: 0..levmax; {level层数}

a: 0..amax {displacement address}

end;

{ lit 0,a : load constant a

opr 0,a : execute operation a

lod l,a : load varible l,a

sto l,a : store varible l,a

cal l,a : call procedure a at level l

int 0,a : increment t-register by a

jmp 0,a : jump to a

jpc 0,a : jump conditional to a }

var ch: char; {last character read 当前字符}

sym: symbol; {last symbol read 当前读入的符号}

id: alfa; {last identifier read 当前标识符}

num: integer; {last number read} {当前数字}

cc: integer; {character count} {当前读入字符数目}

ll: integer; {line length} {当前行数}

kk, err: integer;

cx: integer; {code allocation index} {??????}

line: array [1..81] of char; {当前读入的一行}

a: alfa;

code: array [0..cxmax] of instruction; {存放生成的目标代码}

word: array [1..norw] of alfa; {存放的关键字数组}

wsym: array [1..norw] of symbol; {标识符字符集}

ssym: array [char] of symbol; {符号语义字符集识别符号类似token.seman} mnemonic: array [fct] of

packed array [1..5] of char; {功能码字符数组} declbegsys, statbegsys, facbegsys: symset;

table: array [0..txmax] of { 符号表???}

record name: alfa;

case kind: object1 of

constant: (val: integer);

varible, proc: (level, adr: integer)

end;

fin:text; {存放源文件。。。}

sfile:string;

{----------------------------------------------------------------------------------------------------} procedure error(n: integer); {给出错误提示}

begin writeln(' ****',' ': cc-1, '^',n: 2); err := err+1 {给出错误位置数目+1}

end {error};

{----------------------------------------------------------------------------------------------------} procedure getsym;

var i,j,k: integer;

procedure getch;

begin if cc = ll then {到达行尾}

begin if eof(fin) then {文件结束?}

begin write(' program incomplete'); {goto 99} {文件空,结束。}

close(fin);

exit;

end;

{文件没有结束时:}

ll := 0; cc := 0; write(cx: 5,' '); {行长度和字符个数清零,输出行数:}

while not eoln(fin) do {有回车(换行)时结束循环}

begin

ll := ll+1; read(fin,ch); write(ch); line[ll]:=ch

{此一行长度加1,读一个字符,回显,置于数组中}

end;

writeln; { 读入回车时,换行。。。。。。。。。。。。。。}

readln(fin); {。。。。。。。。}

ll := ll + 1; line[ll] := ' '; {}

end;

cc := cc+1; ch := line[cc] {读入一个字符}

end {getch};

begin {getsym} { getsys.....。。。。。} while ch = ' ' do getch; {空格过滤}

if ch in ['a'..'z'] then

begin {identifier or reserved word} k := 0; {标识符或者保留字} repeat if k < al then {读入一个完整的标识符或者保留字} begin k := k+1; a[k] := ch

end;

getch;

until not(ch in ['a'..'z','0'..'9']);

if k >= kk then kk := k else {如果关键字的个数不足十,补空格} repeat a[kk] := ' '; kk := kk-1

until kk = k;

id := a; i := 1; j := norw; {norw=11-}

repeat k := (i+j) div 2; {查找是否为保留字。。。。。。。。} if id <= word[k] then j := k-1;

if id >= word[k] then i := k+1

until i > j;

if i-1 > j then sym := wsym[k] else sym := ident {是标识符,将内部表示赋给sys…….否则,将”ident”赋给sys}

end else

if ch in ['0'..'9'] then {如果读入的是数字}

begin {number} k := 0; num := 0; sym := number;

repeat num := 10*num + (ord(ch)-ord('0')); {拼数。。。。。}

k := k+1; getch

until not(ch in ['0'..'9']);

if k > nmax then error(30) {数值超出范围,错误} end else

if ch = ':' then

begin getch; {判断是否为赋值语句。。。。。。} if ch = '=' then

begin sym := becomes; getch {赋值语句。。。}

end else sym := nul; {非赋值语句,认为等号。。???} end else

begin sym := ssym[ch]; getch {其它符号。。。取seman赋给sys}

end

end {getsym};

{----------------------------------------------------------------------------------------------------} procedure gen(x: fct; y,z: integer);{生成目标代码。。。。。

目标代码功能码、层次、偏移量}

begin if cx > cxmax then

begin write(' program too long'); {goto 99} {程序太长,结束}

end;

with code[cx] do

begin f := x; l := y; a := z

end;

cx := cx + 1

end {gen};

{----------------------------------------------------------------------------------------------------} procedure test(s1,s2: symset; n: integer);{????????????}

begin if not(sym in s1) then

begin error(n); s1 := s1 + s2;

while not(sym in s1) do getsym

end

end {test};

{----------------------------------------------------------------------------------------------------} procedure block(lev,tx: integer; fsys: symset);

{层次,table中位置,出错处理}

var dx: integer; {data allocation index局部量位置指示}

tx0: integer; {initial table index}

cx0: integer; {initial code index}

procedure enter(k: object1); {参数为变量、常量或者过程}

begin {enter object into table登记到符号表中。。。。}

tx := tx + 1; {符号表序号+1}

with table[tx] do

begin name := id; kind := k;{table[tx].name:=id登记名字,

table[tx].king:=k登记类型}

case k of {根据类型做处理。。。如下:}

{是常量。。。。。}

constant: begin if num > amax then{判断数值越界?}

begin error(30); num :=0 end;

val := num{不越界则赋值给val}

end;

{是变量。。。。}

varible: begin level := lev; adr := dx; dx := dx + 1;

{层数,偏移量存入,偏移量+1}

end;

{是过程。。。。}

proc: level := lev {保存层数}

end

end

end {enter};

{……………………………………………………}

function position(id: alfa): integer;{查找标识符在符号表中位置函数} var i: integer;

begin {find indentifier id in table}

table[0].name := id; i := tx; {tx为符号表标号最大值}

while table[i].name <> id do i := i-1; {从高到低查找}

position := i

end {position};

{----------------------------------------------------------------------------------------------------} procedure constdeclaration; {常量处理部分}

begin if sym = ident then {是标识符?否,出错}

begin getsym; {继续读}

if sym in [eql, becomes] then {是=或者:=?否,出错}

begin if sym = becomes then error(1);{是:=,错误1}

getsym; {读后面数字}

if sym = number then {是数字?否,出错。}

begin enter(constant); getsym

{填写符号表,继续读…}

end

else error(2)

end else error(3)

end else error(4)

end {constdeclaration};

{----------------------------------------------------------------------------------------------------} procedure vardeclaration; {变量处理….}

begin if sym = ident then {是标识符?否,出错}

begin enter(varible); getsym {填写符号表,继续读…}

end else error(4)

end {vardeclaration};

{----------------------------------------------------------------------------------------------------} procedure listcode; {显示中间代码}

var i: integer; {存放中间代码序号}

begin {list code generated for this block列出程序块中间代码}

for i := cx0 to cx-1 do

with code[i] do

writeln(i:5, mnemonic[f]:5, 1:3, a:5){输出序号,功能码} end {listcode};

{------------{表达式、项、因子语法分析,并生成相应的中间代码}

------------------------------------------------------------------------} procedure statement(fsys: symset);{参数为标识符,符号,整数}

var i, cx1, cx2: integer;

procedure expression(fsys: symset);

var addop: symbol; {定义标识符型变量}

procedure term(fsys: symset);

var mulop: symbol; {定义标识符型变量} {………………………………………………………………………..因子语法分析} procedure factor(fsys: symset);

var i: integer;

begin test(facbegsys, fsys, 24);

{判断因子起始符是否为标识符、符号、左括号?否,出错}

while sym in facbegsys do

begin

if sym = ident then {是标识符}

begin i:= position(id); {查找标识符表,没有,出错}

if i = 0 then error(11) else

with table[i] do {查到}

case kind of {根据类型生成中间代码}

constant: gen(lit, 0, val);

varible: gen(lod, lev-level, adr);

proc: error(21) {是过程,报错21}

end;

getsym

end

else

if sym = number then{是数字}

begin if num > amax then

begin error(30); num := 0

end;

gen(lit, 0, num); getsym

end else

if sym = lparen then {是左括号}

begin getsym; expression([rparen]+fsys);

if sym = rparen then getsym else error(22)

end;

test(fsys, [lparen], 23)

end

end {factor};

{…………………..………………………………………项的语法分析。。。}

begin {term} factor(fsys+[times, slash]);{调用因子语法分析}

while sym in [times, slash] do {读到的是*或者/}

{保存运算符;} {继续读;}{调用因子语法分析;}

begin mulop:=sym;getsym;factor(fsys+[times,slash]);

{生成中间代码}

if mulop=times then gen(opr,0,4) else gen(opr,0,5)

end

end {term}; {……………………………………………………………表达式的语法分析} begin {expression}

if sym in [plus, minus] then{如果读到+或者-}

{保存符号;}{继续读;}{}

begin addop := sym; getsym; term(fsys+[plus,minus]);

if addop = minus then gen(opr, 0,1)

end else term(fsys+[plus, minus]);{??????}

while sym in [plus, minus] do

begin addop := sym; getsym; term(fsys+[plus,minus]);

{生成中间代码}

if addop=plus then gen(opr,0,2) else gen(opr,0,3)

end

end {expression};

{----------------------------------------------------------------------------------------------------} procedure condition(fsys: symset); {条件语法检查,生成中间代码} var relop: symbol;

begin

if sym = oddsym then{是奇数关键字odd}

{继续读;}{表达式语法分析;}{中间代码生成}

begin getsym; expression(fsys); gen(opr, 0, 6)

end else{非奇数关键字……………………………………….}

begin expression([eql, neq, lss, gtr, leq, geq]+fsys);

if not(sym in [eql, neq, lss, leq, gtr, geq]) then

error(20) else

begin relop := sym; getsym; expression(fsys);

{保存符号到relop,继续表达式语法检查}

case relop of

eql: gen(opr, 0, 8);

neq: gen(opr, 0, 9);

lss: gen(opr, 0, 10);

geq: gen(opr, 0, 11);

gtr: gen(opr, 0, 12);

leq: gen(opr, 0, 13);

end

end

end

end {condition};

{。。。。。。。。。。。。。。。。。。。。。。语句的语法分析,生成中间代码。。。。。。。。。。。。。。。。。。} begin {statement}

if sym = ident then {是标识符}

begin i := position(id); {查找位置}

if i = 0 then error(11) else {未定义错误}

if table[i].kind <> varible then{不是变量,错误12}

begin {assignment to non-varible} error(12); i := 0

end;

getsym; {继续读}

if sym = becomes then getsym else error(13);{是:=继续读,否,错误13}

expression(fsys); {表达式语法分析}

if i <> 0 then {如果在表中}

with table[i] do gen(sto, lev-level, adr){}

end else

{…………………………………………..对call语句的语法分析}

if sym = callsym then

begin getsym;{继续读}

if sym <> ident then error(14) else {是标识符?否,错误14}

begin i := position(id); {查找位置,没有错误11}

if i = 0 then error(11) else

with table[i] do

{是过程,生成中间代码;否,错误15}

if kind=proc then gen(cal, lev-level, adr)

else error(15);

getsym {继续读}

end

end else

{…………………………………………..if的语法分析}

if sym = ifsym then

{继续读;}{条件语法分析;}

begin getsym; condition([thensym, dosym]+fsys);

if sym = thensym then getsym else error(16);{是then?否,错误16}

cx1 := cx; gen(jpc, 0, 0); {目标代码序号赋给cx1}

statement(fsys); code[cx1].a := cx

end else

{…………………………………………………………begin语法分析} if sym = beginsym then {………………………………………………..调用语句语法分析程序} begin getsym; statement([semicolon, endsym]+fsys);

while sym in [semicolon]+statbegsys do{????????}

begin

if sym = semicolon then getsym else error(10);

statement([semicolon, endsym]+fsys)

end;

if sym = endsym then getsym else error(17){…..end结束?否,错误17} end else {。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。对while语法分析。。。。。。。} if sym = whilesym then

{。。。。。。继续读;条件语法分析。。。。。。。}

begin cx1 := cx; getsym; condition([dosym]+fsys);

cx2 := cx; gen(jpc, 0, 0);

if sym = dosym then getsym else error(18);

statement(fsys); gen(jmp, 0, cx1); code[cx2].a := cx

end;

test(fsys, [], 19)

end {statement};

{------------------------------------------block程序块开始-------------------------------} begin {。。。。。。。。。。block。。。。。。。。}

dx:=3;

tx0:=tx; {表头索引值。。。}

table[tx].adr:=cx; {目标代码索引。。。}

gen(jmp,0,0);

if lev > levmax then error(32); {如果超过最大深度,报错32}

repeat{。。。。。。。。常量定义语法分析。。。。。。。。。。。。。。。}

if sym = constsym then {。。。为常量}

begin getsym; {继续读。。。。}

repeat constdeclaration; {调用常量声明处理。。判断….}

while sym = comma do {读到,……}

begin getsym; constdeclaration {继续读,继续处理。。。}

end;

if sym = semicolon then getsym else error(5){读到分号,继续读下一个}

until sym <> ident{非标识符…结束循环管}

end;

{……………………………..对变量语法处理}

{a::=var <标识符>{,<标识符>}}

if sym = varsym then

begin getsym; {….读下一个}

repeat vardeclaration; {变量声明处理}

while sym = comma do {读到,}

begin getsym; vardeclaration {读下一个;变量声明处理}

end;

if sym = semicolon then getsym else error(5)

{结尾是;?否,错误5}

until sym <> ident;

end;

{。。。。。。。。。。。。对过程的语法处理}

while sym = procsym do

begin getsym; {………………………..继续读}

if sym = ident then {标识符?否,错误4…..}

begin enter(proc); getsym {查表,是否已经定义。。。}

end

else error(4);

if sym = semicolon then getsym else error(5);{是分号?否,出错} {是,继续读}

block(lev+1, tx, [semicolon]+fsys); {递归调用,,层次+1}

if sym = semicolon then {是分号?否,错误5}

{是,继续读。。。。。。}

begin getsym;test(statbegsys+[ident,procsym],fsys,6)

end

else error(5)

end;

test(statbegsys+[ident], declbegsys, 7)

until not(sym in declbegsys);

code[table[tx0].adr].a := cx;

with table[tx0] do

begin adr := cx; {start adr of code}

end;

cx0 := 0{cx}; gen(int, 0, dx);

statement([semicolon, endsym]+fsys);

gen(opr, 0, 0); {return}

test(fsys, [], 8);

listcode;

end {block};

{----------------------------------------------------------------------------------------------------} {解释执行程序。。。。}

procedure interpret;

const stacksize = 500; {堆大小}

var p,b,t: integer; {program-, base-, topstack-registers}

i: instruction; {instruction register}

s: array [1..stacksize] of integer; {datastore}

function base(l: integer): integer;

var b1: integer;

begin b1 := b; {find base l levels down}

while l > 0 do

begin b1 := s[b1]; l := l - 1

end;

base := b1

end {base};

begin writeln(' start pl/0');

t := 0; b := 1; p := 0; {栈顶,栈底,目标代码序号}

s[1] := 0; s[2] := 0; s[3] := 0;

repeat i := code[p]; p := p + 1;

with i do

case f of

lit: begin t := t + 1; s[t] := a {栈顶指针+1,常量值a放到栈顶。。。} end;

opr: case a of {operator}

0: begin {return}

t := b - 1; p := s[t + 3]; b := s[t + 2];

end;

1: s[t] := -s[t]; {栈顶元素取反。。}

2: begin t := t - 1; s[t] := s[t] + s[t + 1] {次栈顶和栈顶元素相加。。。} end;

3: begin t := t - 1; s[t] := s[t] - s[t + 1]

end;

4: begin t := t - 1; s[t] := s[t] * s[t + 1]

end;

5: begin t := t - 1; s[t] := s[t] div s[t + 1]

end;

6: s[t] := ord(odd(s[t]));{栈顶元素奇偶判断,结果值在栈顶}

8: begin t := t - 1; s[t] := ord(s[t] = s[t + 1]){次栈顶与栈顶是否相等} end;

9: begin t := t - 1; s[t] := ord(s[t] <> s[t + 1]) {次栈顶与栈顶是否不相等}

end;

10: begin t := t - 1; s[t] := ord(s[t] < s[t + 1]){次栈顶是否小于栈顶}

end;

11: begin t := t - 1; s[t] := ord(s[t] >= s[t + 1])

end;

12: begin t := t - 1; s[t] := ord(s[t] > s[t + 1])

end;

13: begin t := t - 1; s[t] := ord(s[t] <= s[t + 1])

end;

end;

lod: begin t := t + 1; s[t] := s[base(l) + a]{栈顶指针+1,将变量a取到栈顶} end;

sto: begin s[base(l)+a] := s[t]; writeln(s[t]); t := t – 1{将栈顶内容送到某变量单元中。。。}

end;

cal: begin {generate new block mark}

s[t + 1] := base(l); s[t + 2] := b; s[t + 3] := p;

b := t + 1; p := a

end;

int: t := t + a;{栈顶指针移动a个单元,开辟a大小的空间}

jmp: p := a; {跳到目标代码为序号a的地方}

jpc: begin if s[t] = 0 then p := a; t := t – 1{如果栈顶为0,跳转到a,否则顺序执行。。}

end

end {with, case}

until p = 0;

write(' end pl/0');

end {interpret};

{----------------------------------------------------------------------------------------------------} begin {main program} {主程序}

writeln('please input source program file name:');

readln(sfile);

assign(fin,sfile);

reset(fin);

for ch := chr(0) to chr(255) do ssym[ch] := nul; {初始化为空。。。。。。。。。}

{。。。。。。。。。。。。。。。。。。。。。。。。11个关键字的内部表示…………………………..} 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] := 'then '; word[10] := 'var ';

word[11] := 'while ';

{…………………………token 初始化…………………………………………..} 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] := thensym; wsym[10] := varsym;

wsym[11] := whilesym;

{…………………………….符号的token……………………………………} ssym[ '+'] := plus; ssym[ '-'] := minus;

ssym[ '*'] := times; ssym[ '/'] := slash;

ssym[ '('] := lparen; ssym[ ')'] := rparen;

ssym[ '='] := eql; ssym[ ','] := comma;

ssym[ '.'] := period; ssym[ '#'] := neq;

ssym[ '<'] := lss; ssym[ '>'] := gtr;

ssym[ '['] := leq; ssym[ ']'] := geq;

ssym[ ';'] := semicolon; {……………………………..?????????????…………………} mnemonic[lit] := ' lit'; mnemonic[opr] := ' opr';

mnemonic[lod] := ' lod'; mnemonic[sto] := ' sto';

mnemonic[cal] := ' cal'; mnemonic[int] := ' int';

mnemonic[jmp] := ' jmp'; mnemonic[jpc] := ' jpc';

declbegsys := [constsym, varsym, procsym];

statbegsys := [beginsym, callsym, ifsym, whilesym];

facbegsys := [ident, number, lparen];

{page(output);}

err := 0;

cc := 0; {初始化读入字符数0}

cx := 0;

ll := 0; {初始化读入行数0}

ch := ' '; {字符变量}

kk := al; {初始化kk(关键字)长度al:=10 }

getsym; {调用词法分析}

block(0, 0, [period]+declbegsys+statbegsys);{ 。。。。。。调用?????} if sym <> period then error(9); { 错误提示。。。。。。。} if err=0 then interpret else write(' errors in pl/0 program');

{没有错误,解释。。。。}

99: writeln

end.

编译原理(PL0编译程序源代码)

/*PL/0编译程序(C语言版) *编译和运行环境: *Visual C++6.0 *WinXP/7 *使用方法: *运行后输入PL/0源程序文件名 *回答是否将虚拟机代码写入文件 *回答是否将符号表写入文件 *执行成功会产生四个文件(词法分析结果.txt符号表.txt虚拟代码.txt源程序和地址.txt) */ #include #include"pl0.h" #include"string" #define stacksize 500//解释执行时使用的栈 int main(){ bool nxtlev[symnum]; printf("请输入源程序文件名:"); scanf("%s",fname); fin=fopen(fname,"r");//以只读方式打开pl0源程序文件 cifa=fopen("词法分析结果.txt","w"); fa1=fopen("源程序和地址.txt","w");//输出源文件及各行对应的首地址 fprintf(fa1,"输入pl0源程序文件名:"); fprintf(fa1,"%s\n",fname); if(fin){ printf("是否将虚拟机代码写入文件?(Y/N)");//是否输出虚拟机代码 scanf("%s",fname); listswitch=(fname[0]=='y'||fname[0]=='Y'); printf("是否将符号表写入文件?(Y/N)");//是否输出符号表scanf("%s",fname); tableswitch=(fname[0]=='y'||fname[0]=='Y'); init();//初始化 err=0; cc=cx=ll=0; ch=' '; if(-1!=getsym()){ fa=fopen("虚拟代码.txt","w"); fas=fopen("符号表.txt","w"); addset(nxtlev,declbegsys,statbegsys,symnum); nxtlev[period]=true; if(-1==block(0,0,nxtlev)){//调用编译程序 fclose(fa); fclose(fa1); fclose(fas); fclose(fin); return 0; } if(sym!=period){ error(9);//结尾丢失了句号 }

编译原理实验报告

院系:计算机科学学院 专业、年级: 07计科2大班 课程名称:编译原理 学号姓名: 指导教师: 2010 年11月17 日 组员学号姓名

实验 名称 实验一:词法分析实验室9205 实验目的或要求 通过设计一个具体的词法分析程序,加深对词法分析原理的理解。并掌握在对程序设计语言源程序进行扫描过程中将其分解为各类单词的词法分析方法。 编制一个读单词过程,从输入的源程序中,识别出各个具有独立意义的单词,即基本保留字、标识符、常数、运算符、分隔符五大类。并依次输出各个单词的内部编码及单词符号自身值。 具体要求:输入为某语言源代码,达到以下功能: 程序输入/输出示例:如源程序为C语言。输入如下一段: main() { int a,b; a=10; b=a+20; } 要求输出如下(并以文件形式输出或以界面的形式输出以下结果)。 (2,”main”) (5,”(“) (5,”)“) (5,”{“} (1,”int”) (2,”a”) (5,”,”) (2,”b”) (5,”;”) (2,”a”) (4,”=”) (3,”10”) (5,”;”) (2,”b”) (4,”=”) (2,”a”) (4,”+”) (3,”20”) (5,”;”) (5,”}“) 要求: 识别保留字:if、int、for、while、do、return、break、continue等等,单词种别码为1。 其他的标识符,单词种别码为2。常数为无符号数,单词种别码为3。 运算符包括:+、-、*、/、=、>、<等;可以考虑更复杂情况>=、<=、!= ;单词种别码为4。分隔符包括:“,”“;”“(”“)”“{”“}”等等,单词种别码为5。

编译原理实验报告一

实验一词法分析程序实现 一、实验目得与要求 通过编写与调试一个词法分析程序,掌握在对程序设计语言得源程序进行扫描得过程中,将字符流形式得源程序转化为一个由各类单词符号组成得流得词法分析方法 二、实验内容 基本实验题目:若某一程序设计语言中得单词包括五个关键字begin、end、if、then、else;标识符;无符号常数;六种关系运算符;一个赋值符与四个算术运算符,试构造能识别这些单词得词法分析程序(各类单词得分类码参见表I)。 表I语言中得各类单词符号及其分类码表 输入:由符合与不符合所规定得单词类别结构得各类单词组成得源程序文件。 输出:把所识别出得每一单词均按形如(CLASS,VALUE)得二元式形式输出,并将结果放到某个文件中。对于标识符与无符号常数,CLASS字段为相应得类别码得助记符;V AL UE字段则就是该标识符、常数得具体值;对于关键字与运算符,采用一词一类得编码形式,仅需在二元式得CLASS字段上放置相应单词得类别码得助记符,V ALUE字段则为“空". 三、实现方法与环境 词法分析就是编译程序得第一个处理阶段,可以通过两种途径来构造词法分析程序.其一就是根据对语言中各类单词得某种描述或定义(如BNF),用手工得方式(例如可用C语言)构造词法分析程序。一般地,可以根据文法或状态转换图构造相应得状态矩阵,该状态矩阵连同控制程序一起便组成了编译器得词法分析程序;也可以根据文法或状态转换图直接编写词法分析程序。构造词法分析程序得另外一种途径就是所谓得词法分析程序得自动生成,即首先用正规式对语言中得各类单词符号进行词型描述,并分别指出在识别单词时,词法分析程

编译原理pL0实验报告

一.课程设计要求 基本内容: (1)扩充赋值运算:*= 和/= (2)扩充语句(Pascal的FOR语句): ①FOR <变量>:=<表达式> TO <表达式> DO <语句> ②FOR <变量>:=<表达式> DOWNTO <表达式> DO <语句> 其中,语句①的循环变量的步长为2, 语句②的循环变量的步长为-2。 二.设计思路 在课内实验的基础上,额外增加*=和/=运算符和关键字的语义动作,以下是设计思路: 1. 扩充单词 在头文件pl0.h中的enum symbol中增加关键字forsym, tosym, downtosym, timeseqlsym,slasheqlsym,并修改关键字数#define symnum 46。 /*初始化*/ // ssym['*=']=timeseql; // ssym['/=']=slasheql; /*设置保留字名字,按照字母顺序,便于折半查找*/ strcpy(&(word[14][0]),"to"); /*增加后需要按序排列*/ strcpy(&(word[7][0]),"for");

strcpy(&(word[4][0]),"downto"); strcpy(&(word[3][0]),"do"); /*设置保留字符号*/ wsym[7]=forsym; wsym[14]=tosym; /*语法分析,获取一个符号*/ 在getsym()部分添加: else if(ch=='*'){ /** “*=” **/ getchdo; if(ch=='='){ sym=timeseql; getchdo; printf("check *= success!"); } else sym=times; } else if(ch=='/'){ /* “/=” */ getchdo; if(ch=='='){sym=slasheql; getchdo; printf("check /= success!");

编译原理实验报告(词法分析器语法分析器)

编译原理实验报告

实验一 一、实验名称:词法分析器的设计 二、实验目的:1,词法分析器能够识别简单语言的单词符号 2,识别出并输出简单语言的基本字.标示符.无符号整数.运算符.和界符。 三、实验要求:给出一个简单语言单词符号的种别编码词法分析器 四、实验原理: 1、词法分析程序的算法思想 算法的基本任务是从字符串表示的源程序中识别出具有独立意义的单词符号,其基本思想是根据扫描到单词符号的第一个字符的种类,拼出相应的单词符号。 2、程序流程图 (1 (2)扫描子程序

3

五、实验内容: 1、实验分析 编写程序时,先定义几个全局变量a[]、token[](均为字符串数组),c,s( char型),i,j,k(int型),a[]用来存放输入的字符串,token[]另一个则用来帮助识别单词符号,s用来表示正在分析的字符。字符串输入之后,逐个分析输入字符,判断其是否‘#’,若是表示字符串输入分析完毕,结束分析程序,若否则通过int digit(char c)、int letter(char c)判断其是数字,字符还是算术符,分别为用以判断数字或字符的情况,算术符的判断可以在switch语句中进行,还要通过函数int lookup(char token[])来判断标识符和保留字。 2 实验词法分析器源程序: #include #include #include int i,j,k; char c,s,a[20],token[20]={'0'}; int letter(char s){ if((s>=97)&&(s<=122)) return(1); else return(0); } int digit(char s){ if((s>=48)&&(s<=57)) return(1); else return(0); } void get(){ s=a[i]; i=i+1; } void retract(){ i=i-1; } int lookup(char token[20]){ if(strcmp(token,"while")==0) return(1); else if(strcmp(token,"if")==0) return(2); else if(strcmp(token,"else")==0) return(3); else if(strcmp(token,"switch")==0) return(4); else if(strcmp(token,"case")==0) return(5); else return(0); } void main() { printf("please input string :\n"); i=0; do{i=i+1; scanf("%c",&a[i]);

(完整word版)PL0源代码(C语言版)

/*PL/0 编译系统C版本头文件pl0.h*/ # define norw 13 //a number of reserved word /*关键字个数*/ # define txmax 100 //length of identifier table /*名字表容量*/ # define nmax 14 //max number of digits in numbers /*number的最大位数*/ # define al 10 //length of identifier /*符号的最大长度*/ # define amax 2047 //maximum address /*地址上界*/ # define levmax 3 //max depth of block nesting /*最大允许过程嵌套声明层数[0,lexmax]*/ # define cxmax 200 //size of code array /*最多的虚拟机代码数*/ /*符号*/ enum symbol{ nul, ident, number, plus, minus, times, slash, oddsym, eql, neq, //slash斜线 lss, leq, gtr, geq, lparen, //leq :less than or equal to; gtr: great than;lparen:left parenthesis rparen, comma, semicolon,period, becomes,//comma逗号semicolon分号period句号becomes赋值号 beginsym, endsym, ifsym, thensym, whilesym, writesym, readsym, dosym, callsym, constsym, varsym, procsym, }; #define symnum 32 /*-------------*/ enum object{ //object为三种标识符的类型 constant, variable, procedur, }; /*--------------*/ enum fct{ //fct类型分别标识类PCODE的各条指令 lit, opr, lod, sto, cal, inte, jmp, jpc, //书本P23 }; #define fctnum 8 /*--------------*/ struct instruction //指令 { enum fct f; //功能码 int l; //层次差 int a; //P23 }; FILE * fas; //输出名字表

编译原理实验报告:实验一编写词法分析程序

( 编译原理实验报告 , 实验名称:实验一编写词法分析程序 实验类型:验证型实验 指导教师:何中胜 专业班级:( 13软件四 姓名:丁越 学号: 实验地点:) 秋白楼B720

实验成绩: 日期:2016年 3 月 18 日

一、实验目的 通过设计、调试词法分析程序,实现从源程序中分出各种单词的方法;熟悉词法分析程序所用的工具自动机,进一步理解自动机理论。掌握文法转换成自动机的技术及有穷自动机实现的方法。确定词法分析器的输出形式及标识符与关键字的区分方法。加深对课堂教学的理解;提高词法分析方法的实践能力。通过本实验,应达到以下目标:[ 1、掌握从源程序文件中读取有效字符的方法和产生源程序的内部表示文件的方法。 2、掌握词法分析的实现方法。 3、上机调试编出的词法分析程序。 二、实验过程 以编写PASCAL子集的词法分析程序为例 1.理论部分 > (1)主程序设计考虑 主程序的说明部分为各种表格和变量安排空间。 数组 k为关键字表,每个数组元素存放一个关键字。采用定长的方式,较短的关键字后面补空格。 P数组存放分界符。为了简单起见,分界符、算术运算符和关系运算符都放在 p表中(编程时,还应建立算术运算符表和关系运算符表,并且各有类号),合并成一类。 id和ci数组分别存放标识符和常数。 instring数组为输入源程序的单词缓存。 ¥ outtoken记录为输出内部表示缓存。 还有一些为造表填表设置的变量。 主程序开始后,先以人工方式输入关键字,造 k表;再输入分界符等造p表。 主程序的工作部分设计成便于调试的循环结构。每个循环处理一个单词;接收键盘上送来的一个单词;调用词法分析过程;输出每个单词的内部码。 ⑵词法分析过程考虑 将词法分析程序设计成独立一遍扫描源程序的结构。其流程图见图 1-1。 …

编译原理PL0报告(附源码教程)

编译原理课程设计 学院计算机学院 专业计算机科学与技术班级 学号 姓名 指导教师 20 年月日

一、课程设计要求 基本内容(成绩范围:“中”、“及格”或“不及格”) (1)扩充赋值运算:*= 和/= 扩充语句(Pascal的FOR语句): ①FOR <变量>:=<表达式> TO <表达式> DO <语句> ②FOR <变量>:=<表达式> DOWNTO <表达式> DO <语句> 其中,语句①的循环变量的步长为2, 语句②的循环变量的步长为-2。 (3)增加运算:++ 和--。 选做内容(成绩评定范围扩大到:“优”和“良”) (1)增加类型:①字符类型;②实数类型。(2)扩充函数:①有返回值和返回语句;②有参数函数。(3)增加一维数组类型(可增加指令)。 (4)其他典型语言设施。 二、概述 目标:实现PL0某些特定语句 实现语言:C语言 实现工具平台:VS201 运行平台:WIN7 三、结构设计说明与功能块描述 PL/0编译程序的结构图

PL/0编译程序的总体流程图 四、主要成分描述 1、符号表 编译程序里用了一个枚举类型enum symbol,然后定义了enum symbol sym来存放当前

的符号,前面讲过,主程序定义了一个以字符为元素的一维数组word,称保留字表,这个保留字表也存放在符号表里,为了识别当前的符号是属于哪些保留字;还有标识符,拼数,拼符合词等的符号名都存放在符号表里,当sym存放当前的符号时,我们可以判断它是属于哪类的符号,然后加以处理。 在运行的过程中,主程序中又定义了一个名字表,也就是符号表,来专门存放变量、常量和过程名的各个属性,里面的属性包括name,kind,val/level,adr,size,我们来举一个PL/0语言过程说明部分的片段: Const a=35,b=49; Var c,d,e; Procedure p; Var g; 当遇到标识符的引用时就调用position函数,根据当前sym的符号类型来查table表,看是否有过正确的定义,若已有,则从表中取相应的有关信息,供代码的生成用。若无定义则调用出错处理程序。 2、运行时存储组织和管理 对于源程序的每一个过程(包括主程序),在被调用时,首先在数据段中开辟三个空间,存放静态链SL、动态链DL和返回地址RA。静态链记录了定义该过程的直接外过程(或主程序)运行时最新数据段的基地址。动态链记录调用该过程前正在运行的过程的数据段基址。返回地址记录了调用该过程时程序运行的断点位置。对于主程序来说,SL、DL和RA的值均置为0。静态链的功能是在一个子过程要引用它的直接或间接父过程(这里的父过程是按定义过程时的嵌套情况来定的,而不是按执行时的调用顺序定的)的变量时,可以通过静态链,跳过个数为层差的数据段,找到包含要引用的变量所在的数据段基址,然后通过偏移地址访问它。

第2章 PL0编译程序的实现 完整课后习题答案+吕映芝编

第2章 PL/0编译程序的实现 第1题 PL/0语言允许过程嵌套定义和递归调用,试问它的编译程序如何解决运行时的存储管理。 答案: PL/0语言允许过程嵌套定义和递归调用,它的编译程序在运行时采用了栈式动态存储管理。(数组CODE存放的只读目标程序,它在运行时不改变。)运行时的数据区S是由解释程序定义的一维整型数组,解释执行时对数据空间S的管理遵循后进先出规则,当每个过程(包括主程序)被调用时,才分配数据空间,退出过程时,则所分配的数据空间被释放。应用动态链和静态链的方式分别解决递归调用和非局部变量的引用问题。 第2题 若PL/0编译程序运行时的存储分配策略采用栈式动态分配,并用动态链和静态链的方式分别解决递归调用和非局部变量的引用问题,试写出下列程序执行到赋值语句b∶=10时运行栈的布局示意图。 var x,y; procedure p; var a; procedure q; var b; begin (q) b∶=10; end (q); procedure s; var c,d; procedure r; var e,f; begin (r) call q; end (r); begin (s) call r; end (s); begin (p) call s;

end (p); begin (main) call p; end (main). 答案: 程序执行到赋值语句b∶=10时运行栈的布局示意图为: 第3题 写出题2中当程序编译到r的过程体时的名字表table的内容。 size name kind level/val adr 答案: 题2中当程序编译到r的过程体时的名字表table的内容为: name kind level/val adr size x variable 0 dx y variable 0 dx+1 p procedure 0 过程p的入口(待填) 5

编译原理 杭电 实验报告1-PL0

PL/0 语言编译器分析实验报告 学号:09052304 姓名:张静 指导教师:谌志群 完成时间:2011-12-6

一、实验目的 通过阅读与解析一个实际编译器(PL/0语言编译器)的源代码,加深对编译阶段(包括词法分析、语法分析、语义分析、中间代码生成等)和编译系统软件结构的理解,并达到提高学生学习兴趣的目的。 二、实验要求 (1)要求掌握基本的程序设计技巧(C语言)和阅读较大规模程序源代码的能力; (2)理解并掌握编译过程的逻辑阶段及各逻辑阶段的功能; (3)要求能把握整个系统(PL/0语言编译器)的体系结构,各功能模块的功能,各模块之间的接口; (4)要求能总结出实现编译过程各逻辑阶段功能采用的具体算法与技术。 三、实验步骤 (1) 根据PL/0语言的语法图,理解PL/0语言各级语法单位的结构,掌握PL/0语言合法程序的结构; (2)从总体上分析整个系统的体系结构、各功能模块的功能、各模块之间的调用关系、各模块之间的接口; (3)详细分析各子程序和函数的代码结构、程序流程、采用的主要算法及实现的功能; (4)撰写分析报告,主要内容包括系统结构框图、模块接口、主要算法、各模块程序流程图等。 四、报告内容 1、 PL/0 语言语法的 BNF 表示-1,对语法描述图的解析 <程序> →<程序体>. <程序体> →[<常量说明部分>][变量说明部分>][<过程说明部分>]<语句> <常量说明部分> →const <常量定义>{,<常量定义>}; <常量定义> →<标识符>=<无符号整数> <无符号整数> →<数字>{<数字>} <变量说明部分> →var <标识符>{,<标识符>}; <标识符> →<字母>{<字母>|<数字>} <过程说明部分> →<过程首部><程序体>{;<过程说明部分>}; <过程首部> →procedure <标识符>; <语句> →<赋值语句>|<条件语句>|<当型循环语句>|<过程调用语句>| <复合语句> <赋值语句> →<标识符>:=<表达式> <复合语句> →begin <语句序列> end

编译原理实验报告

编译原理实验报告 课程名称______编译原理_____ 题目名称 PL0上机作业 学生学院__ 计算机学院______ 专业班级__ 12级计科8班 学号____ 3112006110 ____ 学生姓名____ 谢偲灏 _ 指导教师______ 杨劲涛 ___ 2015年 1 月 3 日

一、概述 目的:在分析理解一个教学型编译程序(如PL/0)的基础上,对其词法分析程序、语法分析程序和语义处理程序进行部分修改扩充。达到进一步了解程序编译过程的基本原理和基本实现方法的目的。 1.要求:课内实验(考试前交报告) 对PL/0作以下修改扩充: (1)增加单词:保留字:FOR,TO,DOWNTO,+=,-=,++,--;RETURN 要求:词法识别即可 (2)替换单词:不等号# 改为< >, (3)增加条件语句的ELSE子句,要求:写出相关文法,语法图,语义规则。二、实验环境与工具 (1)源:C语言 (2)程序目标语言: PL/0 (3)实现工具(平台):vc++6.0 (4)运行平台:PC机,Windows7 三、设计方案 1、结构设计说明 (1)PL/0 语言编译器 PL/0语言可看成是PASCAL语言的子集,它的编译程序是一个编译解释执行系统。PL/0的目标程序为假想栈式计算机的汇编语言,与具体计算机无关。

启动 置初值 调用GETSYM 取单词 调用block 过程 当前单词是否为源程序结束 符“。”? 源程序中是否有错误? 调用解释过程interpret 解释执行目标程序 结束 出错 打印错误 Y N Y N PL/0 的编译程序采用一趟扫描方式,以语法分析程序为核心,词法分析程序和代码生 成程序都作为一个独立的过程,当语法分析需要读单词时就用词法分析程序,而当语法分析 正确需生成相应的目标代码时,则调用代码生成程序。此外,用表格管理程序建立变量,常 量和过程标识符的说明与引用之间的信息联系。用出错处理程序对词法和语法分析遇到的错 误给出在源程序中出错的位置和错误性质。 2.各功能模块描述

编译原理实验报告实验一编写词法分析程序

编译原理实验报告实验名称:实验一编写词法分析程序 实验类型:验证型实验 指导教师:何中胜 专业班级:13软件四 姓名:丁越 学号: 电子邮箱: 实验地点:秋白楼B720 实验成绩: 日期:2016年3 月18 日

一、实验目的 通过设计、调试词法分析程序,实现从源程序中分出各种单词的方法;熟悉词法分析 程序所用的工具自动机,进一步理解自动机理论。掌握文法转换成自动机的技术及有穷自动机实现的方法。确定词法分析器的输出形式及标识符与关键字的区分方法。加深对课堂教学的理解;提高词法分析方法的实践能力。通过本实验,应达到以下目标: 1、掌握从源程序文件中读取有效字符的方法和产生源程序的内部表示文件的方法。 2、掌握词法分析的实现方法。 3、上机调试编出的词法分析程序。 二、实验过程 以编写PASCAL子集的词法分析程序为例 1.理论部分 (1)主程序设计考虑 主程序的说明部分为各种表格和变量安排空间。 数组 k为关键字表,每个数组元素存放一个关键字。采用定长的方式,较短的关键字 后面补空格。 P数组存放分界符。为了简单起见,分界符、算术运算符和关系运算符都放在 p表中 (编程时,还应建立算术运算符表和关系运算符表,并且各有类号),合并成一类。 id和ci数组分别存放标识符和常数。 instring数组为输入源程序的单词缓存。 outtoken记录为输出内部表示缓存。 还有一些为造表填表设置的变量。 主程序开始后,先以人工方式输入关键字,造 k表;再输入分界符等造p表。 主程序的工作部分设计成便于调试的循环结构。每个循环处理一个单词;接收键盘上 送来的一个单词;调用词法分析过程;输出每个单词的内部码。 ⑵词法分析过程考虑 将词法分析程序设计成独立一遍扫描源程序的结构。其流程图见图1-1。 图1-1 该过程取名为 lexical,它根据输入单词的第一个字符(有时还需读第二个字符),判断单词类,产生类号:以字符 k表示关键字;i表示标识符;c表示常数;p表示分界符;s表示运算符(编程时类号分别为 1,2,3,4,5)。 对于标识符和常数,需分别与标识符表和常数表中已登记的元素相比较,如表中已有 该元素,则记录其在表中的位置,如未出现过,将标识符按顺序填入数组id中,将常数 变为二进制形式存入数组中 ci中,并记录其在表中的位置。 lexical过程中嵌有两个小过程:一个名为getchar,其功能为从instring中按顺序取出一个字符,并将其指针pint加1;另一个名为error,当出现错误时,调用这个过程, 输出错误编号。 2.实践部分

编译原理PL0编译程序的实现1(希赛教育基础学院)

◇第二章PL/0编译程序的实现 【课前思考】 复习第1章介绍的一个高级程序设计语言编译程序的功能和实现的步骤。编译程序就是一个语言的翻译程序,通常是把一种高级程序设计语言(称源语言)书写的程序翻译成另一种等价功能语言(称目标语言)的程序。换句话说,编译是指把一种用源语言表示的算法转换到另一种等价的用目标语言表示的算法。编译程序实现的必要步骤有词法、语法、语义分析和代码生成。此外必需有符号表管理程序和出错处理程序。本章介绍的PL/0编译程序的实现是用PASCAL语言书写的。 【学习目标】 本章目的:以PL/0语言编译程序为实例,学习编译程序实现的基本步骤和相关技术,对编译程序的构造和实现得到一些感性认识和建立起整体概念,为后面的原理学习打下基础。 ◇了解并掌握用语法图和扩充的巴科斯-瑙尔范式(EBNF)对PL/0语言的形式描述。 ◇了解并掌握PL/0语言编译程序构造和实现的基本技术和步骤。 ◇了解并掌握PL/0语言编译程序的目标程序在运行时数据空间的组织管理。 【学习指南】 ◇要求读者阅读PL/0语言编译程序文本,了解一个编译程序构造的必要步骤和实现技术。一个编译程序的实现比较复杂,读懂一个典型的程序从设计思想到实现技术也有一定难度,特别是入门开始需要耐心。一但读懂,不仅了解编译程序的实现方法和技术,还可学到许多编程技巧和好的编程风格。 ◇阅读PL/0语言编译程序文本时,应从整体结构开始逐步细化,弄清楚每个过程的功能和实现方法及过程之间的相互关系。 ◇建议用一个PL/0源程序的例子为导引作为阅读PL/0语言编译程序文本的入门,然后再逐步全面读懂。 ◇通过对PL/0语言编译程序某些指定功能的扩充,加深对编译程序构造步骤和实现技术的理解,并能在实践中应用。 【难重点】 重点: ◇弄清源语言(PL/0)目标语言(类pcode)实现语言(pascal) 这3个语言之间的关系和作用。 ◇掌握用语法图和扩充的巴科斯-瑙尔范式(EBNF)对一个高级程序设计语言的形式描述。 ◇了解PL/0语言编译程序的语法分析技术采用的是自顶向下递归子程序法。 ◇掌握PL/0语言编译程序的整体结构和实现步骤,并弄清词法分析、语法分析、语义分析、代码生成及符号表管理每个过程的功能和相互联系。 ◇掌握PL/0语言编译程序的目标程序在运行时采用栈式动态存储管理的实现技术。 难点: ◇符号表管理起着编译期间和目标程序运行时信息联系的纽带,符号表的建立并不困难,但信息之间的关系往往需要反复学习才能理解。 【知识结构】

编译原理实验报告总结

编译原理实验报告总结 第学期《编译原理》实验报告学院(系):计算机科学与工程学院班级: A 学号: *** 姓名: 无名氏指导教师: 保密式时间:xx 年7 月目录 1、实验目的 12、实验内容及要求 13、实验方案设计 13、1 编译系统原理介绍 13、1、1 编译程序介绍 23、1、2 对所写编译程序的源语言的描述23、2 词法分析程序的设计 33、3 语法分析程序设计 43、4 语义分析和中间代码生成程序的设计 44、结果及测试分析 44、1软件运行环境及限制 44、2测试数据说明 54、3运行结果及功能说明 55、总结及心得体会

71、实验目的根据Sample语言或者自定义的某种语言,设计该语言的编译前端。包括词法分析,语法分析、语义分析及中间代码生成部分。 2、实验内容及要求(1)词法分析器输入源程序,输出对应的token表,符号表和词法错误信息。按规则拼单词,并转换成二元形式;滤掉空白符,跳过注释、换行符及一些无用的符号;进行行列计数,用于指出出错的行列号,并复制出错部分;列表打印源程序;发现并定位词法错误;(2)语法分析器输入token 串,通过语法分析,寻找其中的语法错误。要求能实现Sample语言或自定义语言中几种最常见的、基本的语法单位的分析:算术表达式、布尔表达式、赋值语句、if语句、for语句、while语句、do while语句等。(3)语义分析和中间代码生成输入token 串,进行语义分析,修改符号表,寻找其中的语义错误,并生成中间代码。要求能实现Sample语言或自定义语言中几种最常见的、基本的语法单位的分析:算术表达式、布尔表达式、赋值语句、if语句、for语句、while语句、do while语句等。实验要求:功能相对完善,有输入、输出描述,有测试数据,并介绍不足。 3、实验方案设计 3、1 编译系统原理介绍编译器逐行扫描高级语言程序源程序,编译的过程如下:

编译原理_实验报告PL0

PL/0 语言编译器分析实验报告 学院:计算机学院 学号:1112057195 姓名:夏建鑫 课程名称:编译原理

一、实验目的 通过阅读与解析一个实际编译器(PL/0语言编译器)的源代码,加深对编译阶段(包括词法分析、语法分析、语义分析、中间代码生成等)和编译系统软件结构的理解,并达到提高学生学习兴趣的目的。 二、实验要求 (1)要求掌握基本的程序设计技巧(C语言)和阅读较大规模程序源代码的能力; (2)理解并掌握编译过程的逻辑阶段及各逻辑阶段的功能; (3)要求能把握整个系统(PL/0语言编译器)的体系结构,各功能模块的功能,各模块之间的接口; (4)要求能总结出实现编译过程各逻辑阶段功能采用的具体算法与技术。 三、实验步骤 (1) 根据PL/0语言的语法图,理解PL/0语言各级语法单位的结构,掌握PL/0语言合法程序的结构; (2)从总体上分析整个系统的体系结构、各功能模块的功能、各模块之间的调用关系、各模块之间的接口; (3)详细分析各子程序和函数的代码结构、程序流程、采用的主要算法及实现的功能; (4)撰写分析报告,主要内容包括系统结构框图、模块接口、主要算法、各模块程序流程图等。 四、报告内容 PL/0 语言语法的 BNF 表示-1,对语法描述图的解析 <程序> →<程序体>. <程序体> →[<常量说明部分>][变量说明部分>][<过程说明部分>]<语句> <常量说明部分> →const <常量定义>{,<常量定义>}; <常量定义> →<标识符>=<无符号整数> <无符号整数> →<数字>{<数字>} <变量说明部分> →var <标识符>{,<标识符>}; <标识符> →<字母>{<字母>|<数字>} <过程说明部分> →<过程首部><程序体>{;<过程说明部分>}; <过程首部> →procedure <标识符>; <语句> →<赋值语句>|<条件语句>|<当型循环语句>|<过程调用语句>| <复合语句> <赋值语句> →<标识符>:=<表达式> <复合语句> →begin <语句序列> end

PL0编译程序设计说明书

PL/0编译程序设计说明书 小组组长:李文(00000000) 小组成员:******(00000000) ******(00000000) ******(00000000) ******(00000000) 2006年1月16日

1引言 (3) 1.1编写目的 (3) 1.2背景 (3) 1.3定义 (3) 1.4参考资料 (5) 2总体设计 (5) 2.1需求规定 (5) 2.2运行环境 (6) 2.3模块流程 (6) 2.4模块机理说明 (7) 2.5模块设计与实现 (10) 2.6人工处理过程 (12) 2.7程序的亮点 (13) 2.8尚未问决的问题 (13) 3程序介绍和使用说明 (13) 4程序测试结果分析 (16)

概要设计说明书 1引言 1.1编写目的 此文档为VK 1.0版PL/0编译器详细设计说明书,旨在说明该编译器的设计思想和实现。此说明书可以在阅读本编译器代码时有效地帮助您理解本编译器的设计方法和实现过程,希望能提供给您所需的帮助。 1.2背景 名称:VK1.0版PL/0编译器 说明: 此编译器为北京师范大学信息科学学院计算机科学与技术系2003级2005-2006学年度第一学期编译原理课程实验作业。 本软件由李文小组合作开发,组长李文,同组人员有吕叶、刘晟忻、肖纯、曲文星。 本软件主要用于PL/0程序的编译,软件提供生成中间代码,并执行检测。本软件为开源软件,故除了用于编译以外还可给编译器开发者提供开发参考。 本软件开发运行在Windows 32位平台上,尚未开发其他平台版本。 1.3定义 本软件开发中,用到了一些PL/0语言和PCODE的定义以及编译原理术语,下面给予说明。 ●PL/0语言: ?BNF范式: 〈程序〉∷=〈分程序〉. 〈分程序〉∷=[〈常量说明部分〉][〈变量说明部分〉][〈过程说明部分〉]〈语 句〉 〈常量说明部分〉∷=CONST〈常量定义〉 {,〈常量定义〉}; 〈常量定义〉∷=〈标识符〉=〈无符号整数〉 〈无符号整数〉∷=〈数字〉{〈数字〉} 〈变量说明部分〉∷=VAR〈标识符〉{,〈标识符〉}; 〈标识符〉∷=〈字母〉{〈字母〉|〈数字〉} 〈过程说明部分〉∷=〈过程首部〉〈分程序〉{;〈过程说明部分〉}; 〈过程首部〉∷=PROCEDURE〈标识符〉; 〈语句〉∷=〈赋值语句〉|〈条件语句〉|〈当型循环语句〉|〈过程调用语句〉| 〈读语句〉|〈写语句〉|〈复合语句〉|〈空〉; 〈赋值语句〉∷=〈标识符〉∶=〈表达式〉

编译原理实验 (词法语法分析 附源代码

编译原理实验报告 ******************************************************************************* ******************************************************************************* PL0语言功能简单、结构清晰、可读性强,而又具备了一般高级程序设计语言的必须部分,因而PL0语言的编译程序能充分体现一个高级语言编译程序实现的基本方法和技术。PL/0语言文法的EBNF表示如下: <程序>::=<分程序>. <分程序> ::=[<常量说明>][<变量说明>][<过程说明>]<语句> <常量说明> ::=CONST<常量定义>{,<常量定义>}; <常量定义> ::=<标识符>=<无符号整数> <无符号整数> ::= <数字>{<数字>} <变量说明> ::=V AR <标识符>{, <标识符>}; <标识符> ::=<字母>{<字母>|<数字>} <过程说明> ::=<过程首部><分程序>{; <过程说明> }; <过程首部> ::=PROCEDURE <标识符>; <语句> ::=<赋值语句>|<条件语句>|<当循环语句>|<过程调用语句> |<复合语句>|<读语句><写语句>|<空> <赋值语句> ::=<标识符>:=<表达式> <复合语句> ::=BEGIN <语句> {;<语句> }END <条件语句> ::= <表达式> <关系运算符> <表达式> |ODD<表达式> <表达式> ::= [+|-]<项>{<加法运算符> <项>} <项> ::= <因子>{<乘法运算符> <因子>} <因子> ::= <标识符>|<无符号整数>| ‘(’<表达式>‘)’ <加法运算符> ::= +|- <乘法运算符> ::= *|/ <关系运算符> ::= =|#|<|<=|>|>= <条件语句> ::= IF <条件> THEN <语句> <过程调用语句> ::= CALL 标识符 <当循环语句> ::= WHILE <条件> DO <语句> <读语句> ::= READ‘(’<标识符>{,<标识符>}‘)’ <写语句> ::= WRITE‘(’<表达式>{,<表达式>}‘)’ <字母> ::= a|b|…|X|Y|Z <数字> ::= 0|1|…|8|9 【预处理】 对于一个pl0文法首先应该进行一定的预处理,提取左公因式,消除左递归(直接或间接),接着就可以根据所得的文法进行编写代码。 【实验一】词法分析 【实验目的】给出PL/0文法规范,要求编写PL/0语言的词法分析程序。 【实验内容】已给PL/0语言文法,输出单词(关键字、专用符号以及其它标记)。

实验一 PL0编译程序

编译原理上机实验一 1.软件准备 (1)、pl/0编译程序:pl0 .exe (2)、pl/0编译程序源代码程序(PASCAL程序):pl0.pas (或pl0pl0.pas) (3)、pl/0程序实例(文本文件): text.pl0, text1.pl0, test2.pl0, … text9.pl0共10个例子 2.实验要求: (1)阅读pl/0源程序实例(text.pl0,test1.pl0,………text9.pl0共10个例子)理解每个PL0程序的功能;熟悉并掌握pl/0语言相关规则。 (2)用pl/0编译程序,对提供的10个例子逐一进行编译并运行。熟悉pl/0编译程序使用操作方法。通过理解每个实例程序的功能,编程思想, 进一步理解PL/0语言的语法及其语义;提高阅读程序的能力,应用 程序设计语言的编程能力;增强程序语言语法、语义意识。 (3)用pl/0语言编写以下程序,进一步熟悉PL/0语言: a、由三角形的三条边长计算三角形面积。 b、编写一个PL0过程,计算以a为直径的圆的面积。用主程序确定圆 的直径,输出计算结果。 c、编写递归程序,计算n!。 d、计算1000之内的所有素数,并输出结果。求出1000之内所有素数之 和。(要求编写3个以上的pl/0过程实现) 3.文件(软件)使用说明 (1)、打开文件目录“PL0编译…”,运行PL/0编译程序(pl0.exe),按提示要求输入PL0源程序文件名(如test1.pl0),┉ (2)、打开Fa2.txt文件,可看到当前经过编译并运行后的pl/0程序的目标代码及其执行结果。 (3)、打开out1.txt或out2.txt、┉或out9.txt文件,可看到各个pl/0程序实例的编译、运行、操作过程结果。 4.提交实验报告及要求 (1)、简述test4.pl0 …test7.pl0各程序语法含义,执行结果。 (2)、提交实验要求编写的4个PL/0源程序及其执行结果。 (3)、简写本次实验的收获与体会。

PL0+语言编译器分析实验

编译原理实验报告 课题名称:PL/0 语言编译器分析实验 学院: 专业: 姓名: 学号: 指导老师: 完成时间:

一、实验目的 通过阅读与解析一个实际编译器(PL/0语言编译器)的源代码,加深对编译阶段(包括词法分析、语法分析、语义分析、中间代码生成等)和编译系统软件结构的理解,并达到提高学生学习兴趣的目的。 二、实验要求 (1)要求掌握基本的程序设计技巧(C语言)和阅读较大规模程序源代码的能力; (2)理解并掌握编译过程的逻辑阶段及各逻辑阶段的功能; (3)要求能把握整个系统(PL/0语言编译器)的体系结构,各功能模块的功能,各模块之间的接口; (4)要求能总结出实现编译过程各逻辑阶段功能采用的具体算法与技术。 三、实验原理

四、实验报告 pl/0语言是pascal语言的一个子集,我们这里分析的pl/0的编译程序包括了对pl/0语言源程序进行分析处理、编译生成类pcode代码,并在虚拟机上解释运行生成的类pcode代码的功能。 pl/0语言编译程序采用以语法分析为核心、一遍扫描的编译方法。词法分析和代码生成作为独立的子程序供语法分析程序调用。语法分析的同时,提供了出

错报告和出错恢复的功能。在源程序没有错误编译通过的情况下,调用类pcode 解释程序解释执行生成的类pcode代码。 词法分析子程序分析: 词法分析子程序名为getsym,功能是从源程序中读出一个单词符号(token),把它的信息放入全局变量sym、id和num中,语法分析器需要单词时,直接从这三个变量中获得。(注意!语法分析器每次用完这三个变量的值就立即调用getsym 子程序获取新的单词供下一次使用。而不是在需要新单词时才调用getsym过程。)getsym过程通过反复调用getch子过程从源程序过获取字符,并把它们拼成单词。getch过程中使用了行缓冲区技术以提高程序运行效率。 词法分析器的分析过程: 调用getsym时,它通过getch过程从源程序中获得一个字符。如果这个字符是字母,则继续获取字符或数字,最终可以拼成一个单词,查保留字表,如果查到为保留字,则把sym变量赋成相应的保留字类型值;如果没有查到,则这个单词应是一个用户自定义的标识符(可能是变量名、常量名或是过程的名字),把sym 置为ident,把这个单词存入id变量。查保留字表时使用了二分法查找以提高效率。如果getch获得的字符是数字,则继续用getch获取数字,并把它们拼成一个整数,然后把sym置为number,并把拼成的数值放入num变量。如果识别出其它合法的符号(比如:赋值号、大于号、小于等于号等),则把sym则成相应的类型。如果遇到不合法的字符,把sym置成nul。 语法分析子程序分析: 语法分析子程序采用了自顶向下的递归子程序法,语法分析同时也根据程序的语意生成相应的代码,并提供了出错处理的机制。语法分析主要由分程序分析过程(block)、常量定义分析过程(constdeclaration)、变量定义分析过程(vardeclaration)、语句分析过程(statement)、表达式处理过程(expression)、项处理过程(term)、因子处理过程(factor)和条件处理过程(condition)构成。这些过程在结构上构成一个嵌套的层次结构。除此之外,还有出错报告过程(error)、代码生成过程(gen)、测试单词合法性及出错恢复过程(test)、登录名字表过程(enter)、查询名字表函数(position)以及列出类pcode代码过程(listcode)作过语法分析的辅助过程。 由pl/0的语法图可知:一个完整的pl/0程序是由分程序和句号构成的。因此,本编译程序在运行的时候,通过主程序中调用分程序处理过程block来分析分程序部分(分程序分析过程中还可能会递归调用block过程),然后,判断最后读入的符号是否为句号。如果是句号且分程序分析中未出错,则是一个合法的pl/0程序,可以运行生成的代码,否则就说明源pl/0程序是不合法的,输出出错提示即可。 语法单元分析: 1、分程序处理过程: 语法分析开始后,首先调用分程序处理过程(block)处理分程序。过程入口参数置为:0层、符号表位置0、出错恢复单词集合为句号、声明符或语句开始符。进入block过程后,首先把局部数据段分配指针设为3,准备分配3个单元供

相关文档
最新文档