📄 symtax.cpp
字号:
{
symbol addop;
CSymset symset;
symset += fsys;
symset += plus;
symset += minus;
if ( sym==plus||sym==minus ) //一个表达式可能会由加号或减号开始,表示正负号
{
addop=sym; //把当前的正号或负号保存起来,以便下面生成相应代码
getsym();
term(symset); //正负号后面应该是一个项,调term子程序分析
if (addop==minus)
pl->code->Gen(opr,0,1); //如果保存下来的符号是负号,生成一条1号操作指令:取反运算
}
else
term(symset); //如果不是由正负号开头,就应是一个项开头
while (sym==plus||sym==minus) //项后应是加运算或减运算
{
addop=sym;
getsym(); //获取下一个token,加减运算符后应跟的是一个项
term(symset);
if (addop==plus)
pl->code->Gen(opr,0,2); //生成2号操作指令:加法
else
pl->code->Gen(opr,0,3); //生成3号操作指令:减法
}
}
//条件处理过程condition
void CSymtax::condition(CSymset fsys)
{
symbol relop; //用于临时记录token(这里一定是一个二元逻辑运算符)的内容
CSymset s1,s2;
s1+=eql;
s1+=neq;
s1+=lss;
s1+=leq;
s1+=gtr;
s1+=geq;
if (sym==oddsym) //如果是odd运算符(一元)
{
getsym();
expression(fsys); //对odd的表达式进行处理计算
pl->code->Gen(opr,0,6); //生成6号操作指令:奇偶判断运算
}
else
{
s2+=s1;
expression(s2+=fsys); //对表达式左部进行处理计算
if (!s1.InSet(sym))
pl->errors->Add(20); //如果token不是逻辑运算符中的一个
else
{
relop=sym;
getsym();
expression(fsys); //对表达式右部进行处理计算
switch (relop)
{
case eql:
pl->code->Gen(opr,0,8);
break; //等号:产生8号判等指令
case neq:
pl->code->Gen(opr,0,9);
break; //不等号:产生9号判不等指令
case lss:
pl->code->Gen(opr,0,10);
break; //小于号:产生10号判小指令
case geq:
pl->code->Gen(opr,0,11);
break; //大于等号号:产生11号判不小于指令
case gtr:
pl->code->Gen(opr,0,12);
break; //大于号:产生12号判大于指令
case leq:
pl->code->Gen(opr,0,13);
break; //小于等于号:产生13号判不大于指令
}
}
}
}
void CSymtax::statement(CSymset fsys)
{
int i,cx1,cx2;
table_type *table = pl->form->table;
CErrors *err = pl->errors;
CCode *cd = pl->code;
CSymset s,s2;
switch (sym)
{
case ident: //所谓"语句"可能是赋值语句,以标识符开头
i = pl->form->Position(pl->wording->id); //在符号表中查到该标识符所在位置
if (i==0)
err->Add(11); //没有找到
else if (table[i].kind!=variable)
{
err->Add(12); //如果在符号表中找到该标识符,但该标识符不是变量名
i=0;
}
getsym();
if (sym==becomes) //获得下一个token,正常应为赋值号
getsym();
else
err->Add(13); //处理表达式
expression(fsys);
if (i>0)
cd->Gen(sto,lev-table[i].level,table[i].adr); //产生一行把表达式值写往指定内存的sto目标代码
break;
case readsym: //遇到了read语句
getsym();
if (sym!=lparen) //获得下一token,正常情况下应为左括号
err->Add(34);
else
do{
getsym(); //获得一个token,正常应是一个变量名
i = (sym==ident) ? pl->form->Position(pl->wording->id) : 0;
if (i==0)
err->Add(35);
else
{
cd->Gen(opr,0,16); //生成16号操作指令:从键盘读入数字
cd->Gen(sto,lev-table[i].level,table[i].adr); //生成sto指令,把读入的值存入指定变量所在的空间
}
getsym();
}while (sym==comma); //获取下一个token,如果是逗号,则read语还没完,否则应当是右括号
if (sym!=rparen)
{
err->Add(33);
while (fsys.InSet(sym))
getsym();
}
else getsym(); //如果read语句正常结束,得到下一个token,一般为分号或end
break;
case writesym: //如果遇到了write语句
s=fsys;
s+=rparen;
s+=comma;
getsym(); //获取下一token,应为左括号
if (sym==lparen)
{
do{
getsym();
expression(s); //调用expression过程分析表达式,用于出错恢复的集合中加上右括号和逗号
pl->code->Gen(opr,0,14); //生成14号指令:向屏幕输出
}while (sym==comma);
if (sym!=rparen)
err->Add(33);
else
getsym();
}
cd->Gen(opr,0,15); //生成一个15号操作的目标代码,功能是输出一个换行
break;
case callsym: //如果是call语句
getsym();
if (sym!=ident) //获取token,应是过程名型标识符
err->Add(14);
else
{
i = pl->form->Position(pl->wording->id);
if (i==0) err->Add(11);
else if (table[i].kind==procedure)
cd->Gen(cal,lev-table[i].level,table[i].adr); //生成cal目标代码,呼叫这个过程
else
err->Add(15);
getsym();
}
break;
case ifsym: //如果是if语句
s=fsys;
s+=thensym;
s+=dosym;
getsym();
condition(s); //对逻辑表达式进行分析计算,出错恢复集中加入then和do语句
if (sym==thensym)
getsym(); //获取then后的token,应是一语句
else
err->Add(16);
cx1 = cd->cx; //记下当前代码分配指针位置
cd->Gen(jpc,0,0); //生成条件跳转指令,跳转位置暂时填0,分析完语句后再填写
s = fsys;
s += elsesym;
statement(s); //分析then后的语句
if (sym==elsesym) //如果后面是else语句
{
getsym();
cx2=cd->cx; //记下当前代码分配指针位置
cd->Gen(jmp,0,0);
statement(fsys);
cd->code[cx1].a = cx2+1;
cd->code[cx2].a = cd->cx;
}
else
cd->code[cx1].a = cd->cx; //上一行指令(cx1所指的)的跳转位置应为当前cx所指位置
break;
case beginsym: //如果遇到begin
s=fsys;
s+=semicolon;
s+=endsym;
s2=statbegsys;
s2+=semicolon;
getsym();
statement(s); //对begin与end之间的语句进行分析处理
while (s2.InSet(sym)) //如果分析完一句后遇到分号或语句开始符循环分析下一句语句
{
if (sym==semicolon) //如果语句是分号(可能是空语句)
getsym();
else
err->Add(10);
statement(s);
}
if (sym==endsym)
getsym();
else
err->Add(17);
break;
case whilesym: //如果遇到while语句
cx1=cd->cx; //记下当前代码分配位置,这是while循环的开始位置
getsym();
s=fsys;
s+=dosym;
condition(s); //对这个逻辑表达式进行分析计算
cx2=cd->cx; //记下当前代码分配位置,这是while的do中的语句的开始位置
cd->Gen(jpc,0,0); //生成条件跳转指令,跳转位置暂时填0
if (sym==dosym) //逻辑表达式后应为do语句
getsym();
else
err->Add(18);
statement(fsys); //分析do后的语句块
cd->Gen(jmp,0,cx1); //循环跳转到cx1位置,即再次进行逻辑判断
cd->code[cx2].a = cd->cx; //把刚才填0的跳转位置改成当前位置,完成while语句的处理
break;
case repeatsym:
getsym();
s=fsys;
s+=semicolon;
s+=untilsym;
cx1=cd->cx; //记下当前代码分配位置,这是while循环的开始位置
statement(s); //分析repeat后的语句块
s2=statbegsys;
s2+=semicolon;
while (s2.InSet(sym)) //如果分析完一句后遇到分号或语句开始符循环分析下一句语句
{
if (sym==semicolon)
getsym();
else
err->Add(10);
statement(s);
}
if (sym==untilsym)
{
getsym();
condition(fsys); //对这个逻辑表达式进行分析计算
cd->Gen(jpc,0,cx1); //生成条件跳转指令,跳转位置为循环位置之前
}
else
err->Add(25);
break;
}
test(fsys,CSymset(),19); //至此一个语句处理完成,一定会遇到fsys集中的符号,如果没有遇到,就抛19号错
}
CSymtax::~CSymtax(void)
{
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -