看了别人写的,不是很明白,谁给我讲一下
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是什么,是宏还是什么函数,不太明白这个怎么实现的。
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)判断跳转的地址
然后跳转到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
又想了一下,是不是这样啊:
根据这个,首先若conditiondo把处理的结果弄到栈顶,
假如是真,gendo(jpc, 0, 0);回填后就不跳转,顺序执行,gendo(jmp,0,0);回填后无条件跳转。这样就跳到了处理完then后,取完下一个单词的地方。
假如是假,gendo(jpc, 0, 0);回填后就跳转,跳转到了第一次回填的地方??还是第二次
这里有不明白了,就是jpc和jmp在两种条件下分别是跳到第几次回填地址的地方呢
/*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 部分
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是什么,是宏还是什么函数,不太明白这个怎么实现的。
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)判断跳转的地址
然后跳转到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
又想了一下,是不是这样啊:
根据这个,首先若conditiondo把处理的结果弄到栈顶,
假如是真,gendo(jpc, 0, 0);回填后就不跳转,顺序执行,gendo(jmp,0,0);回填后无条件跳转。这样就跳到了处理完then后,取完下一个单词的地方。
假如是假,gendo(jpc, 0, 0);回填后就跳转,跳转到了第一次回填的地方??还是第二次
这里有不明白了,就是jpc和jmp在两种条件下分别是跳到第几次回填地址的地方呢
/*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 部分
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.