📄 pl0.c
字号:
if (! (i = position(id)))
error(11);
else //如果找到标识符位于符号表第i位置
if (table[i].kind == ID_PROCEDURE) //如果这个标识符为一个过程名
{
mk = (mask*) &table[i];
gen(CAL, level - mk->level, mk->address); //生成cal目标代码,呼叫这个过程
}
else
error(15); // 如果call后跟的不是过程名,抛出15号错误
getsym(); //获取下一token,为后面作准备
}
}
else
if (sym == SYM_IF) //如果是if语句
{
getsym(); //获取一token应是一个逻辑表达式
set1 = createset(SYM_THEN, SYM_DO, SYM_NULL); //对逻辑表达式进行分析计算,出错恢复集中加入then和do语句
set = uniteset(set1, fsys);
condition(set);
destroyset(set1);
destroyset(set);
if (sym == SYM_THEN) //表达式后应遇到then语句
getsym(); //获取then后的token,应是一语句
else
error(16); // 如果if后没有then,抛出16号错误
cx1 = cx; //记下当前代码分配指针位置,这是then的开始位置
gen(JPC, 0, 0); //生成条件跳转指令,跳转位置暂时填0,分析完语句后再填写
set1 = createset(SYM_ELSE, SYM_NULL);
set = uniteset(set1, fsys);
statement(set);
destroyset(set1);
destroyset(set);
if (sym != SYM_ELSE) //表达式后遇到不是else语句
code[cx1].a = cx;//把then填0的跳转位置改成当前位置,完成if语句的处理
else
{//表达式后遇到else语句
getsym();
cx2=cx;//记下当前代码分配位置,这是else的开始位置
gen(JMP,0,0);//产生一行跳转指令,跳转位置暂时未知填0
statement(fsys);
code[cx1].a = cx2 + 1;//把then语句填0的跳转位置改成当前位置,完成if语句的处理
code[cx2].a = cx;//把else填0的跳转位置改成当前位置,完成else语句的处理
}
}
else
if (sym == SYM_BEGIN) //如果遇到begin
{
getsym(); //获取下一个token
set1 = createset(SYM_SEMICOLON, SYM_END, SYM_NULL);
set = uniteset(set1, fsys);
statement(set); //对begin与end之间的语句进行分析处理
while (sym == SYM_SEMICOLON || inset(sym, statbegsys))
{ //如果分析完一句后遇到分号或语句开始符循环分析下一句语句
if (sym == SYM_SEMICOLON) //如果语句是分号(可能是空语句)
getsym(); //获取下一token继续分析
else
error(10); //如果语句与语句间没有分号,出10号错
statement(set); //分析一个语句
}
destroyset(set1);
destroyset(set);
if (sym == SYM_END)//如果语句全分析完了,应该遇到end
getsym(); // 的确是end,读下一token
else
error(17);
}
else
if (sym == SYM_WHILE)//如果遇到while语句
{
cx1 = cx; //记下当前代码分配位置,这是while循环的开始位置
getsym(); //获取下一token,应为一逻辑表达式
set1 = createset(SYM_DO, SYM_NULL);
set = uniteset(set1, fsys);
condition(set); //对这个逻辑表达式进行分析计算
destroyset(set1);
destroyset(set);
cx2 = cx; //记下当前代码分配位置,这是while的do中的语句的开始位置
gen(JPC, 0, 0); // 生成条件跳转指令,跳转位置暂时填0
if (sym == SYM_DO) //逻辑表达式后应为do语句
getsym(); //获取下一token
else
error(18); //if后缺少then,抛出18号错误
statement(fsys); //分析do后的语句块
gen(JMP, 0, cx1); //循环跳转到cx1位置,即再次进行逻辑判断
code[cx2].a = cx; //把刚才填0的跳转位置改成当前位置,完成while语句的处理
}
else
if(sym == SYM_READ) // 如果不是赋值语句,而是遇到了read语句
{
getsym();//获得下一token,正常情况下应为左括号
if(sym != SYM_LPAREN) //如果read语句后跟的不是左括号
error(40);
else //循环得到read语句括号中的参数表,依次产生相应的“从键盘读入”目标代码
{
do
{
getsym(); //获得一个token,正常应是一个变量名
if (sym == SYM_IDENTIFIER) //如果确为一个标识符
{
if (! (i = position(id))) //查符号表,找到它所在位置给i,找不到时i会为0
error(11);
else
if( table[i].kind!=ID_VARIABLE) //判别类型是否为标识符
{
error(12);
i=0;
}
else
{
mk = (mask*) &table[i];
gen(RED, level - mk->level, mk->address); //生成red指令,把读入的值存入指定变量所在的空间
}
}
else
error(4);
getsym();
}while(sym==SYM_COMMA);//不断生成代码直到read语句的参数表中的变量遍历完为止
if(sym!=SYM_RPAREN)
error(22);
getsym(); //如果read语句正常结束,得到下一个token,一般为分号或end
}
}
else
if(sym == SYM_WRITE)// 如果不是赋值语句,而是遇到了write语句
{
getsym(); //获取下一token,应为左括号
if(sym != SYM_LPAREN)//如果write语句后跟的不是左括号
error(40);
else
{
do
{ //依次获取括号中的每一个值,进行输出
getsym();
set1 =createset(SYM_RPAREN, SYM_COMMA, SYM_NULL);
set=uniteset(set1,fsys);
expression(set);
gen(WRT,0,0);//生成wrt指令,把读入的值存入指定变量所在的空间
}while(sym==SYM_COMMA);
if(sym!=SYM_RPAREN)//如果不是右括号
error(22);
getsym();//正常情况下要获取下一个token,为后面准备好
}
}
else
if(sym == SYM_FOR)//for循环语句
{
getsym();
if(sym != SYM_IDENTIFIER)
error(25);
strcpy(ida, id); //用另一个ida记录当前读到的IDENTIFIER
set1 = createset(SYM_TO, SYM_DOWNTO, SYM_NULL);
set = uniteset(set1, fsys);
statement(set);
destroyset(set1);
destroyset(set);
if((sym != SYM_TO) && (sym != SYM_DOWNTO))
error(26);
q=sym; //记录下当前所读到的字符
cx1=cx;//记下当前代码分配位置,这是to/downto语句的开始位置
gen(JMP,0,0);//产生一行跳转指令,跳转位置暂时未知填0
getsym();
set1 =createset(SYM_DO,SYM_BY,SYM_NULL);
set=uniteset(set1,fsys);
expression(set);
if((sym != SYM_DO) && (sym != SYM_BY))
error(27);
strcpy(id, ida);//将ida记录下的IDENTIFIER拷贝给id
i=position(id);
if(i==0)
error(11);
else
if( table[i].kind!=ID_VARIABLE)//判别类型是否为变量
{
error(12);
i=0;
}
else
{
mk = (mask*) &table[i];
gen(LOD, level - mk->level, mk->address);//生成lod指令,把读入的值存入指定变量所在的空间
if(sym == SYM_BY)
{ //对by后的表达式进行判断
getsym();
//如果前一个字符为downto,则by后的sym应为SYM_MINUS,否则出错
//如果前一个字符为to,则by后的sym应为SYM_PLUS,否则出错
if(( sym==SYM_MINUS) || ( sym == SYM_PLUS))
{
set1 =createset(SYM_DO, SYM_NULL);
set=uniteset(set1,fsys);
expression(set);
if(sym != SYM_DO)
error(28);
}
else
{
if(q==SYM_DOWNTO)
error(35);
else
if(q==SYM_TO)
error(36);
}
}
else //当没有by时,执行默认处理指令
{
gen(LIT,0,1);
//downto默认执行1号操作
if(q==SYM_DOWNTO)
gen(OPR,0,1);
}
gen(OPR,0,2);
mk = (mask*) &table[i];
gen(STO,level - mk->level, mk->address);//生成sto指令,把读入的值存入指定变量所在的空间
gen(LOD,level - mk->level, mk->address);//生成lod指令,把读入的值存入指定变量所在的空间
if(q==SYM_TO)//to默认执行11号操作
gen(OPR,0,11);
else
gen(OPR,0,13);
cx2=cx;//记下当前代码分配位置
gen(JPC,0,0);//生成条件跳转指令,跳转位置暂时填0,分析完语句后再填写
code[cx1].a=cx;//把刚才填0的跳转位置改成当前位置
getsym();
statement(fsys);
gen(JMP,0,cx1+1);//循环跳转到cx1+1位置,即再次进行逻辑判断
code[cx2].a=cx;//把刚才填0的跳转位置改成当前位置
}
}
else
if(sym ==SYM_REPEAT) //重复语句
{
cx1 = cx; //记下当前代码分配位置,这是repeat语句的开始位置
getsym();
set1 = createset(SYM_SEMICOLON, SYM_UNTIL, SYM_NULL);
set = uniteset(set1, fsys);
statement(set);
while (sym == SYM_SEMICOLON || inset(sym, statbegsys))
{
if (sym == SYM_SEMICOLON) //判别是否为‘;’
getsym();
else
error(10);
statement(set);
}
destroyset(set1);
destroyset(set);
if (sym == SYM_UNTIL)
{
getsym();
condition(fsys);
gen(JPC, 0, cx1);//生成条件跳转指令,跳转位置填cx1
}
else
error(29);
}
else
test(fsys, phi, 19); //至此一个语句处理完成,一定会遇到fsys集中的符号,如果没有遇到,就抛19号错
}
///////////////////////////////////////////////////////////////////////////////////////////
//表达式分析处理
void expression(symset fsys)
{
int addop;
symset set;
set = uniteset(fsys, createset(SYM_PLUS, SYM_MINUS, SYM_NULL));
if (sym == SYM_PLUS || sym == SYM_MINUS)//一个表达式可能会由加号或减号开始,表示正负号
{
addop = sym;//把当前的正号或负号保存起来,以便下面生成相应代码
getsym();// 获取一个token
term(set); //正负号后面应该是一个项,调term子程序分析
if (addop == SYM_MINUS) //如果保存下来的符号是负号
gen(OPR, 0, 1); //生成一条1号操作指令:取反运算
//如果不是负号就是正号,不需生成相应的指令
}
else //如果不是由正负号开头,就应是一个项开头
term(set);//调用term子程序分析项
while (sym == SYM_PLUS || sym == SYM_MINUS) //项后应是加运算或减运算
{
addop = sym; //把运算符保存下来
getsym(); //获取下一个token,加减运算符后应跟的是一个项
term(set); //调term子程序分析项
if (addop == SYM_PLUS) //如果项与项之间的运算符是加号
gen(OPR, 0, 2); //生成2号操作指令:加法
else //否则是减法
gen(OPR, 0, 3); //生成3号操作指令:减法
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -