语法分析器是编译原理的一个实验,本文将会详细给出实现的具体步骤,利用java进行示例讲解,完整源码可在 https://download.youkuaiyun.com/download/qq_40121502/10926525 下载。
一、实验目的
设计、编写一个语法分析程序,加深对语法分析原理的理解。
二、实验原理
语法分析器是在词法分析之后,根据词法分析的结果和定义的语法规则判断输入的程序是否有语法错误,LL(1)分析是使用显式栈而不是递归调用来完成分析。以标准方式表示这个栈非常有用,这样LL(1)分析程序的动作就可以快捷地显现出来。LL(1)的含义是:第一个L表明自顶向下分析是从左向右扫描输入串,第2个L表明分析过程中将使用最左推导,1表明只需向右看一个符号便可决定如何推导,即选择哪个产生式(规则)进行推导。
三、实验内容
(1)程序利用Java语言,给出其词法的产生式。希望这个语言中包含数学运算表达式,赋值,函数调用,控制流语句(分支或循环),类型声明等基本元素。
(2)本实验设计的是基于LL(1) 分析的语法分析器,并用程序实现了对所写语言的LL(1) 分析测试。
四、实验方法
(1)定义文法语言,将文法用产生式表示。
(2)提取公共左因子,消除左递归。
(3)求FIRST和FOLLOW集。
(4)构造LL(1)预测分析表。
(5)根据分析表编写程序,测试程序。
五、实验设计
1.定义语法分析使用的文法语言:
<程序> ::= <语句><程序> | Ɛ;
<语句> ::= <变量定义语句> | <赋值语句> | <函数调用语句> | <if语句>
| <循环语句> | Ɛ
<变量定义语句> ::= <变量类型><标识符表>;
<赋值语句> ::= <标识符> = <表达式>;
<函数调用语句> ::= <标识符> ( <标识符表> );
<if语句> ::= if ( <条件表达式> ) { <语句> } <else语句>
<else语句> ::= else{ <语句> } | Ɛ
<循环语句> ::= while ( <条件表达式> ) { <语句> }
<标识符表> ::= <标识符>| <标识符表>,<标识符>
<条件表达式> ::= <表达式><比较运算符><表达式>
<比较运算符> ::= > | >= | < | <= | != | ==
<变量类型> ::= char | short | int | long | float | double
<表达式> ::= +T | -T | T | <表达式> + T | <表达式>-T
T ::= F | T*F | T/F
F ::= <标识符> | <无符号整数> | (<表达式 >)
2.将上述文法用产生式表示:
其中,S’:程序(语句的组合),S:语句,Q:else语句,L:标识符表,E:表达式,X:条件表达式,R:比较运算符,id:标识符,num:常量
S’ → S S’| Ɛ
S → A L; | id=E; | id(L); | if(X){S}Q | while(X){S} | Ɛ
A → char | short | int | long | float | double
Q → else{S} | Ɛ
L → id | L , id
X → ERE
R → > | >= | < | <= | == | !=
E → +T | -T | T | E+T | E-T
T → F | T*F | T/F
F → id | num | (E)
3.提取公共左因子:
S’ → S S’| Ɛ
S → A L; | id B | if(X){S}Q | while(X){S} | Ɛ
A → char | short | int | long | float | double
B → (L); | =E;
L → id | L , id
Q → else{S} | Ɛ
X → ERE
R → > | >= | < | <= | == | !=
E → +T | -T | T | EM
M → +T | -T
T → F | TN
N → *F |/F
F → id | num | (E)
4.消除左递归:
S’ → S S’
S’ → Ɛ
S → A L;
S → id B
S → if(X){S}Q
S → while(X){S}
S → Ɛ
B → (L);
B → =E;
L → id L’
L’→ , id L’
L’→ Ɛ
Q → else{S}
Q → Ɛ
X → ERE
E → TE’
E → +TE’
E → -TE’
E’ → ME’
E’ → Ɛ
M → +T
M → -T
T → FT’
T’ → NT’
T’ → Ɛ
N → *F
N → /F
F → id
F → num
F → (E)
R → >
R → >=
R → <
R → <=
R → ==
R → !=
A → char
A → short
A → int
A → long
A → float
A → double
5.求FIRST集:
First(S’)={ char , short , int , long , float , double , id , if , while , Ɛ }
First(S)={ char , short , int , long , float , double , id , if , while , Ɛ }
First(A)={ char , short , int , long , float , double }
First(B)={ ( , = }
First(L)={ id }
First(L’)={ ,, Ɛ }
First(Q)={ else , Ɛ }
First(X)={ + , - , id , num , ( }
First(R)={ > , >= , < , <= , != , == }
First(E)={ + , - , id , num , ( }
First(E’)={ + , - , Ɛ }
First(M)={ + , - }
First(T)={ id , num , ( }
First(T’)={ * , / , Ɛ }
First(N)={ * , / }
First(F)={ id , num , ( }
6.求FOLLOW集:
Follow (S’)={ $ }
Follow (S)={ $ , } }
Follow (B)={ $ , } }
Follow (L)={ $ , ) , ; , } }
Follow (L’)={ $ , ) , ; , } }
Follow (Q)={ $ , } }
Follow (X)={ ) }
Follow (R)={ + , - , id , num , ( }
Follow (E)={ ) , ; , > , >= , < , <= , != , == }
Follow (E’)={ ) , ; , > , >= , < , <= , != , == }
Follow (M)={ ) , ; , > , >= , < , <= , != , == , + , - }
Follow (T)={ ) , ; , > , >= , < , <= , != , == , + , - }
Follow (T’)={ ) , ; , > , >= , < , <= , != , == , + , - }
Follow (N)={ ) , ; , > , >= , < , <= , != , == , + , - , * , / }
Follow (F)={ ) , ; , > , >= , < , <= , != , == , + , - , * , / }
7.构造LL(1)的预测分析表:
LL(1)预测分析表中的数字分别代表的产生式如下:
0:S → A L;
1:S → id B
2:S → if(X){P}Q
3:S → while(X){P}
4:S → Ɛ
5:B → (L);
6:B → =E;
7:L → id L’
8:L’→ ,id L’
9:L’→ Ɛ
10:Q → else{S}
11:Q → Ɛ
12:X → ERE
13:E → +TE’
14:E → -TE’
15:E → TE’
16:E’→ ME’
17:E’→ Ɛ
18:M → +T
19:M → -T
20:T → FT’
21:T’→ NT’
22:T’→ Ɛ
23:N → *F
24:N → /F
25:F → id
26:F → num
27:F → (E)
28:R → >
29:R → >=
30:R → <
31:R → <=
32:R → ==
33:R → !=
34:S’ → S S’
35:S’ → Ɛ
36:A → char
37:A → short
38:A → int
39:A → long
40:A → float
41:A → double
六、数据结构
(1)使用ArrayList来存储当前栈的内容
(2)使用ArrayList来存储待读队列的内容,Integer此处为单词的种别码,用于表示词法分析器的分析结果。
自定义类Production,产生式类,包含String类型的完整产生式、String类型的产生式左侧符号、String[]类型的产生式右侧符号。(此处左右是相对于产生式中的→而言的)。
七、实现代码
语法分析器接收词法分析器的结果作为输入,即输入为单词种别码和相应的单词的序列。
例如:(种别码和单词间的逗号仅表示分隔)
1.初始化
首先定义了五个全局变量:
private static ArrayList<String> stack = new ArrayList<>(); // 当前栈
private static ArrayList<Integer> reader = new ArrayList<>(); // 待读队列
private static Production[] productions = new Production[42]; // 产生式数组
private static HashMap<Integer, String> map_i2s; // 种别码Map,种别码为键,单词为值
private static HashMap<String, Integer> map_s2i; // 种别码Map,单词为键,种别码为值
初始化种别码Map,要和词法分析器内单词对应的种别码相同:
private static void initMap() {
map_s2i = new HashMap<>();
map_s2i.put("char", 1);
map_s2i.put("short", 2);
map_s2i.put("int", 3);
map_s2i.put("long", 4);
map_s2i.put("float", 5);
map_s2i.put("double", 6);
map_s2i.put("final", 7);
map_s2i.put("static", 8);
map_s2i.put("if", 9);
map_s2i.put("else", 10);
map_s2i.put("while", 11);
map_s2i.put("do", 12);
map_s2i.put("for", 13);
map_s2i.put("break", 14);
map_s2i.put("continue", 15);
map_s2i.put("void", 16);
map_s2i.put("id", 20);
map_s2i.put("num", 30);
map_s2i.put("=", 31);
map_s2i.put("==", 32);
map_s2i.put(">", 33);
map_s2i.put("<", 34);
map_s2i.put(">=", 35);
map_s2i.put("<=", 36);
map_s2i.put("+", 37);
map_s2i.put("-", 38);
map_s2i.put("*", 39);
map_s2i.put("/", 40);
map_s2i.put("(", 41);
map_s2i.put(")", 42);
map_s2i.put("[", 43);
map_s2i.put("]", 44);
map_s2i.put("{", 45);
map_s2i.put("}", 46);
map_s2i.put(",", 47);
map_s2i.put(":", 48);
map_s2i.put(";", 49);
map_s2i.put("!=", 50);
map_s2i.put("$", 60);
map_i2s = new HashMap<>();
map_i2s.put(1, "char");
map_i2s.put(2, "short");
map_i2s.put(3, "int");
map_i2s.put(4, "long");
map_i2s.put(5, "float");
map_i2s.put(6, "double");
map_i2s.put(7, "final");
map_i2s.put(8, "static");
map_i2s.put(9, "if");
map_i2s.put(10, "else");
map_i2s.put(11, "while");
map_i2s.put(12, "do");
map_i2s.put(13, "for");
map_i2s.put(14, "break");
map_i2s.put(15, "continue");
map_i2s.put(16, "void");
map_i2s.put(20, "id");
map_i2s.put(30, "num");
map_i2s.put(31, "=");
map_i2s.put(32, "==");
map_i2s.put(33, ">");
map_i2s.put(34, "<");
map_i2s.put(35, ">=");
map_i2s.put(36, "<=");
map_i2s.put(37, "+");
map_i2s.put(38, "-");
map_i2s.put(39, "*");
map_i2s.put(40, "/");
map_i2s.put(41, "(");
map_i2s.put(42, ")");
map_i2s.put(43, "[");
map_i2s.put(44, "]");
map_i2s.put(45, "{");
map_i2s.put(46, "}");
map_i2s.put(47, ",");
map_i2s.put(48, ":");
map_i2s.put(49, ";");
map_i2s.put(50, "!=");
map_i2s.put(60, "$");
}
初始化产生式:规则自己定义
/**
* 产生式类
*/
private static class Production {
String l_str;
String[] r_str;
String prod;
public Production(String l_str, String[] r_str, String prod) {
this.l_str = l_str;
this.r_str = r_str;
this.prod = prod;
}
}
private static void initProductions() {
productions[0] = new Production("S",
new String[]{
"A", "L", String.valueOf(map_s2i.get(";"))},
"S --> A L;");
productions[1] = new Production("S",
new String[]{
String.valueOf(map_s2i.get("id")), "B"},
"S --> id B");
productions[2] = new Production("S",
new String[]{
String.valueOf(map_s2i.get("if")), String.valueOf(map_s2i.get("(")), "X", String.valueOf(map_s2i.get(")")), String.valueOf(map_s2i.get("{")), "S", String.valueOf(map_s2i.get("}")), "Q"},
"S --> if(X){S}Q")