如何找到第一个集合?
How to find first set?
我正在尝试使用此函数列出给定语法的第一组:
注:
char c
- 查找第一个集合的字符;
first_set
- 存储对应第一个集合的元素;
q1
, q2
- 前一个位置;
rule
- 逐行存储下面列出的所有语法规则;
第一次参数是('S', 0, 0)
.
void findfirst(char c, int q1, int q2){
if(!(isupper(c)) || c=='$'){
first_set[n++] = c;
}
for(int j=0;j<rule_number;j++){
if(rule[j][0]==c){
if(rule[j][2]==';'){
if(rule[q1][q2]=='[=10=]')
first_set[n++] = ';';
else if(rule[q1][q2]!='[=10=]' &&(q1!=0||q2!=0))
findfirst(rule[q1][q2], q1, (q2+1));
else
first_set[n++] = ';';
}
else if(!isupper(rule[j][2]) || rule[j][2]=='$')
first_set[n++] = rule[j][2];
else
findfirst(rule[j][2],j,3);
}
}
}
但是发现如果给定的语法是这样的:
S AC$
C c
C ;
A aBCd
A BQ
B bB
B ;
Q q
Q ;
(左边或右边的任何大写字母都是非终结符,任何小写字母都是终结符)
该函数无法正确输出 S
的第一组,因为它将在找到第一组 Q
时停止并将 ';'
存储到第一组并且不会继续找到 C
的第一组。
有人知道吗?提前致谢。
一次计算一个 FIRST 集是非常低效的,因为它们是相互依赖的。例如,为了计算 A
的第一个集合,您还需要计算 B
的第一个集合,然后因为 B
可以导出 emoty 字符串,您需要 FIRST一组 Q
.
大多数算法使用传递闭包算法的某些变体并行计算所有这些。你可以用深度优先搜索来做到这一点,这似乎是你正在尝试的,但它可能更容易实现龙书中描述的最小不动点算法(和 Wikipedia.
无论哪种方式,您可能会发现首先计算 NULLABLE(即,哪些非终端派生空集)更容易。有一个简单的线性时间算法(与语法大小成线性关系),也很容易找到。
如果您将这项工作作为 class 的一部分进行,您可能会在课程材料中找到相关算法。或者,您可以查找 Dragon book 或其他类似教科书的副本。
你可以像下面这样code
:
used[i]
表示是否使用rule[i]
方法是Depth-first search
,见https://en.wikipedia.org/wiki/Depth-first_search
#include <iostream>
#define MAX_SIZE 1024
char rule[][10] = {
"S AC$",
"C c",
"C ;",
"A aBCd",
"A BQ",
"B bB",
"B ;",
"Q q",
"Q ;"
};
constexpr int rule_number = sizeof(rule) / sizeof(rule[0]);
char first_set[MAX_SIZE];
bool findfirst(int row, int col, int *n, bool* used) {
for (;;) {
char ch = rule[row][col];
if (ch == '$' || ch == ';' || ch == '[=10=]') {
first_set[*n] = '[=10=]';
break;
}
if (islower(ch)) {
first_set[(*n)++] = ch;
++col;
continue;
}
int i;
for (i = 0; i != rule_number; ++i) {
if (used[i] == true || rule[i][0] != ch)
continue;
used[i] = true;
int k = *n;
if (findfirst(i, 2, n, used) == true)
break;
used[i] = false;
*n = k;
}
if (i == rule_number)
return false;
++col;
}
return true;
}
int main() {
bool used[rule_number];
int n = 0;
for (int i = 2; rule[0][i] != '$' && rule[0][i] != '[=10=]'; ++i) {
for (int j = 0; j != rule_number; ++j)
used[j] = false;
used[0] = true;
findfirst(0, i, &n, used);
}
std::cout << first_set << std::endl;
return 0;
}
我正在尝试使用此函数列出给定语法的第一组:
注:
char c
- 查找第一个集合的字符;
first_set
- 存储对应第一个集合的元素;
q1
, q2
- 前一个位置;
rule
- 逐行存储下面列出的所有语法规则;
第一次参数是('S', 0, 0)
.
void findfirst(char c, int q1, int q2){
if(!(isupper(c)) || c=='$'){
first_set[n++] = c;
}
for(int j=0;j<rule_number;j++){
if(rule[j][0]==c){
if(rule[j][2]==';'){
if(rule[q1][q2]=='[=10=]')
first_set[n++] = ';';
else if(rule[q1][q2]!='[=10=]' &&(q1!=0||q2!=0))
findfirst(rule[q1][q2], q1, (q2+1));
else
first_set[n++] = ';';
}
else if(!isupper(rule[j][2]) || rule[j][2]=='$')
first_set[n++] = rule[j][2];
else
findfirst(rule[j][2],j,3);
}
}
}
但是发现如果给定的语法是这样的:
S AC$
C c
C ;
A aBCd
A BQ
B bB
B ;
Q q
Q ;
(左边或右边的任何大写字母都是非终结符,任何小写字母都是终结符)
该函数无法正确输出 S
的第一组,因为它将在找到第一组 Q
时停止并将 ';'
存储到第一组并且不会继续找到 C
的第一组。
有人知道吗?提前致谢。
一次计算一个 FIRST 集是非常低效的,因为它们是相互依赖的。例如,为了计算 A
的第一个集合,您还需要计算 B
的第一个集合,然后因为 B
可以导出 emoty 字符串,您需要 FIRST一组 Q
.
大多数算法使用传递闭包算法的某些变体并行计算所有这些。你可以用深度优先搜索来做到这一点,这似乎是你正在尝试的,但它可能更容易实现龙书中描述的最小不动点算法(和 Wikipedia.
无论哪种方式,您可能会发现首先计算 NULLABLE(即,哪些非终端派生空集)更容易。有一个简单的线性时间算法(与语法大小成线性关系),也很容易找到。
如果您将这项工作作为 class 的一部分进行,您可能会在课程材料中找到相关算法。或者,您可以查找 Dragon book 或其他类似教科书的副本。
你可以像下面这样code
:
used[i]
表示是否使用rule[i]
方法是Depth-first search
,见https://en.wikipedia.org/wiki/Depth-first_search
#include <iostream>
#define MAX_SIZE 1024
char rule[][10] = {
"S AC$",
"C c",
"C ;",
"A aBCd",
"A BQ",
"B bB",
"B ;",
"Q q",
"Q ;"
};
constexpr int rule_number = sizeof(rule) / sizeof(rule[0]);
char first_set[MAX_SIZE];
bool findfirst(int row, int col, int *n, bool* used) {
for (;;) {
char ch = rule[row][col];
if (ch == '$' || ch == ';' || ch == '[=10=]') {
first_set[*n] = '[=10=]';
break;
}
if (islower(ch)) {
first_set[(*n)++] = ch;
++col;
continue;
}
int i;
for (i = 0; i != rule_number; ++i) {
if (used[i] == true || rule[i][0] != ch)
continue;
used[i] = true;
int k = *n;
if (findfirst(i, 2, n, used) == true)
break;
used[i] = false;
*n = k;
}
if (i == rule_number)
return false;
++col;
}
return true;
}
int main() {
bool used[rule_number];
int n = 0;
for (int i = 2; rule[0][i] != '$' && rule[0][i] != '[=10=]'; ++i) {
for (int j = 0; j != rule_number; ++j)
used[j] = false;
used[0] = true;
findfirst(0, i, &n, used);
}
std::cout << first_set << std::endl;
return 0;
}