编译原理LL1文法分析树(绘图过程)算法实现

简介:
import hjzgg.analysistable.AnalysisTable;
import hjzgg.first.First;
import hjzgg.follow.Follow;
import hjzgg.treenode.TreeNode;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.HeadlessException;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.Map;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

public class TreeGraphic {

    private int fatherNode;//treeGraphic搜素是的开始节点
    private TreeNode[] treeGraphic = null;
    
    private final int distNode = 50;//节点之间的距离
    private final int heightNode = 50;//节点的高度
    private final int widthNode = 50;//节点的宽度
    private final int levelHeight = 100;//层与层之间的高度
    private ArrayList<Rectangle> line = new ArrayList<Rectangle>();
    private int curY = 0;
    private int curX = 10;
    
    public TreeGraphic(int fatherNode, TreeNode[] treeGraphic) {
        super();
        this.fatherNode = fatherNode;
        this.treeGraphic = treeGraphic;
        prepareGraphic();
    }
    
    public class TreeFrame extends JFrame{
        private JPanel panel = new JPanel(){
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                for(Rectangle rect : line){
                    g.drawLine(rect.x, rect.y, rect.width, rect.height);
                }
            }
        };
        private JScrollPane scrollPane = new JScrollPane(panel);
        public TreeFrame() throws HeadlessException {
            super();
            init();
        }

        public TreeFrame(String title) throws HeadlessException {
            super(title);
            init();
        }
        
        private void init(){
            setLayout(new BorderLayout());
            panel.setLayout(null);
            drawTree(fatherNode);
            add(scrollPane, BorderLayout.CENTER);
            int width = curX + 50;
            int height = curY + 50;
            //这里要设置面板的PreferredSize,如果当前Frame大小不能显示PreferredSize那么才会出现滚动条
            panel.setPreferredSize(new Dimension(width, height));
            if(width > 600) width = 600;
            if(height > 300) height = 500;
            setBounds(400, 100, width, height);
            setVisible(true);
        }
        
        public void drawTree(int curNode){
            JLabel label = new JLabel(treeGraphic[curNode].content, JLabel.CENTER);
            label.setBounds(treeGraphic[curNode].getRect());
            label.setFont(new Font("宋体",Font.BOLD, 32));
            label.setOpaque(true);
            label.setBackground(Color.RED);
            panel.add(label);
            if(treeGraphic[curNode].child.size()==0) return;
            int x = treeGraphic[curNode].getRect().x;
            int y = treeGraphic[curNode].getLevel()*levelHeight+heightNode;
            int dist = widthNode / treeGraphic[curNode].child.size();//父节点到子节点连线的距离
            for(int i=0; i<treeGraphic[curNode].child.size(); ++i){
                drawTree(treeGraphic[curNode].child.get(i));
                int xx = treeGraphic[treeGraphic[curNode].child.get(i)].getRect().x + widthNode/2;
                int yy = y+levelHeight-heightNode;
                line.add(new Rectangle(x, y, xx, yy));
                x+=dist;
            }
        }
    }
    
    private void prepareNodeLevel(int curNode, int level){//确定每一个节点的层次
        treeGraphic[curNode].setLevel(level);
        for(int i=0; i<treeGraphic[curNode].child.size(); ++i)
            prepareNodeLevel(treeGraphic[curNode].child.get(i), level+1);
        if(curY < (level+1)*levelHeight) curY = (level+1)*levelHeight;
    }
    
    private void prepareNodeSize(int curNode){//确定节点的坐标位置
        if(treeGraphic[curNode].child.size() == 0){//终结点
            int x = curX; curX+=distNode+widthNode;
            int y = treeGraphic[curNode].getLevel()*levelHeight;
            treeGraphic[curNode].setRect(new Rectangle(x, y, widthNode, heightNode));
            return;
        }
        
        for(int i=0; i<treeGraphic[curNode].child.size(); ++i)
            prepareNodeSize(treeGraphic[curNode].child.get(i));
        int leftChildx=treeGraphic[treeGraphic[curNode].child.get(0)].getRect().x;
        int rightChildx=treeGraphic[treeGraphic[curNode].child.get(treeGraphic[curNode].child.size()-1)].getRect().x;
        //根据左右两边孩子的节点,确定父节点的坐标尺寸
        int parentx = (leftChildx+rightChildx)/2;
        int parenty = treeGraphic[curNode].getLevel()*levelHeight;
        treeGraphic[curNode].setRect(new Rectangle(parentx, parenty, widthNode, heightNode));
    }
    
    private void prepareGraphic(){
        prepareNodeLevel(fatherNode, 0);
        prepareNodeSize(fatherNode);
    }
    
    public static void main(String[] args) {
    //        String[] rightLinearGrammar ={
    //        "S->iCtSA|a",
    //        "A->$|eS", 
    //        "C->b"
    //};
    
    String[] rightLinearGrammar = {
//            "E->TE\'",
//            "E\'->+TE\'|$",
//            "T->FT\'",
//            "T\'->*FT\'|$",
//            "F->(E)|i"
            
            "E->TE\'",
            "E\'->ATE\'|$",
            "T->FT\'",
            "T\'->MFT\'|$",
            "F->(E)|i",
            "A->+|-",
            "M->*|/"
        };
        
    //    String[] rightLinearGrammar = {
    //            "S->ABc",
    //            "A->a|$",
    //            "B->b|$"
    //    };
        
        Map<String, String[]> mp = new LinkedHashMap<String, String[]>();
        try{
            for(int i=0; i<rightLinearGrammar.length; ++i){
                String split1[] = rightLinearGrammar[i].split("->");
                String split2[] = split1[1].split("\\|");
                mp.put(split1[0], split2);
            }
            
        } catch(Exception e){
            e.printStackTrace();
            System.out.println("右线性文法错误!");
        }
        First first = new First(mp);
        first.firstKernealCode();
        Follow follow = new Follow(mp, first.getFirstSet());
        follow.followKernealCode();
        AnalysisTable analysisTable = new AnalysisTable(first.getFirstSet(), follow.getFollowSet(), mp);
        analysisTable.analysisTableKernealCode();
        
        analysisTable.predictiveAnalysis("i+i*(i/i)-i#");
     //通过分析表,在分析句子时产生的分析栈建立分析树,并将分析树返回,利用该程序绘制树
        analysisTable.AnalysisTree();
        TreeGraphic treeGraphic = new TreeGraphic(analysisTable.getFatherNode(), analysisTable.getTreeGraphic());
        treeGraphic.new TreeFrame("语法分析树");
    }
}









