编译原理 龙书第4章 作业3

本篇内容涉及上下文无关文法的最左推导、最右推导及语法分析树的构建,同时展示了文法与特定字符串的对应关系。通过对不同文法的解析,阐述了文法在解析过程中的作用和步骤,包括布尔表达式的文法表示。此外,还讨论了如何设计特定语言的文法,以及文法的LL(1)、SLR(1)、LALR(1)性质分析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

4.2.1

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

1)给出这个串的一个最左推导
S→S S *
→S S + S *
→a S + S *
→a a + S *
→a a + a *

2)给出这个串的一个最右推导
S→S S *
→S a *
→S S + a *
→S a + a *
→a a + a *

3)给出这个串的一棵语法分析树
在这里插入图片描述

4.2.2(1-3, 5, 7)[只做4.2.1的1-3小问]

对下列的每一对文法和串重复练习4.2.1
1.S->0 S 1|0 1 和串000111
a.最左推导
S->0 S 1
->0 0 S 1 1
->0 0 0 1 1 1

b.最右推导
S -> 0 S 1
->0 0 S 1 1
->0 0 0 1 1 1

c.语法分析树
在这里插入图片描述

2.S-> + S S | * S S | a和串+*aaa
a.最左推导
S-> + S S
-> + * S S S
-> + * a S S
-> + * a a S
-> + * a a a

b.最右推导
S-> + S S
-> + S a
-> + * S S a
-> + * S a a
-> + * a a a

c.语法分析树
在这里插入图片描述

3.S->S ( S ) S |ε和串(()())
a.最左推导
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
-> ( ( ) ( S ) S ) S
-> ( ( ) ( ) S ) S
-> ( ( ) ( ) ) S
-> ( ( ) ( ) )

b.最右推导
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 ( ( ) ( ) )
-> ( ( ) ( ) )

c.语法分析树
在这里插入图片描述
4.S->( L ) | a以及L->L,S | S和串((a,a),a,(a))
a.最左推导
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 ) )

b.最右推导
S -> ( L )
-> ( L , S )
-> ( L , ( L ) )
-> ( L , ( S ) )
-> ( L , ( a ) )
-> ( 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 ) )

c.语法分析树
在这里插入图片描述

5.下面的布尔表达式对应的文法:
bexpr->bexpr or bterm | bterm
Bterm->bterm and bfactor | bfactor
bfactor->not bfactor | (bexpr) | ture |false
a.最左推导
b.最右推导
c.语法分析树
(这题没看懂,如有友友知道的欢迎留言)

4.2.3(1-2)为下面的语言设计文法:

1.所有由0和1组成的并且每个0之后都至少跟着一个1的串的集合。
答:
正则表达式:(0?1)*
文法:
S -> S T

T -> 0 1
| 1

2.所有由0和1组成的回文(palindrome)的集合,也就是从前面和从后面读结果都相同的串的集合。
答:
文法:
S -> 0 S 0
| 1 S 1
| 0
| 1
| ε

4.2.5

使用练习4.2.4中描述的括号表示法来简化如下的关于语句块和条件语句的文法。
stmt -> if expr then stmt else stmt
| if stmt then stmt
| begin stmtList end
stmtList -> stmt ; stmtList | stmt

括号表示法:一个常用的扩展的文法表示方法,在这个表示方法中,产生式体中的方括号和花括号是元符号(如->或|),且具有如下含义:
1.一个或多个文法符号两边的方括号表示这些构造是可选的。因此,产生式A -> X[Y]Z和两个产生式A -> XYZ及A -> XZ具有相同的效果。
2.一个或多个文法符号两边的花括号表示这些符号可以重复任意多次(包括零次)。因此,证明这两个扩展并没有增加文法的功能。也就是说,由带有这些扩展表示的文法生成的任何语言都可以由一个不带扩展表示的文法生成。
答:
stmt -> if expr then stmt [else stmt]
| begin stmtList end
stmtList -> stmt [; stmtList]或stmtList -> stmt {; stmt}

4.4.1(1-3,5)

为下面的每一个文法设计一个预测分析器,并给出预测分析表。你可能先要对文法进行提取左公因子或消除左递归的操作。
1.练习4.2.2(1)中的文法:S -> 0 S 1 | 0 1
答:
提取左公因子:
S -> 0 S’
S’ -> S 1 | 1

FIRST/FOLLOW/NULLABLE集:
在这里插入图片描述
预测分析表:
在这里插入图片描述
2.练习4.2.2(2)中的文法:S -> + S S | * S S | a
答:
FIRST/FOLLOW/NULLABLE集:
在这里插入图片描述
预测分析表:
在这里插入图片描述
3.练习4.2.2(3)中的文法:S -> S ( S ) S |ε
答:
消除左递归:
S -> S’
S’ -> ( S ) S
-> ε
FIRST/FOLLOW/NULLABLE集:
在这里插入图片描述
预测分析表:
在这里插入图片描述
4.练习4.2.2(5)中的文法:S -> ( L ) | a以及L -> L , S | S
答:
消除左递归:
S -> ( L ) | a
L -> S L’
L’ -> , S L’
| ε
FIRST/FOLLOW/NULLABLE集:
在这里插入图片描述
预测分析表:
在这里插入图片描述

