编译原理 - 期末复习

1.设 Σ = 0 , 1 \Sigma = {0, 1} Σ=0,1 ,请给出 Σ \Sigma Σ 中的下列语言的文法

(1)所有以 0 开头的串。

解1:
S → 0 ∣ S 0 ∣ S 1 S \rightarrow 0 | S0 | S1 S0∣S0∣S1
S 先生成任意的 0,1 串,最后在这个 0,1 串之前生成一个 0,从而保证生成的串是以 0 开头的串。
解2:
S → 0 A ∣ 0 S \rightarrow 0A | 0 S0A∣0
A → 0 ∣ 1 ∣ 0 A ∣ 1 A A \rightarrow 0 | 1 | 0A | 1A A0∣1∣0A∣1A
S 先生成 0A,然后“将任务交给变量 A",由 A 生成 0 后面的任意 0,1 符号串。

(2)所有以 0 开头,以 1 结尾的串。

解1:
S → 0 A 1 S \rightarrow 0A1 S0A1
A → ϵ ∣ 0 A ∣ 1 A A \rightarrow \epsilon | 0A | 1A Aϵ∣0A∣1A
先由 S 生成以 0 开头以 1 结尾的句型,然后由 0,1 之间的 A 生成中间部分。由于 01 本身也是满足要求的串,所以 A 可以产生 ϵ \epsilon ϵ
解 2:
S → 0 A S \rightarrow 0A S0A
A → 1 ∣ 0 A ∣ 1 A A \rightarrow 1 | 0A | 1A A1∣0A∣1A
用产生式 S → 0 A S \rightarrow 0A S0A 保证产生的字符串是以 0 开头的,产生式 A → 0 A ∣ 1 A A \rightarrow 0A | 1A A0A∣1A 被用来生成开头字符 0 之后,结尾字符 1 之前的所有 0,1 子串,产生式 A → 1 A \rightarrow 1 A1 是使除了 S 之外的所有其他句型中的唯一变量 A 变成终极符号的唯一产生式,该产生式保证了在句型的尾部生成一个 1 → 句子是以1结尾的。

(3)所有以 11 开头,以 11 结尾的串。

解:本题的解法与上一题类似,只不过是用 11 分别代替了字符串的首字符 0 和字符串的尾字符 1,其他位置的字符不变。另外,它还有两个特殊的句子 11 和 111,这是由开头的 11 与结尾的 11 一样所决定的,这里将它们作为特例处理。因此,相应的文法如下。对比本题的解法与上题的解法,读者可以进一步理解文法是经过对语言的结构的描述来定义语言的。所以,要构造一个给定语言的文法,最重要的是找出该语言的结构特征。
解1:
S → 11 A 11 ∣ 111 ∣ 11 S \rightarrow 11A11 | 111 | 11 S11A11∣111∣11
A → ϵ ∣ 0 A ∣ 1 A A \rightarrow \epsilon | 0A | 1A Aϵ∣0A∣1A
解2:
S → 11 A ∣ 111 ∣ 11 S \rightarrow 11A | 111 | 11 S11A∣111∣11
A → 11 ∣ 0 A ∣ 1 A A \rightarrow 11 | 0A | 1A A11∣0A∣1A

(4)所有 0 和 1 构成的但不含 00 的串。

文法规则:
S -> A | B
A -> 1A | 1B | 0
B -> 1B | 0B | 1 | 0

(5)所有 0 和 1 构成的含有形如 10110 的子串。

文法规则:
S -> A10110B
A -> 0A | ε
B -> 1B | ε

(6)含偶数个 0 的二进制数组成的串。

文法规则:
S -> AA
A -> 00A | 11A | ε

2.指出下列 Lex 正则式所匹配的字符串:
(1)" { " [ ^ { ] * " } "

该正则表达式匹配以 "{ " 开头,以 " } " 结尾,中间可以包含任意不是 “{” 的字符。
 
例如,匹配的字符串可以是:

  • “{ }”
  • “{ abc }”
  • “{ 123 }”

(2)[ ^ 0-9] | [ \r \n ]

该正则表达式匹配任何不是数字(0-9)的字符,或者回车符(\r)或换行符(\n)。
 
例如,匹配的字符串可以是:

  • “a”
  • “$”
  • “\r”
  • “\n”

(3)\ ’ ( [ ^ ’ \n ] | \’ \’ ) + \’

该正则表达式匹配由单引号包围的字符串,字符串内部可以包含任意不是单引号的字符,或者两个连续的单引号(表示转义的单引号)。
 
例如,匹配的字符串可以是:

  • ‘hello’
  • ‘I’m’
  • ‘John’s’

(4)\ " ([ ^ " \n ] | [ " \n ] ) * \"

该正则表达式匹配由双引号包围的字符串,字符串内部可以包含任意不是双引号的字符,或者双引号和换行符。
 
例如,匹配的字符串可以是:

  • “hello”
  • “I"m”
  • “John’s”

3.已知文法 G [ E ] G[E] G[E]
(1) E → a A ∣ b B E \rightarrow aA | bB EaAbB
(2) A → c A ∣ d A \rightarrow cA | d AcAd
(3) B → c B ∣ d B \rightarrow cB | d BcBd
构造该文法的 L R ( 0 ) LR(0) LR(0) 分析表

4.设有文法 G [ S ] G[S] G[S]
S → a ∣ ( T ) ∣ ∗ S \rightarrow a | (T) | * Sa(T)
T → T , S ∣ S T \rightarrow T , S | S TT,SS
① 构造此文法的 L R ( 0 ) LR(0) LR(0) 项目集规范族,并给出识别活前缀的 DFA。
② 构造其 L R ( 0 ) LR(0) LR(0) 分析表。

5.请利用代码优化的思想(代码外提和强度削弱等),改写下面程序中的循环,得到优化后的 C 语言程序。

Main( )
{
	int i, j;
	int S[20][50];
	for( i = 0; i < 20; i++)
	{
		for(j = 0; j < 50; j++)
			S[i][j] = 10 * i * j;
	}
}

【解答】 本题用到的代码优化技术主要有代码外提和强度消弱。 10 ∗ i 10 * i 10i在内循环是不变计算,可以外提,于是在外循环有 k = 10 ∗ i k = 10 * i k=10i,在内循环有 r [ i ] [ j ] = k ∗ j r[i][j] = k * j r[i][j]=kj;然后把这两个乘法进行轻度消弱,在循环中使用加法,在外循环每次加
10 10 10 r [ i ] [ j ] r[i][j] r[i][j] 在内循环每次加 k k k
C语言中允许使用指针访问数组的首地址,二维数组在存储区域是按行排列。这样,通过指针的加法运算就可以访问数组元素,避免在循环内部寻址的重复运算。优化后的C语言程序如下:

Main()  
{
	int i, j, m, n, k;
	int* p;
	int r[20][10];
	p = &r[0][0]; 
	n = 0;
	for(i = 0; i < 20; i++) 
	{ 
		k = n;
		n + =10; 
		m = 0; 
 		for(j = 0; j < 10; j++)
 		{ 
 			* p = m;
 	  		p++; 
 	 		m + = k;
   		}
	}
}

你可能感兴趣的:(编译原理)