说在前面
- 使用语言:javascript
- 语法分析:LL(1)
- 中间代码生成:三地址码 语法制导翻译
- 目标代码:mips代码
- 接上篇:【编译原理/类C编译器】(二)词法分析
运行界面
流程
-
语法分析使用的是 LL(1) 方法
-
消除左递归
i. 消除直接左递归
ii.消除间接左递归 -
消除回溯
(上述两部分手动完成) -
LL(1)分析条件
- 文法不含左递归
- 对文法中每个非终结符A的各个产生式的候选首符集两两不相交,即A→α1│α2│… │αn , FIRST(αi)∩FIRST(αj) = Φ,(i ≠ j)
- 对文法中的每个非终结符A,若它存在某个候选首符集中包含ε,则FIRST(A)∩ FOLLOW(A) = Φ
- 对于文法G的每个文法符号X∈VT∪VN,构造FIRST(X)
- 若X∈VT,则FIRST(X)={X};
- 若X ∈VN,且有产生式X→a…, a∈VT,则把a加入到 FIRST(X)中,若有X→ε,则把ε加入FIRST(X);
- 若X∈VN , 且X→Y … , Y∈VN, 则 FIRST (Y) - {ε}加到 FIRST (X)中,若X →Y1Y2 … Yk , Y1, Y2, … ,Yi -1 ∈ VN , ε∈FIRST (Yj) (1<=j <= i -1)则 FIRST (Yi) - {ε}加到FIRST (X)中。
特别地,若ε∈FIRST (Yj) (1<=j <= k ),则ε加入FIRST (X)
-
/**
* @func 求first(x) 非终结符的first集合
*/
this.FIRSTX = function () {
//从后向前
//non_terminal即文法的非终结符集合,产生式左部
for (s = this.non_terminal.length - 1; s > 0; s--) {
//productions为产生式集合
for (jj = Productions.length - 1; jj >= 0; jj--) {
var Split_r = Productions[jj].split(" ");//分割产生式
//1.若X∈VT,则FIRST(X)={X};
for (kk = 2; kk < Split_r.length; kk++)
if (Split_r[kk] == this.non_terminal[s] &&
this.Is_terminal(Split_r[kk - 1]) &&
this.non_terminal_first[s].indexOf(Split_r[kk - 1]) < 0)
this.non_terminal_first[s] += " " + Split_r[kk - 1];
//2 3
if (Split_r[0] == this.non_terminal[s]) {
if (Split_r[1] == "@" &&
this.non_terminal_first[s].indexOf("@") < 0) {
this.non_terminal_first[s] += " @";
continue;
}
for (h = 1; h < Split_r.length; h++) {
if (this.Is_terminal(Split_r[h]) &&
this.non_terminal_first[s].indexOf(Split_r[h]) == -1)
this.non_terminal_first[s] += " " + Split_r[h];
if (this.Is_terminal(Split_r[h]))
break;
var Split_t =
(this.non_terminal_first[this.Get_non_i(Split_r[h])]
|| "").split(" ");
for (k = 0; k < Split_t.length; k++)
if ((this.non_terminal_first[s] ||
"").indexOf(Split_t[k]) == -1 && Split_t[k] != "@")
this.non_terminal_first[s] += " " + Split_t[k];
if (this.Is_to_null(Split_r[h])) {
if (h == Split_r.length - 1 &&
this.non_terminal_first[s].indexOf("@") < 0)
this.non_terminal_first[s] += " @";
}
else
break;
}
}
}
}
}
- 对于符号串α= X1X2… Xn,构造 FIRST (α)
- 置 FIRST(α) = FIRST (X1)
- 若对 1<=j<= i -1, ε∈FIRST (Xj), 则把FIRST(Xi) -{ε}加到FIRST(α)中;
- 若对1<= j <=n, ε∈FIRST (Xj), 则把ε加到 FIRST(α)中。
/**
* 参数First_alpha_t即上面的 α
*/
this.FIRST_ALPHA = function (First_alpha_t) {
var Split_r = First_alpha_t.split(" ");//分割α
//这里的 α 为产生式的右部 “ X1 X2 ...... Xn”,用空格来分割
//α最前面有个空格
var bool_null = 0;
var First_alpha_First_t = "";//α的first集合
for (j = 1; j < Split_r.length; j++) {
if (Split_r[j] == "@")
continue;
//1.置 FIRST(α) = FIRST (X1)
if (this.Is_terminal(Split_r[j])) {
First_alpha_First_t += " " + Split_r[j];
break;
}
var Split_t =
this.non_terminal_first[this.Get_non_i(Split_r[j])].split(" ");
//获取Alpha首字符的FIRST集合并分割
if (Split_t.indexOf("@") >= 0)
bool_null = 1;
else
bool_null = 0;
//2.
for (k = 0; k < Split_t.length; k++)
if (Split_t[k] != "@" &&
First_alpha_First_t.indexOf(Split_t[k]) == -1)
First_alpha_First_t += " " + Split_t[k];
//置 FIRST(α) = FIRST (X1) - {ε};
if (bool_null == 0)
break;
//3.
if (bool_null == 1 && j == Split_r.length - 1)
First_alpha_First_t += " @";
}
return First_alpha_First_t;
}
- 对于文法G的每个非终结符,构造FOLLOW(A)
- 若A为文法开始符号,置#于FOLLOW(A)中;
- 若有产生式B→αAβ,则将FIRST( β) - {ε}加到FOLLOW (A)中;
- 若有B→αA 或 B → αAβ, 且β=> * ε;则将FOLLOW(B)加到FOLLOW(A)中;
- 反复使用以上规则, 直至 FOLLOW(A)不再增大为止
/**
* @func 求FOLLOWX
*/
this.FOLLOWX = function () {
if (this.non_terminal_follow[1].indexOf("#") < 0)
this.non_terminal_follow[1] += " #";
for (u = this.non_terminal.length - 1; u >= 0; u--) {
for (w = Productions.length - 1; w >= 0; w--) {
var Split_r = Productions[w].split(" ");
for (z = 1; z < Split_r.length; z++)
if (Split_r[z] == this.non_terminal[u]) {
break;
}
if (this.Is_terminal(Split_r[z + 1]) && (this.non_terminal_follow[u].indexOf(Split_r[z + 1]) < 0)) {
this.non_terminal_follow[u] += " " + Split_r[z + 1];
continue;
}
var temp_s = false;
if (z >= 1 && z < Split_r.length - 1) {
var temp = "";
for (q = z + 1; q < Split_r.length; q++)
temp += " " + Split_r[q];
for (q = z + 1; q < Split_r.length; q++)
if (this.Is_to_null(Split_r[q]))
temp_s = true;
else {
temp_s = false;
break;
}
var follow_t = (this.FIRST_ALPHA(temp) || "").split(" ");
for (e = 0; e < follow_t.length; e++)
if (this.non_terminal_follow[u].indexOf(follow_t[e]) < 0)
this.non_terminal_follow[u] += " " + follow_t[e];
}
if (z == Split_r.length - 1 || temp_s) {
var Split_t = (this.non_terminal_follow[this.Get_non_i(Split_r[0])] || "").split(" ");
for (p = 0; p < Split_t.length; p++)
if (this.non_terminal_follow[u].indexOf(Split_t[p]) < 0 && Split_t[p] != "@")
this.non_terminal_follow[u] += " " + Split_t[p];
}
}
}
}
- 构造预测分析表
- 对文法的每个产生式A ,执行(2)和(3)
- 对FIRST(α)的每个终结符a,把A 加入M[A, a]
- 如果在FIRST(α)中,对FOLLOW(A)的每个终结符b(包括#), 把A 加入M[A, b]
- M中其它没有定义的条目都是error
/**
* @func 初始化分析预测表
*/
this.InitTable = function () {
this.Init();
var MAX = 0;
while (1) {
this.FIRSTX();
var count = 0;
for (y = 0; y < this.non_terminal.length; y++)
count += (this.non_terminal_first[y] || "").length;
if (count > MAX)
MAX = count;
else
break;
}
this.FIRST_ALPHA_ALL();
MAX = 0;
while (1) {
this.FOLLOWX();
var count = 0;
for (x = 0; x < this.non_terminal.length; x++)
count += (this.non_terminal_follow[x] || "").length;
if (count > MAX)
MAX = count;
else
break;
}
for (r = 0; r < this.non_terminal.length; r++) {
this.analyse_table[r] = new Array();
for (v = 0; v < TERMINAL.length; v++)
this.analyse_table[r][v] = "";
for (f = 0; f < Productions.length; f++) {
var Split_r = Productions[f].split(" ");
if (Split_r[0] != this.non_terminal[r])
continue;
if (Split_r[1] == "@") {
var Split_t = this.non_terminal_follow[r].split(" ");
for (b = 1; b < Split_t.length; b++)
this.analyse_table[r][this.Get_ter_i(Split_t[b])] += f + 1;
}
else {
var Split_t = this.right_first[f].split(" ");
for (b = 1; b < Split_t.length; b++)
this.analyse_table[r][this.Get_ter_i(Split_t[b])] += f + 1;
}
}
}
}
- 总控程序
分析栈STACK: 放文法符号, 初始放一个#号, 再放入开始符号S。
设栈顶为X,当前输入符号为a,则对于任何(X,a)执行以下三种动作之一:
- 若X = a =“ #” 则分析成功
- 若X = a ≠“ # ” 则把X从STACK栈中弹出,a指向下一输入符号
- 若X是非终结符, 则按M[X, a]中的产生式进行推导(弹出X, 将右部符号串反序入栈), 或进行出错处理。
/**
* 语法分析
*/
this.Check = function () {
var cnt = 0;
//倒置
this.terminal_array.reverse();
while (this.terminal_array.length > 0) {
if (this.ArrayX.top().str == this.terminal_array.top().str && this.ArrayX.top().str == "#") {
return true;
}
else if ((this.ArrayX.top().str == this.terminal_array.top().str && this.ArrayX.top().str != "#")
|| (this.ArrayX.top().str == "relop" && this.Is_relop(this.terminal_array.top().str))) {
cnt++;
this.Analyse_Stack += "<tr><td>" + cnt + "</td><td>" + "..." + this.ArrayX.top().str
+ "</td><td>" + this.terminal_array.top().str + "..." + "</td><td>REDUCED<td></tr>";
//将TE_Array的lexical复制
this.ArrayX.top().lexical = this.terminal_array.top().data;
if (this.ArrayX.top().str == "relop") {
this.ArrayX.top().op = this.terminal_array.top().data;
}
this.ArrayX.pop();
this.terminal_array.pop();
}
else if (!this.Is_terminal(this.ArrayX.top().str)) {
if (this.analyse_table[this.Get_non_i(this.ArrayX.top().str)][this.Get_ter_i(this.terminal_array.top().str)] == "")
return false;
else {
//从预测分析表中获取产生式ID
var Production_G_ID = this.analyse_table[this.Get_non_i(this.ArrayX.top().str)][this.Get_ter_i(this.terminal_array.top().str)] - 1;
var Split_r = (Productions[Production_G_ID] || "").split(" ");
if (Split_r[1] == "@") {
cnt++;
this.Analyse_Stack += "<tr><td>" + cnt + "</td><td>" + "..."
+ this.ArrayX.top().str + "</td><td>" + this.terminal_array.top().str
+ "..." + "</td><td>@</td></tr>";
this.ArrayX.pop();
continue;
}
//语法数生长
for (jj = 1; jj < Split_r.length; jj++) {
this.ArrayX.top().children.push(new Node(Split_r[jj], Split_r[jj], this.ArrayX.top()));
}
//弹出栈顶
var _top = this.ArrayX.pop();
//界面相关
cnt++;
this.Analyse_Stack += "<tr><td>" + cnt + "</td><td>" + "..."
+ Split_r[0] + "</td><td>" + this.terminal_array.top().str + "..."
+ "</td><td>" + Split_r[0] + "→";
//_top的孩子节点反序入栈
for (ii = 1; ii < Split_r.length; ii++) {
_top.children[Split_r.length - ii - 1].production_id = Production_G_ID;
_top.children[Split_r.length - ii - 1].child_id = Split_r.length - ii - 1;
this.ArrayX.push(_top.children[Split_r.length - ii - 1]);
this.Analyse_Stack += Split_r[ii] + " ";
}
this.Analyse_Stack += "</td></tr>";
}
}
else
return false;
}
return false;
}
}
END (代码等这系列完结后放github)