4.4.4

计算练习4.2.2中各个文法的FIRST和FOLLOW集合。
1.S -> 0 S 1 | 0 1
在这里插入图片描述
2.S -> + S S | * S S | a
在这里插入图片描述
3.S -> S ( S ) S |ε
在这里插入图片描述
4.S -> S + S | S S | ( S ) | S * |a
在这里插入图片描述
5.S -> ( L ) | a以及L -> L , S | S
在这里插入图片描述
6.S -> a S b S| b S a S |ε
在这里插入图片描述
7.下面的布尔表达式对应的文法:
bexpr->bexpr or bterm | bterm
bterm->bterm and bfactor | bfactor
bfactor->not bfactor | (bexpr) | true |false
在这里插入图片描述

4.6.5

说明下面的文法:
S -> A a A b | B b B a
A -> ε
B -> ε
是LL(1)的,但不是SLR(1)的。
答:
1.是LL(1)的:A a A b和B b B a都不能推导出ε;FIRST(A a A b)={a},FIRST(B b B a)={b},不相交,所以该文法是LL(1)的。
2.不是SLR(1)的:
状态S_0:
S ->·A a A b
S ->·B b B a
A ->·ε
B ->·ε
当接受ε时,状态S_0进入到S_1状态:
A ->ε·
B ->ε·
此时会发生规约冲突,故该文法不是SLR(1)的。

4.6.6

说明下面的文法:
S -> S A | A
A -> a
是SLR(1)的,但不是LL(1)的。
答:
1.是SLR(1)的:
构造增广文法:
0:S’ -> S
1:S -> S A
2: | A
3:A -> a
在这里插入图片描述
SLR分析表:
在这里插入图片描述
SLR分析表中没有冲突。故是SLR(1)的。

2.不是LL(1)的:
由产生式S -> S A | A可知,S A和A都不能推出ε;FIRST(SA)={a},FIRST(A)={a},相交,故该文法不是LL(1)的。

4.7.2(5)

为文法S ->( L ) | a以及L->L,S | S构造:
1.规范LR项集族
2.LALR项集族
答:
构造增广文法:
0:S’ -> S $
1:S -> ( L )
2: | a
3:L -> L , S
4: | S

规范LR项集族:
在这里插入图片描述
LALR项集族:
对LR(1)进行同项合并。LR(1)中可以合并的产生式集如下图颜色标出:
在这里插入图片描述
合并后得到LALR项集族:
在这里插入图片描述

4.7.5

说明下面的文法:
S -> A a | b A c | B c | b B a
A -> d
B -> d
是LR(1)的,但不是LALR(1)的
答:
构造增广文法:
0:S’ -> S $
1:S -> A a
2: | b A c
3: | B c
4: | b B a
5:A -> d
6:B -> d
1.是LR(1)的:
LR(1)项集图:
在这里插入图片描述
从项集图可以看出,LR(1)没有冲突。故该文法是LR(1)的。

2.不是LALR(1)的:
找出可合并的项,用相同颜色标出:
在这里插入图片描述
合并后得到LALR(1):
在这里插入图片描述
可以看出,状态5会产生规约冲突,故该文法不是LALR(1)的。

