编译原理龙书第四章部分习题(编译原理作业三)

编译原理作业3

所有题目均为自己所写,觉得有用可以点个赞哟:-)
答案仅供参考,若有问题欢迎评论区讨论~

4.2.1

考虑上下文无关文法:S ->SS+|SS*|a,以及串aa + a*

(1)给出这个串的一个最左推导。

(2)给出这个串的一个最右推导。

(3)给出这个串的一棵语法分析树。


(1)最左推导:

S->SS*

->SS+S*

->aS+S*

->aa+S*

->aa+a*

(2)最右推导:

S->SS*

->Sa*

->SS+a*

->Sa+a*

->aa+a*

(3)语法分析树

4.2.2

对下列的每一对文法和串重复练习4.2.1

  • S->0S1 | 01和串000111。

  • S->+SS | *SS |a和串+*aaa。

  • S->S(S)S | ε 和串(()())

  • S->(L) | a以及L->L,S | S和串((a, a), a, (a))。


  • 1. S->0S1 | 01和串000111

(1)最左推导:

S->0S1

->00S11

->000111

(2)最右推导:

S->0S1

->00S11

->000111

(3)语法分析树

  • S->+SS | *SS |a和串+*aaa

(1)最左推导:

S->+SS

->+*SSS

->+*aSS

->+*aaS

->+*aaa

(2)最右推导:

S->+SS

->+Sa

->+*SSa

->+*Saa

->+*aaa

(3)语法分析树

  • S->S(S)S | ε 和串(()())

(1)最左推导:

S->S(S)S

->(S)S

->(S(S)S)S

->((S)S)S

->(()S)S

->(()S(S)S)S

->(()(S)S)S

->(()()S)S

->(()())S

->(()())

(2)最右推导:

S->S(S)S

->S(S)

->S(S(S)S)

->S(S(S))

->S(S())

->S(S(S)S())

->S(S(S)())

->S(S()())

->S(()())

->(()())

(3)语法分析树:

  • S->(L) | a以及L->L,S | S和串((a, a), a, (a))

(1)最左推导:

S->(L)

->(L,S)

->(L,S,S)

->(S,S,S)

->((L),S,S)

->((L,S),S,S)

->((S,S),S,S)

->((a,S),S,S)

->((a,a),S,S)

->((a,a),a,S)

->((a,a),a,(L))

->((a,a),a,(s))

->((a,a),a,(a))

(2)最右推导:

S->(L)

->(L,S)

->(L,(L))

->(L,(S))

->(L,(a))

->(L,S,(a))

->(L,a,(a))

->(S,a,(a))

->((L),a,(a))

->((L,S),a,(a))

->((L,a),a,(a))

->((S,a),a,(a))

->((a,a),a,(a))

(3)语法分析树

4.2.3

为下面的语言设计文法

(1)所有由0和1组成的并且每个0之后都至少跟着一个1的串的集合。

(2)所有由0和1组成的回文的集合,也就是从前面和从后面读结果都相同的串的集合。


(1)

很容易想到正则表达式为:(0?1)*

但文法应该是:

S->ST

T->01

|1

这个串可以为空,或者是若干个T相连,每个T是01或者1,刚好符合题意。

(2)

s-> 0s0

| 1s1

| 0

| 1

| ε

4.2.5

使用练习4.2.4中描述的括号表示法来简化如下的关于语句块和条件语句的文法。

stmt-> if expr then stmt else stmt

​ | if expr then stmt

​ | begin stmtList end

stmtList-> stmt ; stmtList | stmt


stmt-> if expr then stmt [else stmt]

​ | begin stmtList end

stmtList-> stmt[; stmtList]

stmtList->stmt{;stmt}

4.4.1

为下面的每一个文法设计一个预测分析器,并给出预测分析表。你可能先要对文法进行提取左公因子或消除左递归的操作。

1. 练习4.2.2(1)中的文法。

2. 练习4.2.2(2)中的文法。

3. 练习4.2.2(3)中的文法。

4. 练习4.2.2(5)中的文法。


  • S->0S1 | 01

提取左公因子:

S->0S’

S’->S1

| 1

FIRST/FOLLOW/NULLABLE集:

FIRSTFOLLOWNULLABLE
S{0}{1}FALSE
S’{0,1}{1}FALSE

预测分析表:

01
SS->0S’
S’S’->S1S’->1
  • S->+SS | *SS |a

FIRST/FOLLOW/NULLABLE集:

