语法分析程序的设计与实现

原文地址

环境

  1. win10
  2. vscode
  3. mingw

综述

共实现了三种语法分析程序,即LL1、SLR1和LR1语法分析程序,对满足条件的输入文法能够自动的生成该文法的语法分析程序并执行分析过程,输出所采用的产生式。源代码

对于LL1语法分析程序有以下功能(要求输入文法为LL1文法)

  • 自动构建FIRST集
  • 自动构建FOLLOW集
  • 自动构建预测分析表
  • 执行分析程序分析输入串
  • 输出所采用的产生式

对于SLR1分析程序有以下功能(要求输入文法为SLR1文法)

  • 自动构建FIRST集
  • 自动构建FOLLOW集
  • 自动构建有效项目集规范族和DFA
  • 自动构建SLR1分析表
  • 执行分析程序分析输入串
  • 输出所采用的产生式

对于LR1分析程序有以下功能(要求输入文法为LR1文法)

  • 自动构建FIRST集
  • 自动构建有效项目集规范族和DFA
  • 自动构建LR1分析表
  • 执行分析程序分析输入串
  • 输出所采用的产生式

三种语法分析程序均要求输入的文法符号为单个字符,请将原文法符号不是单个字符自行更换为单文法符号,如S’更换为A,id更换为n,以此类推。具体输入格式见每个程序测试部分的输入样例。

LL1语法分析程序

数据结构

/* 产生式结构体 */
struct Production {char left; // 左部符号vector<char> rigths;  // 右部符号串
};/* 文法结构体 */
struct Grammar {int num;  // 产生式数量vector<char> T;   // 终结符集vector<char> N;   // 非终结符集vector<Production> prods;  //产生式集
} grammar;/* FIRST集和FOLLOW集 */
map<char, set<char> > first;
map<char, set<char> > follow;/* 分析栈 */
stack<char> ST;/* 待分析串 */
string str;/* 预测分析表 */
vector<char> M[50][50];

辅助函数

/* 判断ch是否是终结符, 若是返回所在位置 */
int isInT(char ch);/* 判断ch是否是非终结符, 若是返回所在位置 */
int isInN(char ch);/* 读入并初始化语法 */
void initGrammar();/* 把生成式插入到预测分析表对应的项中 */
void insertTOForecastAnalysisTable(char A, char a, Production &P);/* 取出预测分析表对应的项中的产生式 */
void getFromForecastAnalysisTable(char A, char a, vector<char> &s);

构建FIRST集和FOLLOW集

求单个文法符号的FIRST集

