2.2.1
1)
S1 = aa+
S2 = S1a*
2) *
+
a a a
3)该文法生成的语言是由+和*组成的后缀表达式,怎么证明呢?
2.2.2 同不懂怎么证明
1)前面n个0后面n个1组成的串
2)+/-组成的关于a计算的前缀表达式
3)空串或成对出现的单个或嵌套括号组成的表达式
4)空串或a和b组成的任意表达式
5)由+连接起来的1个或多个a,可以加括号,每个a后面可以有0个或多个*
2.2.3
1)没有二义性
2)有,跟例2.1中语法一样
3)没有
4)有,ab可以随意结合
5)有,S+S和SS无法确定如何结合
2.2.4
1)S -> SS+|SS-|SS*|SS/|a
2)left -> left,expr | expr
3)right -> expr,right|expr
4)这道题中文版翻译有误,应该将书中“标识符”去掉。
expr -> expr+term | expr-term|term
term -> term*factor | term/factor|factor
factor -> digits
digits -> digitdigit|digit
5)+ -单目运算符优先级应该最高
expr -> expr+term1 | expr-term1|term1
term1 -> term1*term2 | term1/term2|term2
term2 -> -factor | +factor|factor
factor -> digits
digits -> digitdigit|digit
2.2.5 根据提示,采用数学归纳法证明如下:
如果节点数是1,显然 11 1001都能被3整除
如果节点数是2,110 10010 1111 10011001都能被3整除
假设节点数小于等于n的情况所有二进制串都能被3整除,则n+1个节点的所有串可能有以下情况
1.节点数为n的串后面加个0,记为Sn0 = Sn*2,显然能被3整除
2.SiSj,SiSj分别表示节点数为i和j的串,则SiSj = Si*2^j+Sj,根据假设,Si和Sj都能被3整除,所以SiSj能被3整除
2.2.6
背景知识 : http://baike.baidu.com/view/42061.htm
首先需要知道罗马数字的表示方法
I、V、X、L、C、D、M
分别表示1 5 10 50 100 500 1000
罗马数字上下文无关文法如下:
number -> digit digit| digit
digit -> I | V | X | L | C | D | M
2.3.1同图2-10,只是前2行不同:
expr->expr1+term expr.t = '+'|expr1.t|term.t
expr->expr1-term expr.t = '-'|expr1.t|term.t
expr->term
term->term1*factor term.t = '*'|term1.t|factor.t
term->term1/factor term.t = '/'|term1.t|factor.t
term->factor
9-5+2
expr.t = +-952
expr.t = -95 + factor.t = 2
expr.t = -9*52
factor.t = 9 - expr.t = *52
factor.t = 5 - factor.t = 2
2.3.2 跟2.3.1差不多
2.3.3 求解
2.3.4 求解
2.3.5 可以分2步实现,先转成中缀,然后转成前缀
2.4.1
1)
void S() { switch( lookahead ) { case +: match(+); S(); S(); break; case -: match(-); S(); S(); break; case a: match(a); break; default:report("syntax error"); } }
2)这种情况就不要用switch了,if比较适合,要注意消除递归,消除方法是在开始加一系列判断,错误处理比较复杂,下面没加,如果要加该怎么处理呢??
void S() { if(lookahead==NULL) return; if(lookahead=='(' && lookahead+1==')') {match('('); match(')');return;S()math('(')S()match(')')S()}
3)两个产生式的FIRST都是0,需要注意,不过相比较2),容易实现
void S() { if(lookahead==0) { match(0); if(lookahead!=1) S(); match(1); } else report("syntax error"); }
2.6.1
1)类似判断数字,连续读入 ‘/’ ‘/’认为是注释
2)类似判断数字,读入‘/’ ‘*’ 以后判断 ‘*’ ‘/’,否则认为是错误
2.6.2 只需要再scan函数中添加类似数字,字母的判断即可
2.6.3 只需在scan判断数字的区域中添加相关代码即可
57页的top:如果把符号表看成一颗数,top表示当前使用的叶子,书中57页第2行符号表链的顶部表示的就是这个意思
package inter; import symbols.*; public class For extends Stmt { Expr expr1; Expr expr2; Expr expr3; Stmt stmt; public If(Expr x1, Expr x2, Expr x3, Stmt s) { expr1 = x1; expr2 = x2; expr3 = x3; stmt = s; if( expr2.type != Type.Bool ) expr.error("boolean required in For"); } public void gen(int b, int a) { int label1 = newlabel(); int label2 = newlavel(); emit(expr1.toString()); emit(label1+":"); Expr n=expr1.rvalue(); emit("ifFalse"+n.toString()+"goto"+label2) stmt.gen(); emit(expr3.toString()); emit("goto"+label1); emit(label2+":"); } }