关于pl0语言编译器实现的几个问题??????

时间:2021-12-02 07:36:46
谁熟悉c语言实现的pl0编译器的源代码啊,我正在 扩充语言成份:”If  条件 then 语句系列1  else  语句系列2” 
看了别人写的,不是很明白,谁给我讲一下


if (sym == ifsym)   /* 准备按照if语句处理 */
   {
      getsymdo;//下一个单词
      memcpy(nxtlev, fsys, sizeof(bool)*symnum);
     //功能:由fsys所指内存区域复制symnum个bool到nxtlev所指内存区域
     //fsym和nxtlev所指内存区域不能重叠,函数返回指向nxtlev的指针。
      nxtlev[thensym] = true;
      nxtlev[dosym] = true;   /* 后跟符号为then或do */
      conditiondo(nxtlev, ptx, lev); /* 调用条件处理(逻辑运算)函数 */
      cx1 = cx;   /* 保存当前指令地址 */
      gendo(jpc, 0, 0);   /* 生成条件跳转指令,跳转地址未知,暂时写0 */
      if (sym == thensym)
       {
 getsymdo;
       }
      else
       {
 error(16);  /* 缺少then */
        }

       statementdo(fsys,ptx,lev);/* 处理then后的语句 */
       cx2=cx;
       gendo(jmp,0,0);
       getsymdo;
//*****************************************************************else****
        if (sym == elsesym)
 {
   cx3=cx;
   code[cx1].a=cx3;
   getsymdo;
   statementdo(fsys,ptx,lev);
   code[cx2].a=cx;
  }
 /*code[cx1].a = cx;    经statement处理后,cx为then后语句执行完的位置,它正是前面未定的跳转地址 */
}



源代码很长,需要的话我贴出,我就是不明白那几个跳转语句是怎样的逻辑

17 个解决方案

#1


也是没有用过的。但顶是必须的。

#2


有高手给讲解一下啊

#3


nxtlev[thensym] 里应该是if后面的条件语句有几个条件,比如 a && b || c;
conditiondo(nxtlev, ptx, lev); /* 调用条件处理(逻辑运算)函数 */ 这个就是分别将各个条件写入nxtlev数组吧;

接下来的if (sym == thensym) 处理then语句,扫描器向前进一个位置,如果没有then出错;
然后处理then后的语句,产生跳转指令,
后面就是处理else的了。
你主要看看这个 getsymdo是什么,是宏还是什么函数,不太明白这个怎么实现的。

#4


getsymdo是词法分析,取下一个单词

#5


他是怎样根据条件选择执行then或者else后的语句的呢

#6


upupuup

#7


帮顶,不知道p10的路过

#8


没有用过,不过看了下,这个作者写的注释真是没有任何意义,还不如不写,只能靠自己调试跟踪一下,自己分析了

#9


新手哈!多多指教哟!

#10


产生代码的话是then后面和else后面都要产生代码,具体跳转是在nxtlev[thensym]数组里的变量全是真跳到then后,如果非true的话跳到else后面。跳转是根据程序运行时变量值才跳的,但在产生汇编代码的时候then和else都要产生代码,这里只记录一下跳转的地址。

#11


这是另外两个函数,听了大家的解释,我明白了:
是不是int condition(bool* fsys, int* ptx, int lev)判断跳转的地址
然后跳转到then或者else后回填的地址呢呢


int condition(bool* fsys, int* ptx, int lev)
{
enum symbol relop;
bool nxtlev[symnum];

if(sym == oddsym)   /* 准备按照odd运算处理 */
{
getsymdo;
expressiondo(fsys, ptx, lev);
gendo(opr, 0, 6);   /* 生成odd指令 */
}
else
{
/* 逻辑表达式处理 */
memcpy(nxtlev, fsys, sizeof(bool)*symnum);
nxtlev[eql] = true;
nxtlev[neq] = true;
nxtlev[lss] = true;
nxtlev[leq] = true;
nxtlev[gtr] = true;
nxtlev[geq] = true;
expressiondo(nxtlev, ptx, lev);
if (sym!=eql && sym!=neq && sym!=lss && sym!=leq && sym!=gtr && sym!=geq)
{
error(20);
}
else
{
relop = sym;
getsymdo;
expressiondo(fsys, ptx, lev);
switch (relop)
{
case eql:
gendo(opr, 0, 8);
break;
case neq:
gendo(opr, 0, 9);
break;
case lss:
gendo(opr, 0, 10);
break;
case geq:
gendo(opr, 0, 11);
break;
case gtr:
gendo(opr, 0, 12);
break;
case leq:
gendo(opr, 0, 13);
break;
}
}
}
return 0;
}



int gen(enum fct x, int y, int z )
{
if (cx >= cxmax)
{
printf("Program too long"); /* 程序过长 */
return -1;
}
code[cx].f = x;
code[cx].l = y;
code[cx].a = z;
cx++;
return 0;
}

#12


又想了一下,是不是这样啊:

/*JMP:无条件转移指令,a为转向地址。
JPC:条件转移指令,当栈顶的布尔值为非真时,转向a域的地址,否则顺序执行。*/

根据这个,首先若conditiondo把处理的结果弄到栈顶,
假如是真,gendo(jpc, 0, 0);回填后就不跳转,顺序执行,gendo(jmp,0,0);回填后无条件跳转。这样就跳到了处理完then后,取完下一个单词的地方。
假如是假,gendo(jpc, 0, 0);回填后就跳转,跳转到了第一次回填的地方??还是第二次



这里有不明白了,就是jpc和jmp在两种条件下分别是跳到第几次回填地址的地方呢

#13


upupup

#14


其实就是汇编里的jmp 和 jpc(jpc是跳转吗,忘了),具体跳到哪里是有那个标号的,"8,9,10,11,12,13"是位置,汇编里有Lable和goto吗。大概意思就这样。

#15


up

#16


搞定了
else  for  dowhile 部分

if (sym == ifsym)   /* 准备按照if语句处理 */
{
getsymdo;//下一个单词
memcpy(nxtlev, fsys, sizeof(bool)*symnum);
//功能:由fsys所指内存区域复制symnum个bool到nxtlev所指内存区域
//fsym和nxtlev所指内存区域不能重叠,函数返回指向nxtlev的指针。
nxtlev[thensym] = true;
nxtlev[dosym] = true;   /* 后跟符号为then或do */
conditiondo(nxtlev, ptx, lev); /* 调用条件处理(逻辑运算)函数 */
if (sym == thensym)
{
getsymdo;
}
else
{
error(16);  /* 缺少then */
}
cx1 = cx;   /* 保存当前指令地址 */
gendo(jpc, 0, 0);   /* 生成条件跳转指令,跳转地址未知,暂时写0 */
/*JMP:无条件转移指令,a为转向地址。
                       JPC:条件转移指令,当栈顶的布尔值为非真时,转向a域的地址,否则顺序执行。*/
statementdo(fsys,ptx,lev);/* 处理then后的语句 */
//*****************************************************************else****


if (sym == elsesym)
{
getsymdo;
cx2=cx;
gendo(jmp,0,0);
code[cx1].a=cx;//回填地址
statementdo(fsys,ptx,lev);//处理else后的语句
code[cx2].a=cx;/*cx为else后语句执行完的位置,它正是前面未定的跳转地址 */
}
else
{
code[cx1].a=cx;//回填地址
}

else
{
if (sym == beginsym)    /* 准备按照复合语句处理 */
{
getsymdo;
memcpy(nxtlev, fsys, sizeof(bool)*symnum);
nxtlev[semicolon] = true;
nxtlev[endsym] = true;  /* 后跟符号为分号或end */
/* 循环调用语句处理函数,直到下一个符号不是语句开始符号或收到end */
statementdo(nxtlev, ptx, lev);

while (inset(sym, statbegsys) || sym==semicolon)
{
if (sym == semicolon)
{
getsymdo;
}
else
{
error(10);  /* 缺少分号 */
}
statementdo(nxtlev, ptx, lev);
}
if(sym == endsym)
{
getsymdo;
}
else
{
error(17);  /* 缺少end或分号 */
}
}
else
{
if (sym == whilesym)    /* 准备按照while语句处理 */
{
cx1 = cx;   /* 保存判断条件操作的位置 */
getsymdo;
memcpy(nxtlev, fsys, sizeof(bool)*symnum);
nxtlev[dosym] = true;   /* 后跟符号为do */
conditiondo(nxtlev, ptx, lev);  /* 调用条件处理 */
cx2 = cx;   /* 保存循环体的结束的下一个位置 */
gendo(jpc, 0, 0);   /* 生成条件跳转,但跳出循环的地址未知 */
if (sym == dosym)
{
getsymdo;
}
else
{
error(18);  /* 缺少do */
}
statementdo(fsys, ptx, lev);    /* 循环体 */
gendo(jmp, 0, cx1); /* 回头重新判断条件 */
code[cx2].a = cx;   /* 反填跳出循环的地址,与if类似 */
}
else
{
if(sym==forsym)   /* 准备按照for语句处理 */
{
getsymdo;
if (sym == ident)   /* 准备按照赋值语句处理 */
{
i = position(id, *ptx);
if (i == 0)
{
error(11);  /* 变量未找到 */
}
else
{
if(table[i].kind != variable)
{
error(12);  /* 赋值语句格式错误 */
i = 0;
}
else
{
getsymdo;
if(sym == becomes)//变量赋初始值
{
getsymdo;
}
else
{
error(13);  /* 没有检测到赋值符号 */
}
memcpy(nxtlev, fsys, sizeof(bool)*symnum);
nxtlev[tosym]=true;
expressiondo(nxtlev, ptx, lev); /* 处理赋值符号右侧表达式 */
if(i != 0)
{
/* expression将执行一系列指令,但最终结果将会保存在栈顶,执行sto命令完成赋值 */
gendo(sto, lev-table[i].level, table[i].adr);
}
if(sym==tosym)

cx1=cx;
gendo(lod,lev-table[i].level,table[i].adr);//读取此变量的值,放入栈顶
getsymdo;
expressiondo(nxtlev, ptx, lev);
gendo(opr,0,13);//次栈顶是否小于等于栈顶
cx2=cx;
gendo(jpc,0,0);
}
else error(36);//没有to
memcpy(nxtlev,fsys,sizeof(bool)* symnum);
nxtlev[beginsym]=true;
if(sym==beginsym)
{
nxtlev[semicolon] = true;
nxtlev[endsym] = true;
getsymdo;
statementdo(fsys,ptx,lev); /*循环体*/
gendo(lod,lev-table[i].level,table[i].adr);
gendo(lit,0,1);//将常量值取到运行栈顶(变量+1)
gendo(opr,0,2);//次栈顶与栈顶相加,退两个栈元素,结果值进栈 
gendo(sto,lev-table[i].level,table[i].adr);// 将栈顶内容送入某变量单元中
while (inset(sym, statbegsys) || sym==semicolon)
{
if (sym == semicolon)
{
getsymdo;
}
else
{
error(10);  /* 缺少分号 */
}
statementdo(nxtlev, ptx, lev);
}
if(sym == endsym)
{
//getsymdo;
}
else
{
error(17);  /* 缺少end或分号 */
}
gendo(jmp,0,cx1);
code[cx2].a=cx;
}
getsymdo;
}
}
}/* sym==ident*/
else
{
error(33); /* FOR 后不是变量产生错误*/
}
}
else
{
if(sym == dowhilesym)
{
cx1=cx;         
getsymdo;
statementdo(nxtlev,ptx,lev); 
if(sym==semicolon)
{
getsymdo;
}
if(sym==untilsym)
{
getsymdo;
conditiondo(nxtlev,ptx,lev);
gendo(jpc,0,cx1);  
}
}

#17


附带测试程序。全部源代码我上传到我的资源了

var a,b;
begin
  read(a);
 read(b);
 if a<b then write(a);
if a<b then write(a)
  else write(b);
end.




var i;
begin
for i:=1  to 5 begin
 write(i);
end;
end.




var a,i;
begin
i:=0;
a:=4;
dowhile
begin
write(a);
i:=i+1;
end;
until i=5;
end.

#1


也是没有用过的。但顶是必须的。

#2


有高手给讲解一下啊

#3


nxtlev[thensym] 里应该是if后面的条件语句有几个条件,比如 a && b || c;
conditiondo(nxtlev, ptx, lev); /* 调用条件处理(逻辑运算)函数 */ 这个就是分别将各个条件写入nxtlev数组吧;

接下来的if (sym == thensym) 处理then语句,扫描器向前进一个位置,如果没有then出错;
然后处理then后的语句,产生跳转指令,
后面就是处理else的了。
你主要看看这个 getsymdo是什么,是宏还是什么函数,不太明白这个怎么实现的。

#4


getsymdo是词法分析,取下一个单词

#5


他是怎样根据条件选择执行then或者else后的语句的呢

#6


upupuup

#7


帮顶,不知道p10的路过

#8


没有用过,不过看了下,这个作者写的注释真是没有任何意义,还不如不写,只能靠自己调试跟踪一下,自己分析了

#9


新手哈!多多指教哟!

#10


产生代码的话是then后面和else后面都要产生代码,具体跳转是在nxtlev[thensym]数组里的变量全是真跳到then后,如果非true的话跳到else后面。跳转是根据程序运行时变量值才跳的,但在产生汇编代码的时候then和else都要产生代码,这里只记录一下跳转的地址。

#11


这是另外两个函数,听了大家的解释,我明白了:
是不是int condition(bool* fsys, int* ptx, int lev)判断跳转的地址
然后跳转到then或者else后回填的地址呢呢


int condition(bool* fsys, int* ptx, int lev)
{
enum symbol relop;
bool nxtlev[symnum];

if(sym == oddsym)   /* 准备按照odd运算处理 */
{
getsymdo;
expressiondo(fsys, ptx, lev);
gendo(opr, 0, 6);   /* 生成odd指令 */
}
else
{
/* 逻辑表达式处理 */
memcpy(nxtlev, fsys, sizeof(bool)*symnum);
nxtlev[eql] = true;
nxtlev[neq] = true;
nxtlev[lss] = true;
nxtlev[leq] = true;
nxtlev[gtr] = true;
nxtlev[geq] = true;
expressiondo(nxtlev, ptx, lev);
if (sym!=eql && sym!=neq && sym!=lss && sym!=leq && sym!=gtr && sym!=geq)
{
error(20);
}
else
{
relop = sym;
getsymdo;
expressiondo(fsys, ptx, lev);
switch (relop)
{
case eql:
gendo(opr, 0, 8);
break;
case neq:
gendo(opr, 0, 9);
break;
case lss:
gendo(opr, 0, 10);
break;
case geq:
gendo(opr, 0, 11);
break;
case gtr:
gendo(opr, 0, 12);
break;
case leq:
gendo(opr, 0, 13);
break;
}
}
}
return 0;
}



int gen(enum fct x, int y, int z )
{
if (cx >= cxmax)
{
printf("Program too long"); /* 程序过长 */
return -1;
}
code[cx].f = x;
code[cx].l = y;
code[cx].a = z;
cx++;
return 0;
}

#12


又想了一下,是不是这样啊:

/*JMP:无条件转移指令,a为转向地址。
JPC:条件转移指令,当栈顶的布尔值为非真时,转向a域的地址,否则顺序执行。*/

根据这个,首先若conditiondo把处理的结果弄到栈顶,
假如是真,gendo(jpc, 0, 0);回填后就不跳转,顺序执行,gendo(jmp,0,0);回填后无条件跳转。这样就跳到了处理完then后,取完下一个单词的地方。
假如是假,gendo(jpc, 0, 0);回填后就跳转,跳转到了第一次回填的地方??还是第二次



这里有不明白了,就是jpc和jmp在两种条件下分别是跳到第几次回填地址的地方呢

#13


upupup

#14


其实就是汇编里的jmp 和 jpc(jpc是跳转吗,忘了),具体跳到哪里是有那个标号的,"8,9,10,11,12,13"是位置,汇编里有Lable和goto吗。大概意思就这样。

#15


up

#16


搞定了
else  for  dowhile 部分

if (sym == ifsym)   /* 准备按照if语句处理 */
{
getsymdo;//下一个单词
memcpy(nxtlev, fsys, sizeof(bool)*symnum);
//功能:由fsys所指内存区域复制symnum个bool到nxtlev所指内存区域
//fsym和nxtlev所指内存区域不能重叠,函数返回指向nxtlev的指针。
nxtlev[thensym] = true;
nxtlev[dosym] = true;   /* 后跟符号为then或do */
conditiondo(nxtlev, ptx, lev); /* 调用条件处理(逻辑运算)函数 */
if (sym == thensym)
{
getsymdo;
}
else
{
error(16);  /* 缺少then */
}
cx1 = cx;   /* 保存当前指令地址 */
gendo(jpc, 0, 0);   /* 生成条件跳转指令,跳转地址未知,暂时写0 */
/*JMP:无条件转移指令,a为转向地址。
                       JPC:条件转移指令,当栈顶的布尔值为非真时,转向a域的地址,否则顺序执行。*/
statementdo(fsys,ptx,lev);/* 处理then后的语句 */
//*****************************************************************else****


if (sym == elsesym)
{
getsymdo;
cx2=cx;
gendo(jmp,0,0);
code[cx1].a=cx;//回填地址
statementdo(fsys,ptx,lev);//处理else后的语句
code[cx2].a=cx;/*cx为else后语句执行完的位置,它正是前面未定的跳转地址 */
}
else
{
code[cx1].a=cx;//回填地址
}

else
{
if (sym == beginsym)    /* 准备按照复合语句处理 */
{
getsymdo;
memcpy(nxtlev, fsys, sizeof(bool)*symnum);
nxtlev[semicolon] = true;
nxtlev[endsym] = true;  /* 后跟符号为分号或end */
/* 循环调用语句处理函数,直到下一个符号不是语句开始符号或收到end */
statementdo(nxtlev, ptx, lev);

while (inset(sym, statbegsys) || sym==semicolon)
{
if (sym == semicolon)
{
getsymdo;
}
else
{
error(10);  /* 缺少分号 */
}
statementdo(nxtlev, ptx, lev);
}
if(sym == endsym)
{
getsymdo;
}
else
{
error(17);  /* 缺少end或分号 */
}
}
else
{
if (sym == whilesym)    /* 准备按照while语句处理 */
{
cx1 = cx;   /* 保存判断条件操作的位置 */
getsymdo;
memcpy(nxtlev, fsys, sizeof(bool)*symnum);
nxtlev[dosym] = true;   /* 后跟符号为do */
conditiondo(nxtlev, ptx, lev);  /* 调用条件处理 */
cx2 = cx;   /* 保存循环体的结束的下一个位置 */
gendo(jpc, 0, 0);   /* 生成条件跳转,但跳出循环的地址未知 */
if (sym == dosym)
{
getsymdo;
}
else
{
error(18);  /* 缺少do */
}
statementdo(fsys, ptx, lev);    /* 循环体 */
gendo(jmp, 0, cx1); /* 回头重新判断条件 */
code[cx2].a = cx;   /* 反填跳出循环的地址,与if类似 */
}
else
{
if(sym==forsym)   /* 准备按照for语句处理 */
{
getsymdo;
if (sym == ident)   /* 准备按照赋值语句处理 */
{
i = position(id, *ptx);
if (i == 0)
{
error(11);  /* 变量未找到 */
}
else
{
if(table[i].kind != variable)
{
error(12);  /* 赋值语句格式错误 */
i = 0;
}
else
{
getsymdo;
if(sym == becomes)//变量赋初始值
{
getsymdo;
}
else
{
error(13);  /* 没有检测到赋值符号 */
}
memcpy(nxtlev, fsys, sizeof(bool)*symnum);
nxtlev[tosym]=true;
expressiondo(nxtlev, ptx, lev); /* 处理赋值符号右侧表达式 */
if(i != 0)
{
/* expression将执行一系列指令,但最终结果将会保存在栈顶,执行sto命令完成赋值 */
gendo(sto, lev-table[i].level, table[i].adr);
}
if(sym==tosym)

cx1=cx;
gendo(lod,lev-table[i].level,table[i].adr);//读取此变量的值,放入栈顶
getsymdo;
expressiondo(nxtlev, ptx, lev);
gendo(opr,0,13);//次栈顶是否小于等于栈顶
cx2=cx;
gendo(jpc,0,0);
}
else error(36);//没有to
memcpy(nxtlev,fsys,sizeof(bool)* symnum);
nxtlev[beginsym]=true;
if(sym==beginsym)
{
nxtlev[semicolon] = true;
nxtlev[endsym] = true;
getsymdo;
statementdo(fsys,ptx,lev); /*循环体*/
gendo(lod,lev-table[i].level,table[i].adr);
gendo(lit,0,1);//将常量值取到运行栈顶(变量+1)
gendo(opr,0,2);//次栈顶与栈顶相加,退两个栈元素,结果值进栈 
gendo(sto,lev-table[i].level,table[i].adr);// 将栈顶内容送入某变量单元中
while (inset(sym, statbegsys) || sym==semicolon)
{
if (sym == semicolon)
{
getsymdo;
}
else
{
error(10);  /* 缺少分号 */
}
statementdo(nxtlev, ptx, lev);
}
if(sym == endsym)
{
//getsymdo;
}
else
{
error(17);  /* 缺少end或分号 */
}
gendo(jmp,0,cx1);
code[cx2].a=cx;
}
getsymdo;
}
}
}/* sym==ident*/
else
{
error(33); /* FOR 后不是变量产生错误*/
}
}
else
{
if(sym == dowhilesym)
{
cx1=cx;         
getsymdo;
statementdo(nxtlev,ptx,lev); 
if(sym==semicolon)
{
getsymdo;
}
if(sym==untilsym)
{
getsymdo;
conditiondo(nxtlev,ptx,lev);
gendo(jpc,0,cx1);  
}
}

#17


附带测试程序。全部源代码我上传到我的资源了

var a,b;
begin
  read(a);
 read(b);
 if a<b then write(a);
if a<b then write(a)
  else write(b);
end.




var i;
begin
for i:=1  to 5 begin
 write(i);
end;
end.




var a,i;
begin
i:=0;
a:=4;
dowhile
begin
write(a);
i:=i+1;
end;
until i=5;
end.