编译原理答案 完整性高 第二 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(&#39;a&#39;,2) = &#39;aa&#39; 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(&#39;M&#39;, low.v)} hundred -> low {hundred.roman = repeat(&#39;C&#39;, low.v)} | 4 {hundred.roman = &#39;CD&#39;} | high {hundred.roman = &#39;D&#39; || repeat(&#39;X&#39;, high.v - 5)} | 9 {hundred.roman = &#39;CM&#39;} ten -> low {ten.roman = repeat(&#39;X&#39;, low.v)} | 4 {ten.roman = &#39;XL&#39;} | high {ten.roman = &#39;L&#39; || repeat(&#39;X&#39;, high.v - 5)} | 9 {ten.roman = &#39;XC&#39;} digit -> low {digit.roman = repeat(&#39;I&#39;, low.v)} | 4 {digit.roman = &#39;IV&#39;} | high {digit.roman = &#39;V&#39; || repeat(&#39;I&#39;, high.v - 5)} | 9 {digit.roman = &#39;IX&#39;} 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 == &#39; &#39; || peek == &#39;\t&#39;){ continue; }else if(peek == &#39;\n&#39;){ line = line + 1; }else{ break; } } // handle comment if(peek == &#39;/&#39;){ peek = (char) stream.read(); if(peek == &#39;/&#39;){ // single line comment for(;;peek = (char)stream.read()){ if(peek == &#39;\n&#39;){ break; } } }else if(peek == &#39;*&#39;){ // block comment char prevPeek = &#39; &#39;; for(;;prevPeek = peek, peek = (char)stream.read()){ if(prevPeek == &#39;*&#39; && peek == &#39;/&#39;){ 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 == &#39;=&#39;){ b.append(peek); } return new Rel(b.toString()); } // handle number, no type sensitive if(Character.isDigit(peek) || peek == &#39;.&#39;){ Boolean isDotExist = false; StringBuffer b = new StringBuffer(); do{ if(peek == &#39;.&#39;){ isDotExist = true; } b.append(peek); peek = (char)stream.read(); }while(isDotExist == true ? Character.isDigit(peek) : Character.isDigit(peek) || peek == &#39;.&#39;); 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 = &#39; &#39;; 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);
目 录 译者序 前言 第1 概论 1 1.1 为什么要用编译器 2 1.2 与编译器相关的程序 3 1.3 翻译步骤 5 1.4 编译器中的主要数据结构 8 1.5 编译器结构中的其他问题 10 1.6 自举与移植 12 1.7 TINY样本语言与编译器 14 1.7.1 TINY语言 15 1.7.2 TINY编译器 15 1.7.3 TM机 17 1.8 C-Minus:编译器项目的一种语言 18 练习 19 注意与参考 20 第2 词法分析 21 2.1 扫描处理 21 2.2 正则表达式 23 2.2.1 正则表达式的定义 23 2.2.2 正则表达式的扩展 27 2.2.3 程序设计语言记号的正则表达式 29 2.3 有穷自动机 32 2.3.1 确定性有穷自动机的定义 32 2.3.2 先行、回溯和非确定性自动机 36 2.3.3 用代码实现有穷自动机 41 2.4 从正则表达式到DFA 45 2.4.1 从正则表达式到NFA 45 2.4.2 从NFA到DFA 48 2.4.3 利用子集构造模拟NFA 50 2.4.4 将DFA中的状态数最小化 51 2.5 TINY扫描程序的实现 52 2.5.1 为样本语言TINY实现一个扫描 程序 53 2.5.2 保留字与标识符 56 2.5.3 为标识符分配空间 57 2.6 利用Lex 自动生成扫描程序 57 2.6.1 正则表达式的Lex 约定 58 2.6.2 Lex输入文件的格式 59 2.6.3 使用Lex的TINY扫描程序 64 练习 65 编程练习 67 注意与参考 67 第3 上下文无关文法及分析 69 3.1 分析过程 69 3.2 上下文无关文法 70 3.2.1 与正则表达式比较 70 3.2.2 上下文无关文法规则的说明 71 3.2.3 推导及由文法定义的语言 72 3.3 分析树与抽象语法树 77 3.3.1 分析树 77 3.3.2 抽象语法树 79 3.4 二义性 83 3.4.1 二义性文法 83 3.4.2 优先权和结合性 85 3.4.3 悬挂else问题 87 3.4.4 无关紧要的二义性 89 3.5 扩展的表示法:EBNF和语法图 89 3.5.1 EBNF表示法 89 3.5.2 语法图 91 3.6 上下文无关语言的形式特性 93 3.6.1 上下文无关语言的形式定义 93 3.6.2 文法规则和等式 94 3.6.3 乔姆斯基层次和作为上下文无关 规则的语法局限 95 3.7 TINY语言的语法 97 3.7.1 TINY的上下文无关文法 97 3.7.2 TINY编译器的语法树结构 98 练习 101 注意与参考 1044 自顶向下的分析 105 4.1 使用递归下降分析算法进行自顶向下 的分析 105 4.1.1 递归下降分析的基本方法 105 4.1.2 重复和选择:使用EBNF 107 4.1.3 其他决定问题 112 4.2 LL(1)分析 113 4.2.1 LL(1)分析的基本方法 113 4.2.2 LL(1)分析与算法 114 4.2.3 消除左递归和提取左因子 117 4.2.4 在LL(1)分析中构造语法树 124 4.3 First集合和Follow集合 125 4.3.1 First 集合 125 4.3.2 Follow 集合 130 4.3.3 构造LL(1)分析表 134 4.3.4 再向前:LL(k)分析程序 135 4.4 TINY语言的递归下降分析程序 136 4.5 自顶向下分析程序中的错误校正 137 4.5.1 在递归下降分析程序中的错误 校正 138 4.5.2 在LL(1)分析程序中的错误校正 140 4.5.3 在TINY分析程序中的错误校正 141 练习 143 编程练习 146 注意与参考 148 第5 自底向上的分析 150 5.1 自底向上分析概览 151 5.2 LR(0)项的有穷自动机与LR(0)分析 153 5.2.1 LR(0)项 153 5.2.2 项目的有穷自动机 154 5.2.3 LR(0)分析算法 157 5.3 SLR(1)分析 160 5.3.1 SLR(1)分析算法 160 5.3.2 用于分析冲突的消除二义性 规则 163 5.3.3 SLR(1)分析能力的局限性 164 5.3.4 SLR(k)文法 165 5.4 一般的LR(1)和LALR(1)分析 166 5.4.1 LR(1)项的有穷自动机 166
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值