引言
编译器工作的本质是将计算机高级语言翻译成计算机能够直接执行的机器码,这个翻译过程比较复杂,需要经历许多阶段。其中,词法分析是其中的基础和前提工作,它为后续的语法分析提供了有效的语法检查单位。
本系统可将指定的源程序字符流识别为单词Token序列,总体实现思路如下:首先将文件中存储的关键字、单字符分界符导入到程序中,然后按行扫描输入的单词序列,对其进行标记化。标记化的过程为用合适的正则化语句将单词进行分隔,调用函数判断单词的类型,最后得到一个标记列表tokens,其中包括行号,内容和种类。然后为每个标记创建一个计时器,用计时器将标记添加到表格中,同时调用函数实现线条颜色变化效果。最后根据表格中添加的tokens序列,将单词导出。
实验内容
主界面设计
词法分析DFA
字符表
关键字表
关键字可以实现增删改查功能,单字符表也一样,下面不做展示。
单词分类
过程展示
系统类图
系统流程图
系统实现
charactertable类:
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class charactertable extends JFrame {
private JTable table;
public charactertable() {
setTitle("词法分析器");
setSize(380, 480);
setLocationRelativeTo(null);
Container all = getContentPane();
setLayout(null);
// 创建表格模型
DefaultTableModel model = new DefaultTableModel();
model.addColumn("ID");
model.addColumn("字符");
table = new JTable(model);
JScrollPane scrollPane = new JScrollPane(table);
scrollPane.setBounds(70, 60, 220, 300);
all.add(scrollPane, BorderLayout.CENTER);
JButton search = new JButton("查询");
all.add(search);
search.setBounds(90, 380, 60, 30);
JButton reverse = new JButton("修改");
all.add(reverse);
reverse.setBounds(200, 380, 60, 30);
JLabel a=new JLabel("注:英文字母区分大小写");
all.add(a);
a.setBounds(20,20,200,20);
search.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
DefaultTableModel model = (DefaultTableModel) table.getModel();
FileUtil file1=new FileUtil();
file1.updateTableData("E:/character.txt",model);
int rowCount = model.getRowCount();
int id = rowCount + 1;
// Object cellValue = model.getValueAt(rowCount, 0); // 行号列
// Integer rowNumber = Integer.parseInt(cellValue.toString());
model.addRow(new Object[]{id, " "});
}
});
setVisible(true);
}
private void updateTableData() {
String filePath = "E:/character.txt"; // 文件路径
DefaultTableModel model = (DefaultTableModel) table.getModel();
try (BufferedReader br = new BufferedReader(new FileReader(filePath))) {
String line;
int id = 1;
while ((line = br.readLine()) != null) {
// 按逗号分割数据
String[] characters = line.split(",");
// 添加每个字符到表格模型
for (String character : characters) {
// 添加到表格模型
model.addRow(new Object[]{id++, character.trim()});
}
// 添加空格到表格模型
model.addRow(new Object[]{id++, " "});
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
FileUtil类:
import javax.swing.table.DefaultTableModel;
import java.io.*;
public class FileUtil {
public void updateTableData(String filePath, DefaultTableModel model) {
try (BufferedReader br = new BufferedReader(new FileReader(filePath))) {
String line;
int id = 1;
while ((line = br.readLine()) != null) {
// 去掉末尾的逗号
line = line.trim();
if (line.endsWith(",")) {
line = line.substring(0, line.length() - 1);
}
// 按逗号分割数据
String[] characters = line.split(",");
// 添加每个字符到表格模型
for (String character : characters) {
// 添加到表格模型
model.addRow(new Object[]{id++, character.trim()});
}
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
//将表格中修改后的内容存进文件
public void saveDataToFile(String filePath,DefaultTableModel model) {
try (BufferedWriter writer = new BufferedWriter(new FileWriter(filePath))) //覆盖文件内容,而不是追加到文件末尾,不加true
{
for (int i = 0; i < model.getRowCount(); i++) {
String keyword = (String) model.getValueAt(i, 1); // 1 是关键字列的索引
if (!keyword.trim().isEmpty()) {//删除逻辑
writer.write(keyword);
if (i < model.getRowCount() - 1) {
writer.write(",");
}
}
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
imagedo类:
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.Path2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Random;
public class imagedo {
private BufferedImage image;
private Graphics2D graphics;
protected BufferedImage getdo() throws IOException {
int width = 290, hight = 500;
image = new BufferedImage(width, hight, BufferedImage.TYPE_INT_RGB);
this.image=image;
//获取图形上下文,graphics想象成一个画笔
graphics = (Graphics2D) image.getGraphics();
//消除线条锯齿
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
//对指定的矩形区域填充颜色
graphics.setColor(Color.WHITE);
graphics.fillRect(0, 0, 290, 500);
graphics.setColor(Color.RED);
graphics.drawLine(20, 40, 40, 40);
// 绘制箭头
drawArrowhead(graphics, 20, 40, 40, 40,Color.RED);
graphics.drawOval(43, 30, 20, 20);//drawOval 方法的作用是在图形上下文中绘制一个矩形内切的椭圆。如果提供的宽度和高度相等(即 diameter 为正方形的边长),则绘制的是一个圆形。
graphics.drawLine(66, 40, 86, 40);
drawArrowhead(graphics, 66, 40, 86, 40,Color.RED);
graphics.drawOval(89, 30, 20, 20);
graphics.drawLine(109, 40, 233, 40);//最上面一行
graphics.drawLine(233, 40, 233, 410);//往下面画,最右竖线
drawArrowhead(graphics, 233, 40, 233, 410,Color.RED);
drawCurve(graphics,94,27,99,5,104,27);
drawArrowhead(graphics, 102,17, 104,29,Color.RED);
drawCurve(graphics,94,77,99,55,104,77);
drawArrowhead(graphics, 102,67, 104,79,Color.RED);
drawCurve(graphics,94,227,99,205,104,227);
drawArrowhead(graphics, 102,217, 104,229,Color.RED);
drawCurve(graphics,94,327,99,305,104,327);
drawArrowhead(graphics, 102,317, 104,329,Color.RED);
// 在箭头上方添加文字
//graphics.setColor(Color.BLACK);
graphics.drawString("S", 48, 45);
graphics.drawString("数字", 61, 35);
graphics.drawString("数字", 108, 25);
graphics.drawString("无符号整数", 170, 35);
graphics.drawString("字母", 61, 85);
graphics.drawString("字母,数字", 108, 75);
graphics.drawString("标识符", 180, 65);
graphics.drawString("关键字", 180, 105);
graphics.drawString("LookUp", 127, 87);
graphics.drawString("+ - * / ( ) [ ] ; = <", 61, 135);
graphics.drawString("单分界符", 177, 135);
graphics.drawString("单分界符", 177, 155);
graphics.drawString("双分界符", 177, 185);
graphics.drawString(":", 70, 185);
graphics.drawString("其他符号", 101, 155);
graphics.drawString("=", 120, 185);
graphics.drawString("{", 70, 235);
graphics.drawString("其他符号", 105, 220);
graphics.drawString("注释", 197, 235);
graphics.drawString("}", 120, 235);
graphics.drawString(".", 70, 285);
graphics.drawString(".", 115, 285);
graphics.drawString("其他符号", 101, 262);
// 保存原始颜色
Color originalColor = graphics.getColor();
// 设置文本颜色为黑色
graphics.setColor(Color.BLACK);
// 绘制文本
graphics.drawString("程序结束标识", 158, 262);
// 恢复原始颜色
graphics.setColor(originalColor);
graphics.drawString("数组下标界限符", 147, 288);
graphics.drawString("‘", 70, 335);
graphics.drawString("’", 125, 335);
graphics.drawString("其他符号", 105, 320);
graphics.drawString("字符串标识符", 158, 335);
graphics.drawString("其他符号", 55, 385);
// 设置文本颜色为黑色
graphics.setColor(Color.BLACK);
graphics.drawString("报错", 200, 385);
graphics.setColor(originalColor);
graphics.drawLine(53, 53, 53, 390);//竖左线
graphics.drawLine(53, 390, 233, 390);//下横线
drawArrowhead(graphics, 53, 390, 233, 390,Color.RED);
graphics.drawOval(223, 410, 20, 20);//最下面的圆
graphics.drawOval(89, 80, 20, 20);//第二行的园
graphics.drawLine(53, 90, 86, 90);
drawArrowhead(graphics, 53, 90, 86, 90,Color.RED);//绘制箭头
graphics.drawLine(112, 90, 172, 90);
graphics.drawLine(172, 90, 172, 70);
graphics.drawLine(172, 90, 172, 110);
graphics.drawLine(172, 70, 233, 70);
drawArrowhead(graphics, 172, 70, 233, 70,Color.RED);//绘制箭头
graphics.drawLine(172, 110, 233, 110);
drawArrowhead(graphics, 172, 110, 233, 110,Color.RED);//绘制箭头
graphics.drawLine(53, 140, 233, 140);//第三行的线
drawArrowhead(graphics, 53, 140, 233, 140,Color.RED);//绘制箭头
graphics.drawOval(89, 180, 20, 20);//第四行园
graphics.drawLine(53, 190, 86, 190);
drawArrowhead(graphics, 53, 190, 86, 190,Color.RED);//绘制箭头
graphics.drawLine(112, 190, 145, 190);
drawArrowhead(graphics, 112, 190, 145, 190,Color.RED);//绘制箭头
graphics.drawOval(145, 180, 20, 20);
graphics.drawLine(99, 180, 99, 160);//向上分支
graphics.drawLine(99, 160, 233, 160);
drawArrowhead(graphics, 99, 160, 233, 160,Color.RED);//绘制箭头
graphics.drawLine(171, 190, 233, 190);
drawArrowhead(graphics, 171, 190, 233, 190,Color.RED);//绘制箭头
graphics.drawOval(89, 230, 20, 20);//第五行园
graphics.drawLine(53, 240, 86, 240);
drawArrowhead(graphics, 53, 240, 86, 240,Color.RED);//绘制箭头
graphics.drawLine(112, 240, 145, 240);
drawArrowhead(graphics, 112, 240, 145, 240,Color.RED);//绘制箭头
graphics.drawOval(145, 230, 20, 20);
graphics.drawLine(171, 240, 233, 240);
drawArrowhead(graphics, 171, 240, 233, 240,Color.RED);//绘制箭头
graphics.drawOval(89, 280, 20, 20);//第六行园
graphics.drawLine(53, 290, 86, 290);
drawArrowhead(graphics, 53, 290, 86, 290,Color.RED);//绘制箭头
graphics.drawLine(112, 290, 125, 290);
drawArrowhead(graphics, 112, 290, 125, 290,Color.RED);//绘制箭头
graphics.drawOval(125, 280, 20, 20);
graphics.drawLine(151, 290, 233, 290);
drawArrowhead(graphics, 171, 290, 233, 290,Color.RED);//绘制箭头
graphics.drawLine(99, 280, 99, 265);
graphics.drawLine(99, 265, 233, 265);
drawArrowhead(graphics, 99, 265, 233, 265,Color.RED);//绘制箭头
graphics.drawOval(89, 330, 20, 20);//第七行园
graphics.drawLine(53, 340, 86, 340);
drawArrowhead(graphics, 53, 340, 86, 340,Color.RED);//绘制箭头
graphics.drawLine(112, 340, 145, 340);
drawArrowhead(graphics, 112, 340, 145, 340,Color.RED);//绘制箭头
graphics.drawOval(145, 330, 20, 20);
graphics.drawLine(171, 340, 233, 340);
drawArrowhead(graphics, 171, 340, 233, 340,Color.RED);//绘制箭头
graphics.dispose();//释放此图形的上下文并释放它所使用的所有系统资源
return image;
}
private void drawArrowhead(Graphics2D g2, int x1, int y1, int x2, int y2, Color color) {
double angle = Math.atan2(y2 - y1, x2 - x1);
int arrowSize = 10;
int x3 = x2 - (int) (arrowSize * Math.cos(angle - Math.PI / 6));
int y3 = y2 - (int) (arrowSize * Math.sin(angle - Math.PI / 6));
int x4 = x2 - (int) (arrowSize * Math.cos(angle + Math.PI / 6));
int y4 = y2 - (int) (arrowSize * Math.sin(angle + Math.PI / 6));
// 设置箭头颜色
g2.setColor(color);
// 绘制箭头
g2.drawLine(x2, y2, x3, y3);
g2.drawLine(x2, y2, x4, y4);
}
private static void drawCurve(Graphics g,int x,int y,int x1,int y1,int x2,int y2) {
Graphics2D g2d = (Graphics2D) g;
// 创建路径
Path2D path = new Path2D.Double();
// 设置起始点
path.moveTo(x, y);
// 添加二次贝塞尔曲线
path.quadTo(x1, y1, x2, y2);
// 设置曲线颜色
g2d.setColor(Color.RED);
// 绘制曲线
g2d.draw(path);
}
}
keywordstable类:
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
public class keywordstable extends JFrame {
private JTable table;
FileUtil file1=new FileUtil();
public keywordstable() {
setTitle("关键字");
setSize(380, 480);
setLocationRelativeTo(null);
Container all = getContentPane();
setLayout(null);
// 创建表格模型
DefaultTableModel model = new DefaultTableModel();
model.addColumn("ID");
model.addColumn("关键字");
table = new JTable(model);
JScrollPane scrollPane = new JScrollPane(table);
scrollPane.setBounds(70, 60, 220, 300);
all.add(scrollPane, BorderLayout.CENTER);
JButton search = new JButton("查询");
all.add(search);
search.setBounds(90, 380, 60, 30);
JButton reverse = new JButton("修改");
all.add(reverse);
reverse.setBounds(200, 380, 60, 30);
JTextField a=new JTextField(10);
all.add(a);
a.setBounds(70,30,80,20);
JButton b=new JButton("添加");
all.add(b);
b.setBounds(200,30,80,20);
//查询
search.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// 从文件中读取数据并更新表格
DefaultTableModel model = (DefaultTableModel) table.getModel();
model.setRowCount(0); // 清空表格
file1.updateTableData("E:/keywords.txt",model);
}
});
//添加
b.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
String newkeyword=a.getText().trim();
if(isKeywordExists(newkeyword))
{
JOptionPane.showMessageDialog(null,"已存在相同的关键字","提示",JOptionPane.WARNING_MESSAGE);
}
else {
DefaultTableModel model = (DefaultTableModel) table.getModel();
int rowCount = model.getRowCount();
int id = rowCount + 1;
model.addRow(new Object[]{id, newkeyword});
// 将新关键字保存到文件中
file1.saveDataToFile("E:/keywords.txt", model);
}
}
});
//修改
reverse.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
DefaultTableModel model = (DefaultTableModel) table.getModel();
stopTableCellEditing(); // 停止单元格编辑,确保获取最新的值
file1.saveDataToFile("E:/keywords.txt", model);
JOptionPane.showMessageDialog(null, "成功更新", "提示", JOptionPane.INFORMATION_MESSAGE);
}
});
setVisible(true);
}
private boolean isKeywordExists(String keyword) {
DefaultTableModel model = (DefaultTableModel) table.getModel();
for (int i = 0; i < model.getRowCount(); i++) {
String existingKeyword = (String) model.getValueAt(i, 1); // 1 是关键字列的索引
if (existingKeyword.equals(keyword)) {
return true; // 关键字已存在
}
}
return false; // 关键字不存在
}
// 停止表格的单元格编辑,确保获取最新编辑过后的值
private void stopTableCellEditing() {
if (table.isEditing()) {
TableCellEditor cellEditor = table.getCellEditor();
if (cellEditor != null) {
cellEditor.stopCellEditing();
}
}
}
}
process类:
import javax.swing.*;
import javax.swing.Timer;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.*;
import java.util.List;
import java.util.regex.Pattern;
public class process extends JFrame {
private JTable table;
private JTextArea j1;
private JLabel j2ImageLabel;
private imagedo imagedo1;
private BufferedImage graphImage;
public process() {
setTitle("词法分析过程");
setSize(880, 660);
setLocationRelativeTo(null);
JMenuBar menuBar=new JMenuBar();
setJMenuBar(menuBar);
JMenu menu=new JMenu("字符表(C)");
menuBar.add(menu);
JMenu menu1=new JMenu("单词分类(W)");
menuBar.add(menu1);
JMenu menu2=new JMenu("关键字表(K)");
menuBar.add(menu2);
JMenu menu3=new JMenu("单字符分界符(S)");
menuBar.add(menu3);
Container all = getContentPane();
setLayout(null);
j1=new JTextArea();
all.add(j1);
j1.setBounds(20,20,200,500);
j2ImageLabel = new JLabel();
all.add(j2ImageLabel);
j2ImageLabel.setBounds(251, 20, 290, 500);
// 获取imagedo类中绘制的图形
imagedo1 = new imagedo();
graphImage = null;
try {
graphImage = imagedo1.getdo();//返回绘制的imagedo1图像
} catch (IOException ex) {
ex.printStackTrace();
}
// 设置JLabel的图标
ImageIcon icon = new ImageIcon(graphImage);
j2ImageLabel.setIcon(icon);
// 创建表格模型
DefaultTableModel model = new DefaultTableModel();
model.addColumn("行号");
model.addColumn("单词内容");
model.addColumn("单词分类");
table = new JTable(model);
JScrollPane scrollPane = new JScrollPane(table);
scrollPane.setBounds(582, 20, 280, 500);
all.add(scrollPane, BorderLayout.CENTER);
JButton a=new JButton("导入源代码");
all.add(a);
a.setBounds(20,540,240,30);
JButton b=new JButton("词法分析");
all.add(b);
b.setBounds(300,540,240,30);
JButton c=new JButton("导出单词");
all.add(c);
c.setBounds(580,540,240,30);
//导入源代码
a.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
importSourceCode();
}
});
//词法分析过程
b.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
performLexicalAnalysis();
}
});
//导出单词
c.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
exportTokens();
}
});
setVisible(true);
}
//传入关键字集合
private Set<String> loadKeywords() {
Set<String> keywords = new HashSet<>();
String filePath = "E:/keywords.txt"; // 关键字文件路径
try (BufferedReader br = new BufferedReader(new FileReader(filePath))) {
String line;
while ((line = br.readLine()) != null) {
// 按逗号分割关键字
String[] keywordArray = line.split(",");
for (String keyword : keywordArray) {
keywords.add(keyword.trim());// 添加到集合中
}
}
} catch (IOException ex) {
ex.printStackTrace();
}
return keywords;//返回Set<String>类型集合
}
//传入单字符分界符
private Set<String> loadSingleCharacters() {
Set<String> characters = new HashSet<>();
try (BufferedReader br = new BufferedReader(new FileReader("E:/singlecharacter.txt")))
{
String line;
while ((line = br.readLine()) != null) {
// 去除空白并按逗号分割
String[] parts = line.trim().split(",");
for (String part : parts) {
characters.add(part);
}
}
} catch (IOException e) {
e.printStackTrace();
}
return characters;
}
//判断是否是关键字
private boolean isKeyword(String word) {
Set<String> keywords = loadKeywords();
return keywords.contains(word);
}
//判断是否是单字符分界符
private boolean isSinglecharacter(String singlecharacter)
{
Set<String> singlecharacters=loadSingleCharacters();
return singlecharacters.contains(singlecharacter);
}
//判断是否是标识符
private boolean isIdentifier(String str) {
// 标识符的正则表达式
String identifierPattern = "^[a-zA-Z_][a-zA-Z0-9_]*$";
return Pattern.matches(identifierPattern, str);
}
// 判断是否是无符号整数
private boolean isUnsignedInteger(String str) {
return str.matches("\\d+"); // 使用正则表达式判断是否是数字
}
//导入源文件
private void importSourceCode() {
JFileChooser fileChooser = new JFileChooser();
// 设置文件选择对话框的标题
fileChooser.setDialogTitle("选择源代码文件");
// 只允许选择文件,而不是文件夹
fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
// 显示文件选择对话框
int result = fileChooser.showOpenDialog(null);
// 处理用户选择
if (result == JFileChooser.APPROVE_OPTION) {
// 获取用户选择的文件
File selectedFile = fileChooser.getSelectedFile();
// 读取文件内容并显示在文本框中
try (BufferedReader br = new BufferedReader(new FileReader(selectedFile))) {
StringBuilder content = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
content.append(line).append("\n");
}
// 将文件内容显示在文本框中
j1.setText(content.toString());
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
// 词法分析过程
private void performLexicalAnalysis() {
DefaultTableModel model = (DefaultTableModel) table.getModel();
model.setRowCount(0);
String sourceCode = j1.getText();
int lineNumber = 1;//每一行为一次
final int[] i = {1};
String[] lines = sourceCode.split("\n");//按行读取
for (String line : lines) {
// 对行进行标记化
List<Token> tokens = tokenizeLine(line);//泛型列表
for (Token token : tokens) {
int finalLineNumber = lineNumber;
Timer timer = new Timer(i[0] * 3000, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// 将标记添加到表格
model.addRow(new Object[]{finalLineNumber, token.getContent(), token.getType()});
changeline(token.getContent());
}
});
timer.setRepeats(false); // 设置为非重复定时器
timer.start();
i[0]++;
}
// 移动到下一行
lineNumber++;
}
}
// 标记的数据结构
private static class Token {
private final String content;//单词内容
private final String type;//单词种类
public Token(String content, String type) {
this.content = content;
this.type = type;
}
public String getContent() {
return content;
}
public String getType() {
return type;
}
}
// 对行进行标记化
private List<Token> tokenizeLine(String line) {
List<Token> tokens = new ArrayList<>();
String[] parts = line.split("\\s+");
for (String part : parts) {
// 处理数组array[]
if (part.contains("[") && part.contains("]")) {
String[] subTokens = part.split("(?<=\\[|\\])|(?=\\[|\\])");// 表示在 [ 或 ] 的前后进行字符串分割。
for (String subToken : subTokens) {
// 处理数组[1..16]
if(subToken.contains("..")){
//在数字和 ".." 之间进行分割。这样,"1..16" 就会被正确分割成 "1"、".." 和 "16"。
String[] subToken1 = subToken.split("(?<=\\d)(?=\\.\\.)|(?<=\\.\\.)(?=\\d)");
for(String sub:subToken1)
tokens.add(new Token(sub, identifyTokenType(sub)));
}
else if (!subToken.isEmpty()) {
tokens.add(new Token(subToken, identifyTokenType(subToken)));
}
else {
}
}
}
//注释情况的处理
else if(part.contains("{")&&part.contains("}")){
tokens.add(new Token("{","注释头符"));
tokens.add(new Token("}","注释尾符"));
}
else if(part.isEmpty())
{//空不做处理
}
else
{
// 处理其他情况
tokens.add(new Token(part, identifyTokenType(part)));
}
}
return tokens;
}
// 添加更多的标记类型识别逻辑
private String identifyTokenType(String token) {
if (isKeyword(token)) {
return "关键字";
} else if (isIdentifier(token)) {
return "标识符";
} else if (isSinglecharacter(token)) {
return "单字符分界符";
} else if(token.equals(":=")){
return "双字符分界符";
}
else if(token.equals("..")){
return "数组下标界限符";
}
else if(isUnsignedInteger(token)){
return "无符号整数";
}
else if(token.equals(".")){
return "程序结束";
}
else if(token.equals("'")){
return "字符串起始、结束符";
}
else {
return "未知类型";
}
}
// 添加更多的标记类型识别逻辑
private String changeline(String token) {
int j=1;
ImageIcon icon = new ImageIcon(graphImage);
if (isKeyword(token)) {
changecolor(graphImage,53, 90, 86, 90);
changecolor(graphImage,112, 90, 172, 90);
changecolor(graphImage,172, 90, 172, 110);
changecolor(graphImage,172, 110, 233, 110);
j2ImageLabel.setIcon(icon);
//直接3秒后触发
Timer timer = new Timer(3000, new ActionListener() {
public void actionPerformed(ActionEvent e) {
recovercolor(graphImage, 53, 90, 86, 90);
recovercolor(graphImage, 112, 90, 172, 90);
recovercolor(graphImage, 172, 90, 172, 110);
recovercolor(graphImage, 172, 110, 233, 110);
j2ImageLabel.setIcon(icon);
}
});
timer.setRepeats(false); // 设置为非重复定时器
timer.start();
return "关键字";
} else if (isIdentifier(token)) {
changecolor(graphImage,53, 90, 86, 90);
changecolor(graphImage,112, 90, 172, 90);
changecolor(graphImage,172, 90, 172, 70);
changecolor(graphImage,172, 70, 233, 70);
j2ImageLabel.setIcon(icon);
Timer timer = new Timer(3000, new ActionListener() {
public void actionPerformed(ActionEvent e) {
recovercolor(graphImage, 53, 90, 86, 90);
recovercolor(graphImage, 112, 90, 172, 90);
recovercolor(graphImage, 172, 90, 172, 70);
recovercolor(graphImage, 172, 70, 233, 70);
j2ImageLabel.setIcon(icon);
}
});
timer.setRepeats(false); // 设置为非重复定时器
timer.start();
return "标识符";
} else if (isSinglecharacter(token)) {
if(token.equals(":")) {
changecolor(graphImage, 53, 190, 86, 190);
changecolor(graphImage, 99, 180, 99, 160);
changecolor(graphImage, 99, 160, 233, 160);
j2ImageLabel.setIcon(icon);
Timer timer = new Timer(3000, new ActionListener() {
public void actionPerformed(ActionEvent e) {
recovercolor(graphImage, 53, 190, 86, 190);
recovercolor(graphImage, 99, 180, 99, 160);
recovercolor(graphImage, 99, 160, 233, 160);
j2ImageLabel.setIcon(icon);
}
});
timer.setRepeats(false); // 设置为非重复定时器
timer.start();
return "单字符分界符";
}
else//单分界符
{
changecolor(graphImage, 53, 140, 233, 140);
j2ImageLabel.setIcon(icon);
Timer timer = new Timer(3000, new ActionListener() {
public void actionPerformed(ActionEvent e) {
recovercolor(graphImage, 53, 140, 233, 140);
j2ImageLabel.setIcon(icon);
}
});
timer.setRepeats(false); // 设置为非重复定时器
timer.start();
return "单字符分界符";
}
} else if(token.equals(":=")){
changecolor(graphImage, 53, 190, 86, 190);
changecolor(graphImage, 109, 190, 145, 190);
changecolor(graphImage, 171, 190, 233, 190);
j2ImageLabel.setIcon(icon);
Timer timer = new Timer(3000, new ActionListener() {
public void actionPerformed(ActionEvent e) {
recovercolor(graphImage, 53, 190, 86, 190);
recovercolor(graphImage, 109, 190, 145, 190);
recovercolor(graphImage, 171, 190, 233, 190);
j2ImageLabel.setIcon(icon);
}
});
timer.setRepeats(false); // 设置为非重复定时器
timer.start();
return "双字符分界符";
}
else if(token.equals("..")){
changecolor(graphImage, 53, 290, 86, 290);
changecolor(graphImage, 112, 290, 125, 290);
changecolor(graphImage, 151, 290, 233, 290);
j2ImageLabel.setIcon(icon);
Timer timer = new Timer(3000, new ActionListener() {
public void actionPerformed(ActionEvent e) {
recovercolor(graphImage, 53, 290, 86, 290);
recovercolor(graphImage, 112, 290, 125, 290);
recovercolor(graphImage, 151, 290, 233, 290);
j2ImageLabel.setIcon(icon);
}
});
timer.setRepeats(false); // 设置为非重复定时器
timer.start();
return "数组下标界限符";
}
else if(isUnsignedInteger(token)){
changecolor(graphImage,63, 40, 86, 40);
changecolor(graphImage,112, 40, 233, 40);
j2ImageLabel.setIcon(icon);
Timer timer = new Timer(3000, new ActionListener() {
public void actionPerformed(ActionEvent e) {
recovercolor(graphImage,63, 40, 86, 40);
recovercolor(graphImage,112, 40, 233, 40);
j2ImageLabel.setIcon(icon);
}
});
timer.setRepeats(false); // 设置为非重复定时器
timer.start();
return "无符号整数";
}
else if(token.equals(".")){
changecolor(graphImage, 53, 290, 86, 290);
changecolor(graphImage, 99, 280, 99, 265);
changecolor(graphImage, 99, 265, 233, 265);
j2ImageLabel.setIcon(icon);
Timer timer = new Timer(3000, new ActionListener() {
public void actionPerformed(ActionEvent e) {
recovercolor(graphImage, 53, 290, 86, 290);
recovercolor(graphImage, 99, 280, 99, 265);
recovercolor(graphImage, 99, 265, 233, 265);
j2ImageLabel.setIcon(icon);
}
});
timer.setRepeats(false); // 设置为非重复定时器
timer.start();
return "程序结束";
}
else if(token.equals("'")){
return "字符串起始、结束符";
}
else {
return "未知类型";
}
}
//导出单词
private void exportTokens() {
// 指定文件路径为 E 盘的 tx.txt
File selectedFile = new File("E:/output.txt");
// 将表格中的单词内容按行号导出到文件
try (BufferedWriter writer = new BufferedWriter(new FileWriter(selectedFile))) {
DefaultTableModel model = (DefaultTableModel) table.getModel();
int rowCount = model.getRowCount();
// 使用 Map<Integer, StringBuilder> 存储每个行号对应的单词内容
Map<Integer, StringBuilder> rowContentMap = new HashMap<>();
// 写入表格数据
for (int i = 0; i < rowCount; i++) {
// 获取行号和单词内容
Object cellValue1 = model.getValueAt(i, 0); // 行号列
Object cellValue2 = model.getValueAt(i, 1); // 单词内容列
// 转换行号为整数
Integer rowNumber = Integer.parseInt(cellValue1.toString());
// 获取当前行号对应的 StringBuilder,如果不存在则创建
StringBuilder rowContent = rowContentMap.computeIfAbsent(rowNumber, k -> new StringBuilder());
// 处理单元格内容,移除 { 和 }
String processedValue = cellValue2.toString().replaceAll("[{}]", "");
// 将处理后的内容拼接到 StringBuilder
rowContent.append(processedValue);
// 在行末尾添加空格分隔符
rowContent.append(" ");
}
// 将拼接好的内容写入文件
for (StringBuilder content : rowContentMap.values()) {
writer.write(content.toString().trim()); // 去除末尾空格
writer.write("\n"); // 在每行末尾添加换行符
}
JOptionPane.showMessageDialog(null, "导出成功!");
} catch (IOException ex) {
ex.printStackTrace();
JOptionPane.showMessageDialog(null, "导出失败:" + ex.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
}
}
protected void changecolor(BufferedImage image,int x1,int y1,int x2,int y2){
Graphics2D graphics=(Graphics2D) image.getGraphics();
Graphics2D g2d = (Graphics2D) graphics;
g2d.setColor(Color.BLUE);
g2d.drawLine(x1, y1, x2, y2);
}
protected void recovercolor(BufferedImage image,int x1,int y1,int x2,int y2){
Graphics2D graphics=(Graphics2D) image.getGraphics();
Graphics2D g2d = (Graphics2D) graphics;
g2d.setColor(Color.RED);
g2d.drawLine(x1, y1, x2, y2);
}
}
Singlecharacter类:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.awt.image.BufferedImage;
public class Test extends JFrame {
private charactertable character1;
private wordclassfy word1;
private keywordstable keywords1;
private Singlecharacter single1;
private process process1;
public Test()
{
setTitle("词法分析器");
setSize(800,560);
setLocationRelativeTo(null);
JMenuBar menuBar=new JMenuBar();
//将菜单栏添加到JFrame窗口中
setJMenuBar(menuBar);
JMenu menu=new JMenu("系统维护(P)");
//将菜单添加到菜单栏上
menuBar.add(menu);
JMenu menu1=new JMenu("词法分析(L)");
menuBar.add(menu1);
JMenu menu2=new JMenu("语法分析(G)");
menuBar.add(menu2);
JMenu menu3=new JMenu("语义分析(S)");
menuBar.add(menu3);
JMenu menu4=new JMenu("中间代码生成(M)");
menuBar.add(menu4);
JMenu menu5=new JMenu("目标代码生成(T)");
menuBar.add(menu5);
JMenu menu6=new JMenu("运行(R)");
menuBar.add(menu6);
JMenu menu7=new JMenu("帮助(H)");
menuBar.add(menu7);
Container all=getContentPane();
setLayout(null);
JButton character=new JButton("字符表");
all.add(character);
character.setBounds(60,100,140,30);
JButton word=new JButton("单词分类");
all.add(word);
word.setBounds(60,180,140,30);
JButton grammer=new JButton("语法规则");
all.add(grammer);
grammer.setBounds(60,260,140,30);
JButton keywords=new JButton("关键字表");
all.add(keywords);
keywords.setBounds(300,100,140,30);
JButton singlecharacter=new JButton("单字符分界符");
all.add(singlecharacter);
singlecharacter.setBounds(300,180,140,30);
JButton dfa=new JButton("词法分析DFA");
all.add(dfa);
dfa.setBounds(300,260,140,30);
JButton processshow=new JButton("词法分析过程展示");
all.add(processshow);
processshow.setBounds(300,340,140,30);
JButton LL1=new JButton("LL(1)分析");
all.add(LL1);
LL1.setBounds(540,100,140,30);
JButton precedenceparse=new JButton("优先分析");
all.add(precedenceparse);
precedenceparse.setBounds(540,180,140,30);
JButton lr=new JButton("LR分析");
all.add(lr);
lr.setBounds(540,260,140,30);
//字符表
character.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
character1=new charactertable();
}
});
//单词分类
word.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
word1=new wordclassfy();
}
});
//关键字表
keywords.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
keywords1=new keywordstable();
}
});
singlecharacter.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
single1=new Singlecharacter();
}
});
processshow.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
process1=new process();
}
});
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置关闭
setVisible(true);//放到最后
}
public static void main(String[] argv) throws IOException {
new Test();
// new process();
}
}
wordclassfy类:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class wordclassfy extends JFrame{
public wordclassfy()
{
setTitle("单词分类");
setSize(380, 480);
setLocationRelativeTo(null);
Container all=getContentPane();
setLayout(null);
JLabel a=new JLabel("标识符");
all.add(a);
a.setBounds(100,20,50,20);
JTextField a1=new JTextField("ID");
all.add(a1);
a1.setBounds(180,20,130,20);
JLabel b=new JLabel("保留字");
all.add(b);
b.setBounds(100,60,50,20);
JTextField b1=new JTextField("标识符子集,内部显示");
all.add(b1);
b1.setBounds(180,60,130,20);
JLabel c=new JLabel("无符号整数");
all.add(c);
c.setBounds(75,100,80,20);
JTextField c1=new JTextField("INTC");
all.add(c1);
c1.setBounds(180,100,130,20);
JLabel d=new JLabel("单字符分界符");
all.add(d);
d.setBounds(65,140,80,20);
JTextField d1=new JTextField("单字符界限符");
all.add(d1);
d1.setBounds(180,140,130,20);
JLabel e=new JLabel("双字符分界符");
all.add(e);
e.setBounds(65,180,80,20);
JTextField e1=new JTextField(":=");
all.add(e1);
e1.setBounds(180,180,130,20);
JLabel f=new JLabel("注释头符");
all.add(f);
f.setBounds(90,220,60,20);
JTextField f1=new JTextField("{");
all.add(f1);
f1.setBounds(180,220,130,20);
JLabel g=new JLabel("注释尾符");
all.add(g);
g.setBounds(90,260,60,20);
JTextField g1=new JTextField("}");
all.add(g1);
g1.setBounds(180,260,130,20);
JLabel h=new JLabel("字符起始、结束符");
all.add(h);
h.setBounds(40,300,110,20);
JTextField h1=new JTextField("'");
all.add(h1);
h1.setBounds(180,300,130,20);
JLabel i=new JLabel("数组下标界限符");
all.add(i);
i.setBounds(55,340,110,20);
JTextField i1=new JTextField("..");
all.add(i1);
i1.setBounds(180,340,130,20);
JButton reverse=new JButton("修改");
all.add(reverse);
reverse.setBounds(65,380,80,30);
JButton cancel=new JButton("取消");
all.add(cancel);
cancel.setBounds(220,380,80,30);
cancel.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
dispose();
}
});
setVisible(true);//放到最后
}
}