实验一 词法分析器【编译原理】
- 前言
- 推荐
- 实验一 词法分析器
- 代码1
- 代码1结果
- 代码2
- 代码2结果
- 高级代码
- 最后
前言
2023-4-2 13:14:26
以下内容源自《【编译原理】》
仅供学习交流使用
推荐
本文代码
全有自己书写
没有推荐
实验一 词法分析器
题目: 词法分析器
要求:1人一组
1.单词的分类。
可将所有标识符归为一类;
将常数归为另一类;
保留字、算符和分隔符则采取一词一类。
2.符号表的建立。
可事先建立一关键字表,以备在识别关键字时进行查询。
变量名表及常数表则在词法分析过程中建立。
3.出错处理
实现错误定位,找出原程序中所有词法错误
4.文件读写
源程序以文件形式读入;
输出以文件形式保存,需输出:1)词法分析的结果 2)符号表文件
5.单词串的输出形式。
所输出的每一单词,均按形如(CLASS,VALUE)的二元式编码。对于变量标识符和常数,CLASS字段为相应的类别码,VALUE字段则是该标识符、常数在其符号表中登记项的序号(要求在变量名表登记项中存放该标识符的字符串,其最大长度为四个字符;常数表登记项中则存放该整数的二进制形式。)。对于保留字和分隔号,由于采用一词一类的编码方式,所以仅需在二元式的CLASS字段上放置相应的单词的类别码,VALUE字段则为“空”。不过,为便于查看由词法分析程序所输出的单词串,也可以在CLASS字段上直接放置单词符号串本身。可以仿照书上图3.3的实现程序的结构来编写上述词法分析程序,但其中的若干语义过程有待于具体编写。
6.过滤无效字符、数值转换、宏展开、预包含处理等(灰色选做)
实习报告内容:
1.目的要求
2.单词分类表
3.单词结构描述(正规式或正规文法)
4.单词状态转换图
5.算法描述
6.程序结构
7.运行结果
8.调试情况
9.设计技巧及体会
10.源程序清单(电子版)
代码1
介绍:
代码1实现了以下功能
加载keywords.txt
构建关键词表
如果没有该文件会默认构建
读取input.txt
单词串进行词法分析
如果没有该文件会随机生成单词串
最后
输出单词分析结果
并把单词分析的结果写入symbols.txt
代码框架
README.md
s1 词法分析器
Symbol 符号类
LexicalAnalyzer 词法分析器
项目/keywords.txt 输入关键词表
项目/symbols.txt 输出单词表
项目/input.txt 输入单词串
Symbol
package s1;
import java.util.Objects;
/**
* 符号类
*/
public class Symbol {
private int id;//种别编码
private String value;//单词符号
private int code;//内码值 符号表中的索引
public Symbol() {
}
public Symbol(int id) {
this.id = id;
}
public Symbol(String value) {
this.value = value;
}
public Symbol(int id, String value) {
this.id = id;
this.value = value;
}
public Symbol(int id, int code) {
this.id = id;
this.code = code;
}
public Symbol(int id, String value, int code) {
this.id = id;
this.value = value;
this.code = code;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Symbol symbol = (Symbol) o;
return Objects.equals(value, symbol.value);
}
@Override
public int hashCode() {
return Objects.hash(value);
}
public String toStringIdCode(){
return "Symbol{" +
"id=" + id +
", code=" + code +
'}';
}
@Override
public String toString() {
return "Symbol{" +
"id=" + id +
", value='" + value + '\'' +
", code=" + code +
'}';
}
}
LexicalAnalyzer
package s1;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
* 词法分析器类
*/
public class LexicalAnalyzer {
public List<Symbol> keywordList=new ArrayList<>();//关键词表
public List<Symbol> identifierList=new ArrayList<>();//变量名表
public List<Symbol> constantList=new ArrayList<>();//常量表
public List<Symbol> symbolList=new ArrayList<>();//运行中单词表 存放<种类,索引> 根据出现的顺序依次添加
private String input;//输入的单词串
private int position;//扫描指针
public LexicalAnalyzer() {
}
public LexicalAnalyzer(String input) {
this.input = input;
this.position = 0;
}
public void toStringSymbolList(){
for (Symbol s:symbolList) {
// System.out.println(s.toStringIdCode());
System.out.println(s.toString());
}
}
//创建关键字表 根据表3.1实现
{
File file = new File("keywords.txt");
if (file.exists()) {
System.out.println("keywords.txt文件存在");
System.out.println("读取文件,加载关键词表");
loadKeywordList();
} else {
System.out.println("keywords.txt文件不存在");
System.out.println("采用默认的关键词表");
initKeywordList();
}
}
//读取keywords.txt文件的内容加载到keywordList中
private void loadKeywordList() {
try {
BufferedReader reader = new BufferedReader(new FileReader("keywords.txt"));
String line;
while ((line = reader.readLine()) != null) {
String[] arr = line.split("\\s+");
keywordList.add(new Symbol(Integer.parseInt(arr[0]), arr[1]));
}
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//默认的关键词表
public void initKeywordList(){
//保留字采用一词一类
keywordList.add(new Symbol(1,"DIM"));
keywordList.add(new Symbol(2,"IF"));
keywordList.add(new Symbol(3,"DO"));
keywordList.add(new Symbol(4,"STOP"));
keywordList.add(new Symbol(5,"END"));
//标识符 二次查询
keywordList.add(new Symbol(6,"identifierList"));
//常量表 二次查询
keywordList.add(new Symbol(7,"constantList"));
//算符采用一词一类
keywordList.add(new Symbol(8,"="));
keywordList.add(new Symbol(9,"+"));
keywordList.add(new Symbol(10,"*"));
keywordList.add(new Symbol(11,"**"));
keywordList.add(new Symbol(12,","));
keywordList.add(new Symbol(13,"("));
keywordList.add(new Symbol(14,")"));
}
//给所有关键字符号赋内码值(也可以不赋值)
{
//取出keywordList的符号,给他赋值其索引
for (Symbol s:keywordList) {
s.setCode(keywordList.indexOf(s));
}
}
//根据3,2,4编写
//字符变量,存放最新读进的源程序字符
private static char ch;
private static final char EOF='#';
// 字符数组,存放构成单词符号的字符串
private String strToken;
//子程序过程,将下一输入字符读到ch中,搜索指示器前移一字符位置。
public void getChar() {
if (position<input.length()){
ch=input.charAt(position++);
}else{
ch=EOF;
}
}
//子程序过程,检查ch中的字符是否为空白。若是,则调用GetChar直至ch中进人一个非空白字符。
public void getBC(){
if(ch==' '){
getChar();
getBC();//递归
}
}
//子程序过程,将ch中的字符连接到strToken之后。
public void concat(){
strToken=strToken.concat(""+ch);
}
//布尔函数过程,它们分别判断ch中的字符是否为字母和数字。
public boolean isLetter(){
return ch >= 'A' && ch <= 'z';
}
public boolean isDigit(){
return ch >= '0' && ch <= '9';
}
//整型函数过程,对stToken中的字符串查找保留字表,若它是一个保留字则返回它的编码,否则返回О值(假定0不是保留字的编码)。
public int reserve(){
Symbol symbol=new Symbol(strToken);
if(keywordList.contains(symbol)){
return keywordList.get(keywordList.indexOf(symbol)).getId();
}
return 0;
}
//子程序过程,将搜索指示器回调一个字符位置,将ch置为空白字符。
public void retract(){
position--;
if(ch!=EOF){
ch=' ';
}
}
//整型函数过程,将strToken中的标识符插入符号表,返回符号表指针。
public int insertId(String strToken){
Symbol symbol=new Symbol(strToken);
identifierList.add(symbol);
return identifierList.indexOf(symbol);
}
//整型函数过程,将strToken中的常数插入常数表,返回常数表指针。
public int insertConst(String strToken){
Symbol symbol=new Symbol(strToken);
constantList.add(symbol);
return constantList.indexOf(symbol);
}
//根据图3.3的状态转移图实现
public void analyzer(){
int id,code;
strToken="";
getChar();
getBC();
if(ch==EOF){
System.out.println("词法分析结束");
return;
}
if(isLetter()){
while ((isLetter()||isDigit())&&ch!=EOF){
concat();
getChar();
}
retract();
id =reserve();
//0是标识符 不是0就是保留字
if(id ==0){
code=insertId(strToken);
Symbol symbol=keywordList.get(keywordList.indexOf(new Symbol("identifierList")));
//<id,value,code> 编码 符号 索引
int idId=symbol.getId();//标识符在关键字中的编码
symbolList.add(new Symbol(idId,strToken,code));
}else{
int keyCode= keywordList.indexOf(new Symbol(id,strToken));//关键字的索引
symbolList.add(new Symbol(id,strToken,keyCode));
}
}else if (isDigit()){
while (isDigit()){
concat();
getChar();
}
retract();
code=insertConst(strToken);
id=keywordList.get(keywordList.indexOf(new Symbol("constantList"))).getId();
symbolList.add(new Symbol(id,strToken,code));
} else if (ch=='=') {
code=keywordList.indexOf(new Symbol("="));
id=keywordList.get(code).getId();
symbolList.add(new Symbol(id,"=",code));
}else if (ch=='+') {
code=keywordList.indexOf(new Symbol("+"));
id=keywordList.get(code).getId();
symbolList.add(new Symbol(id,"+",code));
}else if (ch=='*') {
getChar();
if(ch=='*'){
code=keywordList.indexOf(new Symbol("**"));
id=keywordList.get(code).getId();
symbolList.add(new Symbol(id,"**",code));
}else{
retract();
code=keywordList.indexOf(new Symbol("*"));
id=keywordList.get(code).getId();
symbolList.add(new Symbol(id,"*",code));
}
}else if (ch==',') {
code=keywordList.indexOf(new Symbol(","));
id=keywordList.get(code).getId();
symbolList.add(new Symbol(id,",",code));
}else if (ch=='(') {
code=keywordList.indexOf(new Symbol("("));
id=keywordList.get(code).getId();
symbolList.add(new Symbol(id,"(",code));
}else if (ch==')') {
code=keywordList.indexOf(new Symbol(")"));
id=keywordList.get(code).getId();
symbolList.add(new Symbol(id,")",code));
}else{
procError();//出错处理
}
}
private void procError() {
throw new RuntimeException("词法分析出错"+"\n"+"出错位置为"+position);
}
public void analyzers(){
while (ch!=EOF){
analyzer();
}
}
//测试关键词表的赋值
private static void testKeywordList(){
LexicalAnalyzer lex=new LexicalAnalyzer();
for (Symbol s:lex.keywordList) {
System.out.println(s);
}
}
//测试词法分析器
public void testAnalyzers(){
// String input="DIM IF DO STOP END abc def 123 456 = + * ** , () DIM";
String input=initInput();
System.out.println("输出input串");
System.out.println(input);
LexicalAnalyzer lex=new LexicalAnalyzer(input);
lex.analyzers();
System.out.println("输出单词表");
lex.toStringSymbolList();
System.out.println("正在把单词表存入symbols.txt");
lex.storeSymbols();
}
//初始化input
public String initInput(){
File file = new File("input.txt");
if (file.exists()) {
System.out.println("input.txt文件存在");
System.out.println("读取文件,input");
return loadInput();
} else {
System.out.println("input.txt文件不存在");
System.out.println("随机初始化input");
return randomInput();
}
}
//读入input.txt到input
public String loadInput(){
String input="";
try {
File file = new File("input.txt");
BufferedReader reader = new BufferedReader(new FileReader(file));
String line;
StringBuilder sb = new StringBuilder();
while ((line = reader.readLine()) != null) {
sb.append(line);
}
input = sb.toString();
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
return input;
}
//没有input.txt随机初始化input
public String randomInput(){
final String ERROR="~~";//错误字符
Random rand=new Random();
StringBuilder input= new StringBuilder();
for(int i=0;i<10;i++){
String value;
int index=rand.nextInt(keywordList.size()+1);//故意+1 人为使其出现错误单词
if(index>=keywordList.size()){
value=ERROR;//错误单词
}else{
value=keywordList.get(index).getValue();
if(value.equals("constantList")){
StringBuilder constant= new StringBuilder();
for(int j=0;j<3;j++){
constant.append(rand.nextInt(10));
}
value= constant.toString();
}else if("identifierList".equals(value)){
StringBuilder letter= new StringBuilder();
for(int j=0;j<3;j++){
char c=(char)(rand.nextInt(26)+'a');
letter.append(c);
}
value= letter.toString();
}
}
input.append(value).append(" ");
}
return input.toString();
}
//把symbolList中的数据写入symbols.txt
public void storeSymbols() {
String fileName="symbols.txt";
storeList(fileName,symbolList);
}
//存储表到文件中
public void storeList(String fileName,List<Symbol> list){
FileWriter writer=null;
try {
writer = new FileWriter(fileName);
for (Symbol symbol : list) {
writer.write(symbol.toString() + "\n");
}
writer.flush();
} catch (IOException e) {
e.printStackTrace();
}finally {
if (writer != null) {
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
//测试
//testKeywordList();
//测试
new LexicalAnalyzer().testAnalyzers();
}
}
代码1结果
无keywords.txt
结果如下
keywords.txt文件不存在
采用默认的关键词表
input.txt文件存在
读取文件,input
输出input串
DIM IF DO STOP END abc def 123 456 = + * ** , ()
keywords.txt文件不存在
采用默认的关键词表
词法分析结束
输出单词表
Symbol{id=1, value='DIM', code=0}
Symbol{id=2, value='IF', code=1}
Symbol{id=3, value='DO', code=2}
Symbol{id=4, value='STOP', code=3}
Symbol{id=5, value='END', code=4}
Symbol{id=6, value='abc', code=0}
Symbol{id=6, value='def', code=1}
Symbol{id=7, value='123', code=0}
Symbol{id=7, value='456', code=1}
Symbol{id=8, value='=', code=7}
Symbol{id=9, value='+', code=8}
Symbol{id=10, value='*', code=9}
Symbol{id=11, value='**', code=10}
Symbol{id=12, value=',', code=11}
Symbol{id=13, value='(', code=12}
Symbol{id=14, value=')', code=13}
正在把单词表存入symbols.txt
Process finished with exit code 0
有keywords.txt文件
1 DIM
2 IF
3 DO
4 STOP
5 END
6 identifierList
7 constantList
8 =
9 +
10 *
11 **
12 ,
13 (
14 )
结果
和默认初始化一样
有input.txt文件时
正确情况
DIM IF DO STOP END abc def 123 456 = + * ** , ()
结果如下
keywords.txt文件存在
读取文件,加载关键词表
input.txt文件存在
读取文件,input
输出input串
DIM IF DO STOP END abc def 123 456 = + * ** , ()
keywords.txt文件存在
读取文件,加载关键词表
词法分析结束
输出单词表
Symbol{id=1, value='DIM', code=0}
Symbol{id=2, value='IF', code=1}
Symbol{id=3, value='DO', code=2}
Symbol{id=4, value='STOP', code=3}
Symbol{id=5, value='END', code=4}
Symbol{id=6, value='abc', code=0}
Symbol{id=6, value='def', code=1}
Symbol{id=7, value='123', code=0}
Symbol{id=7, value='456', code=1}
Symbol{id=8, value='=', code=7}
Symbol{id=9, value='+', code=8}
Symbol{id=10, value='*', code=9}
Symbol{id=11, value='**', code=10}
Symbol{id=12, value=',', code=11}
Symbol{id=13, value='(', code=12}
Symbol{id=14, value=')', code=13}
正在把单词表存入symbols.txt
Process finished with exit code 0
错误情况(~是错误单词)
DIM IF DO STOP END abc def 123 456 = + * ** , () ~
结果如下
keywords.txt文件存在
读取文件,加载关键词表
input.txt文件存在
读取文件,input
输出input串
DIM IF DO STOP END abc def 123 456 = + * ** , () ~
keywords.txt文件存在
读取文件,加载关键词表
Exception in thread "main" java.lang.RuntimeException: 词法分析出错
出错位置为50
at s1.LexicalAnalyzer.procError(LexicalAnalyzer.java:242)
at s1.LexicalAnalyzer.analyzer(LexicalAnalyzer.java:237)
at s1.LexicalAnalyzer.analyzers(LexicalAnalyzer.java:246)
at s1.LexicalAnalyzer.testAnalyzers(LexicalAnalyzer.java:265)
at s1.LexicalAnalyzer.main(LexicalAnalyzer.java:379)
没有input.txt文件时
随机生成input单词串
正确情况
keywords.txt文件存在
读取文件,加载关键词表
input.txt文件不存在
随机初始化input
输出input串
DIM IF * IF DIM ( , END ) IF
keywords.txt文件存在
读取文件,加载关键词表
词法分析结束
输出单词表
Symbol{id=1, value='DIM', code=0}
Symbol{id=2, value='IF', code=1}
Symbol{id=10, value='*', code=9}
Symbol{id=2, value='IF', code=1}
Symbol{id=1, value='DIM', code=0}
Symbol{id=13, value='(', code=12}
Symbol{id=12, value=',', code=11}
Symbol{id=5, value='END', code=4}
Symbol{id=14, value=')', code=13}
Symbol{id=2, value='IF', code=1}
正在把单词表存入symbols.txt
错误情况
keywords.txt文件存在
读取文件,加载关键词表
input.txt文件不存在
随机初始化input
输出input串
) ~~ + + DO 438 ~~ IF ** IF
keywords.txt文件存在
读取文件,加载关键词表
Exception in thread "main" java.lang.RuntimeException: 词法分析出错
出错位置为3
at s1.LexicalAnalyzer.procError(LexicalAnalyzer.java:242)
at s1.LexicalAnalyzer.analyzer(LexicalAnalyzer.java:237)
at s1.LexicalAnalyzer.analyzers(LexicalAnalyzer.java:246)
at s1.LexicalAnalyzer.testAnalyzers(LexicalAnalyzer.java:265)
at s1.LexicalAnalyzer.main(LexicalAnalyzer.java:379)
Process finished with exit code 1
symbols.txt
正确情况
Symbol{id=1, value='DIM', code=0}
Symbol{id=2, value='IF', code=1}
Symbol{id=3, value='DO', code=2}
Symbol{id=4, value='STOP', code=3}
Symbol{id=5, value='END', code=4}
Symbol{id=6, value='abc', code=0}
Symbol{id=6, value='def', code=1}
Symbol{id=7, value='123', code=0}
Symbol{id=7, value='456', code=1}
Symbol{id=8, value='=', code=7}
Symbol{id=9, value='+', code=8}
Symbol{id=10, value='*', code=9}
Symbol{id=11, value='**', code=10}
Symbol{id=12, value=',', code=11}
Symbol{id=13, value='(', code=12}
Symbol{id=14, value=')', code=13}
错误情况
不写入
在此处修改,就可以写入了
抛出异常之前
进行输出单词表和写单词表
private void procError() {
toStringSymbolList();
storeSymbols();
throw new RuntimeException("词法分析出错"+"\n"+"出错位置为"+position);
}
结果如下
keywords.txt文件存在
读取文件,加载关键词表
input.txt文件存在
读取文件,input
输出input串
DIM IF DO STOP END abc def 123 456 = + * ** , () ~
keywords.txt文件存在
读取文件,加载关键词表
Symbol{id=1, value='DIM', code=0}
Symbol{id=2, value='IF', code=1}
Symbol{id=3, value='DO', code=2}
Symbol{id=4, value='STOP', code=3}
Symbol{id=5, value='END', code=4}
Symbol{id=6, value='abc', code=0}
Symbol{id=6, value='def', code=1}
Symbol{id=7, value='123', code=0}
Symbol{id=7, value='456', code=1}
Symbol{id=8, value='=', code=7}
Symbol{id=9, value='+', code=8}
Symbol{id=10, value='*', code=9}
Symbol{id=11, value='**', code=10}
Symbol{id=12, value=',', code=11}
Symbol{id=13, value='(', code=12}
Symbol{id=14, value=')', code=13}
Exception in thread "main" java.lang.RuntimeException: 词法分析出错
出错位置为50
at s1.LexicalAnalyzer.procError(LexicalAnalyzer.java:244)
at s1.LexicalAnalyzer.analyzer(LexicalAnalyzer.java:237)
at s1.LexicalAnalyzer.analyzers(LexicalAnalyzer.java:248)
at s1.LexicalAnalyzer.testAnalyzers(LexicalAnalyzer.java:267)
at s1.LexicalAnalyzer.main(LexicalAnalyzer.java:381)
Process finished with exit code 1
2023-4-2 18:05:18
代码2
2023-4-2 18:28:13
为了应对各种词法分析器,我们发现
除了关键字表,
就只有状态转移图不一样
也就是LexicalAnalyzer.analyzer()
方法不一样
所以
我们用一个抽象父类AbstractLexicalAnalyzer来封装其他方法
让不同的子类实现来重写analyzer方法
另外
我们还可以在子类中把父类的出错处理重写了
使其跳过出错,继续分析
AbstractLexicalAnalyzer
package s1;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
* 词法分析器抽象类
*/
public abstract class AbstractLexicalAnalyzer {
public List<Symbol> keywordList=new ArrayList<>();//关键词表
public List<Symbol> identifierList=new ArrayList<>();//变量名表
public List<Symbol> constantList=new ArrayList<>();//常量表
public List<Symbol> symbolList=new ArrayList<>();//运行中单词表 存放<种类,索引> 根据出现的顺序依次添加
String input;//输入的单词串
int position;//扫描指针
protected AbstractLexicalAnalyzer() {
}
protected AbstractLexicalAnalyzer(String input) {
this.input = input;
this.position = 0;
}
public void toStringSymbolList(){
for (Symbol s:symbolList) {
// System.out.println(s.toStringIdCode());
System.out.println(s.toString());
}
}
//创建关键字表 根据表3.1实现
{
File file = new File("keywords.txt");
if (file.exists()) {
System.out.println("keywords.txt文件存在");
System.out.println("读取文件,加载关键词表");
loadKeywordList();
} else {
System.out.println("keywords.txt文件不存在");
System.out.println("采用默认的关键词表");
initKeywordList();
}
}
//读取keywords.txt文件的内容加载到keywordList中
public void loadKeywordList() {
try {
BufferedReader reader = new BufferedReader(new FileReader("keywords.txt"));
String line;
while ((line = reader.readLine()) != null) {
String[] arr = line.split("\\s+");
keywordList.add(new Symbol(Integer.parseInt(arr[0]), arr[1]));
}
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//默认的关键词表
public void initKeywordList(){
//保留字采用一词一类
keywordList.add(new Symbol(1,"DIM"));
keywordList.add(new Symbol(2,"IF"));
keywordList.add(new Symbol(3,"DO"));
keywordList.add(new Symbol(4,"STOP"));
keywordList.add(new Symbol(5,"END"));
//标识符 二次查询
keywordList.add(new Symbol(6,"identifierList"));
//常量表 二次查询
keywordList.add(new Symbol(7,"constantList"));
//算符采用一词一类
keywordList.add(new Symbol(8,"="));
keywordList.add(new Symbol(9,"+"));
keywordList.add(new Symbol(10,"*"));
keywordList.add(new Symbol(11,"**"));
keywordList.add(new Symbol(12,","));
keywordList.add(new Symbol(13,"("));
keywordList.add(new Symbol(14,")"));
}
//给所有关键字符号赋内码值(也可以不赋值)
{
//取出keywordList的符号,给他赋值其索引
for (Symbol s:keywordList) {
s.setCode(keywordList.indexOf(s));
}
}
//根据3,2,4编写
//字符变量,存放最新读进的源程序字符
static char ch;
static final char EOF='#';
// 字符数组,存放构成单词符号的字符串
public String strToken;
//子程序过程,将下一输入字符读到ch中,搜索指示器前移一字符位置。
public void getChar() {
if (position<input.length()){
ch=input.charAt(position++);
}else{
ch=EOF;
}
}
//子程序过程,检查ch中的字符是否为空白。若是,则调用GetChar直至ch中进人一个非空白字符。
public void getBC(){
if(ch==' '){
getChar();
getBC();//递归
}
}
//子程序过程,将ch中的字符连接到strToken之后。
public void concat(){
strToken=strToken.concat(""+ch);
}
//布尔函数过程,它们分别判断ch中的字符是否为字母和数字。
public boolean isLetter(){
return ch >= 'A' && ch <= 'z';
}
public boolean isDigit(){
return ch >= '0' && ch <= '9';
}
//整型函数过程,对stToken中的字符串查找保留字表,若它是一个保留字则返回它的编码,否则返回О值(假定0不是保留字的编码)。
public int reserve(){
Symbol symbol=new Symbol(strToken);
if(keywordList.contains(symbol)){
return keywordList.get(keywordList.indexOf(symbol)).getId();
}
return 0;
}
//子程序过程,将搜索指示器回调一个字符位置,将ch置为空白字符。
public void retract(){
position--;
if(ch!=EOF){
ch=' ';
}
}
//整型函数过程,将strToken中的标识符插入符号表,返回符号表指针。
public int insertId(String strToken){
Symbol symbol=new Symbol(strToken);
identifierList.add(symbol);
return identifierList.indexOf(symbol);
}
//整型函数过程,将strToken中的常数插入常数表,返回常数表指针。
public int insertConst(String strToken){
Symbol symbol=new Symbol(strToken);
constantList.add(symbol);
return constantList.indexOf(symbol);
}
//状态转移图由子类实现
public abstract void analyzer();
//处理错误
//父类抛出异常处理错误
void procError() {
toStringSymbolList();
storeSymbols();
throw new RuntimeException("词法分析出错"+"\n"+"出错位置为"+position);
}
public void analyzers(){
while (ch!=EOF){
analyzer();
}
}
//初始化input
public String initInput(){
File file = new File("input.txt");
if (file.exists()) {
System.out.println("input.txt文件存在");
System.out.println("读取文件,input");
return loadInput();
} else {
System.out.println("input.txt文件不存在");
System.out.println("随机初始化input");
return randomInput();
}
}
//读入input.txt到input
public String loadInput(){
String input="";
try {
File file = new File("input.txt");
BufferedReader reader = new BufferedReader(new FileReader(file));
String line;
StringBuilder sb = new StringBuilder();
while ((line = reader.readLine()) != null) {
sb.append(line);
}
input = sb.toString();
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
return input;
}
//没有input.txt随机初始化input
public String randomInput(){
final String ERROR="~~";//错误字符
Random rand=new Random();
StringBuilder input= new StringBuilder();
for(int i=0;i<10;i++){
String value;
int index=rand.nextInt(keywordList.size()+1);//故意+1 人为使其出现错误单词
if(index>=keywordList.size()){
value=ERROR;//错误单词
}else{
value=keywordList.get(index).getValue();
if(value.equals("constantList")){
StringBuilder constant= new StringBuilder();
for(int j=0;j<3;j++){
constant.append(rand.nextInt(10));
}
value= constant.toString();
}else if("identifierList".equals(value)){
StringBuilder letter= new StringBuilder();
for(int j=0;j<3;j++){
char c=(char)(rand.nextInt(26)+'a');
letter.append(c);
}
value= letter.toString();
}
}
input.append(value).append(" ");
}
return input.toString();
}
//把symbolList中的数据写入symbols.txt
public void storeSymbols() {
String fileName="symbols.txt";
storeList(fileName,symbolList);
}
//存储表到文件中
public void storeList(String fileName,List<Symbol> list){
FileWriter writer=null;
try {
writer = new FileWriter(fileName);
for (Symbol symbol : list) {
writer.write(symbol.toString() + "\n");
}
writer.flush();
} catch (IOException e) {
e.printStackTrace();
}finally {
if (writer != null) {
try {
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
LexicalAnalyzer
package s1;
/**
* 词法分析器类
*/
public class LexicalAnalyzer extends AbstractLexicalAnalyzer{
public LexicalAnalyzer() {
}
public LexicalAnalyzer(String input) {
super(input);
}
//根据图3.3的状态转移图实现
@Override
public void analyzer(){
int id,code;
strToken="";
getChar();
getBC();
if(ch==EOF){
System.out.println("词法分析结束");
return;
}
if(isLetter()){
while ((isLetter()||isDigit())&&ch!=EOF){
concat();
getChar();
}
retract();
id =reserve();
//0是标识符 不是0就是保留字
if(id ==0){
code=insertId(strToken);
Symbol symbol=keywordList.get(keywordList.indexOf(new Symbol("identifierList")));
//<id,value,code> 编码 符号 索引
int idId=symbol.getId();//标识符在关键字中的编码
symbolList.add(new Symbol(idId,strToken,code));
}else{
int keyCode= keywordList.indexOf(new Symbol(id,strToken));//关键字的索引
symbolList.add(new Symbol(id,strToken,keyCode));
}
}else if (isDigit()){
while (isDigit()){
concat();
getChar();
}
retract();
code=insertConst(strToken);
id=keywordList.get(keywordList.indexOf(new Symbol("constantList"))).getId();
symbolList.add(new Symbol(id,strToken,code));
} else if (ch=='=') {
code=keywordList.indexOf(new Symbol("="));
id=keywordList.get(code).getId();
symbolList.add(new Symbol(id,"=",code));
}else if (ch=='+') {
code=keywordList.indexOf(new Symbol("+"));
id=keywordList.get(code).getId();
symbolList.add(new Symbol(id,"+",code));
}else if (ch=='*') {
getChar();
if(ch=='*'){
code=keywordList.indexOf(new Symbol("**"));
id=keywordList.get(code).getId();
symbolList.add(new Symbol(id,"**",code));
}else{
retract();
code=keywordList.indexOf(new Symbol("*"));
id=keywordList.get(code).getId();
symbolList.add(new Symbol(id,"*",code));
}
}else if (ch==',') {
code=keywordList.indexOf(new Symbol(","));
id=keywordList.get(code).getId();
symbolList.add(new Symbol(id,",",code));
}else if (ch=='(') {
code=keywordList.indexOf(new Symbol("("));
id=keywordList.get(code).getId();
symbolList.add(new Symbol(id,"(",code));
}else if (ch==')') {
code=keywordList.indexOf(new Symbol(")"));
id=keywordList.get(code).getId();
symbolList.add(new Symbol(id,")",code));
}else{
procError();//出错处理
}
}
//重写出错处理,跳过1下,继续分析
@Override
public void procError(){
System.out.println("词法分析出错"+"\n"+"出错位置为"+position);
System.out.println("跳过错误,继续分析");
position++;
if(ch!=EOF){
ch=' ';
}
}
//测试关键词表的赋值
private static void testKeywordList(){
LexicalAnalyzer lex=new LexicalAnalyzer();
for (Symbol s:lex.keywordList) {
System.out.println(s);
}
}
//测试词法分析器
private void testAnalyzers(){
// String input="DIM IF DO STOP END abc def 123 456 = + * ** , () DIM";
String input=initInput();
System.out.println("输出input串");
System.out.println(input);
LexicalAnalyzer lex=new LexicalAnalyzer(input);
lex.analyzers();
System.out.println("输出单词表");
lex.toStringSymbolList();
System.out.println("正在把单词表存入symbols.txt");
lex.storeSymbols();
}
public static void main(String[] args) {
//测试
//testKeywordList();
//测试
new LexicalAnalyzer().testAnalyzers();
}
}
代码2结果
input.txt
一处错误
~ DIM IF DO STOP END abc def 123 456 = + * ** , ()
结果如下
keywords.txt文件存在
读取文件,加载关键词表
input.txt文件存在
读取文件,input
输出input串
~ DIM IF DO STOP END abc def 123 456 = + * ** , ()
keywords.txt文件存在
读取文件,加载关键词表
词法分析出错
出错位置为1
跳过错误,继续分析
词法分析结束
输出单词表
Symbol{id=1, value='DIM', code=0}
Symbol{id=2, value='IF', code=1}
Symbol{id=3, value='DO', code=2}
Symbol{id=4, value='STOP', code=3}
Symbol{id=5, value='END', code=4}
Symbol{id=6, value='abc', code=0}
Symbol{id=6, value='def', code=1}
Symbol{id=7, value='123', code=0}
Symbol{id=7, value='456', code=1}
Symbol{id=8, value='=', code=7}
Symbol{id=9, value='+', code=8}
Symbol{id=10, value='*', code=9}
Symbol{id=11, value='**', code=10}
Symbol{id=12, value=',', code=11}
Symbol{id=13, value='(', code=12}
Symbol{id=14, value=')', code=13}
正在把单词表存入symbols.txt
Process finished with exit code 0
多处错误
~ DIM IF DO STOP END abc ~ def 123 456 = + ~ * ** , () ~
结果如下
keywords.txt文件存在
读取文件,加载关键词表
input.txt文件存在
读取文件,input
输出input串
~ DIM IF DO STOP END abc ~ def 123 456 = + ~ * ** , () ~
keywords.txt文件存在
读取文件,加载关键词表
词法分析出错
出错位置为1
跳过错误,继续分析
词法分析出错
出错位置为26
跳过错误,继续分析
词法分析出错
出错位置为44
跳过错误,继续分析
词法分析出错
出错位置为56
跳过错误,继续分析
词法分析结束
输出单词表
Symbol{id=1, value='DIM', code=0}
Symbol{id=2, value='IF', code=1}
Symbol{id=3, value='DO', code=2}
Symbol{id=4, value='STOP', code=3}
Symbol{id=5, value='END', code=4}
Symbol{id=6, value='abc', code=0}
Symbol{id=6, value='def', code=1}
Symbol{id=7, value='123', code=0}
Symbol{id=7, value='456', code=1}
Symbol{id=8, value='=', code=7}
Symbol{id=9, value='+', code=8}
Symbol{id=10, value='*', code=9}
Symbol{id=11, value='**', code=10}
Symbol{id=12, value=',', code=11}
Symbol{id=13, value='(', code=12}
Symbol{id=14, value=')', code=13}
正在把单词表存入symbols.txt
Process finished with exit code 0
2023-4-2 19:01:37
高级代码
要求:代码的高级功能
更多的关键字(运算符)
需要编写keywords.txt
更多的常数(科学计数法 浮点数 字符串常量)
需要重写analyzer
更多的功能(过滤无效字符、数值转换、宏展开、预包含处理)
需要重写analyzer
说明
在关键词表中
6 identifierList
7 constantList
要来做
标识符(id=6,value=identifierList)
常量表(id=7,value=constantList)
没有什么意义
只在随机生成input中用来生成标识符和常量
也可以没有
这样的话,符号表的输出就是
标识符(id=0,value=具体标识符的值)
常量表(id=0,value=具体变量的值)
仅在id有所区别,其余没变
如果需要修改的话
在analyzer()
中标识符和常量表的id设置为0,就行
不再需要在keywordList中查找
还有
出错位置没有行数
需要修改loadInput()
逻辑
使其每读入一行,就进行语法分析处理
并且需要row行数属性来配合
另外需要注意:
代码中EOF
定义为#
号ch=EOF
作为input结束的标志
如果#
号是有意义的符号
就需要重写定义static final char EOF='#';
了
例如:static final char EOF= (char) 128;
请看:
实验一 词法分析器+【编译原理】
最后
2023-4-2 19:01:40
祝大家逢考必过
点赞收藏关注哦