FIRSTFOLLOWNULLABLE
S{+,*,a}{+,*,a}FALSE

预测分析表:

+*a
SS->+SSS->*SSS->a
  • S->S(S)S | ε

消除左递归:

S->S’

S’->(S)SS’

| ε

FIRST/FOLLOW/NULLABLE集:

FIRSTFOLLOWNULLABLE
S{(,),$,ε}{(,),$,ε}TRUE
S’{(,),$,ε}{(,),$,ε}TRUE

预测分析表:

()$
SS->S’S->S’S->S’
S’S’->(S)SS’
S’->ε
S’->εS’->ε
  • S->(L) | a以及L->L,S | S

消除左递归:

S->(L)

|a

L->SL’

L’->,SL’

FIRST/FOLLOW/NULLABLE集:

FIRSTFOLLOWNULLABLE
S{(,a}{,,),ε}(第一个是逗号)FALSE
L{(,a}{)}FALSE
L’{,,),ε}{)}TRUE

预测分析表:

(),a
SS->(L)S->a
LL->SL’L->SL’
L’L’->εL’->,SL’

4.4.4

计算练习4.2.2中各个文法的FIRST和FOLLOW集合。


  • S->0S1 | 01
FIRSTFOLLOW
S{0}{1,$}
  • S->+SS | *SS |a
FIRSTFOLLOW
S{+,*,a}{+,*,a,$}
  • S->S(S)S | ε
FIRSTFOLLOW
S{(,ε}{(,),$}
  • S->(L) | a以及L->L,S | S
FIRSTFOLLOW
S{(,a}{,,),$}(第一个是逗号)
L{(,a}{,,)}(第一个是逗号)

4.6.5

说明下面的文法

S->AaAb | BbBa

A->ε

B->ε

是LL(1)的,但不是SLR(1)的。


(1)该文法是LL(1)的

文法G⇔LL(1),当且仅当G中的任意两条产生式A->α|β满足下列条件

  • 当α与β不能都推导出ε,则FIRST(α)与FIRST(β)不相交
  • 当α或β能推导出ε
  • 当α能推导出ε,则FIRST(β)与FOLLOW(A)不相交
  • 当β能推导出ε,则FIRST(α)与FOLLOW(A)不相交

AaAb与BbBa不能都推导出ε,FIRST(AaAb) = {a},FIRST(BbBa) = {b},不相交,所以该文法是LL(1)的。

(2)该文法不是SLR(1)的

S_0状态:

S-> · AaAb

S-> · BbBa

A-> · ε

B-> · ε

接受一个ε,可以直接到达S_1:

A->ε·

B->ε·

此时就会发生规约冲突,所以该文法不是SLR(1)的。

4.6.6

说明下面的文法

S->SA | A

A->a

是SLR(1)的,但不是LL(1)的。


(1)该文法是SLR(1)的

构造增广文法:

0: S’->S$

1: S->SA

2: | A

3: A->a

S_0状态:

S’->·S$

S->·SA

S->·A

A->·a

S_0状态吃入S到达S_1状态:

S’->S·$

S->S·A

A->·a

S_0状态吃入A到达S_2状态:

S->A·

S_0状态吃入a到达S_3状态:

A->a·

S_1状态吃入A到达S_4状态:

S->SA·

S_1状态吃入a到达S_3状态:

A->a·

FOLLOW(S) = {a,$},FOLLOW(A) = {$}。

该文法的SLR分析表如下:

动作动作转移转移
状态/符号a$SA
S_0s3g1g2
S_1s3Acceptg4
S_2r2r2
S_3r3
S_4r1r1

该文法的SLR分析表没有冲突,所以该文法是SLR(1)的

(2)该文法不是LL(1)的

文法G是LL(1)的条件已经在4.6.5中给出。

对于产生式S->SA|A,SA与A不能都推导出ε,FIRST(SA) = {a},FIRST(A) = {a},相交,所以该文法不是LL(1)的。

4.7.2

为练习4.2.2(5)的文法

S->(L)

|a

L->L,S

|S

构造 1)规范LR项集族;2)LALR项集族。


构造增广文法:

S’->S$

S->(L)

|a

L->L,S

|S

(1)规范LR项集族

(2)LALR项集族

LALR即对LR(1)进行合并同心项。先看一下LR(1)中可以合并的产生式集(已经用相同的颜色标出):

2-6,3-7,4-10,8-12可合并。

合并之后得LALR项集族:

4.7.5

说明下面的文法

