语法分析器实现过程(java)

本文详述了使用Java实现LL(1)语法分析器的步骤,包括实验目的、原理、内容和方法。通过定义文法、提取左因子、消除左递归、构造LL(1)预测分析表等,最终实现对特定语言的语法分析。提供完整源码下载链接。
摘要由CSDN通过智能技术生成

语法分析器是编译原理的一个实验,本文将会详细给出实现的具体步骤,利用java进行示例讲解,完整源码可在 https://download.csdn.net/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")
Java可以通过编写语法分析器实现对程序代码的语法分析。下面是一个简单的实现方法: 1. 定义文法:首先需要定义程序代码的文法,可以使用BNF范式或者EBNF范式来描述。 2. 生成词法分析器:在语法分析之前,需要先进行词法分析,将程序代码转换成一个个的词法单元。可以使用JavaCC等工具来生成词法分析器。 3. 编写语法分析器:根据定义好的文法,编写语法分析器。可以使用递归下降分析法、LL(1)分析法等方法来实现。 4. 进行语法分析:将程序代码转换成语法树或者抽象语法树,进行语法分析。可以在语法分析的过程中进行语义分析和错误检查。 下面是一个简单的Java语法分析器实现代码: ```java import java.io.*; public class SyntaxAnalyzer { private Lexer lexer; private Token token; public SyntaxAnalyzer(String fileName) throws IOException { lexer = new Lexer(fileName); token = lexer.getNextToken(); } public void parse() throws IOException { program(); match(TokenType.EOF); } private void program() throws IOException { // 程序入口 while (token.getType() != TokenType.EOF) { statement(); } } private void statement() throws IOException { // 语句 if (token.getType() == TokenType.IDENTIFIER) { match(TokenType.IDENTIFIER); match(TokenType.ASSIGN); expression(); match(TokenType.SEMICOLON); } else if (token.getType() == TokenType.IF) { match(TokenType.IF); match(TokenType.LPAREN); expression(); match(TokenType.RPAREN); statement(); if (token.getType() == TokenType.ELSE) { match(TokenType.ELSE); statement(); } } else if (token.getType() == TokenType.WHILE) { match(TokenType.WHILE); match(TokenType.LPAREN); expression(); match(TokenType.RPAREN); statement(); } else { error(); } } private void expression() throws IOException { // 表达式 term(); while (token.getType() == TokenType.PLUS || token.getType() == TokenType.MINUS) { match(token.getType()); term(); } } private void term() throws IOException { // 项 factor(); while (token.getType() == TokenType.TIMES || token.getType() == TokenType.DIVIDE) { match(token.getType()); factor(); } } private void factor() throws IOException { // 因子 if (token.getType() == TokenType.NUMBER) { match(TokenType.NUMBER); } else if (token.getType() == TokenType.IDENTIFIER) { match(TokenType.IDENTIFIER); } else if (token.getType() == TokenType.LPAREN) { match(TokenType.LPAREN); expression(); match(TokenType.RPAREN); } else { error(); } } private void match(TokenType type) throws IOException { if (token.getType() == type) { token = lexer.getNextToken(); } else { error(); } } private void error() { System.out.println("Syntax error!"); System.exit(1); } } ```
评论 34
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值