/*
* 该程序用于计算某个非终结符的 FOLLOW 集合
* RexfieldVon
* 2013年6月30日16:02:47
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h> /* 三级指针
* 第一级指向整个产生式组
* 第二级指向单个产生式
* 第三级指向产生式符号单元
* 约定:所有的大写字母为非终结符
* 假设:无左递归、FIRST集中不会出现重复符号
*/
char*** GrammerRule; /*
* 初始化文法序列
*/
void InitizationGrammerRule()
{
// 分配表头空间
GrammerRule = (char***)malloc(sizeof(int) * );
memset(GrammerRule, '\0', sizeof(int) * );
// 分配文法空间并写入产生式
// G -> E
GrammerRule['G'] = (char**)malloc(sizeof(int) * );
GrammerRule['G'][] = (char*)malloc();
memcpy(GrammerRule['G'][], "E\0", ); // E
GrammerRule['G'][] = NULL;
// E -> T F
GrammerRule['E'] = (char**)malloc(sizeof(int) * );
GrammerRule['E'][] = (char*)malloc();
memcpy(GrammerRule['E'][], "TF\0", ); // T F
GrammerRule['E'][] = NULL;
// F -> '+' T F | '-' T F | e
GrammerRule['F'] = (char**)malloc(sizeof(int) * );
GrammerRule['F'][] = (char*)malloc();
memcpy(GrammerRule['F'][], "+TF\0", ); // '+' T F
GrammerRule['F'][] = (char*)malloc();
memcpy(GrammerRule['F'][], "-TF\0", ); // '-' T F
GrammerRule['F'][] = (char*)malloc();
memcpy(GrammerRule['F'][], "\0", ); // e (该产生式存在但是为空)
GrammerRule['F'][] = NULL;
// T -> A U
GrammerRule['T'] = (char**)malloc(sizeof(int) * );
GrammerRule['T'][] = (char*)malloc();
memcpy(GrammerRule['T'][], "AU\0", ); // A U
GrammerRule['T'][] = NULL;
// U -> '*' A U | '/' A U | e
GrammerRule['U'] = (char**)malloc(sizeof(int) * );
GrammerRule['U'][] = (char*)malloc();
memcpy(GrammerRule['U'][], "*AU\0", ); // '*' A U
GrammerRule['U'][] = (char*)malloc();
memcpy(GrammerRule['U'][], "/AU\0", ); // '/' A U
GrammerRule['U'][] = (char*)malloc();
memcpy(GrammerRule['U'][], "\0", ); // e (该产生式存在但是为空)
GrammerRule['U'][] = NULL;
// A -> '(' E ')' | d | n
GrammerRule['A'] = (char**)malloc(sizeof(int) * );
GrammerRule['A'][] = (char*)malloc();
memcpy(GrammerRule['A'][], "(E)\0", ); // '(' E ')'
GrammerRule['A'][] = (char*)malloc();
memcpy(GrammerRule['A'][], "d\0", ); // d
GrammerRule['A'][] = (char*)malloc();
memcpy(GrammerRule['A'][], "n\0", ); // n
GrammerRule['A'][] = NULL;
} /*
* 取得终结符数量
*/
int GetTerminalCount()
{
int i, TerminalCount = ;
for (i = ; i < ; i++)
{
if (GrammerRule[i] != NULL)
{
int k = ;
while (GrammerRule[i][k] != NULL)
{
int n = ;
while (GrammerRule[i][k][n] != '\0')
{
char c = GrammerRule[i][k][n];
if (c < 'A' || c > 'Z')
{
TerminalCount++;
}
n++;
}
k++;
}
}
}
return TerminalCount;
} /*
* 递归取得 FIRST 集
* Token : char 需要打印的符号
* FIRST : char* FIRST集
* Ptr : int* FIRST集的位置指针
*/
void GetFIRST(char Token, char *FIRST, int *Ptr)
{
if (Token >= 'A' && Token <= 'Z' && GrammerRule[Token] != NULL)
{
int i = ;
while (GrammerRule[Token][i] != NULL)
{
GetFIRST(GrammerRule[Token][i++][], FIRST, Ptr);
}
}
else if (Token < 'A' || Token > 'Z')
{
FIRST[*Ptr] = Token;
*Ptr = *Ptr + ;
}
} /*
* 添加符号到 FOLLOW 集
* FOLLOW : char* FOLLOW集
* Ptr : int* FOLLOW集的位置指针
* NewItem : char 将加入的符号
*/
void AddFOLLOWItem(char *FOLLOW, int *Ptr, char NewItem)
{
int i = ;
for (; i < *Ptr; i++)
{
if (FOLLOW[i] == NewItem)
{
return ;
}
}
FOLLOW[*Ptr] = NewItem;
*Ptr = *Ptr + ;
} /*
* 取得 FOLLOW 集
* Unterminal : char 需要打印的非终结符
* FOLLOW : char* FOLLOW集
* Ptr : int* FOLLOW集的位置指针
* TerminalCount : int 终结符数量
*/
void GetFOLLOW(char Unterminal, char *FOLLOW, int *Ptr, int TerminalCount)
{
int RuleIndex, ExprIndex, TokenIndex;
// 开始遍历整个文法
for (RuleIndex = ; RuleIndex < ; RuleIndex++)
{
if (GrammerRule[RuleIndex] == NULL)
{
continue;
}
// 搜索整个文法找到指定的非终结符
for (ExprIndex = ; GrammerRule[RuleIndex][ExprIndex] != ; ExprIndex++)
{
for (TokenIndex = ; GrammerRule[RuleIndex][ExprIndex][TokenIndex] != '\0'; TokenIndex++)
{
if (GrammerRule[RuleIndex][ExprIndex][TokenIndex] == Unterminal)
{
char nc = GrammerRule[RuleIndex][ExprIndex][TokenIndex + ];
if (nc == '\0' && RuleIndex != Unterminal) // 情形三:反复计算:将FOLLOW(P)加入FOLLOW(U)
{
GetFOLLOW((char)RuleIndex, FOLLOW, Ptr, TerminalCount);
}
else if (nc >= 'A' && nc <= 'Z') // 情形二:间接计算:将FIRST(P)加入FOLLOW(U)
{
char *FIRST = (char*)malloc(TerminalCount + );
memset(FIRST, '\0', TerminalCount + );
int FIRSTPtr = , InsertPtr;
GetFIRST(nc, FIRST, &FIRSTPtr);
for (InsertPtr = ; InsertPtr < FIRSTPtr; InsertPtr++)
{
if (FIRST[InsertPtr] != '\0')
{
AddFOLLOWItem(FOLLOW, Ptr, FIRST[InsertPtr]);
}
else // 对于 P->... U B,FOLLOW ← FIRST(B) - <e> + FOLLOW(P)
{
GetFOLLOW((char)RuleIndex, FOLLOW, Ptr, TerminalCount);
}
}
}
else if (nc != '\0') // 情形一:直接计算:将终结符加入FOLLOW(U)
{
AddFOLLOWItem(FOLLOW, Ptr, nc);
}
}
}
}
}
} /*
* 打印指定非终结符的 FOLLOW 集
* Unterminal : char 需要打印的非终结符
* TerminalCount : int 终结符数量
*/
void PrintUnterminalFOLLOW(char Unterminal, int TerminalCount)
{
char *FOLLOW = (char*)malloc(TerminalCount + );
memset(FOLLOW, '\0', TerminalCount + );
int Ptr = , i;
FOLLOW[Ptr++] = '\377'; // 初始化第一个符号为 EOF
GetFOLLOW(Unterminal, FOLLOW, &Ptr, TerminalCount);
printf("FOLLOW(%c): ", Unterminal);
for (i = ; i < Ptr; i++)
{
if (FOLLOW[i] == '\377')
{
printf("<eof> ");
}
else
{
printf("%c ", FOLLOW[i]);
}
}
printf("\n");
} int main(int argc, char **argv)
{
InitizationGrammerRule(); // 初始化文法
int TerminalCount = GetTerminalCount();
PrintUnterminalFOLLOW('E', TerminalCount);
PrintUnterminalFOLLOW('F', TerminalCount);
PrintUnterminalFOLLOW('T', TerminalCount);
PrintUnterminalFOLLOW('U', TerminalCount);
PrintUnterminalFOLLOW('A', TerminalCount);
return ;
}

