编译原理 龙书答案
- 格式:doc
- 大小:458.50 KB
- 文档页数:24
第二章 词法分析2.1 完成下列选择题: (1) 词法分析器的输出结果是 。
a. 单词的种别编码 b. 单词在符号表中的位置 c. 单词的种别编码和自身值 d. 单词自身值 (2) 正规式M1和M2等价是指 。
a. M1和M2的状态数相等 b. M1和M2的有向边条数相等 c. M1和M2所识别的语言集相等 d. M1和M2状态数和有向边条数相等 (3) DFA M(见图2-1)接受的字集为 。
a. 以0开头的二进制数组成的集合 b. 以0结尾的二进制数组成的集合 c. 含奇数个0的二进制数组成的集合 d. 含偶数个0的二进制数组成的集合 【解答】 (1) c (2) c (3) d图2-1 习题的DFA M2.2 什么是扫描器?扫描器的功能是什么? 【解答】 扫描器就是词法分析器,它接受输入的源程序,对源程序进行词法分析并识别出一个个单词符号,其输出结果是单词符号,供语法分析器使用。
通常是把词法分析器作为一个子程序,每当词法分析器需要一个单词符号时就调用这个子程序。
每次调用时,词法分析器就从输入串中识别出一个单词符号交给语法分析器。
2.3 设M=({x,y}, {a,b}, f, x, {y})为一非确定的有限自动机,其中f 定义如下: f(x,a)={x,y} f {x,b}={y} f(y,a)=Φ f{y,b}={x,y} 试构造相应的确定有限自动机M ′。
【解答】 对照自动机的定义M=(S,Σ,f,So,Z),由f 的定义可知f(x,a)、f(y,b)均为多值函数,因此M 是一非确定有限自动机。
先画出NFA M 相应的状态图,如图2-2所示。
图2-2 习题的NFA M用子集法构造状态转换矩阵,如表表2-1 状态转换矩阵1b将转换矩阵中的所有子集重新命名,形成表2-2所示的状态转换矩阵,即得到 M ′=({0,1,2},{a,b},f,0,{1,2}),其状态转换图如图2-3所示。
第四章习题4.2.1:考虑上下文无关文法:S->S S +|S S *|a 以及串aa + a*(1)给出这个串的一个最左推导S -> S S *-> S S + S *-> a S + S *-> a a + S *-> aa + a*(3)给出这个串的一棵语法分析树习题4.3.1:下面是一个只包含符号a和b的正则表达式的文法。
它使用+替代表示并运算的符号|,以避免和文法中作为元符号使用的竖线相混淆:rexpr rexpr + rterm | rtermrterm rterm rfactor | rfactorrfactor rfactor * | rprimaryrprimary a | b1)对这个文法提取公因子2)提取公因子的变换使这个文法适用于自顶向下的语法分析技术吗?3)提取公因子之后,原文法中消除左递归4)得到的文法适用于自顶向下的语法分析吗?解1)提取左公因子之后的文法变为rexpr rexpr + rterm | rtermrterm rterm rfactor | rfactorrfactor rfactor * | rprimaryrprimary a | b2)不可以,文法中存在左递归,而自顶向下技术不适合左递归文法3)消除左递归后的文法rexpr -> rterm rexpr’rexpr’-> + rterm rexpr’|εrterm-> rfactor rterm’rterm’-> rfactor rterm’|εrfactor-> rprimay rfactor’rfactor’-> *rfactor’|εrprimary-> a | b4)该文法无左递归,适合于自顶向下的语法分析习题4.4.1:为下面的每一个文法设计一个预测分析器,并给出预测分析表。
可能要先对文法进行提取左公因子或消除左递归(3)S->S(S)S|ε(5)S->(L)|a L->L,S|S解(3)①消除该文法的左递归后得到文法S->S’S’->(S)SS’|εFIRST(S)={(,ε} FOLLOW(S)={),$}FIRST(S’)={(,ε} FOLLOW(S’)={),$}③(5)①消除该文法的左递归得到文法S->(L)|aL->SL’L’->,SL’|ε用类Pascal语言的一个预测分析器:PROCEDURE SBEGINif (lookahead==’(')THEN BEGINmatch ('(');L;match (')');END;ELSE IF (lookahead=='a')THEN match('a')ELSE errorEND;PROCEDURE L;BEGINS;WHILE (lookahead ==',');BEGINmatch (',');S;END;END;②计算FIRST与FOLLOW集合FIRST(S)={(,a} FOLLOW(S)={ ),, ,$}FIRST(L)={(,a} FOLLOW(L)={ ) }FIRST(L’)={,,ε} FOLLOW(L’)={ ) }③非终结符号输入符号(),a$ S S->(L)S->aL L->SL’L->SL’L’L’->εL’->,SL’习题4.4.4 计算练习4.2.2的文法的FIRST和FOLLOW集合3)S S(S)S|ε5)S(L)|a,L L,S|S解:3)FIRST(S)={ ε,( } FOLLOW(S)={ (,),$ }5)FIRST(S)={ (,a } FOLLOW(S)={ ),,,$ }FIRST(L)={ (,a } FOLLOW(L)={ ),, }习题4.6.2 为练习4.2.1中的增广文法构造SLR 项集,计算这些项集的GOTO 函数,给出这个文法的语法分析表。
第四章部分习题解答Aho:《编译原理技术与工具》书中习题(Aho)4.1 考虑文法S → ( L ) | aL → L, S | Sa)列出终结符、非终结符和开始符号解:终结符:(、)、a、,非终结符:S、L开始符号:Sb)给出下列句子的语法树i)(a, a)ii)(a, (a, a))iii)(a, ((a, a), (a, a)))c)构造b)中句子的最左推导i)S(L)(L, S) (S, S) (a, S) (a, a)ii)S(L)(L, S) (S, S) (a, S) (a, (L)) (a, (L, S)) (a, (S, S)) (a, (a, S) (a, (a, a))iii)S(L)(L, S) (S, S) (a, S) (a, (L)) (a, (L, S)) (a, (S, S)) (a, ((L), S)) (a, ((L, S), S)) (a, ((S, S), S)) (a, ((a, S), S))(a, ((a, a), S)) (a, ((a, a), (L))) (a, ((a, a), (L, S))) (a, ((a, a), (S, S))) (a, ((a, a), (a, S))) (a, ((a, a), (a, a)))d)构造b)中句子的最右推导i)S(L)(L, S) (L, a) (S, a) (a, a)ii)S(L)(L, S) (L, (L)) (L, (L, S)) (L, (L, a)) (L, (S, a)) (L, (a, a)) (S, (a, a)) (a, (a, a))iii)S(L)(L, S) (L, (L)) (L, (L, S)) (L, (L, (L))) (L, (L, (L, S))) (L, (L, (L, a))) (L, (L, (S, a))) (L, (L, (a, a))) (L, (S,(a, a))) (L, ((L), (a, a))) (L, ((L, S), (a, a))) (L, ((L, a), (a,a))) (L, ((S, a), (a, a))) (L, ((a, a), (S, S))) (S, ((a, a), (a,a))) (a, ((a, a), (a, a)))e)该文法产生的语言是什么解:设该文法产生语言(符号串集合)L,则L = { (A1, A2, …, A n) | n是任意正整数,A i=a,或A i∈L,i是1~n之间的整数}(Aho)4.2考虑文法S→aSbS | bSaS |a)为句子构造两个不同的最左推导,以证明它是二义性的S aSbS abS abaSbS ababS ababS aSbS abSaSbS abaSbS ababS ababb)构造abab对应的最右推导S aSbS aSbaSbS aSbaSb aSbab ababS aSbS aSb abSaSb abSab ababc)构造abab对应语法树d)该文法产生什么样的语言?解:生成的语言:a、b个数相等的a、b串的集合(Aho)4.3 考虑文法bexpr→bexpr or bterm | btermbterm→bterm and bfactor | bfactorbfactor→not bfactor | ( bexpr ) | true | falsea)试为句子not ( true or false)构造分析树解:b)试证明该文法产生所有布尔表达式证明:一、首先证明文法产生的所有符号串都是布尔表达式变换命题形式——以bexpr、bterm、bfactor开始的推导得到的所有符号串都是布尔表达式最短的推导过程得到true、false,显然成立假定对步数小于n的推导命题都成立考虑步数等于n 的推导,其开始推导步骤必为以下情况之一bexpr bexpr or btermbexpr btermbterm bterm and bfactorbexpr bfactorbfactor not bfactorbfactor ( bexpr )而后继推导的步数显然<n,因此由归纳假设,第二步句型中的NT推导出的串均为布尔表达式,这些布尔表达式经过or、and、not运算或加括号,得到的仍是布尔表达式因此命题一得证。
1) What is the difference between a compiler and an interpreter?∙ A compiler is a program that can read a program in one language - the source language - and translate it into an equivalent program in another language – the target language and report any errors in the source program that it detects during the translation process.∙ Interpreter directly executes the operations specified in the source program on inputs supplied by the user.2) What are the advantages of:(a) a compiler over an interpretera. The machine-language target program produced by a compiler is usually much faster than an interpreter at mapping inputs to outputs.(b) an interpreter over a compiler?b. An interpreter can usually give better error diagnostics than a compiler, because it executes the source program statement by statement.3) What advantages are there to a language-processing system in which the compiler produces assembly language rather than machine language?The compiler may produce an assembly-language program as its output, becauseassembly language is easier to produce as output and is easier to debug.4.2.3 Design grammars for the following languages:a) The set of all strings of 0s and 1s such that every 0 is immediately followed by at least 1.S -> SS | 1 | 01 | ε4.3.1 The following is a grammar for the regular expressions over symbols a and b only, using + in place of | for unions, to avoid conflict with the use of vertical bar as meta-symbol in grammars:rexpr -> rexpr + rterm | rtermrterm -> rterm rfactor | rfactorrfactor -> rfactor * | rprimaryrprimary -> a | ba) Left factor this grammar.rexpr -> rexpr + rterm | rtermrterm -> rterm rfactor | rfactorrfactor -> rfactor * | rprimaryrprimary -> a | bb) Does left factoring make the grammar suitable for top-down parsing?No, left recursion is still in the grammar.c) In addition to left factoring, eliminate left recursion from the original grammar.rexpr -> rterm rexpr‟rexpr‟ -> + rterm rexpr | εrterm -> rfactor rterm‟rterm‟ -> rfactor rterm | εrfactor -> rprimary rfactor‟rfactor‟ -> * rfactor‟ | εrprimary -> a | bd) Is the resulting grammar suitable for top-down parsing?Yes.Exercise 4.4.1 For each of the following grammars, derive predictive parsers and show the parsing tables. You may left-factor and/or eliminate left-recursion from your grammars first.A predictive parser may be derived by recursive decent or by the table driven approach. Either way you must also show the predictive parse table.a) The grammar of exercise 4.2.2(a).4.2.2 a) S -> 0S1 | 01This grammar has no left recursion. It could possibly benefit from left factoring. Here is the recursive decent PP code.s() {match(…0‟);if (lookahead == …0‟)s();match(…1‟);}OrLeft factoring the grammar first:S -> 0S‟S‟ -> S1 | 1s() {match(…0‟); s‟();}s‟() {if (lookahead == …0‟)s(); match(…1‟);elsematch(…1‟);}Now we will build the PP tableS -> 0S‟S‟ -> S1 | 1First(S) = {0}First(S‟) = {0, 1}Follow(S) = {1, $}The predictive parsing algorithm on page 227 (fig4.19 and 4.20) can use this table for non-recursive predictive parsing.b) The grammar of exercise 4.2.2(b).4.2.2 b) S -> +SS | *SS | a with string +*aaa.Left factoring does not apply and there is no left recursion to remove.s() {if(lookahead == …+‟)match(…+‟); s(); s();else if(lookahead == …*‟)match(…*‟); s(); s();else if(lookahead == …a‟)match(…a‟);elsereport(“syntax error”);}First(S) = {+, *, a}Follow(S) = {$, +, *, a}The predictive parsing algorithm on page 227 (fig4.19 and 4.20) can use this table for non-recursive predictive parsing.5.1.1 a, b, c: Investigating GraphViz as a solution to presenting trees5.1.2: Extend the SDD of Fig. 5.4 to handle expressions as in Fig. 5.1:1.L -> E N1.L.val = E.syn2. E -> F E'1. E.syn = E'.syn2.E'.inh = F.val3.E' -> + T Esubone'1.Esubone'.inh = E'.inh + T.syn2.E'.syn = Esubone'.syn4.T -> F T'1.T'.inh = F.val2.T.syn = T'.syn5.T' -> * F Tsubone'1.Tsubone'.inh = T'.inh * F.val2.T'.syn = Tsubone'.syn6.T' -> epsilon1.T'.syn = T'.inh7.E' -> epsilon1.E'.syn = E'.inh8. F -> digit1. F.val = digit.lexval9. F -> ( E )1. F.val = E.syn10.E -> T1. E.syn = T.syn5.1.3 a, b, c: Investigating GraphViz as a solution to presenting trees5.2.1: What are all the topological sorts for the dependency graph of Fig. 5.7?1.1, 2, 3, 4, 5, 6, 7, 8, 92.1, 2, 3, 5, 4, 6, 7, 8, 93.1, 2, 4, 3, 5, 6, 7, 8, 94.1, 3, 2, 4, 5, 6, 7, 8, 95.1, 3, 2, 5, 4, 6, 7, 8, 96.1, 3, 5, 2, 4, 6, 7, 8, 97.2, 1, 3, 4, 5, 6, 7, 8, 98.2, 1, 3, 5, 4, 6, 7, 8, 99.2, 1, 4, 3, 5, 6, 7, 8, 910.2, 4, 1, 3, 5, 6, 7, 8, 95.2.2 a, b: Investigating GraphViz as a solution to presenting trees5.2.3: Suppose that we have a production A -> BCD. Each of the four nonterminals A, B, C, and D have two attributes: s is a synthesized attribute, and i is an inherited attribute. For each of the sets of rules below, tell whether (1) the rules are consistent with an S-attributed definition (2) the rules are consistent with an L-attributed definition, and (3) whether the rules are consistent with any evaluation order at all?a) A.s = B.i + C.s1.No--contains inherited attribute2.Yes--"From above or from the left"3.Yes--L-attributed so no cyclesb) A.s = B.i + C.s and D.i = A.i + B.s1.No--contains inherited attributes2.Yes--"From above or from the left"3.Yes--L-attributed so no cyclesc) A.s = B.s + D.s1.Yes--all attributes synthesized2.Yes--all attributes synthesized3.Yes--S- and L-attributed, so no cyclesd)∙ A.s = D.i∙ B.i = A.s + C.s∙ C.i = B.s∙ D.i = B.i + C.i1.No--contains inherited attributes2.No--B.i uses A.s, which depends on D.i, which depends on B.i (cycle)3.No--Cycle implies no topological sorts (evaluation orders) using the rules5.3.1: Below is a grammar for expressions involving operator + and integer or floating-point operands. Floating-point numbers are distinguished by having a decimal point.1. E -> E + T | T2.T -> num . num | numa) Give an SDD to determine the type of each term T and expression E.1. E -> Esubone + T1. E.type = if (E.type == float || T.type == float) { E.type = float } else{ E.type = integer }2. E -> T1. E.type = T.type3.T -> numsubone . numsubtwo1.T.type = float4.T -> num1.T.type = integerb) Extend your SDD of (a) to translate expressions into postfix notation. Use the binary operator intToFloat to turn an integer into an equivalent float.Note: I use character ',' to separate floating point numbers in the resulting postfix notation. Also, the symbol "||" implies concatenation.1. E -> Esubone + T1. E.val = Esubone.val || ',' || T.val || '+'2. E -> T1. E.val = T.val3.T -> numsubone . numsubtwo1.T.val = numsubone.val || '.' || numsubtwo.val4.T -> num1.T.val = intToFloat(num.val)5.3.2 Give an SDD to translate infix expressions with + and * into equivalent expressions without redundant parenthesis. For example, since both operators associate from the left, and * takes precedence over +, ((a*(b+c))*(d)) translates into a*(b+c)*d. Note: symbol "||" implies concatenation.1.S -> E1. E.iop = nil2.S.equation = E.equation2. E -> Esubone + T1.Esubone.iop = E.iop2.T.iop = E.iop3. E.equation = Esubone.equation || '+' || T.equation4. E.sop = '+'3. E -> T1.T.iop = E.iop2. E.equation = T.equation3. E.sop = T.sop4.T -> Tsubone * F1.Tsubone.iop = '*'2. F.iop = '*'3.T.equation = Tsubone.equation || '*' || F.equation4.T.sop = '*'5.T -> F1. F.iop = T.iop2.T.equation = F.equation3.T.sop = F.sop6. F -> char1. F.equation = char.lexval2. F.sop = nil7. F -> ( E )1.if (F.iop == '*' && E.sop == '+') { F.equation = '(' || E.equation || ')' }else { F.equation = E.equation }2. F.sop = nil5.3.3: Give an SDD to differentiate expressions such as x * (3*x + x * x) involving the operators + and *, the variable x, and constants. Assume that no simplification occurs, so that, for example, 3*x will be translated into 3*1 + 0*x. Note: symbol "||" implies concatenation. Also, differentiation(x*y) = (x * differentiation(y) + differentiation(x) * y) and differentiation(x+y) = differentiation(x) + differentiation(y).1.S -> E1.S.d = E.d2. E -> T1. E.d = T.d2. E.val = T.val3.T -> F1.T.d = F.d2.T.val = F.val4.T -> Tsubone * F1.T.d = '(' || Tsubone.val || ") * (" || F.d || ") + (" || Tsubone.d || ") * (" ||F.val || ')'2.T.val = Tsubone.val || '*' || F.val5. E -> Esubone + T1. E.d = '(' || Esubone.d || ") + (" || T.d || ')'2. E.val = Esubone.val || '+' || T.val6. F -> ( E )1. F.d = E.d2. F.val = '(' || E.val || ')'7. F -> char1. F.d = 12. F.val = char.lexval8. F -> constant1. F.d = 02. F.val = constant.lexval。
编译原理(龙书)课后习题解答(详细)编译原理(龙书)课后题解答第一章1.1.1 :翻译和编译的区别?答:翻译通常指自然语言的翻译,将一种自然语言的表述翻译成另一种自然语言的表述,而编译指的是将一种高级语言翻译为机器语言(或汇编语言)的过程。
1.1.2 :简述编译器的工作过程?答:编译器的工作过程包括以下三个阶段:(1) 词法分析:将输入的字符流分解成一个个的单词符号,构成一个单词符号序列;(2) 语法分析:根据语法规则分析单词符号序列中各个单词之间的关系,确定它们的语法结构,并生成抽象语法树;(3) 代码生成:根据抽象语法树生成目标程序(机器语言或汇编语言),并输出执行文件。
1.2.1 :解释器和编译器的区别?答:解释器和编译器的主要区别在于执行方式。
编译器将源程序编译成机器语言或汇编语言等,在运行时无需重新编译,程序会一次性运行完毕;而解释器则是边翻译边执行,每次执行都需要进行一次翻译,一次只执行一部分。
1.2.2 :Java语言采用的是解释执行还是编译执行?答:Java一般是编译成字节码的形式,然后由Java虚拟机(JVM)进行解释执行。
但是,Java也有JIT(即时编译器)的存在,当某一段代码被多次执行时,JIT会将其编译成机器语言,提升代码的执行效率。
第二章2.1.1 :使用BNF范式定义简单的加法表达式和乘法表达式答:<加法表达式> ::= <加法表达式> "+" <乘法表达式> | <乘法表达式><乘法表达式> ::= <乘法表达式> "*" <单项式> | <单项式><单项式> ::= <数字> | "(" <加法表达式> ")"2.2.3 :什么是自下而上分析?答:自下而上分析是指从输入字符串出发,自底向上构造推导过程,直到推导出起始符号。
1) What is the difference between a compiler and an interpreter?• A compiler is a program that can read a program in one language - the source language - and translate it into an equivalent program in another language – the target language and report any errors in the source program that it detects during the translation process.• Interpreter directly executes the operations specified in the source program on inputs supplied by the user.2) What are the advantages of:(a) a compiler over an interpretera. The machine-language target program produced by a compiler is usually much faster than an interpreter at mapping inputs to outputs.(b) an interpreter over a compiler?b. An interpreter can usually give better error diagnostics than a compiler, because it executes the source program statement by statement.3) What advantages are there to a language-processing system in which the compiler produces assembly language rather than machine language?The compiler may produce an assembly-language program as its output, becauseassembly language is easier to produce as output and is easier to debug.4.2.3 Design grammars for the following languages:a) The set of all strings of 0s and 1s such that every 0 is immediately followed by at least 1.S -> SS | 1 | 01 | ε4.3.1 The following is a grammar for the regular expressions over symbols a and b only, using + in place of | for unions, to avoid conflict with the use of vertical bar as meta-symbol in grammars:rexpr -> rexpr + rterm | rtermrterm -> rterm rfactor | rfactorrfactor -> rfactor * | rprimaryrprimary -> a | ba) Left factor this grammar.rexpr -> rexpr + rterm | rtermrterm -> rterm rfactor | rfactorrfactor -> rfactor * | rprimaryrprimary -> a | bb) Does left factoring make the grammar suitable for top-down parsing?No, left recursion is still in the grammar.c) In addition to left factoring, eliminate left recursion from the original grammar.rexpr -> rterm rexpr’rexpr’ -> + rterm rexpr | εrterm -> rfactor rterm’rterm’ -> rfactor rterm | εrfactor -> rprimary rfactor’rfactor’ -> * rfactor’ | εrprimary -> a | bd) Is the resulting grammar suitable for top-down parsing?Yes.Exercise 4.4.1 For each of the following grammars, derive predictive parsers and show the parsing tables. You may left-factor and/or eliminate left-recursion from your grammars first.A predictive parser may be derived by recursive decent or by the table driven approach. Either way you must also show the predictive parse table.a) The grammar of exercise 4.2.2(a).4.2.2 a) S -> 0S1 | 01This grammar has no left recursion. It could possibly benefit from left factoring. Here is the recursive decent PP code.s() {match(‘0’);if (lookahead == ‘0’)s();match(‘1’);}OrLeft factoring the grammar first:S -> 0S’S’ -> S1 | 1s() {match(‘0’); s’();}s’() {if (lookahead == ‘0’)s(); match(‘1’);elsematch(‘1’);}Now we will build the PP tableS -> 0S’S’ -> S1 | 1First(S) = {0}First(S’) = {0, 1}Follow(S) = {1, $}The predictive parsing algorithm on page 227 (fig4.19 and 4.20) can use this table for non-recursive predictive parsing.b) The grammar of exercise 4.2.2(b).4.2.2 b) S -> +SS | *SS | a with string +*aaa.Left factoring does not apply and there is no left recursion to remove.s() {if(lookahead == ‘+’)match(‘+’); s(); s();else if(lookahead == ‘*’)match(‘*’); s(); s();else if(lookahead == ‘a’)match(‘a’);elsereport(“syntax error”);}First(S) = {+, *, a}Follow(S) = {$, +, *, a}The predictive parsing algorithm on page 227 (fig4.19 and 4.20) can use this table for non-recursive predictive parsing.5.1.1 a, b, c: Investigating GraphViz as a solution to presenting trees5.1.2: Extend the SDD of Fig. 5.4 to handle expressions as in Fig. 5.1:1.L -> E N1.L.val = E.syn2. E -> F E'1. E.syn = E'.syn2.E'.inh = F.val3.E' -> + T Esubone'1.Esubone'.inh = E'.inh + T.syn2.E'.syn = Esubone'.syn4.T -> F T'1.T'.inh = F.val2.T.syn = T'.syn5.T' -> * F Tsubone'1.Tsubone'.inh = T'.inh * F.val2.T'.syn = Tsubone'.syn6.T' -> epsilon1.T'.syn = T'.inh7.E' -> epsilon1.E'.syn = E'.inh8. F -> digit1. F.val = digit.lexval9. F -> ( E )1. F.val = E.syn10.E -> T1. E.syn = T.syn5.1.3 a, b, c: Investigating GraphViz as a solution to presenting trees5.2.1: What are all the topological sorts for the dependency graph of Fig. 5.7?1.1, 2, 3, 4, 5, 6, 7, 8, 92.1, 2, 3, 5, 4, 6, 7, 8, 93.1, 2, 4, 3, 5, 6, 7, 8, 94.1, 3, 2, 4, 5, 6, 7, 8, 95.1, 3, 2, 5, 4, 6, 7, 8, 96.1, 3, 5, 2, 4, 6, 7, 8, 97.2, 1, 3, 4, 5, 6, 7, 8, 98.2, 1, 3, 5, 4, 6, 7, 8, 99.2, 1, 4, 3, 5, 6, 7, 8, 910.2, 4, 1, 3, 5, 6, 7, 8, 95.2.2 a, b: Investigating GraphViz as a solution to presenting trees5.2.3: Suppose that we have a production A -> BCD. Each of the four nonterminals A, B, C, and D have two attributes: s is a synthesized attribute, and i is an inherited attribute. For each of the sets of rules below, tell whether (1) the rules are consistent with an S-attributed definition (2) the rules are consistent with an L-attributed definition, and (3) whether the rules are consistent with any evaluation order at all?a) A.s = B.i + C.s1.No--contains inherited attribute2.Yes--"From above or from the left"3.Yes--L-attributed so no cyclesb) A.s = B.i + C.s and D.i = A.i + B.s1.No--contains inherited attributes2.Yes--"From above or from the left"3.Yes--L-attributed so no cyclesc) A.s = B.s + D.s1.Yes--all attributes synthesized2.Yes--all attributes synthesized3.Yes--S- and L-attributed, so no cyclesd)• A.s = D.i• B.i = A.s + C.s• C.i = B.s• D.i = B.i + C.i1.No--contains inherited attributes2.No--B.i uses A.s, which depends on D.i, which depends on B.i (cycle)3.No--Cycle implies no topological sorts (evaluation orders) using the rules5.3.1: Below is a grammar for expressions involving operator + and integer or floating-point operands. Floating-point numbers are distinguished by having a decimal point.1. E -> E + T | T2.T -> num . num | numa) Give an SDD to determine the type of each term T and expression E.1. E -> Esubone + T1. E.type = if (E.type == float || T.type == float) { E.type = float } else{ E.type = integer }2. E -> T1. E.type = T.type3.T -> numsubone . numsubtwo1.T.type = float4.T -> num1.T.type = integerb) Extend your SDD of (a) to translate expressions into postfix notation. Use the binary operator intToFloat to turn an integer into an equivalent float.Note: I use character ',' to separate floating point numbers in the resulting postfix notation. Also, the symbol "||" implies concatenation.1. E -> Esubone + T1. E.val = Esubone.val || ',' || T.val || '+'2. E -> T1. E.val = T.val3.T -> numsubone . numsubtwo1.T.val = numsubone.val || '.' || numsubtwo.val4.T -> num1.T.val = intToFloat(num.val)5.3.2 Give an SDD to translate infix expressions with + and * into equivalent expressions without redundant parenthesis. For example, since both operators associate from the left, and * takes precedence over +, ((a*(b+c))*(d)) translates into a*(b+c)*d. Note: symbol "||" implies concatenation.1.S -> E1. E.iop = nil2.S.equation = E.equation2. E -> Esubone + T1.Esubone.iop = E.iop2.T.iop = E.iop3. E.equation = Esubone.equation || '+' || T.equation4. E.sop = '+'3. E -> T1.T.iop = E.iop2. E.equation = T.equation3. E.sop = T.sop4.T -> Tsubone * F1.Tsubone.iop = '*'2. F.iop = '*'3.T.equation = Tsubone.equation || '*' || F.equation4.T.sop = '*'5.T -> F1. F.iop = T.iop2.T.equation = F.equation3.T.sop = F.sop6. F -> char1. F.equation = char.lexval2. F.sop = nil7. F -> ( E )1.if (F.iop == '*' && E.sop == '+') { F.equation = '(' || E.equation || ')' }else { F.equation = E.equation }2. F.sop = nil5.3.3: Give an SDD to differentiate expressions such as x * (3*x + x * x) involving the operators + and *, the variable x, and constants. Assume that no simplification occurs, so that, for example, 3*x will be translated into 3*1 + 0*x. Note: symbol "||" implies concatenation. Also, differentiation(x*y) = (x * differentiation(y) + differentiation(x) * y) and differentiation(x+y) = differentiation(x) + differentiation(y).1.S -> E1.S.d = E.d2. E -> T1. E.d = T.d2. E.val = T.val3.T -> F1.T.d = F.d2.T.val = F.val4.T -> Tsubone * F1.T.d = '(' || Tsubone.val || ") * (" || F.d || ") + (" || Tsubone.d || ") * (" ||F.val || ')'2.T.val = Tsubone.val || '*' || F.val5. E -> Esubone + T1. E.d = '(' || Esubone.d || ") + (" || T.d || ')'2. E.val = Esubone.val || '+' || T.val6. F -> ( E )1. F.d = E.d2. F.val = '(' || E.val || ')'7. F -> char1. F.d = 12. F.val = char.lexval8. F -> constant1. F.d = 02. F.val = constant.lexval。
编译原理龙书第二版课后答案【篇一:编译原理习题答案,1-8 章龙书第二版7.8 章】6 :c 语言函数 f 的定义如下:int f(int x, *py, **ppz){**ppz +=1 ; *py +=2 ;x +=3; return x+*py+**ppz;}变量 a 是一个指向 b 的指针;变量 b 是一个指向 c 的指针,而 c 是一个当前值为 4 的整数变量。
如果我们调用 f(c,b,a), 返回值是什么?答: x 是传值 ,而 b 和 c 是传地址方式;由函数定义可以得到: b=c,a=b, 而**a=**a+1=c+1=5 = c=5; *b=*b+2=c+2=7 =c=7,**a=7;c=c+3=4+3=7所以调用 f(c,b,a) 返回值是 7+7+ 7=21练习7.3.2 :假设我们使用显示表来实现下图中的函数。
请给出对fib0 (1)的第一次调用即将返回时的显示表。
同时指明那时在栈中的各种活动记录中保存的显示表条目答:结果如下第八章练习 8.2.1 :假设所有的变量都存放在内存中,为下面的三地址语句生成代码:5)下面的两个语句序列x=b*cy=a+x答:生成的代码如下练习 8.5.1 :为下面的基本块构造构造dagd=b*ce=a+bb=b*ca=e-d答: dag 如下练习 8.6.1 :为下面的每个 c 语言赋值语句生成三地址代码1)x=a+b*c答:生成的三地址代码如下【篇二:编译原理龙书第二版第4章】.1:考虑上下文无关文法: s-s s +|s s *|a 以及串 aa + a* (1) 给出这个串的一个最左推导 s - s s * - s s + s * - a s + s * - a a + s * - aa+a*(3)给出这个串的一棵语法分析树习题 4.3.1 :下面是一个只包含符号 a 和 b 的正则表达式的文法。
它使用 +替代表示并运算的符号 |,以避免和文法中作为元符号使用的竖线相混淆: rexpr? rexpr + rterm | rterm rterm?rterm rfactor |rfactor rfactor? rfactor * | rprimary rprimary?a | b 1)对这个文法提取公因子2)提取公因子的变换使这个文法适用于自顶向下的语法分析技术吗?3)提取公因子之后,原文法中消除左递归 4) 得到的文法适用于自顶向下的语法分析吗?解1)提取左公因子之后的文法变为rexpr? rexpr + rterm | rterm rterm?rterm rfactor |rfactor rfactor? rfactor * | rprimary rprimary?a | b2)不可以,文法中存在左递归,而自顶向下技术不适合左递归文法3)消除左递归后的文法rexpr - rterm rexpr’rexpr rterm ’-+ rterm rexpr’|? rterm- rfactor rterm’ rterm-rfactor’’ |? rfactor- rprimay rfactor’ rfactor-*rfactor’’ |? rprimary- a| b4)该文法无左递归,适合于自顶向下的语法分析习题 4.4.1 :为下面的每一个文法设计一个预测分析器,并给出预测分析表。
编译原理教程课后习题答案【篇一:编译原理教程课后习题答案——第一章】完成下列选择题:(1) 构造编译程序应掌握a. 源程序b. 目标语言c. 编译方法d. 以上三项都是(2) 编译程序绝大多数时间花在上。
a. 出错处理b. 词法分析c. 目标代码生成d. 表格管理(3) 编译程序是对。
a. 汇编程序的翻译b. 高级语言程序的解释执行c. 机器语言的执行d. 高级语言的翻译【解答】(1) d (2) d(3) d1.2 计算机执行用高级语言编写的程序有哪些途径?它们之间的主要区别是什么?【解答】计算机执行用高级语言编写的程序主要有两种途径:解释和编译。
在解释方式下,翻译程序事先并不采用将高级语言程序全部翻译成机器代码程序,然后执行这个机器代码程序的方法,而是每读入一条源程序的语句,就将其解释(翻译)成对应其功能的机器代码语句串并执行,而所翻译的机器代码语句串在该语句执行后并不保留,最后再读入下一条源程序语句,并解释执行。
这种方法是按源程序中语句的动态执行顺序逐句解释(翻译)执行的,如果一语句处于一循环体中,则每次循环执行到该语句时,都要将其翻译成机器代码后再执行。
在编译方式下,高级语言程序的执行是分两步进行的:第一步首先将高级语言程序全部翻译成机器代码程序,第二步才是执行这个机器代码程序。
因此,编译对源程序的处理是先翻译,后执行。
从执行速度上看,编译型的高级语言比解释型的高级语言要快,但解释方式下的人机界面比编译型好,便于程序调试。
这两种途径的主要区别在于:解释方式下不生成目标代码程序,而编译方式下生成目标代码程序。
1.3 请画出编译程序的总框图。
如果你是一个编译程序的总设计师,设计编译程序时应当考虑哪些问题?【解答】编译程序总框图如图1-1所示。
作为一个编译程序的总设计师,首先要深刻理解被编译的源语言其语法及语义;其次,要充分掌握目标指令的功能及特点,如果目标语言是机器指令,还要搞清楚机器的硬件结构以及操作系统的功能;第三,对编译的方法及使用的软件工具也必须准确化。
第四章部分习题解答Aho:《编译原理技术与工具》书中习题(Aho)4.1 考虑文法S →( L ) | aL →L, S | Sa)列出终结符、非终结符和开始符号解:终结符:(、)、a、,非终结符:S、L开始符号:Sb)给出下列句子的语法树i)(a, a)ii)(a, (a, a))iii)(a, ((a, a), (a, a)))c)构造b)中句子的最左推导i)S⇒(L)⇒(L, S) ⇒(S, S) ⇒(a, S) ⇒(a, a)ii)S⇒(L)⇒(L, S) ⇒(S, S) ⇒(a, S) ⇒(a, (L)) ⇒(a, (L, S)) ⇒(a, (S, S)) ⇒(a, (a, S) ⇒(a, (a, a))iii)S⇒(L)⇒(L, S) ⇒(S, S) ⇒(a, S) ⇒(a, (L)) ⇒(a, (L, S)) ⇒(a, (S, S)) ⇒(a, ((L), S)) ⇒(a, ((L, S), S)) ⇒(a, ((S, S), S)) ⇒(a, ((a, S), S)) ⇒(a, ((a, a), S)) ⇒(a, ((a, a), (L)))⇒(a, ((a, a), (L, S))) ⇒(a, ((a, a), (S, S))) ⇒(a, ((a, a), (a, S))) ⇒(a, ((a, a), (a, a))) d)构造b)中句子的最右推导i)S⇒(L)⇒(L, S) ⇒(L, a) ⇒(S, a) ⇒(a, a)ii)S⇒(L)⇒(L, S) ⇒ (L, (L)) ⇒(L, (L, S)) ⇒(L, (L, a)) ⇒(L, (S, a)) ⇒(L, (a, a)) ⇒(S, (a, a)) ⇒(a, (a, a))iii)S⇒(L)⇒(L, S) ⇒(L, (L)) ⇒(L, (L, S)) ⇒(L, (L, (L))) ⇒(L, (L, (L, S))) ⇒(L, (L, (L,a))) ⇒(L, (L, (S, a))) ⇒(L, (L, (a, a))) ⇒(L, (S, (a, a))) ⇒(L, ((L), (a, a))) ⇒(L, ((L,S), (a, a))) ⇒(L, ((L, a), (a, a))) ⇒(L, ((S, a), (a, a))) ⇒(L, ((a, a), (S, S))) ⇒(S, ((a,a), (a, a))) ⇒(a, ((a, a), (a, a)))e)该文法产生的语言是什么解:设该文法产生语言(符号串集合)L,则L = { (A1, A2, …, A n) | n是任意正整数,A i=a,或A i∈L,i是1~n之间的整数}(Aho)4.2考虑文法S→aSbS | bSaS | εa)为句子构造两个不同的最左推导,以证明它是二义性的S⇒aSbS⇒abS⇒abaSbS⇒ababS⇒ababS⇒aSbS⇒abSaSbS⇒abaSbS⇒ababS⇒ababb)构造abab对应的最右推导S⇒aSbS⇒aSbaSbS⇒aSbaSb⇒aSbab⇒ababS⇒aSbS⇒aSb⇒abSaSb⇒abSab⇒ababc)构造abab对应语法树d)该文法产生什么样的语言?解:生成的语言:a、b个数相等的a、b串的集合(Aho)4.3 考虑文法bexpr→bexpr or bterm | btermbterm→bterm and bfactor | bfactorbfactor→not bfactor | ( bexpr ) | true | falsea)试为句子not ( true or false)构造分析树解:b)试证明该文法产生所有布尔表达式证明:一、首先证明文法产生的所有符号串都是布尔表达式变换命题形式——以bexpr、bterm、bfactor开始的推导得到的所有符号串都是布尔表达式最短的推导过程得到true、false,显然成立假定对步数小于n的推导命题都成立考虑步数等于n 的推导,其开始推导步骤必为以下情况之一bexpr⇒bexpr or btermbexpr⇒btermbterm⇒bterm and bfactorbexpr⇒bfactorbfactor⇒not bfactorbfactor⇒ ( bexpr )而后继推导的步数显然<n,因此由归纳假设,第二步句型中的NT推导出的串均为布尔表达式,这些布尔表达式经过or、and、not运算或加括号,得到的仍是布尔表达式因此命题一得证。
第四章部分习题解答Aho:《编译原理技术与工具》书中习题(Aho)4.1 考虑文法S →( L ) | aL →L, S | Sa)列出终结符、非终结符和开始符号解:终结符:(、)、a、,非终结符:S、L开始符号:Sb)给出下列句子的语法树i)(a, a)ii)(a, (a, a))iii)(a, ((a, a), (a, a)))c)构造b)中句子的最左推导i)S⇒(L)⇒(L, S) ⇒(S, S) ⇒(a, S) ⇒(a, a)ii)S⇒(L)⇒(L, S) ⇒(S, S) ⇒(a, S) ⇒(a, (L)) ⇒(a, (L, S)) ⇒(a, (S, S)) ⇒(a, (a, S) ⇒(a, (a, a))iii)S⇒(L)⇒(L, S) ⇒(S, S) ⇒(a, S) ⇒(a, (L)) ⇒(a, (L, S)) ⇒(a, (S, S)) ⇒(a, ((L), S)) ⇒(a, ((L, S), S)) ⇒(a, ((S, S), S)) ⇒(a, ((a, S), S)) ⇒(a, ((a, a), S)) ⇒(a, ((a, a), (L)))⇒(a, ((a, a), (L, S))) ⇒(a, ((a, a), (S, S))) ⇒(a, ((a, a), (a, S))) ⇒(a, ((a, a), (a, a))) d)构造b)中句子的最右推导i)S⇒(L)⇒(L, S) ⇒(L, a) ⇒(S, a) ⇒(a, a)ii)S⇒(L)⇒(L, S) ⇒ (L, (L)) ⇒(L, (L, S)) ⇒(L, (L, a)) ⇒(L, (S, a)) ⇒(L, (a, a)) ⇒(S, (a, a)) ⇒(a, (a, a))iii)S⇒(L)⇒(L, S) ⇒(L, (L)) ⇒(L, (L, S)) ⇒(L, (L, (L))) ⇒(L, (L, (L, S))) ⇒(L, (L, (L,a))) ⇒(L, (L, (S, a))) ⇒(L, (L, (a, a))) ⇒(L, (S, (a, a))) ⇒(L, ((L), (a, a))) ⇒(L, ((L,S), (a, a))) ⇒(L, ((L, a), (a, a))) ⇒(L, ((S, a), (a, a))) ⇒(L, ((a, a), (S, S))) ⇒(S, ((a,a), (a, a))) ⇒(a, ((a, a), (a, a)))e)该文法产生的语言是什么解:设该文法产生语言(符号串集合)L,则L = { (A1, A2, …, A n) | n是任意正整数,A i=a,或A i∈L,i是1~n之间的整数}(Aho)4.2考虑文法S→aSbS | bSaS | εa)为句子构造两个不同的最左推导,以证明它是二义性的S⇒aSbS⇒abS⇒abaSbS⇒ababS⇒ababS⇒aSbS⇒abSaSbS⇒abaSbS⇒ababS⇒ababb)构造abab对应的最右推导S⇒aSbS⇒aSbaSbS⇒aSbaSb⇒aSbab⇒ababS⇒aSbS⇒aSb⇒abSaSb⇒abSab⇒ababc)构造abab对应语法树d)该文法产生什么样的语言?解:生成的语言:a、b个数相等的a、b串的集合(Aho)4.3 考虑文法bexpr→bexpr or bterm | btermbterm→bterm and bfactor | bfactorbfactor→not bfactor | ( bexpr ) | true | falsea)试为句子not ( true or false)构造分析树解:b)试证明该文法产生所有布尔表达式证明:一、首先证明文法产生的所有符号串都是布尔表达式变换命题形式——以bexpr、bterm、bfactor开始的推导得到的所有符号串都是布尔表达式最短的推导过程得到true、false,显然成立假定对步数小于n的推导命题都成立考虑步数等于n 的推导,其开始推导步骤必为以下情况之一bexpr⇒bexpr or btermbexpr⇒btermbterm⇒bterm and bfactorbexpr⇒bfactorbfactor⇒not bfactorbfactor⇒ ( bexpr )而后继推导的步数显然<n,因此由归纳假设,第二步句型中的NT推导出的串均为布尔表达式,这些布尔表达式经过or、and、not运算或加括号,得到的仍是布尔表达式因此命题一得证。
二、证明所有布尔表达式均可由文法生成变换命题——所有析取式均可由bexpr推导出来,所有合取式均可由bterm(bexpr)推导出来,所有对子布尔表达式施加not运算或加括号或简单true、false都可由bfactor(bexpr、bterm)推导出来最简单的布尔表达式true和false显然成立假定对长度小于n的布尔表达式,均可由文法推导出来考虑长度等于n的布尔表达式B,显然,B只能是以下形式之一B = B1 or B2B = B1 and B2B = not B1B = ( B1 )以上几种情况,B1、B2的长度均小于n对于情况1:B为析取式,B1可为析取式也可为合取式,B2为合取式,根据假设可由bexpr 合bterm推导出来,显然可构造推导过程,由bexpr推导出B其他情况类似,命题二得证综合一、二,可知文法产生的语言就是布尔表达式c)(Aho)4.4考虑文法R→R ‘|’ R | RR | R* | (R) | a | bc)构造等价的非二义性文法R→R ‘|’ A | AA→A B | BB→B* | CC→( R ) | a | b(Aho)4.5下面if-then-else文法试图消除空悬else的二义性,证明它仍是二义性的stmt→if expr then stmt| matched_stmtmatched_stmt→if expr then matched_stmt else stmt| other解:用S、M、E表示stmt、matched_stmt和expr,用i、t、e、o表示if、then、else和other 则句子i E t i E t o e i E t o e o对应两个最左推导:S⇒i E t S⇒i E t M⇒i E t i E t M e S⇒i E t i E t o e S⇒i E t i E t o e M⇒i E t i E t o e i E t M e S⇒i E t i E t o e i E t o e S ⇒i E t i E t o e i E t o e M⇒i E t i E t o e i E t o e oS⇒M⇒i E t M e S⇒i E t i E t M e S e S⇒ i E t i E t o e S e S⇒ i E t i E t o e i E t S e S⇒ i E t i E t o e i E t M e S⇒ i E t i E t o e i E t o e S⇒ i E t i E t o e i E t o e M⇒ i E t i E t o e i E t o e o因此文法是二义性文法直接构造比较困难,可从SLR分析表的构造角度考虑,LR(0)项目集规范族中,项目I8={M→i E t M · e S, S→·M},有移进/归约冲突,这就是是二义性所在。
显然,存在句型...i E t M e S...和...i E t S e S...,当M位于栈顶时,产生移进/归约冲突。
按此思路,构造形如... i E t S e S...的句型即可(Aho)4.6 为下列语言设计上下文无关文法。
哪些语言是正规式?a)满足这样条件的二进制串:每个0之后都紧跟着至少一个1S→0 A | 1 S | εA→1 S正规式:(1 | 01)*b)0和1个数相等的二进制串S→0 S 1 S | 1 S 0 S | εd)不含011子串的二进制串S→0 A | 1 S | εA→0 A | 1 B | εB→0 A | ε正规式:1*(0 | 01)*e)具有形式xy的二进制串,x≠yS→A | B | A B | B AA→D A D | 0B→D B D | 1D→0 | 1A、B分别表示中心符号为0、1的长度为奇数的二进制串将AB串接,长度为偶数,将它从中间分为长度相等的两部分,x、y虽然A、B长度可能不一样,但容易得到,A的中心0在x中的位置,与B的中心1在y 中的位置是相同的,因此x≠yBA的情况类似f)形如xx的0、1串解:此语言无法用上下文无关文法描述(Aho)4.11 对习题4.1中文法a)消除左递归S→( L ) | aL→S L’L’→, S L’ | εb)构造预测分析表,对4.1(b)中句子,给出预测分析器的运行过程FIRST(S) = { (, a )FIRST(L) = { (, a }FIRST(L’) = { ‘,’, ε }FOLLOW(S) = {‘,’, ), $}FOLLOW(L) = { ) }FOLLOW(L’) = { ) }预测分析表:$) L’ S a)$ S→a$) L’ a a)$$) L’)$ L’→ε$) )$$ $其他两个句子的分析过程类似(Aho)4.13 下面文法产生除ε外所有长度为偶数的a的串S →a S a | a aa)试为该文法构造一个带回溯的递归下降语法分析器,对S的两个候选式首先考虑aSa。
证明:S所对应的过程可以成功分析2、4、8个a的串,但6个a的串不行。
解:aa的分析过程,其中√表示匹配成功,×表示匹配失败,匹配失败则尝试下个候选式aaaa分析过程:aaaaaa分析过程:aaaaaaaa分析过程:b)此语法分析器能识别什么样的语言?解:由a)的解可以看出,2N个a的串分析过程中,步骤如下1)产生2N+1个S的语法树,对第2N+1个S进行扩展时输入缓冲已空,失败2)对第2N个S尝试候选式aa,第二个a匹配失败3)对第2N-1个S尝试候选式aa,左边N-1个a匹配,右边最后一个a匹配,倒数第二个a失败4)对第2N-2个S尝试候选式aa,左边N-2个a匹配,右边最后一个a和倒数第二个a匹配,倒数第三个a失败5)对第2N-4个S尝试候选式aa,左边N-4个a匹配,右边最后一个a~倒数第四个a匹配,倒数第五个a失败6)对第2N-8个S尝试候选式aa,…最后正确识别的情况必然是:对第N个S尝试aa,左边N个a和右边N个a恰与输入匹配显然,可以正确识别的符号串的N满足2N – 1 – 1 – 2 – 4 - … = N N=2i(Aho)4.25 试给出图4-60中的优先关系表对应的优先级函数解:有向图如下优先级函数为a ( ) , $f 2 0 2 2 0g 3 3 0 1 0(Aho)4.26 对习题4.1中文法,利用讲义中给出的算法计算终结符之间的优先关系解:S →( L ) | aL →L, S | S由于S →( L ),因此( ≐)S →( L ),而L⇒L , S,L⇒S⇒( L ),L⇒S⇒a因此( ⋖, ,( ⋖ (,( ⋖ a;, ⋗ ),) ⋗ ),a ⋗ )由于L →L, S,而L⇒L , S,L⇒S⇒( L ),L⇒S⇒a,因此, ⋗ ,,) ⋗ ,,a ⋗ ,而S⇒( L ),S⇒a,因此, ⋖( ,, ⋖ a非终结符与$优先关系的计算方法:如果存在S⇒a…,或S⇒Qa…,则$ ⋖ a,若存在S⇒…a,或S⇒…aQ,则a ⋗ $因此,$ ⋖ (,$ ⋖ a,) ⋗ $,a ⋗ $算符优先关系表为:(Aho)4.27 试给下列文法构造算符优先关系a)练习4.2中文法解:S→aSbS | bSaS | ε由S→aSbS可得a≐b由S→bSaS可得b≐a由S→aSbS,和S⇒bSaS可得a⋖b、b⋖b、a⋗b,和S⇒aSbS可得a⋖a、b⋖a、b⋗b 由S→bSaS,和S⇒bSaS可得b⋖b、a⋖b、a⋗a,和S⇒aSbS可得b⋖a、a⋖a、a⋗a文法不是算符优先文法,二义性文法,很自然b)练习4.3中文法bexpr→bexpr or bterm | btermbterm→bterm and bfactor | bfactorbfactor→not bfactor | ( bexpr ) | true | false(Aho)4.30 一个文法称为Greibach范式(GNF)文法,如果它无ε产生式,且每个产生式(S→ε除外)均形如A→aα,其中,a是终结符,α是非终结符串,也可能为空。