JS语法分析器

设计要求:对于任意输入的一个LL(1)文法,构造其预测分析表,并对指定输入串分析其是否为该文法的句子。

思路:首先实现集合FIRST(X)构造算法和集合FOLLOW(A)构造算法,再根据FIRST和FOLLOW集合构造出预测分析表,并对指定的句子打印出分析栈的分析过程,判断是否为该文法的句子。但是现在只是实现了构造预测分析表,并进行分析。

程序结构:


production是指定文法内容如下:


main文件内容:

var fs = require('fs');
function control() {
    var terminator = ['+', '*', 'i', '<', '>', '#'];
    var nonterminator = ['E', 'T', 'K', 'F', 'M'];
    var FI = [['<', 'i'], ['<', 'i'], ['$', '+'], ['<', 'i'], ['$', '*']];
    var FO = [['#', '>'], ['#', '>', '+'], ['#', '>'], ['#', '>', '+', '*'], ['#', '>', '+']];
    fs.readFile('production', 'UTF-8', function (err, data) {
        var test = data.toString().split('->');
        test = test.toString().split('\n');
        // console.log(test)
        // console.log(test[0].slice(2,4))
    })
    var analyse = {
        'Ei': 'TK',
        'E<': 'TK',
        'Ti': 'FM',
        'T<': 'FM',
        'K+': '+TK',
        'Fi': 'i',
        'F<': '<E>',
        'M*': '*FM'
    }
    //定义分析表
    var analysisTable = new Array;
    for (i = 0; i < 100; i++) {
        analysisTable[i] = new Array();
    }

    for (var i = 0; i < nonterminator.length; i++) {

        if (FI[i].find(tag1=>FI[i].some(b=>b === '$'))) {

            var newF = (FI[i].concat(FO[i])).filter(b=>b != '$');
            for (var j = 0; j < terminator.length; j++) {

                if (FI[i].find(tag=>FI[i].some(b=>b === terminator[j]))) {

                    analysisTable[i][j] = analyse[nonterminator[i].concat(terminator[j])];
                } else if (newF.find(tag=>newF.some(b=>b === terminator[j]))) {
                    analysisTable[i][j] = '$';
                } else {
                    analysisTable[i][j] = 'error';
                }
            }
        } else {

            for (var j = 0; j < terminator.length; j++) {

                if (FI[i].find(tag=>FI[i].some(b=>b === terminator[j]))) {
                    analysisTable[i][j] = analyse[nonterminator[i].concat(terminator[j])];
                } else {
                    analysisTable[i][j] = 'error';
                }

            }
        }


    }
    //对字符串的分析过程
    var stack = '#E';

    fs.readFile('test', 'UTF-8', function (err, data) {

            var inputs = data.toString().split('');
            while (stack.length != 0) {
                if (inputs[0] === stack[stack.length - 1] && inputs[0] === '#') {
                    console.log('Accept');
                    return;
                } else if (inputs[0] === stack[stack.length - 1]) {
                    console.log(stack, inputs.join(''), inputs[0] + '匹配成功');
                    stack = stack.slice(0, stack.length - 1);
                    inputs = inputs.slice(1, inputs.length);
                } else {
                    var col = nonterminator.indexOf(stack[stack.length - 1]);
                    var row = terminator.indexOf(inputs[0]);
                    var tag = analysisTable[col][row];
                    if (tag === 'error') {
                        console.log('error');
                        return
                    } else if (tag === '$') {
                        console.log(stack, inputs.join(''), '$');
                        stack = stack.slice(0, stack.length - 1);
                    } else {
                        console.log(stack, inputs.join(''), tag);
                        stack = stack.slice(0, stack.length - 1);
                        for (var j = tag.length - 1; j >= 0; j--) {
                            stack += tag[j];
                        }
                    }
                }
            }
        }
    )
}

control();

test文件输入串:

输入

i+i*i#
结果截屏:

输入:
i+i*ii#
结果截屏:

代码实现思路:

(1)求FIRST集的算法思想

如果产生式右部第一个字符为终结符,则将其计入左部first集  如果产生式右部第一个字符为非终结符  ->求该非终结符的first集  ->将该非终结符的非$first集计入左部的first集 ->若存在$,则将指向产生式的指针右移 ->若不存在$,则停止遍历该产生式,进入下一个产生式 ->若已经到达产生式的最右部的非终结符,则将$加入左部的first集  处理数组中重复的first集中的终结符

(2)求FOLLOW集的算法思想

 对于文法G中每个非终结符A构造FOLLOW(A)的办法是,连续使用下面的规则,直到每个FOLLOW不在增大为止. (1) 对于文法的开始符号S,置#于FOLLOW(S)中; (2) 若A->aBb是一个产生式,则把FIRST(b)\{ε}加至FOLLOW(B)中; (3) 若A->aB是一个产生式,或A->aBb是一个产生式而b=>ε(即ε∈FIRST(b))则把FOLLOW(A)加至FOLLOW(B)中

(3)生成预测分析表的算法思想

构造分析表M的算法是:   (1) 对文法G的每个产生式A->a执行第二步和第三步;  (2) 对每个终结符a∈FIRST(a),把A->a加至M[A,a]中;  (3) 若ε∈FIRST(a),则把任何b∈FOLLOW(A)把A->a加至M[A,b]中;  (4) 把所有无定义的M[A,a]标上出错标志.

(4)对符号串的分析过程

 预测分析程序的总控程序在任何时候都是按STACK栈顶符号X和当前的输入符号行事的,对于任何(X,a),总控程序  每次都执行下述三种可能的动作之一; (1) 若X=a=”#”,则宣布分析成功,停止分析过程. (2) 若X=a≠”#”,则把X从STACK栈顶逐出,让a指向下一个输入符号. (3) 若X是一个非终结符,则查看分析表M,若M[A,a]中存放着关于X的一个产生式,那么,首先把X逐出STACK栈顶,然后 把产生式的右部符号串按反序一一推进STACK栈(若右部符号为ε,则意味着不推什么东西进栈).在把产生式的右部 符号推进栈的同时应做这个产生式相应得语义动作,若M[A,a]中存放着”出错标志”,则调用出错诊察程序ERROR.

总结:不停查阅文档请教同学,才彻底理解了这次实验的思路以及需要实现的内容。用了一个通宵的时间然后一点点
实现了每一步的功能。最开始实现的就是总控程序,做了才发现其实只要明白了原理是很简单很容易实现的。
然后就是实现预测分析表,这个因为与上下关系比较紧密,实现起来比较复杂,最后是低级的实现了一下,就是实现
预测分析的时候要求在上一步实现的FIRST集与FOLLOW集中将他们相对应的过程存放在analyse这个对象表中
用了很长时间没有实现FIRST与FOLLOW集合最后因为时间关系放弃实现这FIRST与FOLLOW。
个人反思:不要放弃,开始做这个实验的时候我绝对没有想到我会实现到现在这一步,很开心,虽然用了很长的时间,
但是那种收获感也让人很激动。所以以后不管遇到什么样的难题,大不了我们就像蜗牛一样,一小步一小步的去实现它
总会获得成功的,哪怕只是迟一点而已。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值