LL(1)的特点
- 表驱动
- 线性。
- 会有冲突。
可以用这个部分来学习分析表的知识。分析表会告诉分析栈一些信息。而分析表是根据语法自动生成的。
读入语法,生成了这个表。
其实就是之前的算法,每次压入时,压入的是正确的表达式
假设我要分析的是我自己写的一个语法,如下:
A=B
|空
B =C C
|C
C= D E F
D=G
|空
G= a a
|a
E=H
|空
H=b b
|b
F=c c
|c
第一件事,先构造FIRST集
FIRST(N)表示从非终结符N开始推到得出的句子开头的所有可能终结符集合。
那么对于N=a…a是终结符
FIRST(N) 并={a}
对于N=M,M是非终结符
FIRST(N)并FIRST(M)
课程来自https://www.bilibili.com/video/BV17W41187gL?p=49
5.1.3
直接在unity里面写了一个:
public List<string> tokens;//当前给出的词法内容
public string S_token;//起始token
public List<string> N_token;//非终结符
public List<string> T_token;//终结符
public Dictionary<string, List<string>> generator_dict;//产生式表
public Dictionary<string, List<string>> FIRST;//FIRST集
public string empty_token = "%";
// Start is called before the first frame update
void Start()
{
generator_dict = new Dictionary<string, List<string>>();
//建立产生式表A的
List<string> tempA = new List<string>();
tempA.Add("B");
tempA.Add(empty_token);
generator_dict["A"] = tempA; //建立产生式表B的
List<string> tempB = new List<string>();
tempB.Add("CC");
tempB.Add("C");
generator_dict["B"] = tempB; //建立产生式表C的
List<string> tempC = new List<string>();
tempC.Add("DEF");
generator_dict["C"] = tempC; //建立产生式表D的
List<string> tempD = new List<string>();
tempD.Add("G");
tempD.Add(empty_token);
generator_dict["D"] = tempD; //建立产生式表G的
List<string> tempG = new List<string>();
tempG.Add("aa");
tempG.Add("a");
generator_dict["G"] = tempG; //建立产生式表E的
List<string> tempE = new List<string>();
tempE.Add("H");
tempE.Add(empty_token);
generator_dict["E"] = tempE; //建立产生式表H的
List<string> tempH = new List<string>();
tempH.Add("bb");
tempH.Add("b");
generator_dict["H"] = tempH; //建立产生式表F的
List<string> tempF = new List<string>();
tempF.Add("cc");
tempF.Add("c");
generator_dict["F"] = tempF; //开始符
S_token = "A";
//非终结符
N_token = new List<string>();
N_token.Add("A");
N_token.Add("B");
N_token.Add("C");
N_token.Add("D");
N_token.Add("E");
N_token.Add("F");
N_token.Add("G");
N_token.Add("H");
//终结符
T_token = new List<string>();
T_token.Add("a");
T_token.Add("b");
T_token.Add("c");
Create_First_Set();
} // Update is called once per frame public void Create_First_Set()
{
FIRST = new Dictionary<string, List<string>>();
foreach (string N in N_token)//轮询所有非终结符
{
FIRST[N] = new List<string>();//初始化成空集
}
bool still_changing = true; while (still_changing)
{
//克隆了一份
Dictionary<string, List<string>> NEWFIRST = new Dictionary<string, List<string>>();
foreach (KeyValuePair<string, List<string>> kvp in FIRST)
{
List<string> templist = new List<string>();
foreach (string a in kvp.Value)
{
templist.Add(a);
}
NEWFIRST[kvp.Key] = templist;
} foreach (string N in N_token)//轮询所有非终结符
{
foreach (string EveryString in generator_dict[N])//对于所有非终结符的产生式。
{
Debug.Log(EveryString);
char[] c_List = EveryString.ToCharArray();
foreach (char C in c_List)
{
if (N_token.Contains(C.ToString()))
{
//如果是非终结符,并集(处理了一遍)
FIRST[N]=FIRST[N].Union(FIRST[C.ToString()]).ToList();
}
else if (T_token.Contains(C.ToString()))
{
//如果是终结符直接加入。
List<string> newt = new List<string>();
newt.Add(C.ToString());
FIRST[N] = FIRST[N].Union(newt).ToList();
}
}
}
Debug.Log("下一个");
}
//判断是否变化了
bool dictionariesEqual = Equal_dict(NEWFIRST,FIRST);
still_changing = !dictionariesEqual; }
//这里应该产生了一个集了。
Debug.Log(FIRST);
}
制造出来的FIRST集是
A=abc
B=abc
C=abc
D=a
E=b
F=c
G=a
H=b
和文法符合!
接下来就是要制造Follow集来包容空集的情况,后面一篇文章更新。