简单的FOLLOW集演示程序的更多相关文章

  1. 简单的FIRST+集演示程序

    /* * 该程序用于计算某个非终结符的 FIRST+ 集合 * RexfieldVon * 2013年6月30日16:02:47 */ #include <stdio.h> #includ ...

  2. 简单的FIRST集演示程序

    /* * 该程序用于计算某个非终结符的 FIRST 集合 * RexfieldVon * 2013年6月29日19:53:45 * 2013年7月3日22:01:57 修改 GetFIRST 例程以简 ...

  3. 【编译原理】语法分析LL(1)分析法的FIRST和FOLLOW集

    近来复习编译原理,语法分析中的自上而下LL(1)分析法,需要构造求出一个文法的FIRST和FOLLOW集,然后构造分析表,利用分析表+一个栈来做自上而下的语法分析(递归下降/预测分析),可是这个FIR ...

  4. 【简单并查集】Farm Irrigation

    Farm Irrigation Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 65536/32768K (Java/Other) Tot ...

  5. POJ 2524 (简单并查集) Ubiquitous Religions

    题意:有编号为1到n的学生,然后有m组调查,每组调查中有a和b,表示该两个学生有同样的宗教信仰,问最多有多少种不同的宗教信仰 简单并查集 //#define LOCAL #include <io ...

  6. FIRST集和FOLLOW集

    省略号代表其他相关产生式得出的终结符号,一开始的时候,省略号里面是没有的   求FIRST集 情况壹  如果A只在→的右边出现,那么FIRST(A)={A},例子M→α,FIRST(α)={α} 情况 ...

  7. poj1611 简单并查集

    The Suspects Time Limit: 1000MS   Memory Limit: 20000K Total Submissions: 32781   Accepted: 15902 De ...

  8. 1213 How Many Tables(简单并查集)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1213 简单并查集,统计单独成树的数量. 代码: #include <stdio.h> #i ...

  9. RocketMQ 简单梳理 及 集群部署笔记【转】

    一.RocketMQ 基础知识介绍Apache RocketMQ是阿里开源的一款高性能.高吞吐量.队列模型的消息中间件的分布式消息中间件. 上图是一个典型的消息中间件收发消息的模型,RocketMQ也 ...

随机推荐

  1. LayoutInflater类详解

    http://www.cnblogs.com/top5/archive/2012/05/04/2482328.html   在实际开发中LayoutInflater这个类还是非常有用的,它的作用类似于 ...

  2. MVC ViewData和ViewBag

        视图数据可以通过ViewBag属性访问,它主要是为了从Controller到view进行传值用的,类似有所使用的ViewData[] 字典类.对于ViewBag是如此的强大,意味着你能动态的s ...

  3. MSSQLSERVER未分离LDF删除情况下的MDF附加

    经过网上资料搜索,此方法可以解决. LDF日志不要轻易删除,恢复主数据要用到,如果删除,记得先分离,然后移动到另外的地方. 下面是针对未分离删除日志文件,MDF文件附加,提示找不到日志的问题的解决方法 ...

  4. Java----多线程知识点归纳(概念)

    一.线程与进程的区别: 多个进程的内部数据和状态都是完全独立的,而多线程是共享一块内存空间和一组系统资源,有可能互相影响. ?线程本身的数据通常只有寄存器数据,以及一个 程序执行时使用的堆栈,所以线程 ...

  5. SGU 144.Meeting

    题目: 两支地区ACM比赛的队伍决定为了国际决赛而在一起集训. 他们约定在某天的 X 时到 Y 时的某一时刻相会. 但由于他们很少按时到 (有的队伍比赛那天都会迟到), 他们没有设定一个确切的相遇时间 ...

  6. Linux技巧总结(个人经验版)

    1:善用桌面:1.图形界面的编辑,2.终端只要开机就在第2桌面,3.浏览器在第3桌面,4.娱乐在第4桌面. 2:cd命令中,输入中文目录很不方便,用 ln -s 桌面 desktop 创建软链接,不必 ...

  7. 解决ListView异步加载图片错乱问题 .

    发一个异步图片加载控件.网上也有大把的异步网络加载图片的控件,但是有一个问题,异步加载会造成列表中的图片混乱,因为列表的每一项的View都可能被重用,异步加载的时候多个异步线程引用到了同一个View将 ...

  8. PHPCMS V9调用时间标签 |日期时间格式化

    PHPCMS V9 如何调用时间标签,下面分享常见的调用时间标签 |日期时间格式化  1.日期时间格式化显示: a标准型:{date('Y-m-d H:i:s', $rs['inputtime'])} ...

  9. Python自动化运维之31、Tornado框架

    Tornado 官网:http://www.tornadoweb.org/en/stable/ Tornado 是 FriendFeed 使用的可扩展的非阻塞式 web 服务器及其相关工具的开源版本. ...

  10. 访问Github过慢解决

    在这个地址查找响应最快的地址:http://tool.chinaz.com/dns?type=1&host=assets-cdn.github.com&ip= 查找:assets-cd ...