/* 求(T U N)的FIRST集 */
void getFirstSet()
{/* 终结符的FIRST集是其本身 */for (int i = 0; i < grammar.T.size(); i++) {char X = grammar.T[i];set<char> tmp;tmp.insert(X);first[X] = tmp;}/* 当非终结符的FIRST集发生变化时循环 */bool change = true;while (change) {change = false;/* 枚举每个产生式 */for (int i = 0; i < grammar.prods.size(); i++) {Production &P = grammar.prods[i];char X = P.left;set<char> &FX = first[X];/* 如果右部第一个符号是空或者是终结符,则加入到左部的FIRST集中 */if (isInT(P.rigths[0]) || P.rigths[0] == '&') {/* 查找是否FIRST集是否已经存在该符号 */auto it = FX.find(P.rigths[0]);/* 不存在 */if (it == FX.end()) {change = true; // 标注FIRST集发生变化,循环继续FX.insert(P.rigths[0]);}} else {/* 当前符号是非终结符,若当前符号可以推出空,则还需判断下一个符号 */bool next = true;/* 待判断符号的下标 */int idx = 0;while (next && idx < P.rigths.size()) {next = false;char Y = P.rigths[idx];set<char> &FY = first[Y];for (auto it = FY.begin(); it != FY.end(); it++) {/* 把当前符号的FIRST集中非空元素加入到左部符号的FIRST集中 */if (*it != '&') {auto itt = FX.find(*it);if (itt == FX.end()) {change = true;FX.insert(*it);}}}/* 当前符号的FIRST集中有空, 标记next为真,idx下标+1 */auto it = FY.find('&');if (it != FY.end()) {next = true;idx = idx + 1;}}}}}
}

求一串文法符号的FIRST集

要求FIRST(α\alphaα),先将α\alphaα的第一个文法符号的FIRST集加入到加入到FIRST(α\alphaα),若当前符号的FIRST集含空,则继续将下一个文法符号的FIRST加入到FIRST(α\alphaα)中,直至末尾。

/* 产找alpha串的FIRST集, 保存到FS集合中 */
void getFirstByAlphaSet(vector<char> &alpha, set<char> &FS)
{/* 当前符号是非终结符,若当前符号可以推出空,则还需判断下一个符号 */bool next = true;int idx = 0;while (idx < alpha.size() && next) {next = false;/* 当前符号是终结符或空,加入到FIRST集中 */if (isInT(alpha[idx]) || alpha[idx] == '&') {/* 判断是否已经在FIRST集中 */auto itt = FS.find(alpha[idx]);if (itt == FS.end()) {FS.insert(alpha[idx]);}} else {char B = alpha[idx];set<char> &FB = first[B];for (auto it = first[B].begin(); it != first[B].end(); it++) {/* 当前符号FIRST集包含空,标记next为真,并跳过当前循环 */if (*it == '&') {next = true;continue;}/* 把非空元素加入到FIRST集中 */auto itt = FS.find(*it);if (itt == FS.end()) {FS.insert(*it);}}}idx = idx + 1;}/* 如果到达产生式右部末尾next还为真,说明alpha可以推空,将空加入到FIRST集中 */if (next) {FS.insert('&');}
}

求非终结符的FOLLOW集

/* 求非终结符的FOLLOW集 */
void getFollowSet()
{/* 初始化终结符的FOLLOW集为空集 */for (int i = 0; i < grammar.N.size(); i++) {char B = grammar.N[i];follow[B] = set<char>();}/* 将$加入到文法的开始符号的FOLLOW集中 */char S = grammar.N[0];follow[S].insert('$');bool change = true;while (change) {change = false;/* 枚举每个产生式 */for (int i = 0; i < grammar.prods.size(); i++) {Production &P = grammar.prods[i];for (int j = 0; j < P.rigths.size(); j++) {char B = P.rigths[j];/* 当前符号是非终结符 */if (isInN(B)) {set<char> &FB = follow[B];set<char> FS;/* alpha是从当前符号下一个符号开始的符号串 */vector<char> alpha(P.rigths.begin() + j + 1, P.rigths.end());/* 求alpha的FIRST集,即FS */getFirstByAlphaSet(alpha, FS);/* 将alpha的FIRST集中所有非空元素加入到当前符号的FOLLOW集中 */for (auto it = FS.begin(); it != FS.end(); it++) {if (*it == '&') {continue;}auto itt = FB.find(*it);if (itt == FB.end()) {change = true;FB.insert(*it);}}/* 如果alpha能推空,或者当前符号是产生式右部末尾,则将文法左部符号的FOLLOW集加入到当前符号的FOLLOW集中 */auto itt = FS.find('&');if (itt != FS.end() || (j + 1) >= P.rigths.size()) {char A = P.left; //A为左部符号for (auto it = follow[A].begin(); it != follow[A].end(); it++) {auto itt = FB.find(*it);if (itt == FB.end()) {change = true;FB.insert(*it);}}    }}}}}
}

构建预测分析表

/* 构建预测分析表 */
void productForecastAnalysisTable()
{/* 枚举所有产生式 */for (int i = 0; i < grammar.prods.size(); i++) {/* 假设P为 A->alpha */Production &P = grammar.prods[i];set<char> FS;/* 对每个 a in FIRST(alpha) 把 A->alpha放入M[A, a]中 */getFirstByAlphaSet(P.rigths, FS);for (auto it = FS.begin(); it != FS.end(); it++) {insertTOForecastAnalysisTable(P.left, *it, P);}/* 如果alpha能推空,则把每个b in FOLLOW(A) 把 A->alpha放入M[A, b]中*/auto itt = FS.find('&');if (itt != FS.end()) {for (auto it = follow[P.left].begin(); it != follow[P.left].end(); it++) {insertTOForecastAnalysisTable(P.left, *it, P);}}}
}

分析程序

/* 分析程序 */
void process()
{/* 指向当前字符 */int ip = 0;/* 栈顶符号X, 和当前输入符号a */char X, a;printf("The answer:\n");do{X = ST.top();a = str[ip];/* 如果是终结符或者$ */if (isInT(X)) {/* 如果栈顶符号和当前符号匹配,出栈,指针前移 */if (X == a) {ST.pop();ip = ip + 1;} else { /* 不匹配报错 */printf("error1\n");}} else {    //非终结符vector<char> s;/* 取出对应预测分析表的项 */getFromForecastAnalysisTable(X, a, s);/* 预测分析表项中有元素 */if (!s.empty()) {/* 弹栈并将右部符号串逆序入栈 */ST.pop();for (int i = s.size() - 1; i >= 3; i--) {if (s[i] != '&') { // 为空时不入栈ST.push(s[i]);}}/* 输出产生式 */for (int i = 0; i < s.size(); i++) {printf("%c", s[i]);}printf("\n");} else { // 空,报错printf("error2\n");}}} while (X != '$');
}

测试

编译源程序

g++ -o LL1 LL1.cpp

执行LL1分析程序

.\LL1.exe

输入一下内容

10
E->TA
A->+TA
A->-TA
A->&
T->FB
B->*FB
B->/FB
B->&
F->(E)
F->n
E T A F B #
n + - * / ( ) #
(n+n)*n-n/n

查看输出结果

FIRST集和FOLLOW集
FIRST:
E: ( n
T: ( n
A: & + -
F: ( n
B: & * /
FOLLOW:
E: $ )
T: $ ) + -
A: $ )
F: $ ) * + - /
B: $ ) + -
预测分析表

输出产生式
The answer:
E->TA
T->FB
F->(E)
E->TA
T->FB
F->n
B->&
A->+TA
T->FB
F->n
B->&
A->&
B->*FB
F->n
B->&
A->-TA
T->FB
F->n
B->/FB
F->n
B->&
A->&

LL1输出最左推导,下面验证其正确性。

E=>TA=>FBA=>(E)BA=>(TA)BA=>(FBA)BA=>(nBA)BA=>(nA)BA=>(n+TA)BA=>(n+FBA)BA=>(n+nBA)BA=>(n+nA)BA=>(n+n)BA=>(n+n)*FBA=>(n+n)*nBA=>(n+n)*nA=>(n+n)*n-TA=>(n+n)*n-FBA=>(n+n)*n-nBA=>(n+n)*n-n/FBA=>(n+n)*n-n/nBA=>(n+n)*n-n/nA=>(n+n)*n-n/n

可以看到,从输出的产生式可以最左推导出我们输入的分析串。

经验证,上述所求的FIRST集、FOLLOW集、预测分析表和输出的产生式均正确。LL1语法分析程序工作正常。

SLR1语法分析程序

数据结构

/* 产生式结构体,左部符号和右部符号串 */
struct Production {char left;vector<char> rigths;
};/* LR0项目 */
struct LR0Item {Production p;/* 点的位置 */int location;
};
/* LR0项目集 */
struct LR0Items {vector<LR0Item> items;
};
/* LR0项目集规范族 */
struct CanonicalCollection {/* 项目集集合 */vector<LR0Items> items;/* 保存DFA的图,first为转移到的状态序号,second是经什么转移 */vector< pair<int, char> > g[100];
}CC;/* 文法结构体 */
struct Grammar {int num;  // 产生式数量vector<char> T;   // 终结符vector<char> N;   // 非终结符vector<Production> prods;  //产生式
}grammar;/* FIRST集和FOLLOW集 */
map<char, set<char> > first;
map<char, set<char> > follow;/* DFA队列, 用于存储待转移的有效项目集 */
queue< pair<LR0Items, int> > Q;/* action表和goto表 */
pair<int, int> action[100][100]; // first表示分析动作,0->ACC 1->S 2->R second表示转移状态或者产生式序号
int goton[100][100];/* 待分析串 */
string str;
/* 分析栈 */
stack< pair<int, char> > ST; // first是state,second 是symble

辅助函数

/* 判断ch是否是非终结符, 若是返回其序号 */
int isInN(char ch);/* 判断ch是否是终结符, 若是返回其序号 */
int isInT(char ch);/* 求(T U N)的FIRST集 */
void getFirstSet();/* 产找alpha串的FIRST集, 保存到FS集合中 */
void getFirstByAlphaSet(vector<char> &alpha, set<char> &FS);/* 求非终结符的FOLLOW集 */
void getFollowSet();/* 判断是LR0项目t否在有效项目集I中 */
bool isInLR0Items(LR0Items &I, LR0Item &t);/* 打印某个项目集 */
void printLR0Items(LR0Items &I);/* 判断是否在项目集规范族中,若在返回序号 */
int isInCanonicalCollection(LR0Items &I);/* 读入并初始化语法 */
void initGrammar();

计算闭包

/* 求I的闭包 */
void closure(LR0Items &I)
{bool change =  true;while (change) {change = false;LR0Items J;/* 枚举每个项目 */J.items.assign(I.items.begin(), I.items.end());for (auto it = J.items.begin(); it != J.items.end(); it++) {LR0Item &L = *it;/* 非规约项目 */if (L.location < L.p.rigths.size()) {char B = L.p.rigths[L.location];if (isInN(B)) {/* 把符合条件的LR0项目加入闭包中 */for (int i = 0; i < grammar.prods.size(); i++) {Production &P = grammar.prods[i];if (P.left == B) {LR0Item t;t.location = 0;t.p.left = P.left;t.p.rigths.assign(P.rigths.begin(), P.rigths.end());if (!isInLR0Items(I, t)) {/* 标记改变 */change = true;I.items.push_back(t);} } }}}}}
}

计算转移

/* 转移函数,I为当前的项目集,J为转移后的项目集, 经X转移 */
void go(LR0Items &I, char X, LR0Items &J)
{for (auto it = I.items.begin(); it != I.items.end(); it++) {LR0Item &L = *it;/* 非规约项目 */if (L.location < L.p.rigths.size()) {char B = L.p.rigths[L.location];/* 如果点后面是非终结符,且非终结符为X,点位置加1, 加入到转移项目集中*/if (B == X) {LR0Item t;t.location = L.location + 1;t.p.left = L.p.left;t.p.rigths.assign(L.p.rigths.begin(), L.p.rigths.end());J.items.push_back(t);}}}/* 若J中有项目,则求其闭包 */if (J.items.size() > 0) {closure(J);}
}

构建有效项目集规范族和DFA

/* 构建DFA和项目集规范族 */
void DFA()
{/* 构建初始项目集 */LR0Item t;t.location = 0;t.p.left = grammar.prods[0].left;t.p.rigths.assign(grammar.prods[0].rigths.begin(), grammar.prods[0].rigths.end());LR0Items I;I.items.push_back(t);closure(I);/* 加入初始有效项目集 */CC.items.push_back(I);/* 把新加入的有效项目集加入待扩展队列中 */Q.push(pair<LR0Items, int>(I, 0));while (!Q.empty()) {LR0Items &S = Q.front().first;int sidx = Q.front().second;/* 遍历每个终结符 */for (int i = 0; i  < grammar.T.size(); i++) {LR0Items D;go(S, grammar.T[i], D);int idx;/* 若不为空 */if (D.items.size() > 0) {/* 查找是否已经在有效项目集族里 */idx = isInCanonicalCollection(D); if (idx > 0) {idx = idx - 1;} else {idx = CC.items.size();CC.items.push_back(D);/* 把新加入的有效项目集加入待扩展队列中 */Q.push(pair<LR0Items, int>(D, idx));}/* 从原状态到转移状态加一条边,边上的值为转移符号 */CC.g[sidx].push_back(pair<char, int>(grammar.T[i], idx));}}/* 遍历每个非终结符 */for (int i = 0; i  < grammar.N.size(); i++) {LR0Items D;go(S, grammar.N[i], D);int idx;if (D.items.size() > 0) {/* 查找是否已经在有效项目集族里 */idx = isInCanonicalCollection(D); if (idx != 0) {idx = idx - 1;} else {idx = CC.items.size();CC.items.push_back(D);/* 把新加入的有效项目集加入待扩展队列中 */Q.push(pair<LR0Items, int>(D, idx));}/* 从原状态到转移状态加一条边,边上的值为转移符号 */CC.g[sidx].push_back(pair<char, int>(grammar.N[i], idx));}}/* 当前状态扩展完毕,移除队列*/Q.pop();}
}

生成分析表(SLR(1))

/* 生成SLR1分析表 */
void productSLR1AnalysisTabel()
{for (int i = 0; i < CC.items.size(); i++) {LR0Items &LIt= CC.items[i];/* 构建action表 */for (auto it = LIt.items.begin(); it != LIt.items.end(); it++) {LR0Item &L = *it;/* 非规约项目 */if (L.location < L.p.rigths.size()) {char a = L.p.rigths[L.location];int j = isInT(a);/* a是终结符 */if (j > 0) {j = j - 1;/* 找到对应a的出边,得到其转移到的状态 */for (int k = 0; k < CC.g[i].size(); k++) {pair<char, int> p = CC.g[i][k];if (p.first == a) {action[i][j].first = 1; // 1->Saction[i][j].second = p.second;  //转移状态break;}}}} else { // 规约项目/* 接受项目 */if (L.p.left == grammar.prods[0].left) {action[i][grammar.T.size() - 1].first = 3;} else {char A = L.p.left;for (auto a = follow[A].begin(); a != follow[A].end(); a++) {int j = isInT(*a);/* 终结符 */if (j > 0) {j = j - 1;/* 找到产生式对应的序号 */for (int k = 0; k < grammar.prods.size(); k++) {if (L.p == grammar.prods[k]) {action[i][j].first = 2;action[i][j].second = k;break;}}}}}}}/* 构建goto表 */for (int k = 0; k < CC.g[i].size(); k++) {pair<char, int> p = CC.g[i][k];char A = p.first;int j = isInN(A);/* 终结符 */if (j > 0) {j = j - 1;goton[i][j] = p.second; //转移状态}}}
}

分析程序

/* 分析程序 */
void process()
{int ip = 0;printf("The ans:\n");do {int s = ST.top().first;char a = str[ip];int j = isInT(a) - 1;/* 移进 */if (action[s][j].first == 1) {ST.push(pair<int, char>(action[s][j].second, a));ip = ip + 1;} else if (action[s][j].first == 2) { // 规约Production &P = grammar.prods[action[s][j].second];/* 弹出并输出产生式 */printf("%c->", P.left);for (int i = 0; i < P.rigths.size(); i++) {ST.pop();printf("%c", P.rigths[i]);}printf("\n");s = ST.top().first;char A = P.left;j = isInN(A) - 1;ST.push(pair<int, char>(goton[s][j], A));} else if (action[s][j].first == 3) {   //接受printf("ACC\n");return;} else {printf("error\n");}} while(1);
}

测试

编译源程序

g++ -o SLR1 SLR1.cpp

执行SLR1分析程序

.\SLR1.exe

输入以下内容

9
A->E
E->E+T
E->E-T
E->T
T->T*F
T->T/F
T->F
F->(E)
F->n
A E T F #
n + - * / ( ) #
(n+n)*n-n/n

查看输出结果

FIRST和FOLLOW集
FIRST:
A: ( n
E: ( n
T: ( n
F: ( n
FOLLOW:
A: $
E: $ ) + -
T: $ ) * + - /
F: $ ) * + - /
查看项目集规范族和DFA
CC size: 16
LR0Items 0:
A->.E E->.E+T E->.E-T E->.T T->.T*F T->.T/F T->.F F->.(E) F->.n
to 1 using n
to 2 using (
to 3 using E
to 4 using T
to 5 using F
LR0Items 1:
F->n.
LR0Items 2:
F->(.E) E->.E+T E->.E-T E->.T T->.T*F T->.T/F T->.F F->.(E) F->.n
to 1 using n
to 2 using (
to 6 using E
to 4 using T
to 5 using F
LR0Items 3:
A->E. E->E.+T E->E.-T
to 7 using +
to 8 using -
LR0Items 4:
E->T. T->T.*F T->T./F
to 9 using *
to 10 using /
LR0Items 5:
T->F.
LR0Items 6:
F->(E.) E->E.+T E->E.-T
to 7 using +
to 8 using -
to 11 using )
LR0Items 7:
E->E+.T T->.T*F T->.T/F T->.F F->.(E) F->.n
to 1 using n
to 2 using (
to 12 using T
to 5 using F
LR0Items 8:
E->E-.T T->.T*F T->.T/F T->.F F->.(E) F->.n
to 1 using n
to 2 using (
to 13 using T
to 5 using F
LR0Items 9:
T->T*.F F->.(E) F->.n
to 1 using n
to 2 using (
to 14 using F
LR0Items 10:
T->T/.F F->.(E) F->.n
to 1 using n
to 2 using (
to 15 using F
LR0Items 11:
F->(E).
LR0Items 12:
E->E+T. T->T.*F T->T./F
to 9 using *
to 10 using /
LR0Items 13:
E->E-T. T->T.*F T->T./F
to 9 using *
to 10 using /
LR0Items 14:
T->T*F.
LR0Items 15:
T->T/F.
查看分析表

查看输出产生式
The ans:
F->n
T->F
E->T
F->n
T->F
E->E+T
F->(E)
T->F
F->n
T->T*F
E->T
F->n
T->F
F->n
T->T/F
E->E-T
ACC

LR输出的产生式是最右推导的逆序列,下面验证其正确性。

E=>E-T=>E-T/F=>E-T/n=>E-F/n=>E-n/n=>T-n/n=>T*F-n/n=>T*n-n/n=>F*n-n/n=>(E)*n-n/n=>(E+T)*n-n/n=>(E+F)*n-n/n=>(E+n)*n-n/n=>(T+n)*n-n/n=>(F+n)*n-n/n=>(n+n)*n-n/n

可以看出,上述产生式的确是最右推导的逆序列,所以其是正确的。

经验证,程序自动构建的有效项目集规范族和DFA均正确,其分析表亦正确,对给定的输出串分析输出的产生式验证也正确。

LR1语法分析程序

仅仅对上面的SLR1语法分析程序做出少量的修改即可实现LR1语法分析程序。

添加向前看符号

/* LR1项目 */
struct LR1Item {Production p;/* 点的位置 */int location;/* 向前看符号 */char next;
};

修改相关函数

闭包

转移函数

构造分析表

主要改动如下


上述函数的实现见源代码,相对于SLR1的改动不多。

测试

编译源文件

g++ -o LR1 LR1.cpp

执行LR1分析 程序

.\LR1.exe

输入以下内容(LR1有效项目集族状态较多,此处给出一个状态相对较少的例子)

4
A->S
S->CC
C->cC
C->d
A S C #
c d #
cccdcd

查看输出结果

FIRST集
FIRST:
A: c d
S: c d
C: c d
查看项目集规范族和DFA
CC size: 10
LR1Items 0:
A->.S,$   S->.CC,$   C->.cC,c   C->.cC,d   C->.d,c   C->.d,d
to 1 using c
to 2 using d
to 3 using S
to 4 using C
LR1Items 1:
C->c.C,c   C->c.C,d   C->.cC,c   C->.d,c   C->.cC,d   C->.d,d
to 1 using c
to 2 using d
to 5 using C
LR1Items 2:
C->d.,c   C->d.,d
LR1Items 3:
A->S.,$
LR1Items 4:
S->C.C,$   C->.cC,$   C->.d,$
to 6 using c
to 7 using d
to 8 using C
LR1Items 5:
C->cC.,c   C->cC.,d
LR1Items 6:
C->c.C,$   C->.cC,$   C->.d,$
to 6 using c
to 7 using d
to 9 using C
LR1Items 7:
C->d.,$
LR1Items 8:
S->CC.,$
LR1Items 9:
C->cC.,$
查看分析表
        action                  gotoc       d       $       |       S       C
0       S1      S2              |       3       4
1       S1      S2              |               5
2       R3      R3              |
3                       ACC     |
4       S6      S7              |               8
5       R2      R2              |
6       S6      S7              |               9
7                       R3      |
8                       R1      |
9                       R2      |
查看输出产生式
The ans:
C->d
C->cC
C->cC
C->cC
C->d
C->cC
S->CC
ACC

LR输出的产生式是最右推导的逆序列,下面验证其正确性。

S=>CC=>CcC=>Ccd=>cCcd=>ccCcd=>cccCcd=>cccdcd

可以看出,上述产生式的确是最右推导的逆序列,所以其是正确的。

经验证,程序自动构建的有效项目集规范族和DFA均正确,其分析表亦正确,对给定的输出串分析输出的产生式验证也正确。

LL1_SLR1_LR1语法分析C++实现相关推荐

  1. LLVM与Clang局部架构与语法分析

    LLVM与Clang局部架构与语法分析 Clang与LLVM LLVM整体架构,前端用的是clang,广义的LLVM是指整个LLVM架构,一般狭义的LLVM指的是LLVM后端(包含代码优化和目标代码生 ...

  2. 关于NLP相关技术全部在这里:预训练模型、图神经网络、模型压缩、知识图谱、信息抽取、序列模型、深度学习、语法分析、文本处理...

    NLP近几年非常火,且发展特别快.像BERT.GPT-3.图神经网络.知识图谱等技术应运而生. 我们正处在信息爆炸的时代.面对每天铺天盖地的网络资源和论文.很多时候我们面临的问题并不是缺资源,而是找准 ...

  3. 2型文法:基于预测分析表的自顶向下语法分析

    文法的预处理 左递归定义 左递归的消除 预测分析表的构造 first集合 follow集合 计算的例子 假设有如下文法: 先计算first集合如下: 计算过程中,要牢牢抓住first集合的概念,即非终 ...

  4. 自顶向下的语法分析(修改)

    自顶向下语法分析可以被看作是为输入串构造语法分析树的问题,它从语法分析树的根结点开始 ,按照先序遍历创建这棵语法分析树的各个结点.自顶向下语法分析也可以被看作寻找输入串的最左推导的过程. 递归下降的语 ...

  5. 【编译原理】词法分析和语法分析两万字全总结(这知识它不进脑子啊~!)

    文章目录 1 引论-一些名词解释 1.1 解释器 1.2 翻译器和编译器 1.3 编译型的程序设计语言和解释型的程序设计语言各有哪些优缺点? 1.4 编译过程六个阶段的任务 1.5 遍的概念 2 词法 ...

  6. go语言笔记——是c开发的 lex yacc进行词法和语法分析,go不支持函数和运算符重载,不支持类型继承,也不支持断言,还有泛型...

    从 Go 1.0.3 版本开始,不再使用 8g,8l 之类的指令进行程序的构建,取而代之的是统一的 go build 和 go install 等命令,而这些指令会自动调用相关的编译器或链接器. 如果 ...

  7. 【计算理论】上下文无关语法 ( 语法组成 | 规则 | 语法 | 语法示例 | 约定的简写形式 | 语法分析树 )

    文章目录 I . 语法组成 II . 规则 III . 语法 IV . 语法示例 V . 语法简写形式 VI . 语法分析树 VII . 代数表达式 语法 I . 语法组成 上下文无关语法 组成 : ...

  8. 跟vczh看实例学编译原理——三:Tinymoe与无歧义语法分析

    文章中引用的代码均来自https://github.com/vczh/tinymoe. 看了前面的三篇文章,大家应该基本对Tinymoe的代码有一个初步的感觉了.在正确分析"print su ...

  9. JavaCC首页、文档和下载 - 语法分析生成器 - 开源中国社区

    JavaCC首页.文档和下载 - 语法分析生成器 - 开源中国社区

最新文章

  1. mysql sa密码是什么_忘记mysql数据库root密码
  2. UNL/EVE关联putty和wireshark
  3. 前端 CSS day03-核心属性
  4. 从servlet中获取spring的WebApplicationContext
  5. php基础教程 第七步数组补充及循环基础
  6. 面试题 01.03. URL化
  7. STL常用函数总结-set
  8. add in Web.config
  9. 计算机组成原理—数据的表示、运算与校验(思维导图)
  10. ViewPager和Tabhost结合,可滑动的tabhost
  11. 【刷题第七天】leetcode611.有效三角形的个数
  12. 常用#免费%代理IP库整理*收藏——实时@更新(大概)
  13. Loadrunner2021安装教程
  14. 《东周列国志》第二十八回 里克两弑孤主 穆公一平晋乱
  15. 程序员根本不是稳定工作!
  16. 构建基于MX1919的超声波阵列驱动板
  17. firefoxos gaia 开发环境
  18. 【uniapp】 判断浏览器环境
  19. error: #79: expected a type specifier
  20. 高速PCB基础——电阻,电容,电感(第三讲)

热门文章

  1. 」北京有名恁地一个 水浒传
  2. 史上最简单的 Spring MVC 教程(九)
  3. psm倾向得分匹配法举例_倾向得分匹配法(PSM)举例及stata实现
  4. PHPMailer发送中文名称附件
  5. GO请求参数规则校验(自定义校验规则、规则中文化)
  6. 怎样开机自动进入系统
  7. python发微信红包群二维码_小伙利用Python群发“支付宝”红包短信,一天赏金可达上千元...
  8. 语言模型_Pytorch_代码超详解
  9. android 4g手机6,6.5毫米4G智能手机 华为P7精美图赏
  10. 关于EB V23激活失败问题