我正在尝试使用此功能列出给定语法的第一组:
注意:
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]=='\0')
first_set[n++] = ';';
else if(rule[q1][q2]!='\0' &&(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
的第一组。
有人知道吗?提前致谢。
答案 0 :(得分:1)
一次计算一个FIRST集是非常低效的,因为它们是相互依赖的。例如,为了计算A
的FIRST集,还需要计算B
的FIRST集,然后由于B
可以得出情感字符串,因此需要FIRST Q
集。
大多数算法使用传递闭包算法的某些变体来并行计算所有算法。您可以通过深度优先搜索来执行此操作,这似乎是您要尝试的方法,但是实现Dragon书(和Wikipedia中描述的最小不动点算法可能会更容易。
无论哪种方式,您都可能会发现首先计算NULLABLE(即,哪些非终端派生空集)会更容易。有一个简单的线性时间算法(语法大小呈线性),又很容易找到。
如果您是在课堂上完成这项工作的,则您可能会在课程资料中找到相关的算法。或者,您可以寻找Dragon book或其他类似教科书的副本。
答案 1 :(得分:0)
您可以喜欢以下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 == '\0') {
first_set[*n] = '\0';
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] != '\0'; ++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;
}