S->Aa | bAc | Bc | bBa

A->d

B->d

是LR(1)的,但不是LALR(1)的。


构造增广文法:

S’->S$

S->Aa

|bAc

|Bc

|bBa

A->d

B->d

(1)LR(1)项集族如图:

没有冲突,故该文法是LR(1)的。

(2)合并前:

LALR(1)项集族如图:

可以看出,在状态5下,会产生规约-规约冲突,故该文法不是LALR(1)的。

笔记:

  • 自底向上的语法分析都不用进行消除左递归/提取左公因子的处理。

  • 语义分析要注意构造增广文法(S’->S$)

PS:(所有题目均为自己所做,图和表均为自己所画,为了美观草稿纸就不往上贴了~)

  • 43
    点赞
  • 267
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
编译原理答案 完整性高 第二章 2.2 Exercises for Section 2.2 2.2.1 Consider the context-free grammar: S -> S S + | S S * | a Show how the string aa+a* can be generated by this grammar. Construct a parse tree for this string. What language does this grammar generate? Justify your answer. answer S -> S S * -> S S + S * -> a S + S * -> a a + S * -> a a + a * L = {Postfix expression consisting of digits, plus and multiple signs} 2.2.2 What language is generated by the following grammars? In each case justify your answer. S -> 0 S 1 | 0 1 S -> + S S | - S S | a S -> S ( S ) S | ε S -> a S b S | b S a S | ε ⧗ S -> a | S + S | S S | S * | ( S ) answer L = {0n1n | n>=1} L = {Prefix expression consisting of plus and minus signs} L = {Matched brackets of arbitrary arrangement and nesting, includes ε} L = {String has the same amount of a and b, includes ε} ? 2.2.3 Which of the grammars in Exercise 2.2.2 are ambiguous answer No No Yes Yes Yes 2.2.4 Construct unambiguous context-free grammars for each of the following languages. In each case show that your grammar is correct. Arithmetic expressions in postfix notation. Left-associative lists of identifiers separated by commas. Right-associative lists of identifiers separated by commas. Arithmetic expressions of integers and identifiers with the four binary operators +, - , *, /. answer 1. E -> E E op | num 2. list -> list , id | id 3. list -> id , list | id 4. expr -> expr + term | expr - term | term term -> term * factor | term / factor | factor factor -> id | num | (expr) 5. expr -> expr + term | expr - term | term term -> term * unary | term / unary | unary unary -> + factor | - factor factor - > id | num | (expr) 2.2.5 Show that all binary strings generated by the following grammar have values divisible by 3. Hint. Use induction on the number of nodes in a parse tree. num -> 11 | 1001 | num 0 | num num Does the grammar generate all binary strings with values divisible by 3? answer prove any string derived from the grammar can be considered to be a sequence consisting of 11, 1001 and 0, and not prefixed with 0. the sum of this string is: sum = Σn (21 + 20) * 2 n + Σm (23 + 20) * 2m = Σn 3 * 2 n + Σm 9 * 2m It is obviously can divisible by 3. No. Consider string "10101", it is divisible by 3, but cannot derived from the grammar. Question: any general prove? 2.2.6 Construct a context-free grammar for roman numerals. Note: we just consider a subset of roman numerals which is less than 4k. answer wikipedia: Roman_numerals via wikipedia, we can categorize the single noman numerals into 4 groups: I, II, III | I V | V, V I, V II, V III | I X then get the production: digit -> smallDigit | I V | V smallDigit | I X smallDigit -> I | II | III | ε and we can find a simple way to map roman to arabic numerals. For example: XII => X, II => 10 + 2 => 12 CXCIX => C, XC, IX => 100 + 90 + 9 => 199 MDCCCLXXX => M, DCCC, LXXX => 1000 + 800 + 80 => 1880 via the upper two rules, we can derive the production: romanNum -> thousand hundred ten digit thousand -> M | MM | MMM | ε hundred -> smallHundred | C D | D smallHundred | C M smallHundred -> C | CC | CCC | ε ten -> smallTen | X L | L smallTen | X C smallTen -> X | XX | XXX | ε digit -> smallDigit | I V | V smallDigit | I X smallDigit -> I | II | III | ε 2.3 Exercises for Section 2.3 2.3.1 Construct a syntax-directed translation scheme that trans­ lates arithmetic expressions from infix notation into prefix notation in which an operator appears before its operands; e.g. , -xy is the prefix notation for x - y . Give annotated parse trees for the inputs 9-5+2 and 9-5*2.。 answer productions: expr -> expr + term | expr - term | term term -> term * factor | term / factor | factor factor -> digit | (expr) translation schemes: expr -> {print("+")} expr + term | {print("-")} expr - term | term term -> {print("*")} term * factor | {print("/")} term / factor | factor factor -> digit {print(digit)} | (expr) 2.3.2 Construct a syntax-directed translation scheme that trans­ lates arithmetic expressions from postfix notation into infix notation. Give annotated parse trees for the inputs 95-2* and 952*-. answer productions: expr -> expr expr + | expr expr - | expr expr * | expr expr / | digit translation schemes: expr -> expr {print("+")} expr + | expr {print("-")} expr - | {print("(")} expr {print(")*(")} expr {print(")")} * | {print("(")} expr {print(")/(")} expr {print(")")} / | digit {print(digit)} Another reference answer E -> {print("(")} E {print(op)} E {print(")"}} op | digit {print(digit)} 2.3.3 Construct a syntax-directed translation scheme that trans­ lates integers into roman numerals answer assistant function: repeat(sign, times) // repeat('a',2) = 'aa' translation schemes: num -> thousand hundred ten digit { num.roman = thousand.roman || hundred.roman || ten.roman || digit.roman; print(num.roman)} thousand -> low {thousand.roman = repeat('M', low.v)} hundred -> low {hundred.roman = repeat('C', low.v)} | 4 {hundred.roman = 'CD'} | high {hundred.roman = 'D' || repeat('X', high.v - 5)} | 9 {hundred.roman = 'CM'} ten -> low {ten.roman = repeat('X', low.v)} | 4 {ten.roman = 'XL'} | high {ten.roman = 'L' || repeat('X', high.v - 5)} | 9 {ten.roman = 'XC'} digit -> low {digit.roman = repeat('I', low.v)} | 4 {digit.roman = 'IV'} | high {digit.roman = 'V' || repeat('I', high.v - 5)} | 9 {digit.roman = 'IX'} low -> 0 {low.v = 0} | 1 {low.v = 1} | 2 {low.v = 2} | 3 {low.v = 3} high -> 5 {high.v = 5} | 6 {high.v = 6} | 7 {high.v = 7} | 8 {high.v = 8} 2.3.4 Construct a syntax-directed translation scheme that trans­ lates roman numerals into integers. answer productions: romanNum -> thousand hundred ten digit thousand -> M | MM | MMM | ε hundred -> smallHundred | C D | D smallHundred | C M smallHundred -> C | CC | CCC | ε ten -> smallTen | X L | L smallTen | X C smallTen -> X | XX | XXX | ε digit -> smallDigit | I V | V smallDigit | I X smallDigit -> I | II | III | ε translation schemes: romanNum -> thousand hundred ten digit {romanNum.v = thousand.v || hundred.v || ten.v || digit.v; print(romanNun.v)} thousand -> M {thousand.v = 1} | MM {thousand.v = 2} | MMM {thousand.v = 3} | ε {thousand.v = 0} hundred -> smallHundred {hundred.v = smallHundred.v} | C D {hundred.v = smallHundred.v} | D smallHundred {hundred.v = 5 + smallHundred.v} | C M {hundred.v = 9} smallHundred -> C {smallHundred.v = 1} | CC {smallHundred.v = 2} | CCC {smallHundred.v = 3} | ε {hundred.v = 0} ten -> smallTen {ten.v = smallTen.v} | X L {ten.v = 4} | L smallTen {ten.v = 5 + smallTen.v} | X C {ten.v = 9} smallTen -> X {smallTen.v = 1} | XX {smallTen.v = 2} | XXX {smallTen.v = 3} | ε {smallTen.v = 0} digit -> smallDigit {digit.v = smallDigit.v} | I V {digit.v = 4} | V smallDigit {digit.v = 5 + smallDigit.v} | I X {digit.v = 9} smallDigit -> I {smallDigit.v = 1} | II {smallDigit.v = 2} | III {smallDigit.v = 3} | ε {smallDigit.v = 0} 2.3.5 Construct a syntax-directed translation scheme that trans­ lates postfix arithmetic expressions into equivalent prefix arithmetic expressions. answer production: expr -> expr expr op | digit translation scheme: expr -> {print(op)} expr expr op | digit {print(digit)} Exercises for Section 2.4 2.4.1 Construct recursive-descent parsers, starting with the follow­ ing grammars: S -> + S S | - S S | a S -> S ( S ) S | ε S -> 0 S 1 | 0 1 Answer 1) S -> + S S | - S S | a void S(){ switch(lookahead){ case "+": match("+"); S(); S(); break; case "-": match("-"); S(); S(); break; case "a": match("a"); break; default: throw new SyntaxException(); } } void match(Terminal t){ if(lookahead = t){ lookahead = nextTerminal(); }else{ throw new SyntaxException() } } 2) S -> S ( S ) S | ε void S(){ if(lookahead == "("){ S(); match("("); S(); match(")"); S(); } } 3) S -> 0 S 1 | 0 1 void S(){ switch(lookahead){ case "0": match("0"); S(); match("1"); break; case "1": // match(epsilon); break; default: throw new SyntaxException(); } } Exercises for Section 2.6 2.6.1 Extend the lexical analyzer in Section 2.6.5 to remove com­ ments, defined as follows: A comment begins with // and includes all characters until the end of that line. A comment begins with /* and includes all characters through the next occurrence of the character sequence */. 2.6.2 Extend the lexical analyzer in Section 2.6.5 to recognize the relational operators <, =, >. 2.6.3 Extend the lexical analyzer in Section 2.6.5 to recognize float­ ing point numbers such as 2., 3.14, and . 5. Answer Source code: commit 8dd1a9a Code snippet(src/lexer/Lexer.java): public Token scan() throws IOException, SyntaxException{ for(;;peek = (char)stream.read()){ if(peek == ' ' || peek == '\t'){ continue; }else if(peek == '\n'){ line = line + 1; }else{ break; } } // handle comment if(peek == '/'){ peek = (char) stream.read(); if(peek == '/'){ // single line comment for(;;peek = (char)stream.read()){ if(peek == '\n'){ break; } } }else if(peek == '*'){ // block comment char prevPeek = ' '; for(;;prevPeek = peek, peek = (char)stream.read()){ if(prevPeek == '*' && peek == '/'){ break; } } }else{ throw new SyntaxException(); } } // handle relation sign if("".indexOf(peek) > -1){ StringBuffer b = new StringBuffer(); b.append(peek); peek = (char)stream.read(); if(peek == '='){ b.append(peek); } return new Rel(b.toString()); } // handle number, no type sensitive if(Character.isDigit(peek) || peek == '.'){ Boolean isDotExist = false; StringBuffer b = new StringBuffer(); do{ if(peek == '.'){ isDotExist = true; } b.append(peek); peek = (char)stream.read(); }while(isDotExist == true ? Character.isDigit(peek) : Character.isDigit(peek) || peek == '.'); return new Num(new Float(b.toString())); } // handle word if(Character.isLetter(peek)){ StringBuffer b = new StringBuffer(); do{ b.append(peek); peek = (char)stream.read(); }while(Character.isLetterOrDigit(peek)); String s = b.toString(); Word w = words.get(s); if(w == null){ w = new Word(Tag.ID, s); words.put(s, w); } return w; } Token t = new Token(peek); peek = ' '; return t; } Exercises for Section 2.8 2.8.1 For-statements in C and Java have the form: for ( exprl ; expr2 ; expr3 ) stmt The first expression is executed before the loop; it is typically used for initializ­ ing the loop index. The second expression is a test made before each iteration of the loop; the loop is exited if the expression becomes O. The loop itself can be thought of as the statement {stmt expr3 ; }. The third expression is executed at the end of each iteration; it is typically used to increment the loop index. The meaning of the for-statement is similar to expr1 ; while ( expr2 ) {stmt expr3 ; } Define a class For for for-statements, similar to class If in Fig. 2.43. Answer class For extends Stmt{ Expr E1; Expr E2; Expr E3; Stmt S; public For(Expr expr1, Expr expr2, Expr expr3, Stmt stmt){ E1 = expr1; E2 = expr2; E3 = expr3; S = stmt; } public void gen(){ E1.gen(); Label start = new Lable(); Lalel end = new Lable(); emit("ifFalse " + E2.rvalue().toString() + " goto " + end); S.gen(); E3.gen(); emit("goto " + start); emit(end + ":") } } 2.8.2 The programming language C does not have a boolean type. Show how a C compiler might translate an if-statement into three-address code. Answer Replace emit("isFalse " + E.rvalue().toString() + " goto " + after); with emit("ifNotEqual " + E.rvalue().toString() + " 0 goto " + after); or emit("isNotEqualZero " + E.rvalue().toString() + " goto " + after);
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值