简单的语法分析器

语法分析的主要任务是接收词法分析程序识别出来的单词符号串,判断它们是否由某种语言的文法产生,即判断被识别符号串是否为某语法成分,除此之外,还要进行语法检查,为后面的语义分析和代码生成做准备。 通过语法分析,可以建立相应的语法树,根据建立语法树方式的不同,可以把语法分析过程分为两大类,即自顶向下和自底向上的分析方法。顾名思义,自顶向下的语法分析程序是沿着从树根到树叶的方向建立,而自底向上的方法则是沿着从树叶到树根的方向建立。

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
import java.util.Vector;

/**
 * 备注:
 *
 * @author wangcao
 * @since 2016-5-21 下午9:02:17
 * @version 1.0
 */
    public class Main {
    // *********************************
    private static char[]           VN              = new char[50];     // 非终结符集
    private static char[]           VT              = new char[50];     // 终结符集
    private static String[]         F               = new String[50];       // 产生式集
    private static StringBuffer[]   FirstVN;                                // 非终结符的First集
    private static int[]            staStack        = new int[50];          // 状态分析栈
    private static char[]           symStack        = new char[50];     // 符号分析栈
    private static boolean[]        VNE;                                    // 非终结符与空串的关系表
    private static int              F_index         = 0;                    // 产生式数组指针
    private static int              staStack_index  = 0;                    // 状态栈指针
    private static int              symStack_index  = 0;                    // 符号栈指针
    private static int              ERROR           = Integer.MAX_VALUE;    // 出错标志
    private static char             emp             = ‘ε‘;                  // 空串
    private static String           error           = "x";                  // 分析表显示的出错标志
                                                                            // //
                                                                            // @jve:decl-index=0:
    private static String           acc             = "acc";                // 分析表显示的分析成功标志
    private static Vector           State           = new Vector();     // 项目集
                                                                            // //
                                                                            // @jve:decl-index=0:
    private static int[][]          Action;                             // Action动作数组
    private static int[][]          Goto;                                   // Goto动作数组
    private static StringBuffer[]   bridge1;                                // 描述项目集之间的转换关系,在createLR1()中初始化
    private static int[][]          bridge2;

    // 生成所有与文法有关的数据,比如项目集,分析表等
    public static void createAll() {

        //renew(); // 如果不是第一次使用,一些数组被改动了,所以要恢复
        addf0();
        //displayInformation();
        createFirstVN();
        createLR1();
        createAction();
        createGoto();
    }

    // 从输入的产生式中提取各种信息元素,包括非终结符和终结符
    public static void getElements(String s) {

        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            if (c >= ‘A‘ && c <= ‘Z‘) { // 若是大写字母,认为是非终结符
                if (!isInVN(c)) // 如过不在里面,就加进去
                    VN = String.valueOf(VN)
                                .trim()
                                .concat(String.valueOf(c))
                                .toCharArray();
                // String trim()的功能是返回字符串的副本,忽略前导空白和尾部空白
            } else { // 除大写字母外都认为是终结符
                if (!isInVT(c)) // 终结符在不在VT中?
                    VT = String.valueOf(VT)
                                .trim()
                                .concat(String.valueOf(c))
                                .toCharArray();
            }
        }
        F[F_index++] = new String(s);
    }

    // 判断C是否在数组VN里面
    public static boolean isInVN(char C) {

        String s = String.valueOf(VN);
        if (s.contains(String.valueOf(C))) // C是不是VN数组里的一个元素?
            return true;
        else
            return false;
    }

    // 判断c是否在数组VT中
    public static boolean isInVT(char c) {

        String s = String.valueOf(VT);
        if (s.contains(String.valueOf(c))) // c是不是VT数组里的一个元素
            return true;
        else
            return false;
    }

    // 判断‘.‘是否在s里面
    public static boolean pointIsTheLastOne(String s) {

        if (s.indexOf(‘,‘) - s.indexOf(‘.‘) == 1)
            return true;
        else
            return false;
    }

    // 显示3个TextArea的信息
    public static void displayInformation() {

        System.out.println("非终结符:" + String.valueOf(VN));
        System.out.println("终结符:  " + String.valueOf(VT));
        /*StringBuffer temp = new StringBuffer("产生式:  \n");
        for (int i = 0; i < F.length; i++) {
            if (F[i] != null) { // 如果不是空串
                if (F[i].charAt(0) == ‘@‘)
                    temp.append("(0)S‘" + "==>" + F[0].substring(1) + "\n");// 把"@"用S‘显示
                else if (F[i].length() > 1)
                    temp.append("(" + i + ")" + F[i].charAt(0) + "==>"
                            + F[i].substring(1) + "\n");
                else
                    temp.append("(" + i + ")" + F[i].charAt(0) + "==>" + emp
                            + "\n");
            } else
                break; // 如果是的话就跳出循环
        }
        //System.out.println(temp.toString());// TODO 显示
        // jTextArea2.setText(temp.toString());
*/  }

    // 删除一个产生式,此函数将修改VN、VT、F三个数组
    public static void delete_a_f(int index) {

        String temp = new String(F[index]);
        for (int i = index; F[i] != null; i++) {
            if (F[i + 1] == null) {
                F[i] = null;
                break;
            } else
                F[i] = F[i + 1];
        }
        F_index--;
        StringBuffer sb = new StringBuffer();
        for (int j = 0; F[j] != null; j++) {
            sb.append(F[j]);
        }
        for (int k = 0; k < temp.length(); k++) {
            char c = temp.charAt(k);
            if (!sb.toString()
                    .contains(String.valueOf(c))) {
                if (c >= ‘A‘ && c <= ‘Z‘)
                    delete_a_vn(c);
                else
                    delete_a_vt(c);
            }
        }
    }

    // 若字符c在VN中,就把它删除
    public static void delete_a_vn(char c) {

        for (int i = 0; i < VN.length; i++) {
            if (c == VN[i]) {
                for (int j = i; j < VN.length - 1; j++)
                    VN[j] = VN[j + 1];
                VN = String.valueOf(VN)
                            .subSequence(0, VN.length - 1)
                            .toString()
                            .toCharArray();
                break;
            }
        }
    }

    // 若字符c在VT中,就把它删除
    public static void delete_a_vt(char c) {

        for (int i = 0; i < VT.length; i++) {
            if (c == VT[i]) {
                for (int j = i; j < VT.length - 1; j++)
                    VT[j] = VT[j + 1];
                VT = String.valueOf(VT)
                            .subSequence(0, VT.length - 1)
                            .toString()
                            .toCharArray();
                break;
            }
        }
    }

    // 清除一切使用到的数组和指针
    public static void clearAll() {

        /*
         * VN = new char[50];
         * VT = new char[50];
         * F = new String[50];
         * staStack = new int[50];
         * symStack = new char[50];
         * State = new Vector();
         */
        F_index = 0;
        staStack_index = 0;
        symStack_index = 0;

    }

    public static void addf0() {

        if (F[0].charAt(0) == ‘@‘) return;
        for (int i = F_index; i > 0; i--)
            F[i] = F[i - 1];
        F[0] = ("@" + String.valueOf(VN[0]));
        F_index++;
    }

    // 求一个字符串的First集,此函数再addPoint函数中调用
    public static String createFirst(String s) { // 设s=X1X2X3X4...

        StringBuffer bf = new StringBuffer();
        for (int i = 0; i < s.length(); i++) {
            if (isInVT(s.charAt(i))) { // 如果最左端是终结符的话
                bf = bf.append(s.charAt(i));
                break;
            }
            // 如果Xi(Xi不是最后一个)能推出空串,则First(Xi)-emp属于First(s)
            else if (VNE[String.valueOf(VN)
                                .indexOf(s.charAt(i))] && i != s.length() - 1) {
                String temps = FirstVN[String.valueOf(VN)
                                                .indexOf(s.charAt(i))].toString();
                if (temps.contains(String.valueOf(emp))) { // 如果FirstVN[Xi]含有emp,删除之
                    FirstVN[String.valueOf(VN)
                                    .indexOf(s.charAt(i))].deleteCharAt(emp);
                    bf = bf.append(FirstVN[String.valueOf(VN)
                                                    .indexOf(s.charAt(i))]);
                } else
                    bf = bf.append(FirstVN[String.valueOf(VN)
                                                    .indexOf(s.charAt(i))]);
            } else {// First(Xi)属于First(s)
                bf = bf.append(FirstVN[String.valueOf(VN)
                                                .indexOf(s.charAt(i))]);
                break;
            }
        }
        return bf.toString();
    }

    // 求全体非终结符的First集合,放在FirstVN[]中
    public static void createFirstVN() {

        createVN_emptyTable(); // 生成非终结符能否产生空串表
        FirstVN = new StringBuffer[VN.length];
        for (int ii = 0; ii < FirstVN.length; ii++)
            FirstVN[ii] = new StringBuffer(); // 初始化FirstVN
        for (int i = 0; i < FirstVN.length; i++)
            if (FirstVN[i].toString()
                            .isEmpty()) // 如果还没求过的话
                myFirstVN(VN[i]);
    }

    // 求得一个非终结符的First集,createFirstVN()中调用
    public static void myFirstVN(char c) {

        String svn = String.valueOf(VN); // 中间变量
        for (int i = 1; i < F_index; i++) {
            String s = F[i];
            if (c == s.charAt(0)) {
                if (s.length() == 1) { // 空产生式
                    FirstVN[svn.indexOf(s.charAt(0))].append(emp);
                } else {
                    for (int j = 1; j < s.length(); j++) { // S=>AB..
                        if (isInVT(s.charAt(j))) {
                            FirstVN[svn.indexOf(s.charAt(0))].append(s.charAt(j));
                            break;
                        } else if (c != s.charAt(j)) { // 阻止A=>..A..这样的情况,防止死循环
                            if (VNE[svn.indexOf(s.charAt(j))]) { // 如果A能推出空串,则First(A)-emp属于First(S)
                                if (FirstVN[svn.indexOf(s.charAt(j))].toString()
                                                                        .isEmpty()) // 如果First(A)还没求过的话
                                    myFirstVN(s.charAt(j)); // 先求出A的first
                                if (j != s.length() - 1) { // 如果s.charAt(j)不是最后一个非终结符
                                                            // 如果First(A)中含有emp应该把空串去掉
                                    for (int k = 0; k < FirstVN[svn.indexOf(s.charAt(j))].length(); k++) {
                                        if (FirstVN[svn.indexOf(s.charAt(j))].charAt(k) == emp)
                                            FirstVN[svn.indexOf(s.charAt(j))] = FirstVN[svn.indexOf(s.charAt(j))].deleteCharAt(k);
                                    }
                                }
                                FirstVN[svn.indexOf(s.charAt(0))].append(FirstVN[svn.indexOf(s.charAt(j))]);
                            } else {// 如果A不能推出空串,则First(A)属于First(S)
                                if (FirstVN[svn.indexOf(s.charAt(j))].toString()
                                                                        .isEmpty()) // 如果First(A)还没求过的话
                                    myFirstVN(s.charAt(j)); // 先求出A的first
                                FirstVN[String.valueOf(VN)
                                                .indexOf(s.charAt(0))].append(FirstVN[svn.indexOf(s.charAt(j))]);
                                break; // 这个产生式分析完毕
                            }
                        } else
                            break;
                    }
                }
            }
        }
    }

    // 生成非终结符和空传之间的关系表,即哪些VN能*推导出空串,哪些不能
    public static void createVN_emptyTable() {

        VNE = new boolean[VN.length]; // 非终结符与空串的关系表
        String[] tempF = (String[]) F.clone(); // 取得产生式的副本
        for (int i = 0; i < VNE.length; i++)
            VNE[i] = false; // 初始化非终结符都不能推出空串
        for (int j = 0; j < F_index; j++) { // 删除含有终结符的产生式
            String s = tempF[j];
            for (int k = 0; k < s.length(); k++) {
                if (isInVT(s.charAt(k))) { // 看看这个产生式中是否含有终结符
                    tempF[j] = null;
                    break; // 如果含有的话,删除此产生式
                }
            }
        }
        for (int m = 0; m < F_index; m++) { // 看看哪些产生式可以直接推出空串
            if (tempF[m] != null && tempF[m].length() == 1) { // 空产生式
                VNE[String.valueOf(VN)
                            .indexOf(tempF[m].charAt(0))] = true;
                tempF[m] = null;
            }
        }
        for (int n = 1; n < F_index; n++) { // 不包含添加的S‘,所以n从1开始
                                            // 处理剩下的形如S==>ABCD..的产生式
            char c;
            if (tempF[n] != null) {
                for (int p = 1; p < tempF[n].length(); p++) {
                    c = tempF[n].charAt(p);
                    if (!VNE[String.valueOf(VN)
                                    .indexOf(c)]) // 如果VNE[c]!=true,即c推不出空串
                        break;
                    if (p == tempF[n].length() - 1) //
                        VNE[String.valueOf(VN)
                                    .indexOf(tempF[n].charAt(0))] = true; // 如果ABCD..都能推出空串,则S也能
                }
            }
        }
    }

    /*
     * 生成LR1项目集
     * 整个函数的执行流程大致如下
     * 首先求出I0,即由第一个产生式所导出的所有项目
     * 根据所求的I0,求其他项目集
     * vtemp为上一个项目集,求由它产生的其他项目集
     * 首先求出vtemp中所有项目的‘.‘之后的所有字符,用s1表示,s1中既可能含有VN,也可能含有VF
     * 逐个字符的扫描s1,即第二个for循环,寻找可以产生新项目的项目s2
     * 把s2的‘.‘向后移动一个位置,得到s3
     * 如果s3是新项目,即s3不在当前项目集中,也不在States中,就加入到v
     * 第四个for循环是计算新得到的s3中的‘.‘之后是否为VN,若是的话,求之
     */
    public static void createLR1() { // 生成LR1项目集

        getI0(); // 求出第一个项目集I0
        for (int j = 0; j < State.size(); j++) {
            Vector vtemp = (Vector) State.get(j); // 取得上一个状态集合
            String s1 = getAfterPoint(vtemp); // 取得上一个状态集合中的‘.‘后的所有符号
            for (int m = 0; m < s1.length(); m++) {
                Vector v = new Vector(); // 中间变量
                char c1 = s1.charAt(m); // 从s1中取一个字符
                for (int k = 0; k < vtemp.size(); k++) {
                    String s2 = vtemp.get(k)
                                        .toString();
                    if (!pointIsTheLastOne(s1)
                            && s2.charAt(s2.indexOf(‘.‘) + 1) == c1) { // 此项目不是规约项目,可以尝试加入
                        String s3 = movePoint(s2); // 中间变量
                        if (!isInState(s3) && !isInCurrentState(s3, v)) {
                            v.addElement(s3);
                            for (int g = 0; g < v.size(); g++) {
                                s3 = v.get(g)
                                        .toString();
                                if (!pointIsTheLastOne(s3)) { // 此部分计算与求State0中的新增项目集相同
                                    char c2 = s3.charAt(s3.indexOf(‘.‘) + 1);
                                    if (isInVN(c2)) { // ‘.‘后面的符号是非终结符吗?
                                        for (int n = 0; n < F_index; n++) {
                                            if (c2 == F[n].charAt(0)) {
                                                String s4 = addPoint(F[n], s3);
                                                if (!isInState(s3)
                                                        && !isInCurrentState(s4, v))
                                                    v.addElement(s4);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                if (v.size() > 0) // 只有v里面加入了项目才把整个项目集加入到项目集数组
                    State.add(arrange(v));
            }
        }
        // 初始化两个关系桥
        bridge1 = new StringBuffer[State.size()];
        for (int s = 0; s < State.size(); s++)
            bridge1[s] = new StringBuffer();
        bridge2 = new int[State.size()][50];
    }

    // 获得I0
    public static void getI0() {

        VT = String.valueOf(VT)
                    .concat(String.valueOf(‘#‘))
                    .toCharArray();// 添加句子括号‘#‘
        Vector v0 = new Vector();
        v0.addElement(addPoint(F[0])); // 初始化第一个State0项目,包括加上",#"
        for (int h = 0; h < v0.size(); h++) {
            String s0 = v0.get(h)
                            .toString();
            if (!pointIsTheLastOne(s0)) { // 判断‘.‘是不是最后一个符号
                char c0 = s0.charAt(s0.indexOf(‘.‘) + 1); // 取得‘.‘后面的符号
                if (isInVN(c0)) { // 是否在VN[]中
                    for (int i = 0; i < F_index; i++)
                        if (c0 == F[i].charAt(0)) {
                            if (!isInCurrentState(addPoint(F[i], s0), v0)) // 防止左递归引起的死循环
                                v0.addElement(addPoint(F[i], s0)); // 把新增项目加到第一个State0中
                            //System.out.println("c0" + c0 + s0);
                        }
                }
            }
        }
        // 以下arrange(v0)的作用是整理一下得到的项目集,主要是合并一下形如A=>string,α
        // 和A=>string,β项目集,即吧它们合并成A=>string,αβ的形式
        State.add(arrange(v0)); // 加入到State中
        // State.add(v0);
    }

    // 整理新得到的一个状态,合并其中可以合并的项目2008.8.6 22:27
    public static Vector arrange(Vector v) {

        Vector v0 = new Vector();
        boolean b[] = new boolean[v.size()]; // 用来标记对应的项目是否已经被处理过,初始化为都未处理
        for (int m = 0; m < b.length; m++)
            b[m] = false;
        String si = new String();
        String sj = new String();
        StringBuffer bf;
        for (int i = 0; i < v.size(); i++) {
            if (b[i] == true) // 如果此项目已归并完毕则处理下一项
                continue;
            si = v.get(i)
                    .toString(); // 获得第i个项目
            bf = new StringBuffer(si);
            for (int j = i + 1; j < v.size(); j++) {
                sj = v.get(j)
                        .toString();
                // 如果si项目的逗号之前的部分与sj项目的逗号之前的部分相同,则合并它们,
                // 即把第二个项目逗号之后部分加到第一个项目逗号之后
                if (si.substring(0, si.indexOf(String.valueOf(‘,‘)))
                        .equals(sj.substring(0, sj.indexOf(String.valueOf(‘,‘))))) {
                    bf = bf.append(sj.substring(sj.indexOf(String.valueOf(‘,‘)) + 1, sj.length()));
                    b[j] = true; // 标记为已处理
                }
            }
            v0.addElement(bf.toString());
        }
        return v0;
    }

    // 判断s在当前状态集中是否已经存在
    public static boolean isInCurrentState(String s, Vector v) {

        for (int i = 0; i < v.size(); i++) {
            if (s.equals(v.get(i)
                            .toString())) return true;
        }
        return false;
    }

    // 生成分析表里的Action部分
    private static void createAction() {

        Action = new int[State.size()][VT.length];
        for (int i = 0; i < State.size(); i++) {
            for (int j = 0; j < VT.length; j++) {
                Action[i][j] = getAction(i, j);
            }
        }
    }

    // 生成分析表里的Goto部分
    private static void createGoto() {

        Goto = new int[State.size()][VN.length];
        for (int i = 0; i < State.size(); i++) {
            for (int j = 0; j < VN.length; j++) {
                Goto[i][j] = getGoto(i, j);
            }
        }
    }

    // 对输入的一字符串进行分析
    private static void analysisInPutString(String s) {

        createAll();
        s = s.concat(String.valueOf(‘#‘)); // 添加句子括号‘#‘,以便分析
        int s_index = 0; // 次索引指向被分析符号串的头
        int i = 0;
        int j = 0;
        int k = 0; // 中间变量
        int step = 0;
        staStack[0] = 0;
        symStack[0] = ‘#‘; // 初始化状态栈与符号栈
        while (true) {
            step++; // 步骤数加1
            i = staStack[staStack_index]; // 栈顶状态
            j = toColumn(s.charAt(s_index)); // 被分析符号头字符在vt数组中的位置
            if (isInVT(s.charAt(s_index)) && j != ERROR) { // 如果是非终结符
                if (Action[i][j] > 0) { // 如果是移进
                    k = Action[i][j];
                    if (k == ERROR) {
                        /*System.out.println("分析失败!\n" + "出错原因:在第" + step
                                + "步分析到第" + i + "个状态时," + "当前面临的符号是"
                                + s.charAt(s_index) + ",\n而在分析表的Action表中(" + i
                                + "," + s.charAt(s_index) + ")这个位置" + "是出错标志!");*/
                        System.out.println("no");
                        break;
                    }
                    staStack[++staStack_index] = k;
                    symStack[++symStack_index] = s.charAt(s_index++);
                } else if (Action[i][j] < 0) { // 如果是归约
                    k = -Action[i][j]; // 按照第k个产生式归约
                    staStack_index -= F[k].length() - 1; // 栈指针减去第k个产生式的右部的长度
                    symStack_index -= F[k].length() - 1;
                    symStack[symStack_index++] = F[k].charAt(0);// 把句柄归约
                    int temp = Goto[staStack[staStack_index]][toColumn(F[k].charAt(0))];// 取得Goto[栈顶状态][刚规约完的VN]
                    if (temp == ERROR) {
                        /*System.out.println("分析失败!\n" + "出错原因:在第" + step
                                + "步分析到第" + staStack[staStack_index] + "个状态时,"
                                + "当前面临的符号是" + F[k].charAt(0)
                                + ",\n而在分析表的Goto表中(" + staStack[staStack_index]
                                + "," + F[k].charAt(0) + ")这个位置是出错标志!");*/
                        System.out.println("no");
                        break;
                    }
                    staStack[++staStack_index] = temp;
                } else {
                    /*System.out.println("分析成功!此符号串是这个文法的句子!");*/
                    System.out.println("yes");
                    break;
                }
            } else {
                /*System.out.println("分析失败!\n" + "出错原因:在第" + step + "步当前面临符号"
                        + s.charAt(s_index) + "不属于该文法的终结符!");*/
                System.out.println("no");
                break;
            }
        }
    }

    // 恢复
    private static void renew() {

        delete_a_vt(‘#‘); // 删掉添加的开始符号‘#‘
        staStack = new int[50];
        symStack = new char[50];
        State = new Vector();
        staStack_index = 0;
        symStack_index = 0;
    }

    // 在产生式S的右部的最前端加上一个‘.‘
    private static String addPoint(String s) {

        StringBuffer bf = new StringBuffer(String.valueOf(s.charAt(0)));
        bf.append(‘.‘);
        bf.append(s.substring(1));
        if (s.equals(F[0])) // 如果是附加产生式,直接加上",#"
            bf.append(",#");
        return bf.toString();
    }

    // s1是s2的附加项目集s2:A->α.Bβ,a s1:B->.γ,b 其中b属于First(βa)
    private static String addPoint(String s1, String s2) {

        StringBuffer bf = new StringBuffer(String.valueOf(s1.charAt(0)));
        StringBuffer bf1 = new StringBuffer(); // 取得βa
        bf.append(‘.‘);
        bf.append(s1.substring(1));
        bf.append(‘,‘);
        bf1.append(s2.substring(s2.indexOf(‘.‘) + 2)); // 取得βa
        if (bf1.indexOf(String.valueOf(‘,‘)) == 0
                || createFirst(bf1.substring(0, bf1.indexOf(String.valueOf(‘,‘)))).contains(String.valueOf(emp))) {
            // 如果β是空串或者可以推出空串的话,那么逗号后面的都属于b
            bf.append(bf1.substring(bf1.indexOf(String.valueOf(‘,‘)) + 1));
        } else { // 否则的话
            bf1.deleteCharAt(bf1.indexOf(String.valueOf(‘,‘)));
            bf.append(createFirst(bf1.toString()));
        }
        return bf.toString();
    }

    // 把‘.’向后移一个位置
    private static String movePoint(String s) {

        char[] c = s.toCharArray();
        char temp = s.charAt(s.indexOf(‘.‘) + 1); // 取得‘.‘后面的字符,放入中间变量,以便和‘.‘交换位置
        c[s.indexOf(‘.‘)] = temp;
        c[s.indexOf(‘.‘) + 1] = ‘.‘;
        return String.valueOf(c);
    }

    // 取得一个状态集的‘,‘之后的符号集合,以便求出此状态的下一个状态
    private static String getAfterPoint(Vector v) {

        StringBuffer bf = new StringBuffer();
        for (int i = 0; i < v.size(); i++) {
            String s = v.get(i)
                        .toString();
            if (!pointIsTheLastOne(s)) { // ‘.‘不是最后一个字符
                char c = s.charAt(s.indexOf(‘.‘) + 1);
                if (!bf.toString()
                        .contains(String.valueOf(c))) bf.append(c);
            }
        }
        return bf.toString();
    }

    // 检查一个项目是否已存在
    private static boolean isInState(String s) {

        Vector v = new Vector();
        for (int i = 0; i < State.size(); i++) {
            v = (Vector) State.get(i);
            for (int j = 0; j < v.size(); j++) {
                if (s.equals(v.get(j)
                                .toString())) return true;
            }
        }
        return false;
    }

    // i为状态行,j为终结符列,确定(i,j)这个位置应该是什么动作(移进,规约,接受,出错)
    private static int getAction(int i, int j) {

        Vector v = (Vector) State.get(i); // 第i个项目集合
        char c = VT[j]; // 第j个终结符,此时VT已添加了句子括号‘#‘,所以c可以等于‘#‘
        // 以下部分是移进动作
        if (isInAfterPoint(c, v)) { // 如果此终结符是这个项目集的‘.‘后面的符号,则检查其移进后的状态
            for (int k = 0; k < v.size(); k++) { // 查找c在这个项目集的位置
                String s = v.get(k)
                            .toString();
                if ((!pointIsTheLastOne(s))
                        && c == s.charAt(s.indexOf(‘.‘) + 1)) { // 如果‘.‘不是最后一个符号,移进
                    for (int m = 0; m < State.size(); m++) {
                        Vector vtemp = (Vector) State.get(m);
                        for (int n = 0; n < vtemp.size(); n++) {
                            if (movePoint(s).equals(vtemp.get(n)
                                                            .toString())) {
                                bridge1[i].append(c);
                                bridge2[i][bridge1[i].length() - 1] = m;
                                return m; // 进入m项目集,即当前状态经c字符后变成下一个m状态
                            }
                        }
                    }
                }
            }
        }
        for (int p = 0; p < v.size(); p++) {
            if (pointIsTheLastOne(v.get(p)
                                    .toString())) {
                String s1 = delete_a_char(‘.‘, v.get(p)
                                                .toString()); // 去掉‘.‘
                String s2 = s1.substring(0, s1.indexOf(‘,‘));
                for (int q = 0; q < F_index; q++) {
                    if (s2.equals(F[q])) {
                        if (s1.substring(s1.indexOf(‘,‘))
                                .contains(String.valueOf(c))) // 规约项目逗号后面是否含有c
                            return -q;
                    }
                }
            }
        }
        return ERROR; // 出错
    }

    // 判断一个字符c是否在状态v里项目中‘.’之后的字符
    private static boolean isInAfterPoint(char c, Vector v) {

        String s = getAfterPoint(v);
        if (s.contains(String.valueOf(c)))
            return true;
        else
            return false;
    }

    // 返回删除一个源字符串中的指定字符得到的字符串,并不影响源字符串
    private static String delete_a_char(char c, String s) {

        StringBuffer bf = new StringBuffer(s);
        return bf.subSequence(0, bf.indexOf(String.valueOf(c)))
                    .toString()
                    .concat(bf.substring(bf.indexOf(String.valueOf(c)) + 1));
    }

    // i为状态行,j为非终结符列,确定状态i经过一个非终结符j后进入哪个状态
    private static int getGoto(int i, int j) {

        Vector v = (Vector) State.get(i); // 第i个项目集合
        char c = VN[j]; // 第j个非终结符
        if (isInAfterPoint(c, v)) { // 如果此非终结符是这个项目集的‘.‘后面的符号,则进行处理
            for (int k = 0; k < v.size(); k++) { // 查找c在这个项目集的位置
                String s = v.get(k)
                            .toString();
                if ((!pointIsTheLastOne(s))
                        && c == s.charAt(s.indexOf(‘.‘) + 1)) { // 如果c不是最后一个符号
                    for (int m = 0; m < State.size(); m++) {
                        Vector vtemp = (Vector) State.get(m);
                        for (int n = 0; n < vtemp.size(); n++) {
                            if (movePoint(s).equals(vtemp.get(n)
                                                            .toString())) {
                                bridge1[i].append(c);
                                bridge2[i][bridge1[i].length() - 1] = m;
                                return m; // 当前状态经非终结符c字符后进入下一个m状态
                            }
                        }
                    }
                }
            }
        }
        return ERROR; // 出错
    }

    // 把待分析字符转换成在VN与VT里的序号
    private static int toColumn(char c) {

        if (isInVT(c)) // 如果是非终结符
            for (int i = 0; i < VT.length; i++) {
                if (c == VT[i]) return i;
            }
        else if (isInVN(c)) for (int j = 0; j < VN.length; j++) {
            if (c == VN[j]) return j;
        }
        return ERROR; // 出错
    }

    /**
     * @param args
     */
    public static void main(String[] args) {

        // TODO 自动生成的方法存根
        Scanner in = null;
        try {
            in = new Scanner(new File("d:\\yufafenxi_in.txt"));
        } catch (FileNotFoundException e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        }
        //System.out.println("产生式:");
        while (in.hasNextLine()) {
            String s = in.nextLine();
            //System.out.println(s);

            getElements(s.replaceAll("->", ""));
        }
        try {
            in = new Scanner(new File("d:\\yufafenxi_juzi.txt"));
        } catch (FileNotFoundException e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        }
        if (in.hasNextLine()) {
            String s = in.nextLine();
            //System.out.println("待测句子:"+s);
            analysisInPutString(s);
        }
    }

}
时间: 2024-11-05 11:26:44

简单的语法分析器的相关文章

小白天堂之编写词法语法分析器何其简单(一)

写小白天堂系列的文章算是从这一篇开始吧,但是写这个词法语法分析器实在是因为编译原理老师扣啊,哎,没办法,只能直接写代码,当时正好将Javascript的语法基本撸了一边,所以就决定写一个JS的词法语法分析器,嗯,当然这个写哪种编程语法的分析器都一样,最多是在词法分析器中有点区别,他们的语法分析器几乎都是一样的,构造First集,Follow集,然后就是构建出预测分析表M基本就OK了,如果你还想增加Select集也可以,虽然这个东西可以不写,但是有些教科书上却讲了这个东西. 也许上面说的东西,有些

构造可配置词法语法分析器生成器(下)

本文为笔者原创,转载请注明出处 http://blog.csdn.net/xinghongduo mylex & xparser mylex & xparser是笔者实现的类似于Lex和Yacc的词法语法分析器生成器,它接受正则表达式定义的词法规则和BNF定义的语法规则,自动构造对应的以C为宿主语言的词法分析器源程序mylex.h, mylex.c和语法分析器源程序xparser.h, xparser.c. mylex & xparser特点如下: 轻量无依赖:构造器的主要代码仅2

构造可配置词法语法分析器生成器(上)

本文为笔者原创,转载请注明出处 http://blog.csdn.net/xinghongduo 前言 源程序在被编译为目标程序需要经过如下6个过程:词法分析,语法分析,语义分析,中间代码生成,代码优化,目标代码生成.词法分析和语法分析是编译过程的初始阶段,是编译器的重要组成部分,早期相关理论和工具缺乏的环境下,编写词法语法分析器是很繁琐的事情.上世纪70年代,贝尔实验室的M. E. Lesk,E. Schmidt和Stephen C. Johnson分别为Unix系统编写了词法分析器生成器Le

构造可配置词法语法分析器生成器(中)

本文为笔者原创,转载请注明出处 http://blog.csdn.net/xinghongduo   语法分析器 语法分析器(grammar parser)是编译器的核心部分之一,它的作用是检测词法分析器返回的token序列是否符合文法定义的规则.一个完整的语法分析器除了检测语法正确性外还要包含对出错的处理以及错误恢复等功能. 文法和文法类型 文法是定义一个语言的所有规则的集合,形式上定义为四元组G={VT,VN,S,P},其中: VT是非空有限符号集合,它的每个符号称为终结符,文法产生的语言由

基于语法分析器GOLD Parser开发的数学表达式计算器

最近发现一款文法分析神器,看完官网(http://goldparser.org/)的介绍后感觉很犀利的样子,于是就拿来测试了一番,写了一个数学表达式分析的小程序,支持的数学运算符如下所示:常规运算:+ - * / ^ sqrt sqrt2(a,b) pow2(a) pow(a,b)三角函数:sin cos tan cot asin acos atan acot指数对数:log2(a) log10(a) ln(a) logn(a,b) e^最大最小:max(a,b,...) min(a,b,...

编译原理 - 实验三 - 递归下降语法分析器的调试及扩展

一. 语法分析介绍 语法分析是编译过程的核心部分,它的主要任务是按照程序语言的语法规则,从由词法分析输出的源程序符号串中识别出各类语法成分,同时进行语法检查,为语义分析和代码生成做准备.执行语法分析任务的程序叫语法分析程序或语法分析器. 二. 所实现的语义分析和代码生成程序能处理什么语句 (1)简单变量的声明语句 (2)表达式语句 (3)if语句. (4)while语句 (5)for语句 (6)write语句 (7)read语句 (8)do语句. (9)处理过程调用和返回 三.实验过程 ①用VC

语法分析器自动生成工具一览

Lex/Yacc 它生于Unix,是最经典的词法\语法分析器,是经典教材中的示例御用工具.现在它也支持在Windows上生成(安装环境),然而其所生成语法分析器的语言仅有C语言. Flex/Bison 与前者类似,Bison与Yacc有很高的兼容性.生成语言为C.C++和Java. CoCo/R 较早的一个语法分析器生成工具.其生成语法分析器的语言极其之多,包括C#. Java. C++.F#.VB.Net.Oberon等等. ANTLR 作为翻译程序的一部分,你可以使用简单的操作符和动作来参数

LR(1)语法分析器生成器(生成Action表和Goto表)java实现(二)

本来这次想好好写一下博客的...结果耐心有限,又想着烂尾总比断更好些.于是还是把后续代码贴上.不过后续代码是继续贴在BNF容器里面的...可能会显得有些臃肿.但目前管不了那么多了.先贴上来吧hhh.说不定哪天觉得羞耻又改了呢.参考资料建议参考<编译器设计>一书. 目前完成进度 : 目前已经完成了表驱动,通过函数输出这个Action 和 Goto表.然后使用者就可以根据两个表来进行LR(1)语法分析.且经过比对,发现和书上的例子(括号语法)是完全吻合的. 1 package cn.vizdl.L

两周自制脚本语言-第5天 设计语法分析器

第5天 设计语法分析器 5.1 Stone语言的语法 代码清单 5.1 Stone 语言的语法定义 primary : "(" expr ")" | NUMBER | IDENTIFIER | STRING factor : "-" primary | primary expr : factor { OP factor } block : "{" [ statement ] { (";" | EOL) [