本文转自 小眼儿 博客园博客,原文链接:http://www.cnblogs.com/hujunzheng/p/4454777.html,如需转载请自行联系原作者
目录
相关文章
|
3月前
|
机器学习/深度学习 算法 搜索推荐
从理论到实践,Python算法复杂度分析一站式教程,助你轻松驾驭大数据挑战!
【10月更文挑战第4天】在大数据时代,算法效率至关重要。本文从理论入手,介绍时间复杂度和空间复杂度两个核心概念,并通过冒泡排序和快速排序的Python实现详细分析其复杂度。冒泡排序的时间复杂度为O(n^2),空间复杂度为O(1);快速排序平均时间复杂度为O(n log n),空间复杂度为O(log n)。文章还介绍了算法选择、分而治之及空间换时间等优化策略,帮助你在大数据挑战中游刃有余。
113 3
|
12天前
|
存储 算法 测试技术
【C++数据结构——树】二叉树的遍历算法(头歌教学实验平台习题) 【合集】
本任务旨在实现二叉树的遍历,包括先序、中序、后序和层次遍历。首先介绍了二叉树的基本概念与结构定义,并通过C++代码示例展示了如何定义二叉树节点及构建二叉树。接着详细讲解了四种遍历方法的递归实现逻辑,以及层次遍历中队列的应用。最后提供了测试用例和预期输出,确保代码正确性。通过这些内容,帮助读者理解并掌握二叉树遍历的核心思想与实现技巧。
37 2
|
19天前
|
存储 算法 安全
基于哈希表的文件共享平台 C++ 算法实现与分析
在数字化时代,文件共享平台不可或缺。本文探讨哈希表在文件共享中的应用,包括原理、优势及C++实现。哈希表通过键值对快速访问文件元数据(如文件名、大小、位置等),查找时间复杂度为O(1),显著提升查找速度和用户体验。代码示例展示了文件上传和搜索功能,实际应用中需解决哈希冲突、动态扩容和线程安全等问题,以优化性能。
|
28天前
|
缓存 算法 搜索推荐
Java中的算法优化与复杂度分析
在Java开发中,理解和优化算法的时间复杂度和空间复杂度是提升程序性能的关键。通过合理选择数据结构、避免重复计算、应用分治法等策略,可以显著提高算法效率。在实际开发中,应该根据具体需求和场景,选择合适的优化方法,从而编写出高效、可靠的代码。
35 6
|
2月前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
82 1
|
2月前
|
算法
树的遍历算法有哪些?
不同的遍历算法适用于不同的应用场景。深度优先搜索常用于搜索、路径查找等问题;广度优先搜索则在图的最短路径、层次相关的问题中较为常用;而二叉搜索树的遍历在数据排序、查找等方面有重要应用。
47 2
|
3月前
|
并行计算 算法 IDE
【灵码助力Cuda算法分析】分析共享内存的矩阵乘法优化
本文介绍了如何利用通义灵码在Visual Studio 2022中对基于CUDA的共享内存矩阵乘法优化代码进行深入分析。文章从整体程序结构入手,逐步深入到线程调度、矩阵分块、循环展开等关键细节,最后通过带入具体值的方式进一步解析复杂循环逻辑,展示了通义灵码在辅助理解和优化CUDA编程中的强大功能。
|
3月前
|
存储 算法 关系型数据库
数据结构与算法学习二一:多路查找树、二叉树与B树、2-3树、B+树、B*树。(本章为了解基本知识即可,不做代码学习)
这篇文章主要介绍了多路查找树的基本概念,包括二叉树的局限性、多叉树的优化、B树及其变体(如2-3树、B+树、B*树)的特点和应用,旨在帮助读者理解这些数据结构在文件系统和数据库系统中的重要性和效率。
40 0
数据结构与算法学习二一:多路查找树、二叉树与B树、2-3树、B+树、B*树。(本章为了解基本知识即可,不做代码学习)
|
3月前
|
算法
PID算法原理分析
【10月更文挑战第12天】PID控制方法从提出至今已有百余年历史,其由于结构简单、易于实现、鲁棒性好、可靠性高等特点,在机电、冶金、机械、化工等行业中应用广泛。
|
4月前
|
大数据 UED 开发者
实战演练:利用Python的Trie树优化搜索算法,性能飙升不是梦!
在数据密集型应用中,高效搜索算法至关重要。Trie树(前缀树/字典树)通过优化字符串处理和搜索效率成为理想选择。本文通过Python实战演示Trie树构建与应用,显著提升搜索性能。Trie树利用公共前缀减少查询时间,支持快速插入、删除和搜索。以下为简单示例代码,展示如何构建及使用Trie树进行搜索与前缀匹配,适用于自动补全、拼写检查等场景,助力提升应用性能与用户体验。
80 2

热门文章

最新文章