编译原理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("语法分析树");
    }
}
时间: 2024-12-09 10:51:42

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

编译原理LL1文法分析表算法实现

import hjzgg.first.First; import hjzgg.follow.Follow; import hjzgg.tablenode.TableNode; import hjzgg.treenode.TreeNode; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; import java.util.Stack; im

编译原理 LL1文法First集算法实现

import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; public class First { private Map<String, Set<Character>> first = new TreeMap<String, Set<Character>>();

编译原理LL1文法Follow集算法实现

import hjzgg.first.First; import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; public class Follow { private Map<String, Set<Character>> first = null; private Map<St

编译原理之文法

关于编译原理这块之前根本没有涉及过,这次要用到这里的知识就需要来接触一下这里的内容.编译原理顾名思义就是处理高级语言,使之称为计算机能够识别的语言(低级语言)的原理.而文法呢?就是用来描述程序设计语言的方法.类似佛法,用来描述佛家的诵经禅道的规则的.不用去纠结这个名字,知道这个含义,足以. 文法 概念 终结符和非终结符 如图:在p这个推导式的集合中,存在六个推导式.其中S.A.B为非终结符.a.b.c.d.q.p为终结符.终结符是原子不可分的. 分类 文法的分类也就这几种了,先看各自的定义,在定

编译原理:正规式转变成DFA算法

//将正规式转变成NFA package hjzgg.formal_ceremony_to_dfa; import java.util.ArrayList; class Edge{ public int u, v; public char key; public Edge(int u, int v, char key) { super(); this.u = u; this.v = v; this.key = key; } @Override public String toString() {

【编译原理】语法分析LL(1)分析法的FIRST和FOLLOW集

近来复习编译原理,语法分析中的自上而下LL(1)分析法,需要构造求出一个文法的FIRST和FOLLOW集,然后构造分析表,利用分析表+一个栈来做自上而下的语法分析(递归下降/预测分析),可是这个FIRST集合FOLLOW集看得我头大... 教课书上的规则如下,用我理解的语言描述的: 任意符号α的FIRST集求法: 1. α为终结符,则把它自身加入FIRSRT(α) 2. α为非终结符,则: (1)若存在产生式α->a...,则把a加入FIRST(α),其中a可以为ε (2)若存在一串非终结符Y1

编译原理

编译原理 语法是指这样的一组规则,用它可以形成和产生一个合适的程序. 词法规则是指单词符号的形成规则. 语法规则是语法单位的形成规则,规定了如何从单词符号形成更大的结构(即语法单位或语法范畴). 一般程序语言的语法单位有:表达式.语句.分程序.函数.过程和程序等. 程序语言的基本功能是描述数据和对数据的运算.所谓程序,从本质上来说是描述一定数据的处理过程.   强制式语言也称过程式语言.其特点是命令驱动,面向语句.一个强制式语言程序由一系列的语句组成,每个语句的执行引起若干存储单元中的值的改变.

《编译原理实践与指导教程》——1.2 实验指导

1.2 实验指导 词法分析和语法分析这两块,可以说是在整个编译器当中被自动化得最好的部分.也就是说即使没有任何的理论基础,在掌握了工具的用法之后,也可以在短时间内做出功能很全很棒的词法分析程序和语法分析程序.当然这并不意味着,词法分析和语法分析部分的理论基础并不重要.恰恰相反,这一部分被认为是计算机理论在工程实践中最成功的应用之一,对它的介绍也是编译理论课中的重点.但本节指导内容的重点不在于理论而在于工具的使用. 本节指导内容将分别介绍词法分析工具GNU Flex和语法分析工具GNU Bison

大前端开发者需要了解的基础编译原理和语言知识

在我刚刚进入大学,从零开始学习 C 语言的时候,我就不断的从学长的口中听到一个又一个语言,比如 C++.Java.Python.JavaScript 这些大众的,也有 Lisp.Perl.Ruby 这些相对小众的.一般来说,当程序员讨论一门语言的时候,默认的上下文经常是:"用 xxx 语言来完成 xxx 任务".所以一直困扰着的我的一个问题就是,为什么完成某个任务,一定要选择特定的语言,比如安卓开发是 Java,前端要用 JavaScript,iOS 开发使用 Objective-C