E -> (E) | -E | D (A) | N | F A -> E;A | E判断是否为LL(1)文法
时间: 2023-10-26 22:07:50 浏览: 138
首先,LL(1)文法要求每个非终结符在同一输入符号下只有一个产生式可以被选择。接下来,我们对该文法进行分析:
1. 对于非终结符E,存在三个产生式:E -> (E) | -E | D (A)。这三个产生式都以左括号、减号和D开始,因此无法通过一个输入符号来区分它们。因此,该文法不是LL(1)文法。
2. 对于非终结符A,存在两个产生式:A -> E;A | E。这两个产生式都以E开始,但是可以通过分号来区分它们:第一个产生式以分号结尾,第二个产生式不以分号结尾。因此,该文法是LL(1)文法。
综上,该文法不是LL(1)文法。
相关问题
解答下列问题并给出过程:1.判断下面文法是否为LL(1)文法 S→aH H→aMd|d M →Ab|k A →aM|e
首先,LL(1)文法要求在进行预测分析时,每个非终结符的一个产生式都有唯一的一个前缀来区分其后继。因此,我们需要分析该文法的每个非终结符的FIRST集和FOLLOW集,来判断是否满足LL(1)文法的条件。
首先,计算出每个符号的FIRST集:
- FIRST(S)={a}
- FIRST(H)={a, d}
- FIRST(M)={a, k}
- FIRST(A)={a, e}
然后,计算出每个符号的FOLLOW集:
- FOLLOW(S)={$}
- FOLLOW(H)={b, c}
- FOLLOW(M)={b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, $}
- FOLLOW(A)={d, k}
最后,我们来检查每个非终结符的产生式,看是否存在冲突。因为该文法比较简单,我们直接检查每个产生式:
- S→aH
- FIRST(a)∩FIRST(H)=空集,无冲突
- H→aMd
- FIRST(a)∩FIRST(M)=FIRST(a),有冲突
- H→d
- FIRST(d)∩FIRST(M)=空集,无冲突
- M→Ab
- FIRST(a)∩FIRST(B)=FIRST(a),有冲突
- M→k
- FIRST(k)∩FIRST(B)=空集,无冲突
- A→aM
- FIRST(a)∩FIRST(M)=FIRST(a),有冲突
- A→e
- FIRST(e)∩FIRST(M)=空集,无冲突
由于存在冲突的产生式,所以该文法不是LL(1)文法。
编写一个C程序,读入该文法,判断该文法是否为LL(1)文法。如果是LL(1)文法,则构造并输出该文法的LL(1)分析表。
好的,以下是一个简单的C程序,它可以读入一个文法,判断它是否是LL(1)文法,并构造LL(1)分析表:
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_PROD 100
#define MAX_TERMS 100
#define MAX_NON_TERMS 100
char productions[MAX_PROD][MAX_TERMS];
char non_terms[MAX_NON_TERMS];
char terms[MAX_TERMS];
int num_productions, num_terms, num_non_terms;
char first[128][MAX_TERMS], follow[128][MAX_TERMS], select[MAX_NON_TERMS][MAX_TERMS];
char parsing_table[MAX_NON_TERMS][MAX_TERMS][MAX_TERMS];
int has_eps[MAX_NON_TERMS];
int is_non_term(char c) {
return c >= 'A' && c <= 'Z';
}
int is_term(char c) {
return c >= 'a' && c <= 'z';
}
int is_eps(char *s) {
return strlen(s) == 1 && s[0] == '@';
}
void add_to_set(char set[MAX_TERMS], char c) {
int i;
for (i = 0; i < strlen(set); i++) {
if (set[i] == c) {
return;
}
}
set[strlen(set)] = c;
}
void compute_first() {
int i, j, k;
for (i = 0; i < num_terms; i++) {
first[terms[i]][0] = terms[i];
}
for (i = 0; i < num_non_terms; i++) {
has_eps[i] = 0;
for (j = 0; j < num_productions; j++) {
if (productions[j][0] == non_terms[i]) {
if (is_term(productions[j][2])) {
add_to_set(first[non_terms[i]], productions[j][2]);
} else if (is_non_term(productions[j][2])) {
for (k = 0; k < strlen(first[productions[j][2]]); k++) {
if (first[productions[j][2]][k] != '@') {
add_to_set(first[non_terms[i]], first[productions[j][2]][k]);
}
}
if (is_eps(first[productions[j][2]])) {
has_eps[i] = 1;
}
}
}
}
}
}
void compute_follow() {
int i, j, k, l, m;
follow[non_terms[0]][0] = '$';
for (i = 0; i < num_non_terms; i++) {
for (j = 0; j < num_productions; j++) {
for (k = 2; k < strlen(productions[j]); k++) {
if (productions[j][k] == non_terms[i]) {
for (l = k + 1; l < strlen(productions[j]); l++) {
if (is_term(productions[j][l])) {
add_to_set(follow[productions[j][k]], productions[j][l]);
break;
} else if (is_non_term(productions[j][l])) {
for (m = 0; m < strlen(first[productions[j][l]]); m++) {
if (first[productions[j][l]][m] != '@') {
add_to_set(follow[productions[j][k]], first[productions[j][l]][m]);
}
}
if (!has_eps[productions[j][l] - 'A']) {
break;
}
}
}
if (l == strlen(productions[j])) {
for (m = 0; m < strlen(follow[productions[j][0]]); m++) {
add_to_set(follow[productions[j][k]], follow[productions[j][0]][m]);
}
}
}
}
}
}
}
void compute_select() {
int i, j, k;
for (i = 0; i < num_productions; i++) {
if (is_eps(&productions[i][2])) {
for (j = 0; j < strlen(follow[productions[i][0]]); j++) {
add_to_set(select[i], follow[productions[i][0]][j]);
}
} else {
for (j = 0; j < strlen(first[productions[i][2]]); j++) {
if (first[productions[i][2]][j] != '@') {
add_to_set(select[i], first[productions[i][2]][j]);
}
}
}
}
}
void build_parsing_table() {
int i, j, k;
for (i = 0; i < num_productions; i++) {
for (j = 0; j < strlen(select[i]); j++) {
if (select[i][j] != '@') {
if (parsing_table[productions[i][0] - 'A'][select[i][j]] != '\0') {
printf("Grammar is not LL(1)\n");
exit(1);
}
for (k = 0; k < strlen(productions[i]); k++) {
parsing_table[productions[i][0] - 'A'][select[i][j]][k] = productions[i][k];
}
} else {
for (j = 0; j < strlen(follow[productions[i][0]]); j++) {
if (parsing_table[productions[i][0] - 'A'][follow[productions[i][0]][j]] != '\0') {
printf("Grammar is not LL(1)\n");
exit(1);
}
for (k = 0; k < strlen(productions[i]); k++) {
parsing_table[productions[i][0] - 'A'][follow[productions[i][0]][j]][k] = productions[i][k];
}
}
}
}
}
}
void print_parsing_table() {
int i, j, k;
printf("Parsing Table:\n");
printf("Non-Terminals/Terminals\t");
for (i = 0; i < num_terms; i++) {
printf("%c\t", terms[i]);
}
printf("\n");
for (i = 0; i < num_non_terms; i++) {
printf("%c\t\t\t", non_terms[i]);
for (j = 0; j < num_terms; j++) {
printf("%s\t", parsing_table[non_terms[i] - 'A'][terms[j]]);
}
printf("\n");
}
}
int main() {
int i, j;
printf("Enter the number of productions: ");
scanf("%d", &num_productions);
printf("Enter the productions:\n");
for (i = 0; i < num_productions; i++) {
scanf("%s", productions[i]);
}
for (i = 0; i < num_productions; i++) {
add_to_set(non_terms, productions[i][0]);
for (j = 2; j < strlen(productions[i]); j++) {
if (is_non_term(productions[i][j])) {
add_to_set(non_terms, productions[i][j]);
} else if (is_term(productions[i][j])) {
add_to_set(terms, productions[i][j]);
}
}
}
num_non_terms = strlen(non_terms);
num_terms = strlen(terms);
compute_first();
compute_follow();
compute_select();
build_parsing_table();
print_parsing_table();
return 0;
}
```
这个程序的输入格式如下:
- 第一行是产生式的数量。
- 接下来的每一行都是一个产生式。
- 在每个产生式中,左部是一个大写字母(非终结符),右部可以是任意数量的终结符和非终结符,用空格分开。
- 在右部中,非终结符使用大写字母表示,终结符使用小写字母表示。
- 空串使用符号“@”表示。
例如,以下是一个输入示例:
```
4
E -> T E'
E' -> + T E' | @
T -> F T'
T' -> * F T' | @
F -> ( E ) | id
```
该程序会输出该文法的LL(1)分析表。如果该文法不是LL(1)文法,程序会输出一条错误消息并退出。
希望这个程序能帮助到您,有任何问题请随时问我。
阅读全文