首先,这道题用C++肯定不方便,毕竟字符串处理题,所以目标选定pascal(会两种语言就是好)。
然后,我们来思考怎么构建这个程序。
你的第一个想法基本上是:一行一行做下来,然后用一些数组记录每个变量,然后每做到一个变量或每句话判断一下。
然而,很显然,只做一遍是很难实现的,至少在逻辑上不是很简单。
所以,我的方法是这样的:
PARAM语句unreachable的情况,在这一遍中,遇到的变量用一个判断这是第一,二部分
xxxxxxxxxxprocedure swap(var x,y:char);//交换var t:char;begint:=x;x:=y;y:=t;end;function got(var st:string):string;//在一个字符串中读取一段子串var k:longint;begink:=pos(' ',st);//找到最近的空格got:=copy(st,1,k-1);delete(st,1,k);//删掉不要的东西end;function compare(s1,s2:string):boolean;//判断s1的前面若干位是否等于s2beginif copy(s1,1,length(s2))=s2 then exit(true);exit(false);end;procedure start;//开始读入+转化var st:string;a,b,c:char;beginreadln(st);st:=st+' ';//加空格是为了got语句的方便delete(st,1,6);//把PARAM这个单词删去while st<>'' do f[got(st)[1]]:=true;//处理一开始就定义的变量line:=1;//行数while not(eof) dobegininc(line);readln(st);st:=st+' ';if compare(st,'IF') then//IF语句begindelete(st,1,3);a:=got(st)[1];got(st);b:=got(st)[1];if a=b then b:=' ';//两个相同只要做一个if a>b then swap(a,b);//两个必须按顺序排列,不然以后调用错误1时会很麻烦op[line]:=1;//操作类型ct[line,1]:=a;//操作变量1ct[line,2]:=b;//操作变量2end elseif compare(st,'END IF') then op[line]:=3else if compare(st,'ELSE') then op[line]:=2else if compare(st,'RETURN') thenbegindelete(st,1,7);op[line]:=4;ct[line,1]:=got(st)[1];endelsebeginop[line]:=0;a:=got(st)[1];got(st);b:=got(st)[1];if st<>'' then//如果还有第三个参数begingot(st);c:=got(st)[1];if b=c then c:=' ';if b>c then swap(b,c);ct[line,1]:=b;ct[line,2]:=c;endelse ct[line,1]:=b;ct[line,3]:=a;//操作变量3end;end;end;
这是第三部分
我们用来记录当前的级别
我们用数组来记录当前级别内是处于模式还是模式
我们用来记录是否可以出现错误1,即如果这句话没有被做到的话,
我们用数组来记录在该级别,该模式下是否存在过,若有,即为
值得注意的是,如果那么
这点相当于
xxxxxxxxxxPARAM AIF A > 0 THENRETURN 0ELSERETURN 0END IFRETURN P
第7行是不会被做到的
如果做一句话的时候,,且这句话不为和,那么报告2错误。
xxxxxxxxxxfunction ischar(a:char):boolean;beginif (a>='A') and (a<='Z') then exit(true);exit(false);end;procedure error2(line:longint);beginwriteln('Line ',line,': unreachable code');end;procedure run;var level,i:longint;noerror1:boolean;none:longint;beginlevel:=1;stack2[1]:=0;for i:=2 to line dobeginnoerror1:=false;if (die[level,stack2[level]])and(op[i] in [0,1,4]) then//如果这句话$die$了(即没有办法做到)beginerror2(i);noerror1:=true;end;case op[i] of1:begin//ifinc(level);//下一级别stack2[level]:=0;if die[level-1,stack2[level-1]] then//如果上一级就die了,那么下一级就更die了begindie[level,0]:=true;die[level,1]:=true;endelsebegindie[level,0]:=false;die[level,1]:=false;end;if noerror1=false thenbeginif ischar(ct[i,1]) then judge(ct[i,1],i,level);//判断参数一是否错误if ischar(ct[i,2]) then judge(ct[i,2],i,level);//判断参数2是否错误end;end;2:begin//elsestack2[level]:=1;//从if模式换到else模式end;3:begin//end ifdie[level,0]:=false;die[level,1]:=false;dec(level);//上一级别end;4:begin//returndie[level,stack2[level]]:=true;//这一级的这一模式die了if noerror1=false thenbeginif ischar(ct[i,1]) then judge(ct[i,1],i,level);end;if (die[level,0])and(die[level,1]) then//die记号上传begindie[level-1,stack2[level-1]]:=true;end;end;0:begin//赋值语句if noerror1=false thenbeginif ischar(ct[i,1]) then judge(ct[i,1],i,level);if ischar(ct[i,2]) then judge(ct[i,2],i,level);end;end;end;end;end;
第四部分
同样用一个数组,一个数组(和相似)
用一个来表示这一句话是否可以被做到,如果不能做到,那么这一句赋值就是白搭(如果你想的话也可以再用一次数组哦)
xxxxxxxxxxprocedure error1(line:longint;c:char);beginwriteln('Line ',line,': variable ',c,' might not have been initialized');end;procedure judge(c:char;line,lvl:longint);var level,unreach:longint;i,j:longint;beginif f[c] then exit;//如果本来就在PARAM里出现过那就直接oklevel:=1;unreach:=0;for i:=1 to 100 dofor j:=0 to 1 doget[i,j]:=false;//fillchar出毛病了,所以手动改for i:=1 to 100 do stack[i]:=0;stack[level]:=0;for i:=2 to line-1 dobegincase op[i] of0:begin//赋值语句if (ct[i,3]=c)and(unreach=0) then//如果被赋值的参数里有目标参数,且可以被做到,那么这一级别的这一模式可以被录用get[level,stack[level]]:=true;end;1:begin//ifinc(level);stack[level]:=0;end;2:begin//elsestack[level]:=1;if unreach=level then unreach:=0;//die的简化版,如果就在这一级别前面的if被咔嚓了,那么免除死刑end;3:begin//end ifif get[level,1] and get[level,0] then//get标记上传(同die标记)beginget[level-1,stack[level-1]]:=true;end;get[level,1]:=false;get[level,0]:=false;//注意清空if unreach=level then unreach:=0;dec(level);end;4:beginget[level,stack[level]]:=true;//return也可以表示这个变量被赋值(见注释1)if unreach=0 then unreach:=level;end;end;end;if get[1,0] then exit;//如果在最外层被赋值直接okfor i:=2 to lvl-1 dobeginif get[i,1] or get[i,0] then exit;//前面一句话的展开版本end;if get[lvl,stack[level]] then exit;//最后一层必须在同一模式内(见注释2)error1(line,c);//啥都没找到返回错误end;
注释1:
xxxxxxxxxxPARAM AIF A > 0 THENRETURN AELSEK = AEND IFRETURN K
这里不该返回错误
注释2:
xxxxxxxxxxPARAM AIF A > 0 THENK = AELSERETURN KEND IF
这里应该在第5行返回错误
xxxxxxxxxxPARAM AA = A + 1第2行出错PARAM AIF A > 0 THENRETURN 0ELSERETURN 0END IFC = K第7行应该返回unreachable的错误PARAM AIF A > 0 THENK = 1ELSEK = 2END IFC = K没有错误
xxxxxxxxxxvar stack,stack2,op:array[0..100]of longint;get,die:array[0..100,0..1]of boolean;ct:array[0..100,0..3]of char;f:array['A'..'Z']of boolean;line:longint;function ischar(a:char):boolean;beginif (a>='A') and (a<='Z') then exit(true);exit(false);end;procedure swap(var x,y:char);var t:char;begint:=x;x:=y;y:=t;end;procedure error1(line:longint;c:char);beginwriteln('Line ',line,': variable ',c,' might not have been initialized');end;procedure error2(line:longint);beginwriteln('Line ',line,': unreachable code');end;function got(var st:string):string;var k:longint;begink:=pos(' ',st);got:=copy(st,1,k-1);delete(st,1,k);end;function compare(s1,s2:string):boolean;beginif copy(s1,1,length(s2))=s2 then exit(true);exit(false);end;procedure start;var st:string;a,b,c:char;beginreadln(st);st:=st+' ';delete(st,1,6);while st<>'' do f[got(st)[1]]:=true;line:=1;while not(eof) dobegininc(line);readln(st);st:=st+' ';if compare(st,'IF') thenbegindelete(st,1,3);a:=got(st)[1];got(st);b:=got(st)[1];if a=b then b:=' ';if a>b then swap(a,b);op[line]:=1;ct[line,1]:=a;ct[line,2]:=b;end elseif compare(st,'END IF') then op[line]:=3else if compare(st,'ELSE') then op[line]:=2else if compare(st,'RETURN') thenbegindelete(st,1,7);op[line]:=4;ct[line,1]:=got(st)[1];endelsebeginop[line]:=0;a:=got(st)[1];got(st);b:=got(st)[1];if st<>'' thenbegingot(st);c:=got(st)[1];if b=c then c:=' ';if b>c then swap(b,c);ct[line,1]:=b;ct[line,2]:=c;endelse ct[line,1]:=b;ct[line,3]:=a;end;end;end;procedure judge(c:char;line,lvl:longint);var level,unreach:longint;i,j:longint;beginif f[c] then exit;level:=1;unreach:=0;for i:=1 to 100 dofor j:=0 to 1 doget[i,j]:=false;for i:=1 to 100 do stack[i]:=0;stack[level]:=0;for i:=2 to line-1 dobegincase op[i] of0:beginif (ct[i,3]=c)and(unreach=0) thenget[level,stack[level]]:=true;end;1:begininc(level);stack[level]:=0;end;2:beginstack[level]:=1;if unreach=level then unreach:=0;end;3:beginif get[level,1] and get[level,0] thenbeginget[level-1,stack[level-1]]:=true;end;get[level,1]:=false;get[level,0]:=false;if unreach=level then unreach:=0;dec(level);end;4:beginget[level,stack[level]]:=true;if unreach=0 then unreach:=level;end;end;end;if get[1,0] then exit;for i:=2 to lvl-1 dobeginif get[i,1] or get[i,0] then exit;end;if get[lvl,stack[level]] then exit;error1(line,c);end;procedure run;var level,i:longint;noerror1:boolean;none:longint;beginlevel:=1;stack2[1]:=0;for i:=2 to line dobeginnoerror1:=false;if (die[level,stack2[level]])and(op[i] in [0,1,4]) thenbeginerror2(i);noerror1:=true;end;case op[i] of1:begininc(level);stack2[level]:=0;if die[level-1,stack2[level-1]] thenbegindie[level,0]:=true;die[level,1]:=true;endelsebegindie[level,0]:=false;die[level,1]:=false;end;if noerror1=false thenbeginif ischar(ct[i,1]) then judge(ct[i,1],i,level);if ischar(ct[i,2]) then judge(ct[i,2],i,level);end;end;2:beginstack2[level]:=1;end;3:begindie[level,0]:=false;die[level,1]:=false;dec(level);end;4:begindie[level,stack2[level]]:=true;if noerror1=false thenbeginif ischar(ct[i,1]) then judge(ct[i,1],i,level);end;if (die[level,0])and(die[level,1]) thenbegindie[level-1,stack2[level-1]]:=true;end;end;0:beginif noerror1=false thenbeginif ischar(ct[i,1]) then judge(ct[i,1],i,level);if ischar(ct[i,2]) then judge(ct[i,2],i,level);end;end;end;end;end;beginstart;run;end.